]> git.neil.brown.name Git - history.git/commitdiff
Linux 2.0.36pre14 2.0.36pre14
authorAlan Cox <alan@lxorguk.ukuu.org.uk>
Fri, 23 Nov 2007 20:12:02 +0000 (15:12 -0500)
committerAlan Cox <alan@lxorguk.ukuu.org.uk>
Fri, 23 Nov 2007 20:12:02 +0000 (15:12 -0500)
The big highlights of this update are all SCSI

o AIC7xxx revision 5.1 - this is the Adaptec driver that should
support all the new stuff nicely
o Updated ICP vortex driver. This supports all the current models
including the LVD and fibrechannel controllers Im told
o AMI Megaraid controller support

Additional changes

o The tcp oopses a very few people saw on extremely loaded boxes,
or brutal beat up machine tests should be gone

o mmap of very high addresses patch from 2.1.x

o block read ahead bug fix from 2.1.x

o Cyclades patch

o de4x5 update

o configuration files bug fixes.

40 files changed:
CREDITS
Documentation/Configure.help
drivers/net/de4x5.c
drivers/net/pcnet32.c
drivers/net/soundmodem/sm_tbl_afsk1200.h [new file with mode: 0644]
drivers/net/soundmodem/sm_tbl_afsk2400_7.h [new file with mode: 0644]
drivers/net/soundmodem/sm_tbl_afsk2400_8.h [new file with mode: 0644]
drivers/net/soundmodem/sm_tbl_afsk2666.h [new file with mode: 0644]
drivers/net/soundmodem/sm_tbl_fsk9600.h [new file with mode: 0644]
drivers/net/soundmodem/sm_tbl_hapn4800.h [new file with mode: 0644]
drivers/net/soundmodem/sm_tbl_psk4800.h [new file with mode: 0644]
drivers/pci/pci.c
drivers/scsi/Config.in
drivers/scsi/Makefile
drivers/scsi/README.aic7xxx
drivers/scsi/aic7xxx.c
drivers/scsi/aic7xxx/aic7xxx.reg
drivers/scsi/aic7xxx/aic7xxx.seq
drivers/scsi/aic7xxx/bsd_q.h [new file with mode: 0644]
drivers/scsi/aic7xxx/sequencer.h
drivers/scsi/aic7xxx_proc.c
drivers/scsi/aic7xxx_reg.h
drivers/scsi/aic7xxx_seq.c [new file with mode: 0644]
drivers/scsi/aic7xxx_seq.h [deleted file]
drivers/scsi/gdth.c
drivers/scsi/gdth.h
drivers/scsi/gdth_proc.c
drivers/scsi/gdth_proc.h
drivers/scsi/hosts.c
drivers/scsi/megaraid.c [new file with mode: 0644]
drivers/scsi/megaraid.h [new file with mode: 0644]
drivers/sound/Config.in
drivers/sound/sb_common.c
fs/block_dev.c
fs/proc/mem.c
include/linux/cyclades.h
include/linux/pci.h
include/linux/proc_fs.h
kernel/sys.c
net/ipv4/tcp.c

diff --git a/CREDITS b/CREDITS
index bd9ee52be32cb7d34ed9eae056d79c5a5fb2a3d9..f72065f40d826e5073b880670edd5de3bb792195 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -455,15 +455,11 @@ S: Oak Park, Illinois 60302
 S: USA
 
 N: Jim Freeman
-E: jfree@caldera.com
+E: jfree@sovereign.org
 W: http://www.sovereign.org/
 D: Initial GPL'd Frame Relay driver
 D: Dynamic PPP devices
 D: Sundry modularizations (PPP, IPX, ...) and fixes
-S: Caldera, Inc.
-S: 240 West Center St.
-S: Orem, Utah 84059-1920
-S: USA
 
 N: Bob Frey
 E: bobf@advansys.com
index 0481e8009153437d06950308ec01e7c95d09f411..193dc7ef05e99413cc1a34c1f4444882c8867699 100644 (file)
@@ -390,24 +390,22 @@ Parallel port generic ATAPI devices
 CONFIG_PARIDE_PG
   This option enables a special high-level driver for generic ATAPI
   devices connected through a parallel port. The driver allows user
-  programs, such as cdrecord, to send ATAPI commands directly to a
-  device. If you chose to build PARIDE support into your kernel, you 
-  may answer Y here to build in the parallel port generic ATAPI driver, 
-  otherwise you should answer M to build it as a loadable module.
-  The module will be called pg.o.  You must also have at least one 
-  parallel port protocol driver in your system.  This driver 
-  implements an API loosely related to the generic SCSI driver.  
-  See /usr/include/linux/pg.h for details. 
-
-  You can obtain the most recent version of cdrecord from
-  ftp://ftp.fokus.gmd.de/pub/unix/cdrecord/ .  Versions 1.6.1a3 and
-  later fully support the pg driver.
+  programs, such as cdrecord, to send ATAPI commands directly to
+  a device.  If you chose to build PARIDE support into your kernel,
+  you may answer Y here to build in the parallel port generic ATAPI
+  driver, otherwise you should answer M to build it as a loadable
+  module.  The module will be called pg.o.  You must also have at
+  least one parallel port protocol driver in your system.  This driver
+  implements an API loosely related to the generic SCSI driver.  See
+  /usr/include/linux/pg.h for details.  You can obtain the most recent
+  version of cdrecord from ftp://ftp.fokus.gmd.de/pub/unix/cdrecord/ .
+  Versions 1.6.1a3 and later fully support the pg driver.
 
 ATEN EH-100 protocol
 CONFIG_PARIDE_ATEN 
   This option enables support for the ATEN EH-100 parallel port IDE
   protocol.  This protocol is used in some inexpensive low performance 
-  parallel port kits made in Hong Kong. If you chose to build PARIDE 
+  parallel port kits made in Hong Kong.  If you chose to build PARIDE 
   support into your kernel, you may answer Y here to build in the 
   protocol driver, otherwise you should answer M to build it as a 
   loadable module.  The module will be called aten.o.  You must also 
index 1b641b1e11dfac499effff9f21e8e1768f9afb7b..6a3b590e7d5e21da7279dc7b7ef23ede80d48e16 100644 (file)
       0.534  24-Jan-98    Fix last (?) endian bug from 
                            <Geert.Uytterhoeven@cs.kuleuven.ac.be>
       0.535  21-Feb-98    Fix Ethernet Address PROM reset bug for DC21040.
+      0.5351  4-Oct-98    Atomicize assertion of dev->interrupt for SMP (not
+                           for Alpha arch.) from <lma@varesearch.com>
+                         Add TP, AUI and BNC cases to 21140m_autoconf() for
+                          case where a 21140 under SROM control uses, e.g. AUI
+                          from problem report by <delchini@lpnp09.in2p3.fr>
+                         Add MII parallel detection to 2114x_autoconf() for
+                          case where no autonegotiation partner exists from
+                          problem report by <mlapsley@ndirect.co.uk>.
+                         Add ability to force connection type directly even
+                          when using SROM control from problem report by
+                          <earl@exis.net>.
+                         Fix is_anc_capable() bug reported by 
+                          <Austin.Donnelly@cl.cam.ac.uk>.
+                         Fix type[13]_infoblock() bug: during MII search, PHY
+                          lp->rst not run because lp->ibn not initialised -
+                          from report & fix by <paubert@iram.es>.
+                         Fix probe bug with EISA & PCI cards present from
+                          report by <eirik@netcom.com>.
+                         Fix compiler problems associated with i386-string
+                          ops from multiple bug reports and temporary fix
+                          from <paubert@iram.es>.
+                         Add an_exception() for old ZYNX346 and fix compile
+                          warning on PPC & SPARC, from <ecd@skynet.be>.
+                         Fix lastPCI to correctly work with compiled in
+                          kernels and modules from bug report by 
+                          <Zlatko.Calusic@CARNet.hr> et al.
+                         Fix dc2114x_autoconf() to stop multiple messages
+                          when media is unconnected.
+                         Change dev->interrupt to lp->interrupt to ensure
+                          alignment for Alpha's and avoid their unaligned
+                          access traps. This flag is merely for log messages:
+                          should do something more definitive though...
 
     =========================================================================
 */
 
-static const char *version = "de4x5.c:V0.535 1998/2/21 davies@maniac.ultranet.com\n";
+static const char *version = "de4x5.c:V0.5351 1998/10/4 davies@maniac.ultranet.com\n";
 
 #include <linux/module.h>
 
@@ -728,6 +760,7 @@ struct de4x5_desc {
 
 struct de4x5_private {
     char adapter_name[80];                  /* Adapter name                 */
+    u_long interrupt;                       /* Aligned ISR flag             */
     struct de4x5_desc rx_ring[NUM_RX_DESC]; /* RX descriptor ring           */
     struct de4x5_desc tx_ring[NUM_TX_DESC]; /* TX descriptor ring           */
     struct sk_buff *tx_skb[NUM_TX_DESC];    /* TX skb for freeing when sent */
@@ -948,7 +981,8 @@ static void    SetMulticastFilter(struct device *dev);
 static int     get_hw_addr(struct device *dev);
 static void    srom_repair(struct device *dev, int card);
 static int     test_bad_enet(struct device *dev, int status);
-#ifndef __sparc_v9__
+static int     an_exception(struct bus_type *lp);
+#if !defined(__sparc_v9__) && !defined(__powerpc__)
 static void    eisa_probe(struct device *dev, u_long iobase);
 #endif
 static void    pci_probe(struct device *dev, u_long iobase);
@@ -999,12 +1033,15 @@ static int loading_module = 0;
 #endif /* MODULE */
 
 static char name[DE4X5_NAME_LENGTH + 1];
-#ifndef __sparc_v9__
+#if !defined(__sparc_v9__) && !defined(__powerpc__)
 static u_char de4x5_irq[] = EISA_ALLOWED_IRQ_LIST;
+static int lastEISA = 0;
+#else
+static int lastEISA = MAX_EISA_SLOTS;           /* Only PCI probes */
 #endif
 static int num_de4x5s = 0;
 static int cfrv = 0, useSROM = 0;
-static int lastEISA = 0, lastPCI = -1;
+static int lastPCI = -1;
 static struct device *lastModule = NULL;
 
 /*
@@ -1069,10 +1106,12 @@ de4x5_probe(struct device *dev))
 {
     u_long iobase = dev->base_addr;
 
-#ifndef __sparc_v9__
+#if !defined(__sparc_v9__) && !defined(__powerpc__)
     eisa_probe(dev, iobase);
 #endif
-    pci_probe(dev, iobase);
+    if (lastEISA == MAX_EISA_SLOTS) {
+       pci_probe(dev, iobase);
+    }
     
     return (dev->priv ? 0 : -ENODEV);
 }
@@ -1169,21 +1208,15 @@ de4x5_hw_init(struct device *dev, u_long iobase))
        /*
        ** Choose correct autosensing in case someone messed up
        */
-       if ((lp->params.autosense & AUTO) || lp->useSROM) {
-           lp->autosense = AUTO;
-       } else {
-           if (lp->chipset != DC21140) {
-               if ((lp->chipset==DC21040) && (lp->params.autosense&TP_NW)) {
-                   lp->params.autosense = TP;
-               }
-               if ((lp->chipset==DC21041) && (lp->params.autosense&BNC_AUI)) {
-                   lp->params.autosense = BNC;
-               }
-               lp->autosense = lp->params.autosense & 0x001f;
-           } else {
-               lp->autosense = lp->params.autosense & 0x00c0;
-           }
-       }
+        lp->autosense = lp->params.autosense;
+        if (lp->chipset != DC21140) {
+            if ((lp->chipset==DC21040) && (lp->params.autosense&TP_NW)) {
+                lp->params.autosense = TP;
+            }
+            if ((lp->chipset==DC21041) && (lp->params.autosense&BNC_AUI)) {
+                lp->params.autosense = BNC;
+            }
+        }
        lp->fdx = lp->params.fdx;
        sprintf(lp->adapter_name,"%s (%s)", name, dev->name);
        
@@ -1347,7 +1380,7 @@ de4x5_open(struct device *dev)
 
     dev->tbusy = 0;                         
     dev->start = 1;
-    dev->interrupt = UNMASK_INTERRUPTS;
+    lp->interrupt = UNMASK_INTERRUPTS;
     dev->trans_start = jiffies;
     
     START_DE4X5;
@@ -1467,7 +1500,7 @@ de4x5_sw_reset(struct device *dev)
 }
 
 /* 
-** Writes a socket buffer address to the next available transmit descriptor
+** Writes a socket buffer address to the next available transmit descriptor.
 */
 static int
 de4x5_queue_pkt(struct sk_buff *skb, struct device *dev)
@@ -1491,12 +1524,12 @@ de4x5_queue_pkt(struct sk_buff *skb, struct device *dev)
     sti();
 
     /* Test if cache is already locked - requeue skb if so */
-    if (test_and_set_bit(0, (void *)&lp->cache.lock) && !dev->interrupt) 
+    if (test_and_set_bit(0, (void *)&lp->cache.lock) && !lp->interrupt) 
        return -1;
 
     /* Transmit descriptor ring full or stale skb */
     if (dev->tbusy || lp->tx_skb[lp->tx_new]) {
-       if (dev->interrupt) {
+       if (lp->interrupt) {
            de4x5_putb_cache(dev, skb);          /* Requeue the buffer */
        } else {
            de4x5_put_cache(dev, skb);
@@ -1506,7 +1539,7 @@ de4x5_queue_pkt(struct sk_buff *skb, struct device *dev)
        }
     } else if (skb->len > 0) {
        /* If we already have stuff queued locally, use that first */
-       if (lp->cache.skb && !dev->interrupt) {
+       if (lp->cache.skb && !lp->interrupt) {
            de4x5_put_cache(dev, skb);
            skb = de4x5_get_cache(dev);
        }
@@ -1563,14 +1596,14 @@ de4x5_interrupt(int irq, void *dev_id, struct pt_regs *regs)
     lp = (struct de4x5_private *)dev->priv;
     iobase = dev->base_addr;
        
-    if (test_and_set_bit(0, (void*) &dev->interrupt))
-      printk("%s: Re-entering the interrupt handler.\n", dev->name);
-       
     DISABLE_IRQs;                        /* Ensure non re-entrancy */
+
+    if (test_and_set_bit(MASK_INTERRUPTS, (void*) &lp->interrupt))
+       printk("%s: Re-entering the interrupt handler.\n", dev->name);
+
 #if    LINUX_VERSION_CODE >= ((2 << 16) | (1 << 8))
     synchronize_irq();
 #endif
-    dev->interrupt = MASK_INTERRUPTS;
        
     for (limit=0; limit<8; limit++) {
        sts = inl(DE4X5_STS);            /* Read IRQ status */
@@ -1608,7 +1641,7 @@ de4x5_interrupt(int irq, void *dev_id, struct pt_regs *regs)
        lp->cache.lock = 0;
     }
 
-    dev->interrupt = UNMASK_INTERRUPTS;
+    lp->interrupt = UNMASK_INTERRUPTS;
     ENABLE_IRQs;
     
     return;
@@ -1740,7 +1773,7 @@ de4x5_tx(struct device *dev)
 
     if (TX_BUFFS_AVAIL && dev->tbusy) {  /* Any resources available? */
        dev->tbusy = 0;                  /* Clear TX busy flag */
-       if (dev->interrupt) mark_bh(NET_BH);
+       if (lp->interrupt) mark_bh(NET_BH);
     }
        
     return 0;
@@ -2001,7 +2034,7 @@ SetMulticastFilter(struct device *dev)
     return;
 }
 
-#ifndef __sparc_v9__
+#if !defined(__sparc_v9__) && !defined(__powerpc__)
 /*
 ** EISA bus I/O device probe. Probe from slot 1 since slot 0 is usually
 ** the motherboard. Upto 15 EISA devices are supported.
@@ -2069,7 +2102,7 @@ eisa_probe(struct device *dev, u_long ioaddr))
 
     return;
 }
-#endif                         /* !(__sparc_v9__) */
+#endif                         /* !(__sparc_v9__) && !(__powerpc__) */
 
 /*
 ** PCI bus I/O device probe
@@ -2197,10 +2230,8 @@ pci_probe(struct device *dev, u_long ioaddr))
                dev->irq = irq;
                if ((status = de4x5_hw_init(dev, iobase)) == 0) {
                    num_de4x5s++;
-                   if (loading_module) {
-                       link_modules(lastModule, dev);
-                       lastPCI = index;
-                   }
+                   lastPCI = index;
+                   if (loading_module) link_modules(lastModule, dev);
                    return;
                }
            } else if (ioaddr != 0) {
@@ -2210,7 +2241,7 @@ pci_probe(struct device *dev, u_long ioaddr))
        }
     }
 
-    if (loading_module) lastPCI = NO_MORE_PCI;
+    lastPCI = NO_MORE_PCI;
 
     return;
 }
@@ -2381,7 +2412,7 @@ dc21040_autoconf(struct device *dev)
     s32 imr;
     
     switch (lp->media) {
-      case INIT:
+    case INIT:
        DISABLE_IRQs;
        lp->tx_enable = NO;
        lp->timeout = -1;
@@ -2399,36 +2430,36 @@ dc21040_autoconf(struct device *dev)
        next_tick = dc21040_autoconf(dev);
        break;
        
-      case TP:
+    case TP:
        next_tick = dc21040_state(dev, 0x8f01, 0xffff, 0x0000, 3000, BNC_AUI, 
                                                         TP_SUSPECT, test_tp);
        break;
        
-      case TP_SUSPECT:
+    case TP_SUSPECT:
        next_tick = de4x5_suspect_state(dev, 1000, TP, test_tp, dc21040_autoconf);
        break;
        
-      case BNC:
-      case AUI:
-      case BNC_AUI:
+    case BNC:
+    case AUI:
+    case BNC_AUI:
        next_tick = dc21040_state(dev, 0x8f09, 0x0705, 0x0006, 3000, EXT_SIA, 
                                                  BNC_AUI_SUSPECT, ping_media);
        break;
        
-      case BNC_AUI_SUSPECT:
+    case BNC_AUI_SUSPECT:
        next_tick = de4x5_suspect_state(dev, 1000, BNC_AUI, ping_media, dc21040_autoconf);
        break;
        
-      case EXT_SIA:
+    case EXT_SIA:
        next_tick = dc21040_state(dev, 0x3041, 0x0000, 0x0006, 3000, 
                                              NC, EXT_SIA_SUSPECT, ping_media);
        break;
        
-      case EXT_SIA_SUSPECT:
+    case EXT_SIA_SUSPECT:
        next_tick = de4x5_suspect_state(dev, 1000, EXT_SIA, ping_media, dc21040_autoconf);
        break;
        
-      case NC:
+    case NC:
        /* default to TP for all */
        reset_init_sia(dev, 0x8f01, 0xffff, 0x0000);
        if (lp->media != lp->c_media) {
@@ -2453,13 +2484,13 @@ dc21040_state(struct device *dev, int csr13, int csr14, int csr15, int timeout,
     int linkBad;
 
     switch (lp->local_state) {
-      case 0:
+    case 0:
        reset_init_sia(dev, csr13, csr14, csr15);
        lp->local_state++;
        next_tick = 500;
        break;
            
-      case 1:
+    case 1:
        if (!lp->tx_enable) {
            linkBad = fn(dev, timeout);
            if (linkBad < 0) {
@@ -2492,7 +2523,7 @@ de4x5_suspect_state(struct device *dev, int timeout, int prev_state,
     int linkBad;
 
     switch (lp->local_state) {
-      case 1:
+    case 1:
        if (lp->linkOK) {
            lp->media = prev_state;
        } else {
@@ -2501,7 +2532,7 @@ de4x5_suspect_state(struct device *dev, int timeout, int prev_state,
        }
        break;
 
-      case 2:
+    case 2:
        linkBad = fn(dev, timeout);
        if (linkBad < 0) {
            next_tick = linkBad & ~TIMER_CB;
@@ -2535,7 +2566,7 @@ dc21041_autoconf(struct device *dev)
     int next_tick = DE4X5_AUTOSENSE_MS;
     
     switch (lp->media) {
-      case INIT:
+    case INIT:
        DISABLE_IRQs;
        lp->tx_enable = NO;
        lp->timeout = -1;
@@ -2555,7 +2586,7 @@ dc21041_autoconf(struct device *dev)
        next_tick = dc21041_autoconf(dev);
        break;
        
-      case TP_NW:
+    case TP_NW:
        if (lp->timeout < 0) {
            omr = inl(DE4X5_OMR);/* Set up full duplex for the autonegotiate */
            outl(omr | OMR_FDX, DE4X5_OMR);
@@ -2575,7 +2606,7 @@ dc21041_autoconf(struct device *dev)
        }
        break;
        
-      case ANS:
+    case ANS:
        if (!lp->tx_enable) {
            irqs = STS_LNP;
            irq_mask = IMR_LPM;
@@ -2597,11 +2628,11 @@ dc21041_autoconf(struct device *dev)
        }
        break;
        
-      case ANS_SUSPECT:
+    case ANS_SUSPECT:
        next_tick = de4x5_suspect_state(dev, 1000, ANS, test_tp, dc21041_autoconf);
        break;
        
-      case TP:
+    case TP:
        if (!lp->tx_enable) {
            if (lp->timeout < 0) {
                omr = inl(DE4X5_OMR);          /* Set up half duplex for TP */
@@ -2631,11 +2662,11 @@ dc21041_autoconf(struct device *dev)
        }
        break;
        
-      case TP_SUSPECT:
+    case TP_SUSPECT:
        next_tick = de4x5_suspect_state(dev, 1000, TP, test_tp, dc21041_autoconf);
        break;
        
-      case AUI:
+    case AUI:
        if (!lp->tx_enable) {
            if (lp->timeout < 0) {
                omr = inl(DE4X5_OMR);          /* Set up half duplex for AUI */
@@ -2661,13 +2692,13 @@ dc21041_autoconf(struct device *dev)
        }
        break;
        
-      case AUI_SUSPECT:
+    case AUI_SUSPECT:
        next_tick = de4x5_suspect_state(dev, 1000, AUI, ping_media, dc21041_autoconf);
        break;
        
-      case BNC:
+    case BNC:
        switch (lp->local_state) {
-         case 0:
+       case 0:
            if (lp->timeout < 0) {
                omr = inl(DE4X5_OMR);          /* Set up half duplex for BNC */
                outl(omr & ~OMR_FDX, DE4X5_OMR);
@@ -2683,7 +2714,7 @@ dc21041_autoconf(struct device *dev)
            }
            break;
            
-         case 1:
+       case 1:
            if (!lp->tx_enable) {
                if ((sts = ping_media(dev, 3000)) < 0) {
                    next_tick = sts & ~TIMER_CB;
@@ -2703,11 +2734,11 @@ dc21041_autoconf(struct device *dev)
        }
        break;
        
-      case BNC_SUSPECT:
+    case BNC_SUSPECT:
        next_tick = de4x5_suspect_state(dev, 1000, BNC, ping_media, dc21041_autoconf);
        break;
        
-      case NC:
+    case NC:
        omr = inl(DE4X5_OMR);    /* Set up full duplex for the autonegotiate */
        outl(omr | OMR_FDX, DE4X5_OMR);
        reset_init_sia(dev, 0xef01, 0xffff, 0x0008);/* Initialise the SIA */
@@ -2737,7 +2768,7 @@ dc21140m_autoconf(struct device *dev)
     u_long imr, omr, iobase = dev->base_addr;
 
     switch(lp->media) {
-      case INIT: 
+    case INIT: 
         if (lp->timeout < 0) {
            DISABLE_IRQs;
            lp->tx_enable = FALSE;
@@ -2783,9 +2814,9 @@ dc21140m_autoconf(struct device *dev)
        }
        break;
        
-      case ANS:
+    case ANS:
        switch (lp->local_state) {
-         case 0:
+       case 0:
            if (lp->timeout < 0) {
                mii_wr(MII_CR_ASSE | MII_CR_RAN, MII_CR, lp->phy[lp->active].addr, DE4X5_MII);
            }
@@ -2803,7 +2834,7 @@ dc21140m_autoconf(struct device *dev)
            }
            break;
            
-         case 1:
+       case 1:
            if ((sr=test_mii_reg(dev, MII_SR, MII_SR_ASSC, TRUE, 2000)) < 0) {
                next_tick = sr & ~TIMER_CB;
            } else {
@@ -2831,7 +2862,7 @@ dc21140m_autoconf(struct device *dev)
        }
        break;
        
-      case SPD_DET:                              /* Choose 10Mb/s or 100Mb/s */
+    case SPD_DET:                              /* Choose 10Mb/s or 100Mb/s */
         if (lp->timeout < 0) {
            lp->tmp = (lp->phy[lp->active].id ? MII_SR_LKS : 
                                                  (~gep_rd(dev) & GEP_LNP));
@@ -2851,7 +2882,7 @@ dc21140m_autoconf(struct device *dev)
        }
        break;
        
-      case _100Mb:                               /* Set 100Mb/s */
+    case _100Mb:                               /* Set 100Mb/s */
         next_tick = 3000;
        if (!lp->tx_enable) {
            SET_100Mb;
@@ -2867,7 +2898,9 @@ dc21140m_autoconf(struct device *dev)
        }
        break;
        
-      case _10Mb:                                /* Set 10Mb/s */
+    case BNC:
+    case AUI:
+    case _10Mb:                                /* Set 10Mb/s */
         next_tick = 3000;
        if (!lp->tx_enable) {
            SET_10Mb;
@@ -2883,7 +2916,7 @@ dc21140m_autoconf(struct device *dev)
        }
        break;
        
-      case NC:
+    case NC:
         if (lp->media != lp->c_media) {
            de4x5_dbg_media(dev);
            lp->c_media = lp->media;
@@ -2919,33 +2952,54 @@ dc2114x_autoconf(struct device *dev)
     int next_tick = DE4X5_AUTOSENSE_MS;
 
     switch (lp->media) {
-      case INIT:
+    case INIT:
         if (lp->timeout < 0) {
            DISABLE_IRQs;
            lp->tx_enable = FALSE;
            lp->linkOK = 0;
             lp->timeout = -1;
-           de4x5_save_skbs(dev);          /* Save non transmitted skb's */
+           de4x5_save_skbs(dev);            /* Save non transmitted skb's */
+           if (lp->params.autosense & ~AUTO) {
+               srom_map_media(dev);         /* Fixed media requested      */
+               if (lp->media != lp->params.autosense) {
+                   lp->tcount++;
+                   lp->media = INIT;
+                   return next_tick;
+               }
+               lp->media = INIT;
+           }
        }
        if ((next_tick = de4x5_reset_phy(dev)) < 0) {
            next_tick &= ~TIMER_CB;
        } else {
-            lp->media = SPD_DET;
-           if ((lp->infoblock_media == ANS) && 
+           if (lp->autosense == _100Mb) {
+               lp->media = _100Mb;
+           } else if (lp->autosense == _10Mb) {
+               lp->media = _10Mb;
+           } else if (lp->autosense == TP) {
+               lp->media = TP;
+           } else if (lp->autosense == BNC) {
+               lp->media = BNC;
+           } else if (lp->autosense == AUI) {
+               lp->media = AUI;
+           } else {
+               lp->media = SPD_DET;
+               if ((lp->infoblock_media == ANS) && 
                                    ((sr=is_anc_capable(dev)) & MII_SR_ANC)) {
                    ana = (((sr >> 6) & MII_ANA_TAF) | MII_ANA_CSMA);
                    ana &= (lp->fdx ? ~0 : ~MII_ANA_FDAM);
                    mii_wr(ana, MII_ANA, lp->phy[lp->active].addr, DE4X5_MII);
                    lp->media = ANS;
+               }
            }
            lp->local_state = 0;
            next_tick = dc2114x_autoconf(dev);
         }
        break;
        
-      case ANS:
+    case ANS:
        switch (lp->local_state) {
-         case 0:
+       case 0:
            if (lp->timeout < 0) {
                mii_wr(MII_CR_ASSE | MII_CR_RAN, MII_CR, lp->phy[lp->active].addr, DE4X5_MII);
            }
@@ -2963,7 +3017,7 @@ dc2114x_autoconf(struct device *dev)
            }
            break;
            
-         case 1:
+       case 1:
            if ((sr=test_mii_reg(dev, MII_SR, MII_SR_ASSC, TRUE, 2000)) < 0) {
                next_tick = sr & ~TIMER_CB;
            } else {
@@ -2985,15 +3039,15 @@ dc2114x_autoconf(struct device *dev)
                    }
                }                       /* Auto Negotiation failed to finish */
                next_tick = dc2114x_autoconf(dev);
-           }                           /* Auto Negotiation failed to start */
+           }                           /* Auto Negotiation failed to start  */
            break;
        }
        break;
        
-      case AUI:
+    case AUI:
        if (!lp->tx_enable) {
            if (lp->timeout < 0) {
-               omr = inl(DE4X5_OMR);          /* Set up half duplex for AUI */
+               omr = inl(DE4X5_OMR);   /* Set up half duplex for AUI        */
                outl(omr & ~OMR_FDX, DE4X5_OMR);
            }
            irqs = 0;
@@ -3016,15 +3070,15 @@ dc2114x_autoconf(struct device *dev)
        }
        break;
        
-      case AUI_SUSPECT:
+    case AUI_SUSPECT:
        next_tick = de4x5_suspect_state(dev, 1000, AUI, ping_media, dc2114x_autoconf);
        break;
        
-      case BNC:
+    case BNC:
        switch (lp->local_state) {
-         case 0:
+       case 0:
            if (lp->timeout < 0) {
-               omr = inl(DE4X5_OMR);          /* Set up half duplex for BNC */
+               omr = inl(DE4X5_OMR);   /* Set up half duplex for BNC        */
                outl(omr & ~OMR_FDX, DE4X5_OMR);
            }
            irqs = 0;
@@ -3033,12 +3087,12 @@ dc2114x_autoconf(struct device *dev)
            if (sts < 0) {
                next_tick = sts & ~TIMER_CB;
            } else {
-               lp->local_state++;             /* Ensure media connected */
+               lp->local_state++;      /* Ensure media connected            */
                next_tick = dc2114x_autoconf(dev);
            }
            break;
            
-         case 1:
+       case 1:
            if (!lp->tx_enable) {
                if ((sts = ping_media(dev, 3000)) < 0) {
                    next_tick = sts & ~TIMER_CB;
@@ -3059,11 +3113,11 @@ dc2114x_autoconf(struct device *dev)
        }
        break;
        
-      case BNC_SUSPECT:
+    case BNC_SUSPECT:
        next_tick = de4x5_suspect_state(dev, 1000, BNC, ping_media, dc2114x_autoconf);
        break;
        
-      case SPD_DET:                              /* Choose 10Mb/s or 100Mb/s */
+    case SPD_DET:                       /* Choose 10Mb/s or 100Mb/s          */
          if (srom_map_media(dev) < 0) {
              lp->tcount++;
              lp->media = INIT;
@@ -3080,9 +3134,17 @@ dc2114x_autoconf(struct device *dev)
                  return PDET_LINK_WAIT;
              }
          } 
-         if (((lp->media == _100Mb) && is_100_up(dev)) ||
-             ((lp->media == _10Mb)  && is_10_up(dev)) ||
-              (lp->media == BNC) || (lp->media == AUI)) {
+         if (lp->media == ANS) {           /* Do MII parallel detection */
+             if (is_spd_100(dev)) {
+                 lp->media = _100Mb;
+             } else {
+                 lp->media = _10Mb;
+             }
+             next_tick = dc2114x_autoconf(dev);
+         } else if (((lp->media == _100Mb) && is_100_up(dev)) ||
+                    (((lp->media == _10Mb) || (lp->media == TP) ||
+                      (lp->media == BNC)   || (lp->media == AUI)) && 
+                     is_10_up(dev))) {
              next_tick = dc2114x_autoconf(dev);
          } else {
              lp->tcount++;
@@ -3090,7 +3152,7 @@ dc2114x_autoconf(struct device *dev)
          }
          break;
        
-      case _10Mb:
+    case _10Mb:
         next_tick = 3000;
        if (!lp->tx_enable) {
            SET_10Mb;
@@ -3106,7 +3168,7 @@ dc2114x_autoconf(struct device *dev)
        }
        break;
 
-      case _100Mb:
+    case _100Mb:
         next_tick = 3000;
        if (!lp->tx_enable) {
            SET_100Mb;
@@ -3122,7 +3184,7 @@ dc2114x_autoconf(struct device *dev)
        }
        break;
 
-      default:
+    default:
        lp->tcount++;
 printk("Huh?: media:%02x\n", lp->media);
        lp->media = INIT;
@@ -3492,7 +3554,7 @@ is_anc_capable(struct device *dev)
     if (lp->phy[lp->active].id && (!lp->useSROM || lp->useMII)) {
        return (mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII));
     } else if ((lp->chipset & ~0x00ff) == DC2114x) {
-       return (inl(DE4X5_SISR) & SISR_LPN) >> 11;
+       return (inl(DE4X5_SISR) & SISR_LPN) >> 12;
     } else {
        return 0;
     }
@@ -3905,7 +3967,7 @@ de4x5_ms_delay(u32 msec)
 static int
 EISA_signature(char *name, s32 eisa_id)
 {
-    c_char *signatures[] = DE4X5_SIGNATURE;
+    static c_char *signatures[] = DE4X5_SIGNATURE;
     char ManCode[DE4X5_STRLEN];
     union {
        s32 ID;
@@ -3940,7 +4002,7 @@ EISA_signature(char *name, s32 eisa_id)
 static int
 PCI_signature(char *name, struct bus_type *lp)
 {
-    c_char *de4x5_signatures[] = DE4X5_SIGNATURE;
+    static c_char *de4x5_signatures[] = DE4X5_SIGNATURE;
     int i, status = 0, siglen = sizeof(de4x5_signatures)/sizeof(c_char *);
     
     if (lp->chipset == DC21040) {
@@ -4119,6 +4181,21 @@ get_hw_addr(struct device *dev)
     /* If possible, try to fix a broken card - SMC only so far */
     srom_repair(dev, broken);
 
+#ifdef CONFIG_PMAC
+    /* 
+    ** If the address starts with 00 a0, we have to bit-reverse
+    ** each byte of the address.
+    */
+    if (dev->dev_addr[0] == 0 && dev->dev_addr[1] == 0xa0) {
+       for (i = 0; i < ETH_ALEN; ++i) {
+           int x = dev->dev_addr[i];
+           x = ((x & 0xf) << 4) + ((x & 0xf0) >> 4);
+           x = ((x & 0x33) << 2) + ((x & 0xcc) >> 2);
+           dev->dev_addr[i] = ((x & 0x55) << 1) + ((x & 0xaa) >> 1);
+       }
+    }
+#endif /* CONFIG_PMAC */
+
     /* Test for a bad enet address */
     status = test_bad_enet(dev, status);
 
@@ -4198,7 +4275,9 @@ test_bad_enet(struct device *dev, int status)
                if (dev->dev_addr[i] != 0) break;
            }
            for (i=0; i<ETH_ALEN; i++) last.addr[i] = dev->dev_addr[i];
-           dev->irq = last.irq;
+           if (!an_exception(lp)) {
+               dev->irq = last.irq;
+           }
 
            status = 0;
        }
@@ -4212,6 +4291,20 @@ test_bad_enet(struct device *dev, int status)
     return status;
 }
 
+/*
+** List of board exceptions with correctly wired IRQs
+*/
+static int
+an_exception(struct bus_type *lp)
+{
+    if ((*(u_short *)lp->srom.sub_vendor_id == 0x00c0) && 
+       (*(u_short *)lp->srom.sub_system_id == 0x95e0)) {
+       return -1;
+    }
+
+    return 0;
+}
+
 /*
 ** SROM Read
 */
@@ -4658,6 +4751,7 @@ type1_infoblock(struct device *dev, u_char count, u_char *p)
 
     p += 2;
     if (lp->state == INITIALISED) {
+        lp->ibn = 1;
        lp->active = *p++;
        lp->phy[lp->active].gep = (*p ? p : 0); p += (*p + 1);
        lp->phy[lp->active].rst = (*p ? p : 0); p += (*p + 1);
@@ -4737,6 +4831,7 @@ type3_infoblock(struct device *dev, u_char count, u_char *p)
 
     p += 2;
     if (lp->state == INITIALISED) {
+        lp->ibn = 3;
         lp->active = *p++;
        lp->phy[lp->active].gep = (*p ? p : 0); p += (2 * (*p) + 1);
        lp->phy[lp->active].rst = (*p ? p : 0); p += (2 * (*p) + 1);
@@ -5484,24 +5579,24 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
     } tmp;
     
     switch(ioc->cmd) {
-      case DE4X5_GET_HWADDR:           /* Get the hardware address */
+    case DE4X5_GET_HWADDR:           /* Get the hardware address */
        ioc->len = ETH_ALEN;
        status = verify_area(VERIFY_WRITE, (void *)ioc->data, ioc->len);
        if (status)
-         break;
+           break;
        for (i=0; i<ETH_ALEN; i++) {
            tmp.addr[i] = dev->dev_addr[i];
        }
        copy_to_user(ioc->data, tmp.addr, ioc->len);
        
        break;
-      case DE4X5_SET_HWADDR:           /* Set the hardware address */
+    case DE4X5_SET_HWADDR:           /* Set the hardware address */
        status = verify_area(VERIFY_READ, (void *)ioc->data, ETH_ALEN);
        if (status)
-         break;
+           break;
        status = -EPERM;
        if (!suser())
-         break;
+           break;
        status = 0;
        copy_from_user(tmp.addr, ioc->data, ETH_ALEN);
        for (i=0; i<ETH_ALEN; i++) {
@@ -5517,7 +5612,7 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
        dev->tbusy = 0;                              /* Unlock the TX ring */
        
        break;
-      case DE4X5_SET_PROM:             /* Set Promiscuous Mode */
+    case DE4X5_SET_PROM:             /* Set Promiscuous Mode */
        if (suser()) {
            omr = inl(DE4X5_OMR);
            omr |= OMR_PR;
@@ -5528,7 +5623,7 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
        }
        
        break;
-      case DE4X5_CLR_PROM:             /* Clear Promiscuous Mode */
+    case DE4X5_CLR_PROM:             /* Clear Promiscuous Mode */
        if (suser()) {
            omr = inl(DE4X5_OMR);
            omr &= ~OMR_PR;
@@ -5539,11 +5634,11 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
        }
        
        break;
-      case DE4X5_SAY_BOO:              /* Say "Boo!" to the kernel log file */
+    case DE4X5_SAY_BOO:              /* Say "Boo!" to the kernel log file */
        printk("%s: Boo!\n", dev->name);
        
        break;
-      case DE4X5_MCA_EN:               /* Enable pass all multicast addressing */
+    case DE4X5_MCA_EN:               /* Enable pass all multicast addressing */
        if (suser()) {
            omr = inl(DE4X5_OMR);
            omr |= OMR_PM;
@@ -5553,18 +5648,18 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
        }
        
        break;
-      case DE4X5_GET_STATS:            /* Get the driver statistics */
+    case DE4X5_GET_STATS:            /* Get the driver statistics */
        ioc->len = sizeof(lp->pktStats);
        status = verify_area(VERIFY_WRITE, (void *)ioc->data, ioc->len);
        if (status)
-         break;
+           break;
        
        cli();
        copy_to_user(ioc->data, &lp->pktStats, ioc->len); 
        sti();
        
        break;
-      case DE4X5_CLR_STATS:            /* Zero out the driver statistics */
+    case DE4X5_CLR_STATS:            /* Zero out the driver statistics */
        if (suser()) {
            cli();
            memset(&lp->pktStats, 0, sizeof(lp->pktStats));
@@ -5574,14 +5669,14 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
        }
        
        break;
-      case DE4X5_GET_OMR:              /* Get the OMR Register contents */
+    case DE4X5_GET_OMR:              /* Get the OMR Register contents */
        tmp.addr[0] = inl(DE4X5_OMR);
        if (!(status = verify_area(VERIFY_WRITE, (void *)ioc->data, 1))) {
            copy_to_user(ioc->data, tmp.addr, 1);
        }
        
        break;
-      case DE4X5_SET_OMR:              /* Set the OMR Register contents */
+    case DE4X5_SET_OMR:              /* Set the OMR Register contents */
        if (suser()) {
            if (!(status = verify_area(VERIFY_READ, (void *)ioc->data, 1))) {
                copy_from_user(tmp.addr, ioc->data, 1);
@@ -5592,7 +5687,7 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
        }
        
        break;
-      case DE4X5_GET_REG:              /* Get the DE4X5 Registers */
+    case DE4X5_GET_REG:              /* Get the DE4X5 Registers */
        j = 0;
        tmp.lval[0] = inl(DE4X5_STS); j+=4;
        tmp.lval[1] = inl(DE4X5_BMR); j+=4;
@@ -5700,7 +5795,7 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
        
        break;
 */
-      default:
+    default:
        status = -EOPNOTSUPP;
     }
     
@@ -5781,16 +5876,17 @@ unlink_modules(struct device *p)
 static int
 count_adapters(void)
 {
-    int i, j;
-    char name[DE4X5_STRLEN];
+    int i, j=0;
     u_char pb, dev_fn, dev_num;
     u_short dev_id, vendor;
     u_int class = DE4X5_CLASS_CODE;
     u_int device;
-#ifndef __sparc_v9__
+
+#if !defined(__sparc_v9__) && !defined(__powerpc__)
+    char name[DE4X5_STRLEN];
     u_long iobase = 0x1000;
 
-    for (j=0, i=1; i<MAX_EISA_SLOTS; i++, iobase+=EISA_SLOT_INC) {
+    for (i=1; i<MAX_EISA_SLOTS; i++, iobase+=EISA_SLOT_INC) {
        if (EISA_signature(name, EISA_ID)) j++;
     }
 #endif
index 64828b32313573a1baf451da04f55a8c29c00c9f..1430d7326becafd7770d11d73c7b70e51295cf19 100644 (file)
@@ -304,6 +304,8 @@ static int pcnet32_probe1(struct device *dev, unsigned int ioaddr, unsigned char
           The first six bytes are the station address. */
        for (i = 0; i < 6; i++)
                printk(" %2.2x", dev->dev_addr[i] = inb(ioaddr + i));
+               
+       printk("\n");
 
        dev->base_addr = ioaddr;
        request_region(ioaddr, PCNET32_TOTAL_SIZE, dev->name);
diff --git a/drivers/net/soundmodem/sm_tbl_afsk1200.h b/drivers/net/soundmodem/sm_tbl_afsk1200.h
new file mode 100644 (file)
index 0000000..ea22abe
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * THIS FILE IS GENERATED AUTOMATICALLY BY ./gentbl, DO NOT EDIT!
+ */
+
+
+/*
+ * small cosine table in U8 format
+ */
+#define OFFSCOSTABBITS 6
+#define OFFSCOSTABSIZE (1<<OFFSCOSTABBITS)
+
+static unsigned char offscostab[OFFSCOSTABSIZE] = {
+        255, 254, 252, 249, 245, 240, 233, 226,
+        217, 208, 198, 187, 176, 164, 152, 140,
+        128, 115, 103,  91,  79,  68,  57,  47,
+         38,  29,  22,  15,  10,   6,   3,   1,
+          1,   1,   3,   6,  10,  15,  22,  29,
+         38,  47,  57,  68,  79,  91, 103, 115,
+        127, 140, 152, 164, 176, 187, 198, 208,
+        217, 226, 233, 240, 245, 249, 252, 254
+};
+
+#define OFFSCOS(x) offscostab[((x)>>10)&0x3f]
+
+
+/*
+ * more accurate cosine table
+ */
+
+static const short costab[64] = {
+        32767,  32609,  32137,  31356,  30272,  28897,  27244,  25329, 
+        23169,  20787,  18204,  15446,  12539,   9511,   6392,   3211, 
+            0,  -3211,  -6392,  -9511, -12539, -15446, -18204, -20787, 
+       -23169, -25329, -27244, -28897, -30272, -31356, -32137, -32609, 
+       -32767, -32609, -32137, -31356, -30272, -28897, -27244, -25329, 
+       -23169, -20787, -18204, -15446, -12539,  -9511,  -6392,  -3211, 
+            0,   3211,   6392,   9511,  12539,  15446,  18204,  20787, 
+        23169,  25329,  27244,  28897,  30272,  31356,  32137,  32609
+};
+
+#define COS(x) costab[((x)>>10)&0x3f]
+#define SIN(x) COS((x)+0xc000)
+
+
+/*
+ * afsk1200 specific tables
+ */
+#define AFSK12_SAMPLE_RATE 9600
+#define AFSK12_TX_FREQ_LO 1200
+#define AFSK12_TX_FREQ_HI 2200
+#define AFSK12_CORRLEN 8
+
+static const int afsk12_tx_lo_i[] = {
+         127,   89,    0,  -89, -127,  -89,    0,   89 
+};
+#define SUM_AFSK12_TX_LO_I 0
+
+static const int afsk12_tx_lo_q[] = {
+           0,   89,  127,   89,    0,  -89, -127,  -89 
+};
+#define SUM_AFSK12_TX_LO_Q 0
+
+static const int afsk12_tx_hi_i[] = {
+         127,   16, -122,  -48,  109,   77,  -89, -100 
+};
+#define SUM_AFSK12_TX_HI_I -30
+
+static const int afsk12_tx_hi_q[] = {
+           0,  125,   32, -117,  -63,  100,   89,  -77 
+};
+#define SUM_AFSK12_TX_HI_Q 89
+
diff --git a/drivers/net/soundmodem/sm_tbl_afsk2400_7.h b/drivers/net/soundmodem/sm_tbl_afsk2400_7.h
new file mode 100644 (file)
index 0000000..21104ca
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * THIS FILE IS GENERATED AUTOMATICALLY BY ./gentbl, DO NOT EDIT!
+ */
+
+
+/*
+ * small cosine table in U8 format
+ */
+#define OFFSCOSTABBITS 6
+#define OFFSCOSTABSIZE (1<<OFFSCOSTABBITS)
+
+static unsigned char offscostab[OFFSCOSTABSIZE] = {
+        255, 254, 252, 249, 245, 240, 233, 226,
+        217, 208, 198, 187, 176, 164, 152, 140,
+        128, 115, 103,  91,  79,  68,  57,  47,
+         38,  29,  22,  15,  10,   6,   3,   1,
+          1,   1,   3,   6,  10,  15,  22,  29,
+         38,  47,  57,  68,  79,  91, 103, 115,
+        127, 140, 152, 164, 176, 187, 198, 208,
+        217, 226, 233, 240, 245, 249, 252, 254
+};
+
+#define OFFSCOS(x) offscostab[((x)>>10)&0x3f]
+
+
+/*
+ * more accurate cosine table
+ */
+
+static const short costab[64] = {
+        32767,  32609,  32137,  31356,  30272,  28897,  27244,  25329, 
+        23169,  20787,  18204,  15446,  12539,   9511,   6392,   3211, 
+            0,  -3211,  -6392,  -9511, -12539, -15446, -18204, -20787, 
+       -23169, -25329, -27244, -28897, -30272, -31356, -32137, -32609, 
+       -32767, -32609, -32137, -31356, -30272, -28897, -27244, -25329, 
+       -23169, -20787, -18204, -15446, -12539,  -9511,  -6392,  -3211, 
+            0,   3211,   6392,   9511,  12539,  15446,  18204,  20787, 
+        23169,  25329,  27244,  28897,  30272,  31356,  32137,  32609
+};
+
+#define COS(x) costab[((x)>>10)&0x3f]
+#define SIN(x) COS((x)+0xc000)
+
+
+/*
+ * afsk2400 specific tables (tcm3105 clk 7372800.000000Hz)
+ */
+#define AFSK24_TX_FREQ_LO 1995
+#define AFSK24_TX_FREQ_HI 3658
+#define AFSK24_BITPLL_INC 9830
+#define AFSK24_SAMPLERATE 16000
+
+static const int afsk24_tx_lo_i[] = {
+          10,   11,    0,  -43,  -89,  -80,   -1,   87,  112,   64,    0,  -24,  -16,   -7 
+};
+#define SUM_AFSK24_TX_LO_I 24
+
+static const int afsk24_tx_lo_q[] = {
+           0,   11,   35,   43,    0,  -78, -125,  -89,   -1,   62,   61,   25,    0,   -7 
+};
+#define SUM_AFSK24_TX_LO_Q -63
+
+static const int afsk24_tx_hi_i[] = {
+          10,    2,  -34,  -24,   76,   69,  -86, -101,   53,   83,  -14,  -35,    0,   10 
+};
+#define SUM_AFSK24_TX_HI_I 9
+
+static const int afsk24_tx_hi_q[] = {
+           0,   16,    9,  -56,  -45,   88,   90,  -74,  -98,   31,   59,   -3,  -16,   -1 
+};
+#define SUM_AFSK24_TX_HI_Q 0
+
diff --git a/drivers/net/soundmodem/sm_tbl_afsk2400_8.h b/drivers/net/soundmodem/sm_tbl_afsk2400_8.h
new file mode 100644 (file)
index 0000000..2a5505c
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * THIS FILE IS GENERATED AUTOMATICALLY BY ./gentbl, DO NOT EDIT!
+ */
+
+
+/*
+ * small cosine table in U8 format
+ */
+#define OFFSCOSTABBITS 6
+#define OFFSCOSTABSIZE (1<<OFFSCOSTABBITS)
+
+static unsigned char offscostab[OFFSCOSTABSIZE] = {
+        255, 254, 252, 249, 245, 240, 233, 226,
+        217, 208, 198, 187, 176, 164, 152, 140,
+        128, 115, 103,  91,  79,  68,  57,  47,
+         38,  29,  22,  15,  10,   6,   3,   1,
+          1,   1,   3,   6,  10,  15,  22,  29,
+         38,  47,  57,  68,  79,  91, 103, 115,
+        127, 140, 152, 164, 176, 187, 198, 208,
+        217, 226, 233, 240, 245, 249, 252, 254
+};
+
+#define OFFSCOS(x) offscostab[((x)>>10)&0x3f]
+
+
+/*
+ * more accurate cosine table
+ */
+
+static const short costab[64] = {
+        32767,  32609,  32137,  31356,  30272,  28897,  27244,  25329, 
+        23169,  20787,  18204,  15446,  12539,   9511,   6392,   3211, 
+            0,  -3211,  -6392,  -9511, -12539, -15446, -18204, -20787, 
+       -23169, -25329, -27244, -28897, -30272, -31356, -32137, -32609, 
+       -32767, -32609, -32137, -31356, -30272, -28897, -27244, -25329, 
+       -23169, -20787, -18204, -15446, -12539,  -9511,  -6392,  -3211, 
+            0,   3211,   6392,   9511,  12539,  15446,  18204,  20787, 
+        23169,  25329,  27244,  28897,  30272,  31356,  32137,  32609
+};
+
+#define COS(x) costab[((x)>>10)&0x3f]
+#define SIN(x) COS((x)+0xc000)
+
+
+/*
+ * afsk2400 specific tables (tcm3105 clk 8000000.000000Hz)
+ */
+#define AFSK24_TX_FREQ_LO 2165
+#define AFSK24_TX_FREQ_HI 3970
+#define AFSK24_BITPLL_INC 9830
+#define AFSK24_SAMPLERATE 16000
+
+static const int afsk24_tx_lo_i[] = {
+          10,   11,   -4,  -51,  -86,  -49,   47,  118,   97,   17,  -37,  -35,  -11,    0 
+};
+#define SUM_AFSK24_TX_LO_I 27
+
+static const int afsk24_tx_lo_q[] = {
+           0,   12,   35,   34,  -22, -100, -115,  -40,   55,   87,   48,    2,  -11,  -10 
+};
+#define SUM_AFSK24_TX_LO_Q -25
+
+static const int afsk24_tx_hi_i[] = {
+          10,    0,  -35,   -2,   89,    6, -124,  -10,  111,    9,  -61,   -4,   16,    1 
+};
+#define SUM_AFSK24_TX_HI_I 6
+
+static const int afsk24_tx_hi_q[] = {
+           0,   16,    0,  -61,   -4,  112,    8, -124,  -10,   88,    7,  -35,   -2,   10 
+};
+#define SUM_AFSK24_TX_HI_Q 5
+
diff --git a/drivers/net/soundmodem/sm_tbl_afsk2666.h b/drivers/net/soundmodem/sm_tbl_afsk2666.h
new file mode 100644 (file)
index 0000000..839c7b1
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * THIS FILE IS GENERATED AUTOMATICALLY BY ./gentbl, DO NOT EDIT!
+ */
+
+
+/*
+ * small cosine table in U8 format
+ */
+#define OFFSCOSTABBITS 6
+#define OFFSCOSTABSIZE (1<<OFFSCOSTABBITS)
+
+static unsigned char offscostab[OFFSCOSTABSIZE] = {
+        255, 254, 252, 249, 245, 240, 233, 226,
+        217, 208, 198, 187, 176, 164, 152, 140,
+        128, 115, 103,  91,  79,  68,  57,  47,
+         38,  29,  22,  15,  10,   6,   3,   1,
+          1,   1,   3,   6,  10,  15,  22,  29,
+         38,  47,  57,  68,  79,  91, 103, 115,
+        127, 140, 152, 164, 176, 187, 198, 208,
+        217, 226, 233, 240, 245, 249, 252, 254
+};
+
+#define OFFSCOS(x) offscostab[((x)>>10)&0x3f]
+
+
+/*
+ * more accurate cosine table
+ */
+
+static const short costab[64] = {
+        32767,  32609,  32137,  31356,  30272,  28897,  27244,  25329, 
+        23169,  20787,  18204,  15446,  12539,   9511,   6392,   3211, 
+            0,  -3211,  -6392,  -9511, -12539, -15446, -18204, -20787, 
+       -23169, -25329, -27244, -28897, -30272, -31356, -32137, -32609, 
+       -32767, -32609, -32137, -31356, -30272, -28897, -27244, -25329, 
+       -23169, -20787, -18204, -15446, -12539,  -9511,  -6392,  -3211, 
+            0,   3211,   6392,   9511,  12539,  15446,  18204,  20787, 
+        23169,  25329,  27244,  28897,  30272,  31356,  32137,  32609
+};
+
+#define COS(x) costab[((x)>>10)&0x3f]
+#define SIN(x) COS((x)+0xc000)
+
+
+/*
+ * afsk2666 specific tables
+ */
+#define AFSK26_DEMCORRLEN 12
+#define AFSK26_SAMPLERATE 16000
+
+static const unsigned int afsk26_carfreq[2] = { 0x2000, 0x3555 };
+
+
+static const struct {
+       int i[12];
+       int q[12];
+} afsk26_dem_tables[2][2] = {
+       {
+               {{      1,      7,    -18,    -73,   -100,    -47,     47,    100,     73,     18,     -7,     -1 }, {      0,     17,     43,     30,    -41,   -115,   -115,    -41,     30,     43,     17,      0 }},
+#define AFSK26_DEM_SUM_I_0_0 0
+#define AFSK26_DEM_SUM_Q_0_0 -132
+               {{      1,     -7,    -46,    -10,    100,     76,    -75,   -100,     10,     46,      7,     -1 }, {      1,     17,     -6,    -79,    -41,     99,     99,    -41,    -79,     -6,     17,      1 }}
+#define AFSK26_DEM_SUM_I_0_1 1
+#define AFSK26_DEM_SUM_Q_0_1 -18
+       },
+       {
+               {{      8,     22,      0,    -67,   -118,    -89,      0,     67,     63,     22,      0,      0 }, {      0,     22,     63,     67,      0,    -89,   -118,    -67,      0,     22,      8,      0 }},
+#define AFSK26_DEM_SUM_I_1_0 -92
+#define AFSK26_DEM_SUM_Q_1_0 -92
+               {{      8,      8,    -54,    -67,     59,    122,      0,    -91,    -31,     22,      7,      0 }, {      0,     30,     31,    -67,   -102,     32,    118,     24,    -54,    -22,      4,      0 }}
+#define AFSK26_DEM_SUM_I_1_1 -17
+#define AFSK26_DEM_SUM_Q_1_1 -6
+       }
+};
+
diff --git a/drivers/net/soundmodem/sm_tbl_fsk9600.h b/drivers/net/soundmodem/sm_tbl_fsk9600.h
new file mode 100644 (file)
index 0000000..c3384a9
--- /dev/null
@@ -0,0 +1,302 @@
+/*
+ * THIS FILE IS GENERATED AUTOMATICALLY BY ./gentbl, DO NOT EDIT!
+ */
+
+
+/*
+ * fsk9600 specific tables
+ */
+static unsigned char fsk96_txfilt_4[] = {
+         37,  37,  35,  36,  39,  40,  38,  38,
+         53,  53,  51,  52,  55,  56,  54,  54,
+        210, 210, 208, 209, 212, 213, 211, 211,
+        226, 226, 224, 225, 228, 229, 227, 227,
+         23,  23,  22,  22,  26,  26,  24,  24,
+         39,  39,  38,  38,  42,  42,  40,  40,
+        196, 196, 195, 195, 199, 199, 197, 197,
+        212, 212, 211, 211, 215, 215, 213, 213,
+         43,  43,  42,  42,  46,  46,  44,  44,
+         59,  59,  58,  58,  62,  62,  60,  60,
+        216, 216, 215, 215, 219, 219, 217, 217,
+        232, 232, 231, 231, 235, 235, 233, 233,
+         29,  29,  28,  28,  32,  32,  30,  30,
+         45,  45,  44,  44,  48,  48,  46,  46,
+        202, 202, 201, 201, 205, 205, 203, 203,
+        218, 218, 217, 217, 221, 221, 219, 219,
+         36,  36,  34,  34,  38,  38,  37,  37,
+         52,  52,  50,  50,  54,  54,  53,  53,
+        209, 209, 207, 207, 211, 211, 210, 210,
+        225, 225, 223, 223, 227, 227, 226, 226,
+         22,  22,  20,  20,  24,  24,  23,  23,
+         38,  38,  36,  36,  40,  40,  39,  39,
+        195, 195, 193, 193, 197, 197, 196, 196,
+        211, 211, 209, 209, 213, 213, 212, 212,
+         42,  42,  40,  40,  44,  44,  43,  43,
+         58,  58,  56,  56,  60,  60,  59,  59,
+        215, 215, 213, 213, 217, 217, 216, 216,
+        231, 231, 229, 229, 233, 233, 232, 232,
+         28,  28,  26,  27,  30,  31,  29,  29,
+         44,  44,  42,  43,  46,  47,  45,  45,
+        201, 201, 199, 200, 203, 204, 202, 202,
+        217, 217, 215, 216, 219, 220, 218, 218,
+         37,  37,  37,  37,  29,  29,  29,  30,
+        108, 108, 108, 108, 100, 100, 100, 100,
+        169, 169, 169, 170, 161, 161, 162, 162,
+        240, 240, 240, 240, 232, 232, 232, 232,
+         19,  19,  19,  20,  11,  11,  12,  12,
+         90,  90,  90,  90,  82,  82,  82,  82,
+        151, 151, 152, 152, 143, 143, 144, 144,
+        222, 222, 222, 222, 214, 214, 215, 215,
+         41,  41,  41,  41,  33,  33,  33,  34,
+        112, 112, 112, 112, 104, 104, 104, 104,
+        173, 173, 173, 174, 165, 165, 166, 166,
+        244, 244, 244, 244, 236, 236, 236, 236,
+         23,  23,  23,  24,  15,  15,  16,  16,
+         94,  94,  94,  94,  86,  86,  86,  86,
+        155, 155, 156, 156, 147, 147, 148, 148,
+        226, 226, 226, 226, 218, 218, 219, 219,
+         36,  36,  37,  37,  29,  29,  29,  29,
+        107, 107, 108, 108,  99,  99, 100, 100,
+        169, 169, 169, 169, 161, 161, 161, 161,
+        239, 239, 240, 240, 231, 232, 232, 232,
+         19,  19,  19,  19,  11,  11,  11,  11,
+         89,  89,  90,  90,  81,  82,  82,  82,
+        151, 151, 151, 151, 143, 143, 143, 143,
+        221, 222, 222, 222, 214, 214, 214, 214,
+         40,  40,  41,  41,  33,  33,  33,  33,
+        111, 111, 112, 112, 103, 103, 104, 104,
+        173, 173, 173, 173, 165, 165, 165, 165,
+        243, 243, 244, 244, 235, 236, 236, 236,
+         23,  23,  23,  23,  15,  15,  15,  15,
+         93,  93,  94,  94,  85,  86,  86,  86,
+        155, 155, 155, 155, 147, 147, 147, 147,
+        225, 226, 226, 226, 218, 218, 218, 218,
+         37,  36,  41,  40,  19,  19,  23,  23,
+        169, 169, 173, 173, 151, 151, 155, 155,
+        108, 107, 112, 111,  90,  89,  94,  93,
+        240, 239, 244, 243, 222, 221, 226, 225,
+         29,  29,  33,  33,  11,  11,  15,  15,
+        161, 161, 165, 165, 143, 143, 147, 147,
+        100,  99, 104, 103,  82,  81,  86,  85,
+        232, 231, 236, 235, 214, 214, 218, 218,
+         37,  37,  41,  41,  19,  19,  23,  23,
+        169, 169, 173, 173, 152, 151, 156, 155,
+        108, 108, 112, 112,  90,  90,  94,  94,
+        240, 240, 244, 244, 222, 222, 226, 226,
+         29,  29,  33,  33,  12,  11,  16,  15,
+        162, 161, 166, 165, 144, 143, 148, 147,
+        100, 100, 104, 104,  82,  82,  86,  86,
+        232, 232, 236, 236, 215, 214, 219, 218,
+         37,  36,  41,  40,  19,  19,  23,  23,
+        169, 169, 173, 173, 151, 151, 155, 155,
+        108, 107, 112, 111,  90,  89,  94,  93,
+        240, 239, 244, 243, 222, 222, 226, 226,
+         29,  29,  33,  33,  11,  11,  15,  15,
+        161, 161, 165, 165, 143, 143, 147, 147,
+        100,  99, 104, 103,  82,  82,  86,  86,
+        232, 232, 236, 236, 214, 214, 218, 218,
+         37,  37,  41,  41,  20,  19,  24,  23,
+        170, 169, 174, 173, 152, 151, 156, 155,
+        108, 108, 112, 112,  90,  90,  94,  94,
+        240, 240, 244, 244, 222, 222, 226, 226,
+         30,  29,  34,  33,  12,  11,  16,  15,
+        162, 161, 166, 165, 144, 143, 148, 147,
+        100, 100, 104, 104,  82,  82,  86,  86,
+        232, 232, 236, 236, 215, 214, 219, 218,
+         37,  36,  43,  42,  23,  22,  29,  28,
+        210, 209, 216, 215, 196, 195, 202, 201,
+         53,  52,  59,  58,  39,  38,  45,  44,
+        226, 225, 232, 231, 212, 211, 218, 217,
+         39,  38,  46,  44,  26,  24,  32,  30,
+        212, 211, 219, 217, 199, 197, 205, 203,
+         55,  54,  62,  60,  42,  40,  48,  46,
+        228, 227, 235, 233, 215, 213, 221, 219,
+         35,  34,  42,  40,  22,  20,  28,  26,
+        208, 207, 215, 213, 195, 193, 201, 199,
+         51,  50,  58,  56,  38,  36,  44,  42,
+        224, 223, 231, 229, 211, 209, 217, 215,
+         38,  37,  44,  43,  24,  23,  30,  29,
+        211, 210, 217, 216, 197, 196, 203, 202,
+         54,  53,  60,  59,  40,  39,  46,  45,
+        227, 226, 233, 232, 213, 212, 219, 218,
+         37,  36,  43,  42,  23,  22,  29,  28,
+        210, 209, 216, 215, 196, 195, 202, 201,
+         53,  52,  59,  58,  39,  38,  45,  44,
+        226, 225, 232, 231, 212, 211, 218, 217,
+         40,  38,  46,  44,  26,  24,  32,  31,
+        213, 211, 219, 217, 199, 197, 205, 204,
+         56,  54,  62,  60,  42,  40,  48,  47,
+        229, 227, 235, 233, 215, 213, 221, 220,
+         36,  34,  42,  40,  22,  20,  28,  27,
+        209, 207, 215, 213, 195, 193, 201, 200,
+         52,  50,  58,  56,  38,  36,  44,  43,
+        225, 223, 231, 229, 211, 209, 217, 216,
+         38,  37,  44,  43,  24,  23,  30,  29,
+        211, 210, 217, 216, 197, 196, 203, 202,
+         54,  53,  60,  59,  40,  39,  46,  45,
+        227, 226, 233, 232, 213, 212, 219, 218
+};
+
+static unsigned char fsk96_txfilt_5[] = {
+         39,  40,  38,  38,  42,  43,  41,  41,
+         51,  51,  50,  50,  54,  54,  53,  53,
+        209, 209, 207, 208, 212, 212, 210, 211,
+        221, 221, 219, 219, 224, 224, 222, 222,
+         28,  28,  27,  27,  31,  31,  30,  30,
+         40,  40,  38,  39,  43,  43,  41,  42,
+        198, 198, 196, 196, 201, 201, 199, 199,
+        209, 210, 208, 208, 212, 213, 211, 211,
+         45,  45,  44,  44,  48,  48,  47,  47,
+         57,  57,  56,  56,  60,  60,  59,  59,
+        215, 215, 213, 213, 218, 218, 216, 216,
+        227, 227, 225, 225, 230, 230, 228, 228,
+         34,  34,  32,  33,  37,  37,  35,  36,
+         46,  46,  44,  44,  49,  49,  47,  47,
+        203, 204, 202, 202, 206, 207, 205, 205,
+        215, 215, 214, 214, 218, 218, 217, 217,
+         38,  38,  37,  37,  41,  41,  40,  40,
+         50,  50,  48,  49,  53,  53,  51,  52,
+        208, 208, 206, 206, 211, 211, 209, 209,
+        219, 220, 218, 218, 222, 223, 221, 221,
+         27,  27,  25,  25,  30,  30,  28,  28,
+         39,  39,  37,  37,  42,  42,  40,  40,
+        196, 196, 195, 195, 199, 199, 198, 198,
+        208, 208, 207, 207, 211, 211, 210, 210,
+         44,  44,  42,  43,  47,  47,  45,  46,
+         56,  56,  54,  54,  59,  59,  57,  57,
+        213, 214, 212, 212, 216, 217, 215, 215,
+        225, 225, 224, 224, 228, 228, 227, 227,
+         33,  33,  31,  31,  36,  36,  34,  34,
+         44,  45,  43,  43,  47,  48,  46,  46,
+        202, 202, 201, 201, 205, 205, 204, 204,
+        214, 214, 212, 213, 217, 217, 215, 216,
+         39,  40,  39,  39,  35,  35,  35,  35,
+         91,  91,  90,  90,  86,  87,  86,  86,
+        183, 183, 182, 182, 178, 179, 178, 178,
+        234, 234, 234, 234, 230, 230, 229, 230,
+         21,  22,  21,  21,  17,  17,  17,  17,
+         73,  73,  72,  72,  68,  69,  68,  68,
+        165, 165, 164, 164, 161, 161, 160, 160,
+        216, 216, 216, 216, 212, 212, 211, 212,
+         44,  44,  44,  44,  40,  40,  40,  40,
+         95,  96,  95,  95,  91,  91,  91,  91,
+        187, 188, 187, 187, 183, 183, 183, 183,
+        239, 239, 238, 239, 235, 235, 234, 234,
+         26,  26,  26,  26,  22,  22,  22,  22,
+         77,  78,  77,  77,  73,  73,  73,  73,
+        170, 170, 169, 169, 165, 165, 165, 165,
+        221, 221, 220, 221, 217, 217, 216, 216,
+         39,  39,  38,  38,  34,  35,  34,  34,
+         90,  90,  90,  90,  86,  86,  85,  85,
+        182, 182, 182, 182, 178, 178, 177, 178,
+        233, 233, 233, 233, 229, 229, 229, 229,
+         21,  21,  20,  20,  16,  17,  16,  16,
+         72,  72,  72,  72,  68,  68,  67,  68,
+        164, 164, 164, 164, 160, 160, 159, 160,
+        215, 215, 215, 215, 211, 211, 211, 211,
+         43,  44,  43,  43,  39,  39,  39,  39,
+         95,  95,  94,  94,  91,  91,  90,  90,
+        187, 187, 186, 187, 183, 183, 182, 182,
+        238, 238, 238, 238, 234, 234, 233, 234,
+         25,  26,  25,  25,  21,  21,  21,  21,
+         77,  77,  76,  77,  73,  73,  72,  72,
+        169, 169, 168, 169, 165, 165, 164, 164,
+        220, 220, 220, 220, 216, 216, 215, 216,
+         39,  39,  41,  41,  26,  26,  28,  28,
+        139, 139, 141, 141, 126, 125, 128, 128,
+        139, 139, 141, 141, 126, 125, 128, 127,
+        238, 238, 240, 240, 225, 225, 227, 227,
+         26,  26,  28,  28,  13,  13,  15,  15,
+        126, 125, 128, 128, 112, 112, 115, 114,
+        126, 125, 128, 127, 112, 112, 115, 114,
+        225, 225, 227, 227, 212, 212, 214, 214,
+         41,  41,  44,  43,  28,  28,  30,  30,
+        141, 141, 143, 143, 128, 128, 130, 130,
+        141, 141, 143, 143, 128, 127, 130, 130,
+        240, 240, 242, 242, 227, 227, 229, 229,
+         28,  28,  30,  30,  15,  15,  17,  17,
+        128, 128, 130, 130, 115, 114, 117, 116,
+        128, 127, 130, 130, 115, 114, 117, 116,
+        227, 227, 229, 229, 214, 214, 216, 216,
+         39,  39,  41,  41,  26,  26,  28,  28,
+        139, 138, 141, 140, 125, 125, 128, 127,
+        139, 138, 141, 140, 125, 125, 127, 127,
+        238, 238, 240, 240, 225, 225, 227, 227,
+         26,  26,  28,  28,  13,  13,  15,  15,
+        125, 125, 128, 127, 112, 112, 114, 114,
+        125, 125, 127, 127, 112, 112, 114, 114,
+        225, 225, 227, 227, 212, 211, 214, 214,
+         41,  41,  43,  43,  28,  28,  30,  30,
+        141, 140, 143, 143, 128, 127, 130, 129,
+        141, 140, 143, 143, 127, 127, 130, 129,
+        240, 240, 242, 242, 227, 227, 229, 229,
+         28,  28,  30,  30,  15,  15,  17,  17,
+        128, 127, 130, 129, 114, 114, 116, 116,
+        127, 127, 130, 129, 114, 114, 116, 116,
+        227, 227, 229, 229, 214, 214, 216, 216,
+         39,  39,  44,  43,  21,  21,  26,  25,
+        183, 182, 187, 187, 165, 164, 170, 169,
+         91,  90,  95,  95,  73,  72,  77,  77,
+        234, 233, 239, 238, 216, 215, 221, 220,
+         35,  34,  40,  39,  17,  16,  22,  21,
+        178, 178, 183, 183, 161, 160, 165, 165,
+         86,  86,  91,  91,  68,  68,  73,  73,
+        230, 229, 235, 234, 212, 211, 217, 216,
+         39,  38,  44,  43,  21,  20,  26,  25,
+        182, 182, 187, 186, 164, 164, 169, 168,
+         90,  90,  95,  94,  72,  72,  77,  76,
+        234, 233, 238, 238, 216, 215, 220, 220,
+         35,  34,  40,  39,  17,  16,  22,  21,
+        178, 177, 183, 182, 160, 159, 165, 164,
+         86,  85,  91,  90,  68,  67,  73,  72,
+        229, 229, 234, 233, 211, 211, 216, 215,
+         40,  39,  44,  44,  22,  21,  26,  26,
+        183, 182, 188, 187, 165, 164, 170, 169,
+         91,  90,  96,  95,  73,  72,  78,  77,
+        234, 233, 239, 238, 216, 215, 221, 220,
+         35,  35,  40,  39,  17,  17,  22,  21,
+        179, 178, 183, 183, 161, 160, 165, 165,
+         87,  86,  91,  91,  69,  68,  73,  73,
+        230, 229, 235, 234, 212, 211, 217, 216,
+         39,  38,  44,  43,  21,  20,  26,  25,
+        182, 182, 187, 187, 164, 164, 169, 169,
+         90,  90,  95,  94,  72,  72,  77,  77,
+        234, 233, 239, 238, 216, 215, 221, 220,
+         35,  34,  40,  39,  17,  16,  22,  21,
+        178, 178, 183, 182, 160, 160, 165, 164,
+         86,  85,  91,  90,  68,  68,  73,  72,
+        230, 229, 234, 234, 212, 211, 216, 216,
+         39,  38,  45,  44,  28,  27,  34,  33,
+        209, 208, 215, 213, 198, 196, 203, 202,
+         51,  50,  57,  56,  40,  39,  46,  44,
+        221, 219, 227, 225, 209, 208, 215, 214,
+         42,  41,  48,  47,  31,  30,  37,  36,
+        212, 211, 218, 216, 201, 199, 206, 205,
+         54,  53,  60,  59,  43,  42,  49,  47,
+        224, 222, 230, 228, 212, 211, 218, 217,
+         38,  37,  44,  42,  27,  25,  32,  31,
+        207, 206, 213, 212, 196, 195, 202, 201,
+         50,  48,  56,  54,  38,  37,  44,  43,
+        219, 218, 225, 224, 208, 207, 214, 212,
+         41,  40,  47,  45,  30,  28,  35,  34,
+        210, 209, 216, 215, 199, 198, 205, 204,
+         53,  51,  59,  57,  41,  40,  47,  46,
+        222, 221, 228, 227, 211, 210, 217, 215,
+         40,  38,  45,  44,  28,  27,  34,  33,
+        209, 208, 215, 214, 198, 196, 204, 202,
+         51,  50,  57,  56,  40,  39,  46,  45,
+        221, 220, 227, 225, 210, 208, 215, 214,
+         43,  41,  48,  47,  31,  30,  37,  36,
+        212, 211, 218, 217, 201, 199, 207, 205,
+         54,  53,  60,  59,  43,  42,  49,  48,
+        224, 223, 230, 228, 213, 211, 218, 217,
+         38,  37,  44,  43,  27,  25,  33,  31,
+        208, 206, 213, 212, 196, 195, 202, 201,
+         50,  49,  56,  54,  39,  37,  44,  43,
+        219, 218, 225, 224, 208, 207, 214, 213,
+         41,  40,  47,  46,  30,  28,  36,  34,
+        211, 209, 216, 215, 199, 198, 205, 204,
+         53,  52,  59,  57,  42,  40,  47,  46,
+        222, 221, 228, 227, 211, 210, 217, 216
+};
+
diff --git a/drivers/net/soundmodem/sm_tbl_hapn4800.h b/drivers/net/soundmodem/sm_tbl_hapn4800.h
new file mode 100644 (file)
index 0000000..39de6d9
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * THIS FILE IS GENERATED AUTOMATICALLY BY ./gentbl, DO NOT EDIT!
+ */
+
+
+/*
+ * hapn4800 specific tables
+ */
+
+static unsigned char hapn48_txfilt_8[] = {
+        128, 127,  92,  91, 151, 150, 115, 114,
+        141, 140, 105, 104, 164, 163, 128, 128,
+        127, 128,  63,  63, 193, 194, 129, 129,
+        126, 126,  61,  62, 192, 192, 127, 128,
+        128, 129,  37,  38, 224, 226, 134, 135,
+        120, 121,  29,  31, 217, 218, 126, 127,
+        128, 132,  19,  24, 239, 243, 130, 135,
+        120, 125,  12,  16, 231, 236, 123, 127,
+        128, 135,  16,  24, 236, 243, 125, 132,
+        123, 130,  12,  19, 231, 239, 120, 127,
+        128, 135,  31,  38, 218, 226, 121, 129,
+        126, 134,  29,  37, 217, 224, 120, 127,
+        127, 129,  62,  63, 192, 194, 126, 128,
+        127, 129,  61,  63, 192, 193, 126, 128,
+        128, 114, 104,  91, 163, 150, 140, 127,
+        128, 115, 105,  92, 164, 151, 141, 127
+};
+
+static unsigned char hapn48_txfilt_10[] = {
+        128, 127,  94,  94, 146, 146, 113, 112,
+        143, 142, 109, 109, 161, 161, 128, 128,
+        128, 127,  72,  72, 182, 182, 126, 126,
+        129, 129,  73,  73, 183, 183, 128, 127,
+        127, 128,  49,  50, 211, 212, 133, 133,
+        122, 122,  43,  44, 205, 206, 127, 128,
+        127, 130,  30,  33, 231, 233, 133, 136,
+        119, 122,  22,  24, 222, 225, 125, 128,
+        127, 133,  18,  23, 240, 245, 130, 135,
+        120, 125,  10,  15, 232, 237, 122, 128,
+        128, 135,  15,  23, 237, 245, 125, 133,
+        122, 130,  10,  18, 232, 240, 120, 128,
+        127, 136,  24,  33, 225, 233, 122, 130,
+        125, 133,  22,  30, 222, 231, 119, 128,
+        128, 133,  44,  50, 206, 212, 122, 128,
+        127, 133,  43,  49, 205, 211, 122, 127,
+        127, 126,  73,  72, 183, 182, 129, 127,
+        128, 126,  73,  72, 183, 182, 129, 128,
+        128, 112, 109,  94, 161, 146, 142, 127,
+        128, 113, 109,  94, 161, 146, 143, 127
+};
+
+static unsigned char hapn48_txfilt_pm8[] = {
+         12,   6, 242, 237,  18,  12, 248, 243,
+         12,   7, 243, 237,  18,  13, 249, 243,
+         12,  18, 243, 248,   7,  12, 237, 243,
+         12,  18, 243, 248,   7,  12, 237, 243,
+         12,  39, 225, 252,   3,  30, 216, 243,
+         12,  39, 225, 252,   3,  30, 216, 243,
+         11,  70, 193, 252,   3,  62, 185, 244,
+         11,  70, 193, 252,   3,  62, 185, 244,
+         11, 109, 152, 250,   5, 103, 146, 244,
+         11, 109, 152, 250,   5, 103, 146, 244,
+          9, 150, 107, 248,   7, 148, 105, 246,
+          9, 150, 107, 248,   7, 148, 105, 246,
+          8, 189,  66, 248,   7, 189,  66, 247,
+          8, 189,  66, 248,   7, 189,  66, 247,
+          7, 221,  34, 248,   7, 221,  34, 248,
+          7, 221,  34, 248,   7, 221,  34, 248
+};
+
+static unsigned char hapn48_txfilt_pm10[] = {
+         12,  12,   8,   8, 243, 243, 238, 238,
+         17,  17,  12,  12, 247, 247, 243, 243,
+          8,   8,  12,  13, 238, 239, 243, 243,
+         12,  12,  16,  17, 242, 243, 247, 247,
+          8,   8,  28,  28, 227, 227, 247, 247,
+          8,   8,  28,  28, 227, 227, 247, 247,
+          9,   8,  50,  50, 207, 206, 248, 248,
+          7,   7,  49,  48, 205, 205, 247, 246,
+         10,   9,  79,  78, 179, 178, 249, 248,
+          7,   6,  77,  76, 177, 176, 246, 245,
+         11,   8, 113, 110, 147, 144, 249, 246,
+          9,   6, 111, 108, 145, 142, 247, 244,
+         12,   7, 148, 143, 114, 109, 250, 245,
+         10,   5, 146, 141, 112, 107, 248, 243,
+         12,   5, 181, 174,  82,  74, 251, 244,
+         11,   4, 181, 173,  81,  74, 250, 243,
+         12,   3, 210, 201,  54,  45, 252, 243,
+         12,   3, 210, 201,  54,  45, 252, 243,
+         12,   4, 231, 223,  32,  24, 251, 243,
+         12,   4, 231, 223,  32,  24, 251, 243
+};
+
diff --git a/drivers/net/soundmodem/sm_tbl_psk4800.h b/drivers/net/soundmodem/sm_tbl_psk4800.h
new file mode 100644 (file)
index 0000000..e3d57ba
--- /dev/null
@@ -0,0 +1,373 @@
+/*
+ * THIS FILE IS GENERATED AUTOMATICALLY BY ./gentbl, DO NOT EDIT!
+ */
+
+
+/*
+ * psk4800 specific tables
+ */
+#define PSK48_TXF_OVERSAMPLING 5
+#define PSK48_TXF_NUMSAMPLES 16
+
+#define PSK48_SAMPLERATE  8000
+#define PSK48_CAR_FREQ    2000
+#define PSK48_PSK_LEN     5
+#define PSK48_RXF_LEN     64
+#define PSK48_PHASEINC    (0x10000*PSK48_CAR_FREQ/PSK48_SAMPLERATE)
+#define PSK48_SPHASEINC   (0x10000/(2*PSK48_PSK_LEN))
+
+static const short psk48_tx_table[PSK48_TXF_OVERSAMPLING*PSK48_TXF_NUMSAMPLES*8*2] = {
+          -12,     -8,      0,      8,     12,      8,      0,     -8, 
+            0,     -8,    -12,     -8,      0,      8,     12,      8, 
+          -20,    -14,      0,     14,     20,     14,      0,    -14, 
+            0,    -14,    -20,    -14,      0,     14,     20,     14, 
+          -45,    -32,      0,     32,     45,     32,      0,    -32, 
+            0,    -32,    -45,    -32,      0,     32,     45,     32, 
+          -92,    -65,      0,     65,     92,     65,      0,    -65, 
+            0,    -65,    -92,    -65,      0,     65,     92,     65, 
+         -172,   -122,      0,    122,    172,    122,      0,   -122, 
+            0,   -122,   -172,   -122,      0,    122,    172,    122, 
+         -307,   -217,      0,    217,    307,    217,      0,   -217, 
+            0,   -217,   -307,   -217,      0,    217,    307,    217, 
+         -564,   -399,      0,    399,    564,    399,      0,   -399, 
+            0,   -399,   -564,   -399,      0,    399,    564,    399, 
+        -1322,   -935,      0,    935,   1322,    935,      0,   -935, 
+            0,   -935,  -1322,   -935,      0,    935,   1322,    935, 
+        12256,   8666,      0,  -8666, -12256,  -8666,      0,   8666, 
+            0,   8666,  12256,   8666,      0,  -8666, -12256,  -8666, 
+         1066,    754,      0,   -754,  -1066,   -754,      0,    754, 
+            0,    754,   1066,    754,      0,   -754,  -1066,   -754, 
+          495,    350,      0,   -350,   -495,   -350,      0,    350, 
+            0,    350,    495,    350,      0,   -350,   -495,   -350, 
+          273,    193,      0,   -193,   -273,   -193,      0,    193, 
+            0,    193,    273,    193,      0,   -193,   -273,   -193, 
+          153,    108,      0,   -108,   -153,   -108,      0,    108, 
+            0,    108,    153,    108,      0,   -108,   -153,   -108, 
+           81,     57,      0,    -57,    -81,    -57,      0,     57, 
+            0,     57,     81,     57,      0,    -57,    -81,    -57, 
+           38,     27,      0,    -27,    -38,    -27,      0,     27, 
+            0,     27,     38,     27,      0,    -27,    -38,    -27, 
+           17,     12,      0,    -12,    -17,    -12,      0,     12, 
+            0,     12,     17,     12,      0,    -12,    -17,    -12, 
+          -20,    -14,      0,     14,     20,     14,      0,    -14, 
+            0,    -14,    -20,    -14,      0,     14,     20,     14, 
+          -38,    -27,      0,     27,     38,     27,      0,    -27, 
+            0,    -27,    -38,    -27,      0,     27,     38,     27, 
+          -85,    -60,      0,     60,     85,     60,      0,    -60, 
+            0,    -60,    -85,    -60,      0,     60,     85,     60, 
+         -170,   -120,      0,    120,    170,    120,      0,   -120, 
+            0,   -120,   -170,   -120,      0,    120,    170,    120, 
+         -314,   -222,      0,    222,    314,    222,      0,   -222, 
+            0,   -222,   -314,   -222,      0,    222,    314,    222, 
+         -557,   -394,      0,    394,    557,    394,      0,   -394, 
+            0,   -394,   -557,   -394,      0,    394,    557,    394, 
+        -1048,   -741,      0,    741,   1048,    741,      0,   -741, 
+            0,   -741,  -1048,   -741,      0,    741,   1048,    741, 
+        -2783,  -1968,      0,   1968,   2783,   1968,      0,  -1968, 
+            0,  -1968,  -2783,  -1968,      0,   1968,   2783,   1968, 
+         6591,   4660,      0,  -4660,  -6591,  -4660,      0,   4660, 
+            0,   4660,   6591,   4660,      0,  -4660,  -6591,  -4660, 
+         1434,   1014,      0,  -1014,  -1434,  -1014,      0,   1014, 
+            0,   1014,   1434,   1014,      0,  -1014,  -1434,  -1014, 
+          707,    500,      0,   -500,   -707,   -500,      0,    500, 
+            0,    500,    707,    500,      0,   -500,   -707,   -500, 
+          395,    279,      0,   -279,   -395,   -279,      0,    279, 
+            0,    279,    395,    279,      0,   -279,   -395,   -279, 
+          219,    155,      0,   -155,   -219,   -155,      0,    155, 
+            0,    155,    219,    155,      0,   -155,   -219,   -155, 
+          114,     80,      0,    -80,   -114,    -80,      0,     80, 
+            0,     80,    114,     80,      0,    -80,   -114,    -80, 
+           53,     37,      0,    -37,    -53,    -37,      0,     37, 
+            0,     37,     53,     37,      0,    -37,    -53,    -37, 
+           25,     17,      0,    -17,    -25,    -17,      0,     17, 
+            0,     17,     25,     17,      0,    -17,    -25,    -17, 
+            0,      0,      0,      0,      0,      0,      0,      0, 
+            0,      0,      0,      0,      0,      0,      0,      0, 
+            0,      0,      0,      0,      0,      0,      0,      0, 
+            0,      0,      0,      0,      0,      0,      0,      0, 
+            0,      0,      0,      0,      0,      0,      0,      0, 
+            0,      0,      0,      0,      0,      0,      0,      0, 
+            0,      0,      0,      0,      0,      0,      0,      0, 
+            0,      0,      0,      0,      0,      0,      0,      0, 
+            0,      0,      0,      0,      0,      0,      0,      0, 
+            0,      0,      0,      0,      0,      0,      0,      0, 
+            0,      0,      0,      0,      0,      0,      0,      0, 
+            0,      0,      0,      0,      0,      0,      0,      0, 
+            0,      0,      0,      0,      0,      0,      0,      0, 
+            0,      0,      0,      0,      0,      0,      0,      0, 
+            0,      0,      0,      0,      0,      0,      0,      0, 
+            0,      0,      0,      0,      0,      0,      0,      0, 
+            0,      0,      0,      0,      0,      0,      0,      0, 
+            0,      0,      0,      0,      0,      0,      0,      0, 
+            0,      0,      0,      0,      0,      0,      0,      0, 
+            0,      0,      0,      0,      0,      0,      0,      0, 
+            0,      0,      0,      0,      0,      0,      0,      0, 
+            0,      0,      0,      0,      0,      0,      0,      0, 
+            0,      0,      0,      0,      0,      0,      0,      0, 
+            0,      0,      0,      0,      0,      0,      0,      0, 
+            0,      0,      0,      0,      0,      0,      0,      0, 
+            0,      0,      0,      0,      0,      0,      0,      0, 
+            0,      0,      0,      0,      0,      0,      0,      0, 
+            0,      0,      0,      0,      0,      0,      0,      0, 
+            0,      0,      0,      0,      0,      0,      0,      0, 
+            0,      0,      0,      0,      0,      0,      0,      0, 
+            0,      0,      0,      0,      0,      0,      0,      0, 
+            0,      0,      0,      0,      0,      0,      0,      0, 
+           25,     17,      0,    -17,    -25,    -17,      0,     17, 
+            0,     17,     25,     17,      0,    -17,    -25,    -17, 
+           53,     37,      0,    -37,    -53,    -37,      0,     37, 
+            0,     37,     53,     37,      0,    -37,    -53,    -37, 
+          114,     80,      0,    -80,   -114,    -80,      0,     80, 
+            0,     80,    114,     80,      0,    -80,   -114,    -80, 
+          219,    155,      0,   -155,   -219,   -155,      0,    155, 
+            0,    155,    219,    155,      0,   -155,   -219,   -155, 
+          395,    279,      0,   -279,   -395,   -279,      0,    279, 
+            0,    279,    395,    279,      0,   -279,   -395,   -279, 
+          707,    500,      0,   -500,   -707,   -500,      0,    500, 
+            0,    500,    707,    500,      0,   -500,   -707,   -500, 
+         1434,   1014,      0,  -1014,  -1434,  -1014,      0,   1014, 
+            0,   1014,   1434,   1014,      0,  -1014,  -1434,  -1014, 
+         6591,   4660,      0,  -4660,  -6591,  -4660,      0,   4660, 
+            0,   4660,   6591,   4660,      0,  -4660,  -6591,  -4660, 
+        -2783,  -1968,      0,   1968,   2783,   1968,      0,  -1968, 
+            0,  -1968,  -2783,  -1968,      0,   1968,   2783,   1968, 
+        -1048,   -741,      0,    741,   1048,    741,      0,   -741, 
+            0,   -741,  -1048,   -741,      0,    741,   1048,    741, 
+         -557,   -394,      0,    394,    557,    394,      0,   -394, 
+            0,   -394,   -557,   -394,      0,    394,    557,    394, 
+         -314,   -222,      0,    222,    314,    222,      0,   -222, 
+            0,   -222,   -314,   -222,      0,    222,    314,    222, 
+         -170,   -120,      0,    120,    170,    120,      0,   -120, 
+            0,   -120,   -170,   -120,      0,    120,    170,    120, 
+          -85,    -60,      0,     60,     85,     60,      0,    -60, 
+            0,    -60,    -85,    -60,      0,     60,     85,     60, 
+          -38,    -27,      0,     27,     38,     27,      0,    -27, 
+            0,    -27,    -38,    -27,      0,     27,     38,     27, 
+          -20,    -14,      0,     14,     20,     14,      0,    -14, 
+            0,    -14,    -20,    -14,      0,     14,     20,     14, 
+           17,     12,      0,    -12,    -17,    -12,      0,     12, 
+            0,     12,     17,     12,      0,    -12,    -17,    -12, 
+           38,     27,      0,    -27,    -38,    -27,      0,     27, 
+            0,     27,     38,     27,      0,    -27,    -38,    -27, 
+           81,     57,      0,    -57,    -81,    -57,      0,     57, 
+            0,     57,     81,     57,      0,    -57,    -81,    -57, 
+          153,    108,      0,   -108,   -153,   -108,      0,    108, 
+            0,    108,    153,    108,      0,   -108,   -153,   -108, 
+          273,    193,      0,   -193,   -273,   -193,      0,    193, 
+            0,    193,    273,    193,      0,   -193,   -273,   -193, 
+          495,    350,      0,   -350,   -495,   -350,      0,    350, 
+            0,    350,    495,    350,      0,   -350,   -495,   -350, 
+         1066,    754,      0,   -754,  -1066,   -754,      0,    754, 
+            0,    754,   1066,    754,      0,   -754,  -1066,   -754, 
+        12256,   8666,      0,  -8666, -12256,  -8666,      0,   8666, 
+            0,   8666,  12256,   8666,      0,  -8666, -12256,  -8666, 
+        -1322,   -935,      0,    935,   1322,    935,      0,   -935, 
+            0,   -935,  -1322,   -935,      0,    935,   1322,    935, 
+         -564,   -399,      0,    399,    564,    399,      0,   -399, 
+            0,   -399,   -564,   -399,      0,    399,    564,    399, 
+         -307,   -217,      0,    217,    307,    217,      0,   -217, 
+            0,   -217,   -307,   -217,      0,    217,    307,    217, 
+         -172,   -122,      0,    122,    172,    122,      0,   -122, 
+            0,   -122,   -172,   -122,      0,    122,    172,    122, 
+          -92,    -65,      0,     65,     92,     65,      0,    -65, 
+            0,    -65,    -92,    -65,      0,     65,     92,     65, 
+          -45,    -32,      0,     32,     45,     32,      0,    -32, 
+            0,    -32,    -45,    -32,      0,     32,     45,     32, 
+          -20,    -14,      0,     14,     20,     14,      0,    -14, 
+            0,    -14,    -20,    -14,      0,     14,     20,     14, 
+          -12,     -8,      0,      8,     12,      8,      0,     -8, 
+            0,     -8,    -12,     -8,      0,      8,     12,      8
+};
+
+static const short psk48_rx_coeff[PSK48_RXF_LEN] = {
+           -7,    11,    28,    35,    24,    -6,   -48,   -79,
+          -76,   -22,    68,   157,   186,   114,   -53,  -250,
+         -370,  -315,   -58,   318,   636,   694,   371,  -281,
+        -1014, -1444, -1200,   -86,  1793,  4033,  6035,  7215,
+         7215,  6035,  4033,  1793,   -86, -1200, -1444, -1014,
+         -281,   371,   694,   636,   318,   -58,  -315,  -370,
+         -250,   -53,   114,   186,   157,    68,   -22,   -76,
+          -79,   -48,    -6,    24,    35,    28,    11,    -7
+};
+
+
+/*
+ * more accurate cosine table
+ */
+
+static const short costab[256] = {
+        32767,  32757,  32727,  32678,  32609,  32520,  32412,  32284, 
+        32137,  31970,  31785,  31580,  31356,  31113,  30851,  30571, 
+        30272,  29955,  29621,  29268,  28897,  28510,  28105,  27683, 
+        27244,  26789,  26318,  25831,  25329,  24811,  24278,  23731, 
+        23169,  22594,  22004,  21402,  20787,  20159,  19519,  18867, 
+        18204,  17530,  16845,  16150,  15446,  14732,  14009,  13278, 
+        12539,  11792,  11038,  10278,   9511,   8739,   7961,   7179, 
+         6392,   5601,   4807,   4011,   3211,   2410,   1607,    804, 
+            0,   -804,  -1607,  -2410,  -3211,  -4011,  -4807,  -5601, 
+        -6392,  -7179,  -7961,  -8739,  -9511, -10278, -11038, -11792, 
+       -12539, -13278, -14009, -14732, -15446, -16150, -16845, -17530, 
+       -18204, -18867, -19519, -20159, -20787, -21402, -22004, -22594, 
+       -23169, -23731, -24278, -24811, -25329, -25831, -26318, -26789, 
+       -27244, -27683, -28105, -28510, -28897, -29268, -29621, -29955, 
+       -30272, -30571, -30851, -31113, -31356, -31580, -31785, -31970, 
+       -32137, -32284, -32412, -32520, -32609, -32678, -32727, -32757, 
+       -32767, -32757, -32727, -32678, -32609, -32520, -32412, -32284, 
+       -32137, -31970, -31785, -31580, -31356, -31113, -30851, -30571, 
+       -30272, -29955, -29621, -29268, -28897, -28510, -28105, -27683, 
+       -27244, -26789, -26318, -25831, -25329, -24811, -24278, -23731, 
+       -23169, -22594, -22004, -21402, -20787, -20159, -19519, -18867, 
+       -18204, -17530, -16845, -16150, -15446, -14732, -14009, -13278, 
+       -12539, -11792, -11038, -10278,  -9511,  -8739,  -7961,  -7179, 
+        -6392,  -5601,  -4807,  -4011,  -3211,  -2410,  -1607,   -804, 
+            0,    804,   1607,   2410,   3211,   4011,   4807,   5601, 
+         6392,   7179,   7961,   8739,   9511,  10278,  11038,  11792, 
+        12539,  13278,  14009,  14732,  15446,  16150,  16845,  17530, 
+        18204,  18867,  19519,  20159,  20787,  21402,  22004,  22594, 
+        23169,  23731,  24278,  24811,  25329,  25831,  26318,  26789, 
+        27244,  27683,  28105,  28510,  28897,  29268,  29621,  29955, 
+        30272,  30571,  30851,  31113,  31356,  31580,  31785,  31970, 
+        32137,  32284,  32412,  32520,  32609,  32678,  32727,  32757
+};
+
+#define COS(x) costab[((x)>>8)&0xff]
+#define SIN(x) COS((x)+0xc000)
+
+
+/*
+ * arctan table (indexed by i/q; should really be indexed by i/(i+q)
+ */
+#define ATAN_TABLEN 1024
+
+static const unsigned short atan_tab[ATAN_TABLEN+2] = {
+            0,     10,     20,     30,     40,     50,     61,     71, 
+           81,     91,    101,    112,    122,    132,    142,    152, 
+          162,    173,    183,    193,    203,    213,    224,    234, 
+          244,    254,    264,    274,    285,    295,    305,    315, 
+          325,    336,    346,    356,    366,    376,    386,    397, 
+          407,    417,    427,    437,    447,    458,    468,    478, 
+          488,    498,    508,    519,    529,    539,    549,    559, 
+          569,    579,    590,    600,    610,    620,    630,    640, 
+          651,    661,    671,    681,    691,    701,    711,    722, 
+          732,    742,    752,    762,    772,    782,    792,    803, 
+          813,    823,    833,    843,    853,    863,    873,    884, 
+          894,    904,    914,    924,    934,    944,    954,    964, 
+          974,    985,    995,   1005,   1015,   1025,   1035,   1045, 
+         1055,   1065,   1075,   1085,   1096,   1106,   1116,   1126, 
+         1136,   1146,   1156,   1166,   1176,   1186,   1196,   1206, 
+         1216,   1226,   1236,   1246,   1256,   1266,   1277,   1287, 
+         1297,   1307,   1317,   1327,   1337,   1347,   1357,   1367, 
+         1377,   1387,   1397,   1407,   1417,   1427,   1437,   1447, 
+         1457,   1467,   1477,   1487,   1497,   1507,   1517,   1527, 
+         1537,   1547,   1556,   1566,   1576,   1586,   1596,   1606, 
+         1616,   1626,   1636,   1646,   1656,   1666,   1676,   1686, 
+         1696,   1706,   1715,   1725,   1735,   1745,   1755,   1765, 
+         1775,   1785,   1795,   1805,   1814,   1824,   1834,   1844, 
+         1854,   1864,   1874,   1884,   1893,   1903,   1913,   1923, 
+         1933,   1943,   1952,   1962,   1972,   1982,   1992,   2002, 
+         2011,   2021,   2031,   2041,   2051,   2060,   2070,   2080, 
+         2090,   2100,   2109,   2119,   2129,   2139,   2148,   2158, 
+         2168,   2178,   2187,   2197,   2207,   2217,   2226,   2236, 
+         2246,   2255,   2265,   2275,   2285,   2294,   2304,   2314, 
+         2323,   2333,   2343,   2352,   2362,   2372,   2381,   2391, 
+         2401,   2410,   2420,   2430,   2439,   2449,   2459,   2468, 
+         2478,   2488,   2497,   2507,   2516,   2526,   2536,   2545, 
+         2555,   2564,   2574,   2583,   2593,   2603,   2612,   2622, 
+         2631,   2641,   2650,   2660,   2669,   2679,   2688,   2698, 
+         2708,   2717,   2727,   2736,   2746,   2755,   2765,   2774, 
+         2784,   2793,   2802,   2812,   2821,   2831,   2840,   2850, 
+         2859,   2869,   2878,   2887,   2897,   2906,   2916,   2925, 
+         2935,   2944,   2953,   2963,   2972,   2981,   2991,   3000, 
+         3010,   3019,   3028,   3038,   3047,   3056,   3066,   3075, 
+         3084,   3094,   3103,   3112,   3122,   3131,   3140,   3149, 
+         3159,   3168,   3177,   3187,   3196,   3205,   3214,   3224, 
+         3233,   3242,   3251,   3260,   3270,   3279,   3288,   3297, 
+         3307,   3316,   3325,   3334,   3343,   3352,   3362,   3371, 
+         3380,   3389,   3398,   3407,   3416,   3426,   3435,   3444, 
+         3453,   3462,   3471,   3480,   3489,   3498,   3508,   3517, 
+         3526,   3535,   3544,   3553,   3562,   3571,   3580,   3589, 
+         3598,   3607,   3616,   3625,   3634,   3643,   3652,   3661, 
+         3670,   3679,   3688,   3697,   3706,   3715,   3724,   3733, 
+         3742,   3751,   3759,   3768,   3777,   3786,   3795,   3804, 
+         3813,   3822,   3831,   3839,   3848,   3857,   3866,   3875, 
+         3884,   3893,   3901,   3910,   3919,   3928,   3937,   3945, 
+         3954,   3963,   3972,   3981,   3989,   3998,   4007,   4016, 
+         4024,   4033,   4042,   4051,   4059,   4068,   4077,   4085, 
+         4094,   4103,   4112,   4120,   4129,   4138,   4146,   4155, 
+         4164,   4172,   4181,   4189,   4198,   4207,   4215,   4224, 
+         4233,   4241,   4250,   4258,   4267,   4275,   4284,   4293, 
+         4301,   4310,   4318,   4327,   4335,   4344,   4352,   4361, 
+         4369,   4378,   4386,   4395,   4403,   4412,   4420,   4429, 
+         4437,   4446,   4454,   4462,   4471,   4479,   4488,   4496, 
+         4505,   4513,   4521,   4530,   4538,   4546,   4555,   4563, 
+         4572,   4580,   4588,   4597,   4605,   4613,   4622,   4630, 
+         4638,   4646,   4655,   4663,   4671,   4680,   4688,   4696, 
+         4704,   4713,   4721,   4729,   4737,   4745,   4754,   4762, 
+         4770,   4778,   4787,   4795,   4803,   4811,   4819,   4827, 
+         4836,   4844,   4852,   4860,   4868,   4876,   4884,   4892, 
+         4901,   4909,   4917,   4925,   4933,   4941,   4949,   4957, 
+         4965,   4973,   4981,   4989,   4997,   5005,   5013,   5021, 
+         5029,   5037,   5045,   5053,   5061,   5069,   5077,   5085, 
+         5093,   5101,   5109,   5117,   5125,   5133,   5141,   5148, 
+         5156,   5164,   5172,   5180,   5188,   5196,   5204,   5211, 
+         5219,   5227,   5235,   5243,   5251,   5258,   5266,   5274, 
+         5282,   5290,   5297,   5305,   5313,   5321,   5328,   5336, 
+         5344,   5352,   5359,   5367,   5375,   5383,   5390,   5398, 
+         5406,   5413,   5421,   5429,   5436,   5444,   5452,   5459, 
+         5467,   5475,   5482,   5490,   5497,   5505,   5513,   5520, 
+         5528,   5535,   5543,   5550,   5558,   5566,   5573,   5581, 
+         5588,   5596,   5603,   5611,   5618,   5626,   5633,   5641, 
+         5648,   5656,   5663,   5671,   5678,   5686,   5693,   5700, 
+         5708,   5715,   5723,   5730,   5738,   5745,   5752,   5760, 
+         5767,   5774,   5782,   5789,   5797,   5804,   5811,   5819, 
+         5826,   5833,   5841,   5848,   5855,   5862,   5870,   5877, 
+         5884,   5892,   5899,   5906,   5913,   5921,   5928,   5935, 
+         5942,   5949,   5957,   5964,   5971,   5978,   5985,   5993, 
+         6000,   6007,   6014,   6021,   6028,   6036,   6043,   6050, 
+         6057,   6064,   6071,   6078,   6085,   6093,   6100,   6107, 
+         6114,   6121,   6128,   6135,   6142,   6149,   6156,   6163, 
+         6170,   6177,   6184,   6191,   6198,   6205,   6212,   6219, 
+         6226,   6233,   6240,   6247,   6254,   6261,   6268,   6275, 
+         6282,   6288,   6295,   6302,   6309,   6316,   6323,   6330, 
+         6337,   6344,   6350,   6357,   6364,   6371,   6378,   6385, 
+         6391,   6398,   6405,   6412,   6419,   6425,   6432,   6439, 
+         6446,   6453,   6459,   6466,   6473,   6480,   6486,   6493, 
+         6500,   6506,   6513,   6520,   6527,   6533,   6540,   6547, 
+         6553,   6560,   6567,   6573,   6580,   6586,   6593,   6600, 
+         6606,   6613,   6620,   6626,   6633,   6639,   6646,   6653, 
+         6659,   6666,   6672,   6679,   6685,   6692,   6698,   6705, 
+         6711,   6718,   6724,   6731,   6737,   6744,   6750,   6757, 
+         6763,   6770,   6776,   6783,   6789,   6796,   6802,   6809, 
+         6815,   6821,   6828,   6834,   6841,   6847,   6853,   6860, 
+         6866,   6873,   6879,   6885,   6892,   6898,   6904,   6911, 
+         6917,   6923,   6930,   6936,   6942,   6949,   6955,   6961, 
+         6967,   6974,   6980,   6986,   6992,   6999,   7005,   7011, 
+         7017,   7024,   7030,   7036,   7042,   7048,   7055,   7061, 
+         7067,   7073,   7079,   7086,   7092,   7098,   7104,   7110, 
+         7116,   7122,   7129,   7135,   7141,   7147,   7153,   7159, 
+         7165,   7171,   7177,   7183,   7190,   7196,   7202,   7208, 
+         7214,   7220,   7226,   7232,   7238,   7244,   7250,   7256, 
+         7262,   7268,   7274,   7280,   7286,   7292,   7298,   7304, 
+         7310,   7316,   7322,   7328,   7333,   7339,   7345,   7351, 
+         7357,   7363,   7369,   7375,   7381,   7387,   7392,   7398, 
+         7404,   7410,   7416,   7422,   7428,   7433,   7439,   7445, 
+         7451,   7457,   7462,   7468,   7474,   7480,   7486,   7491, 
+         7497,   7503,   7509,   7514,   7520,   7526,   7532,   7537, 
+         7543,   7549,   7555,   7560,   7566,   7572,   7577,   7583, 
+         7589,   7594,   7600,   7606,   7611,   7617,   7623,   7628, 
+         7634,   7640,   7645,   7651,   7657,   7662,   7668,   7673, 
+         7679,   7685,   7690,   7696,   7701,   7707,   7712,   7718, 
+         7724,   7729,   7735,   7740,   7746,   7751,   7757,   7762, 
+         7768,   7773,   7779,   7784,   7790,   7795,   7801,   7806, 
+         7812,   7817,   7823,   7828,   7833,   7839,   7844,   7850, 
+         7855,   7861,   7866,   7871,   7877,   7882,   7888,   7893, 
+         7898,   7904,   7909,   7914,   7920,   7925,   7931,   7936, 
+         7941,   7947,   7952,   7957,   7963,   7968,   7973,   7978, 
+         7984,   7989,   7994,   8000,   8005,   8010,   8015,   8021, 
+         8026,   8031,   8036,   8042,   8047,   8052,   8057,   8063, 
+         8068,   8073,   8078,   8083,   8089,   8094,   8099,   8104, 
+         8109,   8115,   8120,   8125,   8130,   8135,   8140,   8145, 
+         8151,   8156,   8161,   8166,   8171,   8176,   8181,   8186, 
+         8192,   8192
+};
+
index baabbcb8955a9176bd43f176e654421b14fad2ef..7e3e3e50ac2d27817606af0e6fc6419f6b3cf4f6 100644 (file)
@@ -525,6 +525,10 @@ struct pci_dev_info dev_info[] = {
        DEVICE( ADAPTEC,        ADAPTEC_7883,   "AIC-7883U"),
        DEVICE( ADAPTEC,        ADAPTEC_7884,   "AIC-7884U"),
        DEVICE( ADAPTEC,        ADAPTEC_1030,   "ABA-1030 DVB receiver"),
+  DEVICE( ADAPTEC2, ADAPTEC2_2940U2, "AHA-2940U2"),
+  DEVICE( ADAPTEC2, ADAPTEC2_7890, "AIC-7890/1"),
+  DEVICE( ADAPTEC2, ADAPTEC2_3940U2, "AHA-3940U2"),
+  DEVICE( ADAPTEC2, ADAPTEC2_7896, "AIC-7896/7"),
        DEVICE( ATRONICS,       ATRONICS_2015,  "IDE-2015PL"),
        DEVICE( TIGERJET,       TIGERJET_300,   "Tiger300 ISDN"),
        DEVICE( ARK,            ARK_STING,      "Stingray"),
@@ -826,6 +830,7 @@ const char *pci_strvendor(unsigned int vendor)
              case PCI_VENDOR_ID_INTEL:         return "Intel";
              case PCI_VENDOR_ID_KTI:           return "KTI";
              case PCI_VENDOR_ID_ADAPTEC:       return "Adaptec";
+             case PCI_VENDOR_ID_ADAPTEC2:      return "Adaptec";
              case PCI_VENDOR_ID_ATRONICS:      return "Atronics";
              case PCI_VENDOR_ID_ARK:           return "ARK Logic";
              default:                          return "Unknown vendor";
index d9f93971975d3f300e0061274c57d1e34ca0592a..1656221dd27a1953d7ddfb96de092ae7346dec9b 100644 (file)
@@ -30,6 +30,7 @@ fi
 dep_tristate 'AdvanSys SCSI support' CONFIG_SCSI_ADVANSYS $CONFIG_SCSI
 dep_tristate 'Always IN2000 SCSI support' CONFIG_SCSI_IN2000 $CONFIG_SCSI
 dep_tristate 'AM53/79C974 PCI SCSI support' CONFIG_SCSI_AM53C974 $CONFIG_SCSI
+dep_tristate 'AMI MegaRAID support' CONFIG_SCSI_MEGARAID $CONFIG_SCSI
 dep_tristate 'BusLogic SCSI support' CONFIG_SCSI_BUSLOGIC $CONFIG_SCSI
 if [ "$CONFIG_SCSI_BUSLOGIC" != "n" ]; then
     bool '  Omit FlashPoint support' CONFIG_SCSI_OMIT_FLASHPOINT
index 8d12efc7b239c562fc31b0e789012c823de4d279..2db9f4d490cadadf767ecde21fb20258634ef9a9 100644 (file)
@@ -363,6 +363,13 @@ else
   endif
 endif
 
+ifeq ($(CONFIG_SCSI_MEGARAID),y)
+L_OBJS += megaraid.o
+else
+  ifeq ($(CONFIG_SCSI_MEGARAID),m)
+  M_OBJS += megaraid.o
+  endif
+endif
 
 ifeq ($(CONFIG_BLK_DEV_IDESCSI),y)
 L_OBJS += ide-scsi.o
@@ -376,7 +383,7 @@ aha152x.o: aha152x.c
 gdth.o: gdth.c gdth.h gdth_proc.c gdth_proc.h
        $(CC) $(CFLAGS) $(GDTH) -c gdth.c 
 
-aic7xxx.o: aic7xxx.c aic7xxx_seq.h aic7xxx_reg.h
+aic7xxx.o: aic7xxx.c aic7xxx_seq.c aic7xxx_reg.h
        $(CC) $(CFLAGS) -c -o $@ aic7xxx.c
 
 seagate.o: seagate.c
@@ -395,6 +402,9 @@ tmscsim.o : tmscsim.c
 g_NCR5380.o: g_NCR5380.c
        $(CC) $(CFLAGS) -DGENERIC_NCR5380_OVERRIDE="{{(NCR5380_map_type)0x350,5,0, BOARD_NCR53C400}};" -c g_NCR5380.c
 
+megaraid.o: megaraid.c
+       $(CC) $(CFLAGS) -c megaraid.c
+
 scsi_mod.o: $(MX_OBJS) hosts.o scsi.o scsi_ioctl.o constants.o \
                scsicam.o scsi_proc.o
        $(LD) $(LD_RFLAG) -r -o $@ $(MX_OBJS) hosts.o scsi.o scsi_ioctl.o constants.o scsicam.o scsi_proc.o
index 0fe83465b8aad4a5c89a44d3021d3c77eacaa962..b350d9d5812f67bfce4f9e9c4b24a3490a58f83d 100644 (file)
@@ -21,15 +21,24 @@ linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD
     AHA-2940W              
     AHA-2940U              
     AHA-2940UW
-    AHA-2940AU             
+    AHA-2940AU 
+    AHA-2940U2W
+    AHA-2940U2
+    AHA-2940U2B
+    AHA-2940U2BOEM
     AHA-2944D              
     AHA-2944WD
     AHA-2944UD
     AHA-2944UWD
+    AHA-2950U2
+    AHA-2950U2W
+    AHA-2950U2B
     AHA-3940
     AHA-3940U
     AHA-3940W
     AHA-3940UW
+    AHA-3940U2W
+    AHA-3950U2B
     AHA-3985
     AHA-3985U
     AHA-3985W
@@ -42,13 +51,14 @@ linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD
     AIC-786x
     AIC-787x
     AIC-788x
-    AIC-7895
+    AIC-789x
 
     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.
+    U2- Ultra 2 SCSI, transfer rates up to 80MB/s.
     D - Differential SCSI.
     T - Twin Channel SCSI. Up to 14 SCSI devices.
 
@@ -72,7 +82,7 @@ linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD
       (Original Linux FTP/patch maintainer)
     Jess Johnson    jester@frenzy.com
       (AIC7xxx FAQ author)
-    Doug Ledford    dledford@dialnet.net
+    Doug Ledford    dledford@redhat.com
       (Current Linux aic7xxx-5.x.x Driver/Patch/FTP/FAQ maintainer)
     
     Special thanks go to John Aycock (aycock@cpsc.ucalgary.ca), the original
@@ -100,40 +110,45 @@ linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD
     
   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=no_reset" -  Eliminate the SCSI bus reset during startup.
+        Some SCSI devices need the initial reset that this option disables
+       in order to work.  If you have problems at bootup, please make sure
+       you aren't using this option.
+       
+    "aic7xxx=reverse_scan" - Certain PCI motherboards scan for devices at
+        bootup by scanning from the highest numbered PCI device to the
+       lowest numbered PCI device, others do just the opposite and scan
+       from lowest to highest numbered PCI device.  There is no reliable
+       way to autodetect this ordering.  So, we default to the most common
+       order, which is lowest to highest.  Then, in case your motherboard
+       scans from highest to lowest, we have this option.  If your BIOS
+       finds the drives on controller A before controller B but the linux
+       kernel finds your drives on controller B before A, then you should
+       use this option.
+       
     "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).
+        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=pci_parity:x" - This option controls whether or not the driver
         enables PCI parity error checking on the PCI bus.  By default, this
         checking is disabled.  To enable the checks, simply specify pci_parity
@@ -145,6 +160,145 @@ linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD
         NOTE: In order to get Even PCI parity checking, you must use the
         version of the option that does not include the : and a number at
         the end (unless you want to enter exactly 2^32 - 1 as the number).
+       
+    "aic7xxx=no_probe" - This option will disable the probing for any VLB
+        based 2842 controllers and any EISA based controllers.  This is
+       needed on certain newer motherboards where the normal EISA I/O ranges
+       have been claimed by other PCI devices.  Probing on those machines
+       will often result in the machine crashing or spontaneously rebooting
+       during startup.  Examples of machines that need this are the
+       Dell PowerEdge 6300 machines.
+       
+    "aic7xxx=panic_on_abort" - This option is for debugging and will cause
+        the driver to panic the linux kernel and freeze the system the first
+       time the drivers abort or reset routines are called.  This is most
+       helpful when some problem causes infinite reset loops that scroll too
+       fast to see.  By using this option, you can write down what the errors
+       actually are and send that information to me so it can be fixed.
+       
+    "aic7xxx=dump_card" - This option will print out the *entire* set of
+        configuration registers on the card during the init sequence.  This
+       is a debugging aid used to see exactly what state the card is in
+       when we finally finish our initialization routines.  If you don't
+       have documentation on the chipsets, this will do you absolutely
+       no good unless you are simply trying to write all the information
+       down in order to send it to me.
+       
+    "aic7xxx=dump_sequencer" - This is the same as the above options except
+        that instead of dumping the register contents on the card, this
+       option dumps the contents of the sequencer program RAM.  This gives
+       the ability to verify that the instructions downloaded to the
+       card's sequencer are indeed what they are suppossed to be.  Again,
+       unless you have documentation to tell you how to interpret these
+       numbers, then it is totally useless.
+       
+    "aic7xxx=override_term:0xffffffff" - This option is used to force the
+       termination on your SCSI controllers to a particular setting.  This
+       is a bit mask variable that applies for up to 8 aic7xxx SCSI channels.
+       Each channel gets 4 bits, divided as follows:
+       bit   3   2   1   0
+             |   |   |   Enable/Disable Single Ended Low Byte Termination
+             |   |   En/Disable Single Ended High Byte Termination
+             |   En/Disable Low Byte LVD Termination
+             En/Disable High Byte LVD Termination
+
+       The upper 2 bits that deal with LVD termination only apply to Ultra2
+       controllers.  Futhermore, due to the current Ultra2 controller
+       designs, these bits are tied together such that setting either bit
+       enables both low and high byte LVD termination.  It is not possible
+       to only set high or low byte LVD termination in this manner.  This is
+       an artifact of the BIOS definition on Ultra2 controllers.  For other
+       controllers, the only important bits are the two lowest bits.  Setting
+       the higher bits on non-Ultra2 controllers has no effect.  A few
+       examples of how to use this option:
+
+       Enable low and high byte termination on a non-ultra2 controller that
+       is the first aic7xxx controller (the correct bits are 0011), 
+       aic7xxx=override_term:0x3
+
+       Enable all termination on the third aic7xxx controller, high byte
+       termination on the second aic7xxx controller, and low and high byte
+       SE termination on the first aic7xxx controller 
+       (bits are 1111 0010 0011), 
+       aic7xxx=override_term:0xf23
+       
+       No attempt has been made to make this option non-cryptic.  It really
+       shouldn't be used except in dire circumstances, and if that happens,
+       I'm probably going to be telling you what to set this to anyway :)
+
+    "aic7xxx=stpwlev:0xffffffff" - This option is used to control the STPWLEV
+        bit in the DEVCONFIG PCI register.  Currently, this is one of the
+       very few registers that we have absolutely *no* way of detecting
+       what the variable should be.  It depends entirely on how the chipset
+       and external terminators were coupled by the card/motherboard maker.
+       Further, a chip reset (at power up) always sets this bit to 0.  If
+       there is no BIOS to run on the chipset/card (such as with a 2910C
+       or a motherboard controller with the BIOS totally disabled) then
+       the variable may not get set properly.  Of course, if the proper
+       setting was 0, then that's what it would be after the reset, but if
+       the proper setting is actually 1.....you get the picture.  Now, since
+       we can't detect this at all, I've added this option to force the
+       setting.  If you have a BIOS on your controller then you should never
+       need to use this option.  However, if you are having lots of SCSI
+       reset problems and can't seem to get them knocked out, this may help.
+
+       Here's a test to know for certain if you need this option.  Make
+       a boot floppy that you can use to boot your computer up and that
+       will detect the aic7xxx controller.  Next, power down your computer.
+       While it's down, unplug all SCSI cables from your Adaptec SCSI
+       controller.  Boot the system back up to the Adaptec EZ-SCSI BIOS
+       and then make sure that termination is enabled on your adapter (if
+       you have an Adaptec BIOS of course).  Next, boot up the floppy you
+       made and wait for it to detect the aic7xxx controller.  If the kernel
+       finds the controller fine, says scsi : x hosts and then tries to
+       detect your devices like normal, up to the point where it fails to
+       mount your root file system and panics, then you're fine.  If, on
+       the other hand, the system goes into an infinite reset loop, then
+       you need to use this option and/or the previous option to force the
+       proper termination settings on your controller.   If this happens,
+       then you next need to figure out what your settings should be.
+
+       To find the correct settings, power your machine back down, connect
+       back up the SCSI cables, and boot back into your machine like normal.
+       However, boot with the aic7xxx=verbose:0x39 option.  Record the
+       initial DEVCONFIG values for each of your aic7xxx controllers as
+       they are listed, and also record what the machine is detecting as
+       the proper termination on your controllers.  NOTE: the order in
+       which the initial DEVCONFIG values are printed out is not gauranteed
+       to be the same order as the SCSI controllers are registered.  The
+       above option and this option both work on the order of the SCSI
+       controllers as they are registered, so make sure you match the right
+       DEVCONFIG values with the right controllers if you have more than
+       one aic7xxx controller.
+
+       Once you have the detected termination settings and the initial
+       DEVCONFIG values for each controller, then figure out what the
+       termination on each of the controllers *should* be.  Hopefully, that
+       part is correct, but it could possibly be wrong if there is
+       bogus cable detection logic on your controller or something similar.
+       If all the controllers have the correct termination settings, then
+       don't set the aic7xxx=override_term variable at all, leave it alone.
+       Next, on any controllers that go into an infinite reset loop when
+       you unplug all the SCSI cables, get the starting DEVCONFIG value.
+       If the initial DEVCONFIG value is divisible by 2, then the correct
+       setting for that controller is 0.  If it's an odd number, then
+       the correct setting for that controller is 1.  For any other
+       controllers that didn't have an infinite reset problem, then reverse
+       the above options.  If DEVCONFIG was even, then the correct setting
+       is 1, if not then the correct setting is 0.
+
+       Now that you know what the correct setting was for each controller,
+       we need to encode that into the aic7xxx=stpwlev:0x... variable.
+       This variable is a bit field encoded variable.  Bit 0 is for the first
+       aic7xxx controller, bit 1 for the next, etc.  Put all these bits
+       together and you get a number.  For example, if the third aic7xxx
+       needed a 1, but the second and first both needed a 0, then the bits
+       would be 100 in binary.  This then translates to 0x04.  You would
+       therefore set aic7xxx=stpwlev:0x04.  This is fairly standard binary
+       to hexadecimal conversions here.  If you aren't up to speed on the
+       binary->hex conversion then send an email to the aic7xxx mailing
+       list and someone can help you out.
+
     "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
@@ -212,8 +366,8 @@ linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD
     
     aic7xxx=verbose,extended,irq_trigger:1
     
-    The only requirement is that individual options be separated by a comma on
-    the command line.
+    The only requirement is that individual options be separated by a comma or
+    a period on the command line.
         
   Module Loading command options
   ------------------------------
@@ -261,11 +415,35 @@ linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD
     Thanks to Michael Neuffer for his upper-level SCSI help, and
     Matthew Jacob for statistics support.
 
+  Debugging the driver
+  ------------------------------
+    Should you have problems with this driver, and would like some help in
+    getting them solved, there are a couple debugging items built into
+    the driver to facilitate getting the needed information from the system.
+    In general, I need a complete description of the problem, with as many
+    logs as possible concerning what happens.  To help with this, there is
+    a command option aic7xxx=panic_on_abort.  This option, when set, forces
+    the driver to panic the kernel on the first SCSI abort issued by the
+    mid level SCSI code.  If your system is going to reset loops and you
+    can't read the screen, then this is what you need.  Not only will it
+    stop the system, but it also prints out a large amount of state
+    information in the process.  Second, if you specify the option
+    "aic7xxx=verbose:0x1ffff", the system will print out *SOOOO* much
+    information as it runs that you won't be able to see anything.
+    However, this can actually be very usefull if your machine simply
+    locks up when trying to boot, since it will pin-point what was last
+    happening (in regards to the aic7xxx driver) immediately prior to
+    the lockup.  This is really only usefull if your machine simply can
+    not boot up successfully.  If you can get your machine to run, then
+    this will produce far too much information.
+
   FTP sites
   ------------------------------
-    ftp://ftp.dialnet.net/pub/linux/aic7xxx/
+    ftp://ftp.redhat.com/pub/aic/
       - Primary site for Doug Ledford developed driver releases
-      - US Linux mirror of Teleport site
+    ftp://ftp.dialnet.net/pub/linux/aic7xxx
+      - Temporary mirror of the redhat.com ftp site while people
+        get used to the new address
     ftp://ftp.pcnet.com/users/eischen/Linux/
       - Dan Eischen's driver distribution area
     ftp://ekf2.vsb.cz/pub/linux/kernel/aic7xxx/ftp.teleport.com/
index de6a30f02016fd79553ff291f20e32b235892128..e528e0cc08c18a9b0c3a3573f5b6a55f01369446 100644 (file)
@@ -98,7 +98,7 @@
 
 /*+M**************************************************************************
  *
- * Further driver modifications made by Doug Ledford <dledford@dialnet.net>
+ * Further driver modifications made by Doug Ledford <dledford@redhat.com>
  *
  * Copyright (c) 1997-1998 Doug Ledford
  *
  *
  *_M*************************************************************************/
 
+/*
+ * The next three defines are user configurable.  These should be the only
+ * defines a user might need to get in here and change.  There are other
+ * defines buried deeper in the code, but those really shouldn't need touched
+ * under normal conditions.
+ */
+
+/*
+ * AIC7XXX_FAKE_NEGOTIATION_CMDS
+ *   We now have two distinctly different methods of device negotiation
+ *   in this code.  The two methods are selected by either defining or not
+ *   defining this option.  The difference is as follows:
+ *
+ *   With AIC7XXX_FAKE_NEGOTIATION_CMDS not set (commented out)
+ *     When the driver is in need of issuing a negotiation command for any
+ *     given device, it will add the negotiation message on to part of a
+ *     regular SCSI command for the device.  In the process, if the device
+ *     is configured for and using tagged queueing, then the code will
+ *     also issue that single command as a non-tagged command, attach the
+ *     negotiation message to that one command, and use a temporary
+ *     queue depth of one to keep the untagged and tagged commands from
+ *     overlapping.
+ *       Pros: This doesn't use any extra SCB structures, it's simple, it
+ *         works most of the time (if not all of the time now), and
+ *         since we get the device capability info frmo the INQUIRY data
+ *         now, shouldn't cause any problems.
+ *       Cons: When we need to send a negotiation command to a device, we
+ *         must use a command that is being sent to LUN 0 of the device.
+ *         If we try sending one to high LUN numbers, then some devices
+ *         get noticeably upset.  Since we have to wait for a command with
+ *         LUN == 0 to come along, we may not be able to renegotiate when
+ *         we want if the user is actually using say LUN 1 of a CD Changer
+ *         instead of using LUN 0 for an extended period of time.
+ *
+ *   With AIC7XXX_FAKE_NEGOTIATION_CMDS defined
+ *     When we need to negotiate with a device, instead of attaching our
+ *     negotiation message to an existing command, we insert our own
+ *     fictional Scsi_Cmnd into the chain that has the negotiation message
+ *     attached to it.  We send this one command as untagged regardless
+ *     of the device type, and we fiddle with the queue depth the same as
+ *     we would with the option unset to avoid overlapping commands.  The
+ *     primary difference between this and the unset option is that the
+ *     negotiation message is no longer attached to a specific command,
+ *     instead it is its own command and is merely triggered by a
+ *     combination of both A) We need to negotiate and B) The mid level
+ *     SCSI code has sent us a command.  We still don't do any negotiation
+ *     unless there is a valid SCSI command to be processed.
+ *       Pros: This fixes the problem above in the Cons section.  Since we
+ *         issue our own fake command, we can set the LUN to 0 regardless
+ *         of what the LUN is in the real command.  It also means that if
+ *         the device get's nasty over negotiation issues, it won't be
+ *         showing up on a regular command, so we won't get any SENSE buffer
+ *         data or STATUS_BYTE returns to the mid level code that are caused
+ *         by snits in the negotiation code.
+ *       Cons: We add more code, and more complexity.  This means more ways
+ *         in which things could break.  It means a larger driver.  It means
+ *         more resource consumption for the fake commands.  However, the
+ *         biggest problem is this.  Take a system where there is a CD-ROM
+ *         on the SCSI bus.  Someone has a CD in the CD-ROM and is using it.
+ *         For some reason the SCSI bus gets reset.  We don't touch the
+ *         CD-ROM again for quite a period of time (so we don't renegotiate
+ *         after the reset until we do touch the CD-ROM again).  In the
+ *         time while we aren't using the CD-ROM, the current disc is
+ *         removed and a new one put in.  When we go to check that disc, we
+ *         will first have to renegotiate.  In so doing, we issue our fake
+ *         SCSI command, which happens to be TEST_UNIT_READY.  The CD-ROM
+ *         negotiates with us, then responds to our fake command with a
+ *         CHECK_CONDITION status.  We REQUEST_SENSE from the CD-ROM, it
+ *         then sends the SENSE data to our fake command to tell it that
+ *         it has been through a disc change.  There, now we've cleared out
+ *         the SENSE data along with our negotiation command, and when the
+ *         real command executes, it won't pick up that the CD was changed.
+ *         That's the biggest Con to this approach.  In the future, I could
+ *         probably code around this problem though, so this option is still
+ *         viable.
+ *
+ *  So, which command style should you use?  I would appreciate it if people
+ *  could try out both types.  I want to know about any cases where one
+ *  method works and the other doesn't.  If one method works on significantly
+ *  more systems than another, then it will become the default.  If the second
+ *  option turns out to work best, then I'll find a way to work around that
+ *  big con I listed.
+ *
+ *  -- July 7, 02:33
+ *    OK...I just added some code that should make the Con listed for the
+ *    fake commands a non issue now.  However, it needs testing.  For now,
+ *    I'm going to make the default to use the fake commands, we'll see how
+ *    it goes.
+ */
+#define AIC7XXX_FAKE_NEGOTIATION_CMDS
+
+/*
+ * AIC7XXX_STRICT_PCI_SETUP
+ *   Should we assume the PCI config options on our controllers are set with
+ *   sane and proper values, or should we be anal about our PCI config
+ *   registers and force them to what we want?  The main advantage to
+ *   defining this option is on non-Intel hardware where the BIOS may not
+ *   have been run to set things up, or if you have one of the BIOSless
+ *   Adaptec controllers, such as a 2910, that don't get set up by the
+ *   BIOS.  However, keep in mind that we really do set the most important
+ *   items in the driver regardless of this setting, this only controls some
+ *   of the more esoteric PCI options on these cards.  In that sense, I
+ *   would default to leaving this off.  However, if people wish to try
+ *   things both ways, that would also help me to know if there are some
+ *   machines where it works one way but not another.
+ *
+ *   -- July 7, 17:09
+ *     OK...I need this on my machine for testing, so the default is to
+ *     leave it defined.
+ *
+ *   -- July 7, 18:49
+ *     I needed it for testing, but it didn't make any difference, so back
+ *     off she goes.
+ *
+ *   -- July 16, 23:04
+ *     I turned it back on to try and compensate for the 2.1.x PCI code
+ *     which no longer relies solely on the BIOS and now tries to set
+ *     things itself.
+ */
+
+#define AIC7XXX_STRICT_PCI_SETUP
+
+/*
+ * AIC7XXX_VERBOSE_DEBUGGING
+ *   This option enables a lot of extra printk();s in the code, surrounded
+ *   by if (aic7xxx_verbose ...) statements.  Executing all of those if
+ *   statements and the extra checks can get to where it actually does have
+ *   an impact on CPU usage and such, as well as code size.  Disabling this
+ *   define will keep some of those from becoming part of the code.
+ *
+ *   NOTE:  Currently, this option has no real effect, I will be adding the
+ *   various #ifdef's in the code later when I've decided a section is
+ *   complete and no longer needs debugging.  OK...a lot of things are now
+ *   surrounded by this define, so turning this off does have an impact.
+ */
+/*
+ * #define AIC7XXX_VERBOSE_DEBUGGING
+ */
 #ifdef MODULE
 #include <linux/module.h>
 #endif
 #include "hosts.h"
 #include "aic7xxx.h"
 
+#include "aic7xxx/bsd_q.h"
 #include "aic7xxx/sequencer.h"
 #include "aic7xxx/scsi_message.h"
 #include "aic7xxx_reg.h"
-#include "aic7xxx_seq.h"
 
 #include <linux/stat.h>
 #include <linux/malloc.h>        /* for kmalloc() */
@@ -209,7 +350,7 @@ struct proc_dir_entry proc_scsi_aic7xxx = {
     0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL
 };
 
-#define AIC7XXX_C_VERSION  "5.0.20"
+#define AIC7XXX_C_VERSION  "5.1.0"
 
 #define NUMBER(arr)     (sizeof(arr) / sizeof(arr[0]))
 #define MIN(a,b)        (((a) < (b)) ? (a) : (b))
@@ -242,17 +383,15 @@ struct proc_dir_entry proc_scsi_aic7xxx = {
 #  include <linux/bios32.h>
 #endif
 
-#if defined(__powerpc__) || defined(__i386__)
-#  define MMAPIO
-#endif
-
 #if defined(__powerpc__)
+#  define MMAPIO
 #  ifdef mb
 #    undef mb
 #  endif
 #  define mb() \
      __asm__ __volatile__("eieio" ::: "memory")
 #elif defined(__i386__)
+#  define MMAPIO
 #  ifdef mb
 #    undef mb
 #  endif
@@ -330,7 +469,7 @@ struct proc_dir_entry proc_scsi_aic7xxx = {
  *       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.
+ *       by use of this array that a person can enable 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:
@@ -396,6 +535,9 @@ typedef struct
  */
 
 /*
+ * NOTE: The below structure is for reference only, the actual structure
+ *       to modify in order to change things is located around line
+ *       number 1305
 adapter_tag_info_t aic7xxx_tag_info[] =
 {
   {DEFAULT_TAG_COMMANDS},
@@ -429,7 +571,11 @@ static const char *board_names[] = {
   "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 */
+  "Adaptec AIC-7895 Ultra SCSI host adapter",           /* AIC_7895 */
+  "Adaptec AIC-7890/1 Ultra2 SCSI host adapter",        /* AIC_7890 */
+  "Adaptec AHA-294X Ultra2 SCSI host adapter",          /* AIC_7890 */
+  "Adaptec AIC-7896/7 Ultra2 SCSI host adapter",        /* AIC_7896 */
+  "Adaptec AHA-394X Ultra2 SCSI host adapter"           /* AIC_7897 */
 };
 
 /*
@@ -467,10 +613,10 @@ static const char *board_names[] = {
 /*
  * 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 AHC_HID0              0x80   /* 0,1: msb of ID2, 2-7: ID1      */
+#define AHC_HID1              0x81   /* 0-4: ID3, 5-7: LSB ID2         */
+#define AHC_HID2              0x82   /* product                        */
+#define AHC_HID3              0x83   /* firmware revision              */
 
 /*
  * AIC-7770 I/O range to reserve for a card
@@ -494,11 +640,13 @@ static const char *board_names[] = {
 #define                LATTIME                0x0000FF00ul
 
 #define        DEVCONFIG                0x40
-#define                SCBSIZE32        0x00010400ul        /* aic789X only */
+#define                SCBSIZE32        0x00010000ul        /* aic789X only */
 #define                MPORTMODE        0x00000400ul        /* aic7870 only */
 #define                RAMPSM           0x00000200ul        /* aic7870 only */
+#define                RAMPSM_ULTRA2    0x00000004
 #define                VOLSENSE         0x00000100ul
 #define                SCBRAMSEL        0x00000080ul
+#define                SCBRAMSEL_ULTRA2 0x00000008
 #define                MRDCEN           0x00000040ul
 #define                EXTSCBTIME       0x00000020ul        /* aic7870 only */
 #define                EXTSCBPEN        0x00000010ul        /* aic7870 only */
@@ -507,6 +655,8 @@ static const char *board_names[] = {
 #define                STPWLEVEL        0x00000002ul
 #define                DIFACTNEGEN      0x00000001ul        /* aic7870 only */
 
+#define        SCAMCTL                  0x1a                /* Ultra2 only  */
+#define        CCSCBBADDR               0xf0                /* aic7895/6/7  */
 
 /*
  * Define the different types of SEEPROMs on aic7xxx adapters
@@ -569,7 +719,9 @@ struct seeprom_config {
 #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 */
+#define CFSEAUTOTERM    0x0400  /* aic7890 Perform SE Auto Term */
+#define CFLVDSTERM      0x0800  /* aic7890 LVD Termination */
+/* UNUSED                0xF280 */
   unsigned short adapter_control;        /* word 17 */
 
 /*
@@ -682,7 +834,6 @@ struct aic7xxx_hwscb {
 
 typedef enum {
         SCB_FREE                = 0x0000,
-        SCB_WDTR_16BIT          = 0x0001,
         SCB_WAITINGQ            = 0x0002,
         SCB_ACTIVE              = 0x0004,
         SCB_SENSE               = 0x0008,
@@ -691,11 +842,12 @@ typedef enum {
         SCB_RESET               = 0x0040,
         SCB_RECOVERY_SCB        = 0x0080,
         SCB_WAS_BUSY            = 0x0100,
+        SCB_MSGOUT_SENT         = 0x0200,
         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_MSGOUT_BITS         = SCB_MSGOUT_SENT | 
+                                  SCB_MSGOUT_SDTR |
+                                  SCB_MSGOUT_WDTR,
         SCB_QUEUED_ABORT        = 0x1000,
         SCB_QUEUED_FOR_DONE     = 0x2000
 } scb_flag_type;
@@ -711,7 +863,9 @@ typedef enum {
         AHC_EXTEND_TRANS_A        = 0x00000100,
         AHC_EXTEND_TRANS_B        = 0x00000200,
         AHC_TERM_ENB_A            = 0x00000400,
+        AHC_TERM_ENB_SE_LOW       = 0x00000400,
         AHC_TERM_ENB_B            = 0x00000800,
+        AHC_TERM_ENB_SE_HIGH      = 0x00000800,
         AHC_HANDLING_REQINITS     = 0x00001000,
         AHC_TARGETMODE            = 0x00002000,
         AHC_NEWEEPROM_FMT         = 0x00004000,
@@ -726,45 +880,62 @@ typedef enum {
         AHC_B_SCANNED             = 0x00200000,
         AHC_MULTI_CHANNEL         = 0x00400000,
         AHC_BIOS_ENABLED          = 0x00800000,
-        AHC_ABORT_PENDING         = 0x02000000,
-        AHC_RESET_PENDING         = 0x04000000,
+        AHC_SEEPROM_FOUND         = 0x01000000,
+        AHC_TERM_ENB_LVD          = 0x02000000,
+        AHC_ABORT_PENDING         = 0x04000000,
+        AHC_RESET_PENDING         = 0x08000000,
 #define AHC_IN_ISR_BIT              28
         AHC_IN_ISR                = 0x10000000,
         AHC_IN_ABORT              = 0x20000000,
-        AHC_IN_RESET              = 0x40000000
+        AHC_IN_RESET              = 0x40000000,
+        AHC_EXTERNAL_SRAM         = 0x80000000
 } 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;
+  AHC_NONE             = 0x0000,
+  AHC_CHIPID_MASK      = 0x00ff,
+  AHC_AIC7770          = 0x0001,
+  AHC_AIC7850          = 0x0002,
+  AHC_AIC7860          = 0x0003,
+  AHC_AIC7870          = 0x0004,
+  AHC_AIC7880          = 0x0005,
+  AHC_AIC7890          = 0x0006,
+  AHC_AIC7895          = 0x0007,
+  AHC_AIC7896          = 0x0008,
+  AHC_VL               = 0x0100,
+  AHC_EISA             = 0x0200,
+  AHC_PCI              = 0x0400,
+} ahc_chip;
+
+typedef enum {
+  AHC_FENONE           = 0x0000,
+  AHC_ULTRA            = 0x0001,
+  AHC_ULTRA2           = 0x0002,
+  AHC_WIDE             = 0x0004,
+  AHC_TWIN             = 0x0008,
+  AHC_MORE_SRAM        = 0x0010,
+  AHC_CMD_CHAN         = 0x0020,
+  AHC_QUEUE_REGS       = 0x0040,
+  AHC_SG_PRELOAD       = 0x0080,
+  AHC_SPIOCAP          = 0x0100,
+  AHC_AIC7770_FE       = AHC_FENONE,
+  AHC_AIC7850_FE       = AHC_SPIOCAP,
+  AHC_AIC7860_FE       = AHC_ULTRA|AHC_SPIOCAP,
+  AHC_AIC7870_FE       = AHC_FENONE,
+  AHC_AIC7880_FE       = AHC_ULTRA,
+  AHC_AIC7890_FE       = AHC_MORE_SRAM|AHC_CMD_CHAN|AHC_ULTRA2|
+                         AHC_QUEUE_REGS|AHC_SG_PRELOAD,
+  AHC_AIC7895_FE       = AHC_MORE_SRAM|AHC_CMD_CHAN|AHC_ULTRA,
+  AHC_AIC7896_FE       = AHC_AIC7890_FE,
+} ahc_feature;
 
 struct aic7xxx_scb {
         struct aic7xxx_hwscb  *hscb;          /* corresponding hardware scb */
         Scsi_Cmnd             *cmd;              /* Scsi_Cmnd for this scb */
         struct aic7xxx_scb    *q_next;        /* next scb in queue */
-        scb_flag_type          flags;         /* current state of scb */
+        volatile scb_flag_type flags;         /* current state of scb */
         struct hw_scatterlist *sg_list;       /* SG list in adapter format */
+        void                  *kmalloc_ptr;
         unsigned char          tag_action;
         unsigned char          sg_count;
         unsigned char          sense_cmd[6];  /*
@@ -792,28 +963,50 @@ static struct {
   { ILLHADDR,  "Illegal Host Access" },
   { ILLSADDR,  "Illegal Sequencer Address referenced" },
   { ILLOPCODE, "Illegal Opcode in sequencer program" },
-  { SQPARERR,  "Sequencer Ram Parity Error" }
+  { SQPARERR,  "Sequencer Ram Parity Error" },
+  { DPARERR,   "Data-Path Ram Parity Error" },
+  { MPARERR,   "Scratch Ram/SCB Array Ram Parity Error" },
+  { PCIERRSTAT,"PCI Error detected" },
+  { CIOPARERR, "CIOBUS Parity Error" }
 };
 
 static unsigned char
 generic_sense[] = { REQUEST_SENSE, 0, 0, 0, 255, 0 };
 
 typedef struct {
-  struct aic7xxx_hwscb *hscbs;
   scb_queue_type free_scbs;        /*
                                     * SCBs assigned to free slot on
                                     * card (no paging required)
                                     */
+  struct aic7xxx_scb   *scb_array[AIC7XXX_MAXSCB];
+  struct aic7xxx_hwscb *hscbs;
   unsigned char  numscbs;          /* current number of scbs */
   unsigned char  maxhscbs;         /* hardware scbs */
   unsigned char  maxscbs;          /* max scbs including pageable scbs */
-  struct aic7xxx_scb   *scb_array[AIC7XXX_MAXSCB];
+  void          *hscb_kmalloc_ptr;
 } scb_data_type;
 
+struct target_cmd {
+  unsigned char mesg_bytes[4];
+  unsigned char command[28];
+};
+
+#define AHC_TRANS_CUR    0x0001
+#define AHC_TRANS_ACTIVE 0x0002
+#define AHC_TRANS_GOAL   0x0004
+#define AHC_TRANS_USER   0x0008
+#define AHC_TRANS_QUITE  0x0010
 typedef struct {
-  unsigned char period;
-  unsigned char offset;
-} syncinfo_type;
+  unsigned char cur_width;
+  unsigned char goal_width;
+  unsigned char cur_period;
+  unsigned char goal_period;
+  unsigned char cur_offset;
+  unsigned char goal_offset;
+  unsigned char user_width;
+  unsigned char user_period;
+  unsigned char user_offset;
+} transinfo_type;
 
 /*
  * Define a structure used for each host adapter.  Note, in order to avoid
@@ -841,15 +1034,18 @@ struct aic7xxx_host {
   spinlock_t               spin_lock;
 #endif
   volatile unsigned char   cpu_lock_count[NR_CPUS];
-  ahc_type                 type;             /* card type */
+  ahc_chip                 chip;             /* chip type */
+  ahc_feature              features;         /* chip features */
   unsigned long            last_reset;
   unsigned long            isr_count;        /* Interrupt count */
   unsigned long            spurious_int;
+  struct target_cmd       *targetcmds;
+  unsigned int             num_targetcmds;
   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;
+  volatile unsigned char   max_activescbs;
   unsigned char            unpause;          /* unpause value for HCNTRL */
   unsigned char            pause;            /* pause value for HCNTRL */
   volatile unsigned char   qoutfifonext;
@@ -870,7 +1066,7 @@ struct aic7xxx_host {
 #define  DEVICE_SCANNED                 0x80
   volatile unsigned char   dev_flags[MAX_TARGETS];
   volatile unsigned char   dev_active_cmds[MAX_TARGETS];
-  unsigned char            dev_temp_queue_depth[MAX_TARGETS];
+  volatile unsigned char   dev_temp_queue_depth[MAX_TARGETS];
   unsigned char            dev_commands_sent[MAX_TARGETS];
 
   /*
@@ -917,7 +1113,7 @@ struct aic7xxx_host {
 #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];
+  transinfo_type           transinfo[MAX_TARGETS];
   volatile scb_queue_type  waiting_scbs;     /*
                                               * SCBs waiting for space in
                                               * the QINFIFO.
@@ -945,10 +1141,10 @@ struct aic7xxx_host {
   volatile unsigned char   qoutfifo[256];
   volatile unsigned char   qinfifo[256];
   unsigned int             irq;              /* IRQ for this adapter */
-  unsigned short           needsdtr;
-  unsigned short           sdtr_pending;
-  unsigned short           needwdtr;
-  unsigned short           wdtr_pending;
+  volatile unsigned short  needsdtr;
+  volatile unsigned short  sdtr_pending;
+  volatile unsigned short  needwdtr;
+  volatile 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 */
@@ -965,8 +1161,10 @@ struct aic7xxx_host {
 #endif
   unsigned char            pci_bus;
   unsigned char            pci_device_fn;
+  struct seeprom_config    sc;
+  unsigned short           sc_type;
+  unsigned short           sc_size;
 
-#ifdef AIC7XXX_PROC_STATS
   /*
    * Statistics Kept:
    *
@@ -980,18 +1178,21 @@ struct aic7xxx_host {
    *
    * 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.
+   * cache lines and is CPU time consuming.  We keep the xfer count always
+   * for use by the aic7xxx_proc.c code, but only do the bins if the
+   * proc stats code is enabled.
    */
   struct aic7xxx_xferstats {
     long xfers;                              /* total xfer count */
     long w_total;                            /* total writes */
     long w_total512;                         /* 512 byte blocks written */
-    long w_bins[10];                         /* binned write */
     long r_total;                            /* total reads */
     long r_total512;                         /* 512 byte blocks read */
+#ifdef AIC7XXX_PROC_STATS
+    long w_bins[10];                         /* binned write */
     long r_bins[10];                         /* binned reads */
-  } stats[MAX_TARGETS][MAX_LUNS];            /* [(channel << 3)|target][lun] */
 #endif /* AIC7XXX_PROC_STATS */
+  } stats[MAX_TARGETS][MAX_LUNS];            /* [(channel << 3)|target][lun] */
 };
 
 /*
@@ -999,29 +1200,33 @@ struct aic7xxx_host {
  * Provides a mapping of transfer periods in ns/4 to the proper value to
  * stick in the SCSIRATE reg to use that transfer rate.
  */
-static struct {
-  short period;
+#define AHC_SYNCRATE_ULTRA2 0
+#define AHC_SYNCRATE_ULTRA  2
+#define AHC_SYNCRATE_FAST   5
+static struct aic7xxx_syncrate {
   /* Rates in Ultra mode have bit 8 of sxfr set */
 #define                ULTRA_SXFR 0x100
-  short rate;
-  const char *english;
+  int sxfr_ultra2;
+  int sxfr;
+  unsigned char period;
+  const char *rate[2];
 } aic7xxx_syncrates[] = {
-  { 12,  0x100,  "20.0"  },
-  { 15,  0x110,  "16.0"  },
-  { 18,  0x120,  "13.4"  },
-  { 25,  0x000,  "10.0"  },
-  { 31,  0x010,   "8.0"  },
-  { 37,  0x020,   "6.67" },
-  { 43,  0x030,   "5.7"  },
-  { 50,  0x040,   "5.0"  },
-  { 56,  0x050,   "4.4"  },
-  { 62,  0x060,   "4.0"  },
-  { 68,  0x070,   "3.6"  }
+  { 0x13,  0x000,  10,  {"40.0", "80.0"} },
+  { 0x14,  0x000,  11,  {"33.0", "66.6"} },
+  { 0x15,  0x100,  12,  {"20.0", "40.0"} },
+  { 0x16,  0x110,  15,  {"16.0", "32.0"} },
+  { 0x17,  0x120,  18,  {"13.4", "26.8"} },
+  { 0x18,  0x000,  25,  {"10.0", "20.0"} },
+  { 0x19,  0x010,  31,  {"8.0",  "16.0"} },
+  { 0x1a,  0x020,  37,  {"6.67", "13.3"} },
+  { 0x1b,  0x030,  43,  {"5.7",  "11.4"} },
+  { 0x10,  0x040,  50,  {"5.0",  "10.0"} },
+  { 0x00,  0x050,  56,  {"4.4",  "8.8" } },
+  { 0x00,  0x060,  62,  {"4.0",  "8.0" } },
+  { 0x00,  0x070,  68,  {"3.6",  "7.2" } },
+  { 0x00,  0x000,  0,   {NULL, NULL}   },
 };
 
-static int num_aic7xxx_syncrates =
-    sizeof(aic7xxx_syncrates) / sizeof(aic7xxx_syncrates[0]);
-
 #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)
@@ -1041,58 +1246,170 @@ static int num_aic7xxx_syncrates =
 
 /*
  * XXX - these options apply unilaterally to _all_ 274x/284x/294x
- *       cards in the system.  This should be fixed.
+ *       cards in the system.  This should be fixed.  Exceptions to this
+ *       rule are noted in the comments.
  */
-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;         /*
-                                              * -1 use board setting
-                                              *  0 use edge triggered
-                                              *  1 use level triggered
-                                              */
-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.
-                                              */
-static int aic7xxx_pci_parity = 0;           /*
-                                              * Set this to:
-                                              *   0 - Shut off PCI parity check
-                                              *  -1 - Normal parity check
-                                              *  anything else - reverse pci
-                                              *    pci parity checking
-                                              */
+
+
+/*
+ * Skip the scsi bus reset.  Non 0 make us skip the reset at startup.  This
+ * has no effect on any later resets that might occur due to things like
+ * SCSI bus timeouts.
+ */
+static unsigned int aic7xxx_no_reset = 0;
+/*
+ * Certain PCI motherboards will scan PCI devices from highest to lowest,
+ * others scan from lowest to highest, and they tend to do all kinds of
+ * strange things when they come into contact with PCI bridge chips.  The
+ * net result of all this is that the PCI card that is actually used to boot
+ * the machine is very hard to detect.  Most motherboards go from lowest
+ * PCI slot number to highest, and the first SCSI controller found is the
+ * one you boot from.  The only exceptions to this are when a controller
+ * has its BIOS disabled.  So, we by default sort all of our SCSI controllers
+ * from lowest PCI slot number to highest PCI slot number.  We also force
+ * all controllers with their BIOS disabled to the end of the list.  This
+ * works on *almost* all computers.  Where it doesn't work, we have this
+ * option.  Setting this option to non-0 will reverse the order of the sort
+ * to highest first, then lowest, but will still leave cards with their BIOS
+ * disabled at the very end.  That should fix everyone up unless there are
+ * really strange cirumstances.
+ */
+static int aic7xxx_reverse_scan = 0;
+/*
+ * This setting enables a hack to fix the IRQ settings on buggy 7895
+ * MB controller setups:
+ *    -1 == Disable this hack
+ *     0 == Use the Channel A IRQ for both channels
+ *     1 == Use the Channel B IRQ for both channels
+ */
+static unsigned int aic7xxx_extended = 0;
+/*
+ * The IRQ trigger method used on EISA controllers. Does not effect PCI cards.
+ *   -1 = Use detected settings.
+ *    0 = Force Edge triggered mode.
+ *    1 = Force Level triggered mode.
+ */
+static int aic7xxx_irq_trigger = -1;
+/*
+ * This variable is used to override the termination settings on a controller.
+ * This should not be used under normal conditions.  However, in the case
+ * that a controller does not have a readable SEEPROM (so that we can't
+ * read the SEEPROM settings directly) and that a controller has a buggered
+ * version of the cable detection logic, this can be used to force the 
+ * correct termination.  It is preferable to use the manual termination
+ * settings in the BIOS if possible, but some motherboard controllers store
+ * those settings in a format we can't read.  In other cases, auto term
+ * should also work, but the chipset was put together with no auto term
+ * logic (common on motherboard controllers).  In those cases, we have
+ * 32 bits here to work with.  That's good for 8 controllers/channels.  The
+ * bits are organized as 4 bits per channel, with scsi0 getting the lowest
+ * 4 bits in the int.  A 1 in a bit position indicates the termination setting
+ * that corresponds to that bit should be enabled, a 0 is disabled.
+ * It looks something like this:
+ *
+ *    0x0f =  1111-Single Ended Low Byte Termination on/off
+ *            ||\-Single Ended High Byte Termination on/off
+ *            |\-LVD Low Byte Termination on/off
+ *            \-LVD High Byte Termination on/off
+ *
+ * For non-Ultra2 controllers, the upper 2 bits are not important.  So, to
+ * enable both high byte and low byte termination on scsi0, I would need to
+ * make sure that the override_term variable was set to 0x03 (bits 0011).
+ * To make sure that all termination is enabled on an Ultra2 controller at
+ * scsi2 and only high byte termination on scsi1 and high and low byte
+ * termination on scsi0, I would set override_term=0xf23 (bits 1111 0010 0011)
+ *
+ * For the most part, users should never have to use this, that's why I
+ * left it fairly cryptic instead of easy to understand.  If you need it,
+ * most likely someone will be telling you what your's needs to be set to.
+ */
+static int aic7xxx_override_term = -1;
+/*
+ * Certain motherboard chipset controllers tend to screw
+ * up the polarity of the term enable output pin.  Use this variable
+ * to force the correct polarity for your system.  This is a bitfield variable
+ * similar to the previous one, but this one has one bit per channel instead
+ * of four.
+ *    0 = Force the setting to active low.
+ *    1 = Force setting to active high.
+ * Most Adaptec cards are active high, several motherboards are active low.
+ * To force a 2940 card at SCSI 0 to active high and a motherboard 7895
+ * controller at scsi1 and scsi2 to active low, and a 2910 card at scsi3
+ * to active high, you would need to set stpwlev=0x9 (bits 1001).
+ *
+ * People shouldn't need to use this, but if you are experiencing lots of
+ * SCSI timeout problems, this may help.  There is one sure way to test what
+ * this option needs to be.  Using a boot floppy to boot the system, configure
+ * your system to enable all SCSI termination (in the Adaptec SCSI BIOS) and
+ * if needed then also pass a value to override_term to make sure that the
+ * driver is enabling SCSI termination, then set this variable to either 0
+ * or 1.  When the driver boots, make sure there are *NO* SCSI cables
+ * connected to your controller.  If it finds and inits the controller
+ * without problem, then the setting you passed to stpwlev was correct.  If
+ * the driver goes into a reset loop and hangs the system, then you need the
+ * other setting for this variable.  If neither setting lets the machine
+ * boot then you have definite termination problems that may not be fixable.
+ */
+static int aic7xxx_stpwlev = -1;
+/*
+ * Set this to non-0 in order to force the driver to panic the kernel
+ * and print out debugging info on a SCSI abort or reset cycle.
+ */
+static int aic7xxx_panic_on_abort = 0;
+/*
+ * PCI bus parity checking of the Adaptec controllers.  This is somewhat
+ * dubious at best.  To my knowledge, this option has never actually
+ * solved a PCI parity problem, but on certain machines with broken PCI
+ * chipset configurations, it can generate tons of false error messages.
+ * It's included in the driver for completeness.
+ *   0 = Shut off PCI parity check
+ *  -1 = Normal polarity pci parity checking
+ *   1 = reverse polarity pci parity checking
+ *
+ * NOTE: you can't actually pass -1 on the lilo prompt.  So, to set this
+ * variable to -1 you would actually want to simply pass the variable
+ * name without a number.  That will invert the 0 which will result in
+ * -1.
+ */
+static int aic7xxx_pci_parity = 0;
+/*
+ * Set this to any non-0 value to cause us to dump the contents of all
+ * the card's registers in a hex dump format tailored to each model of
+ * controller.
+ * 
+ * NOTE: THE CONTROLLER IS LEFT IN AN UNUSEABLE STATE BY THIS OPTION.
+ *       YOU CANNOT BOOT UP WITH THIS OPTION, IT IS FOR DEBUGGING PURPOSES
+ *       ONLY
+ */
+static int aic7xxx_dump_card = 0;
+/*
+ * Set this to a non-0 value to make us dump out the 32 bit instruction
+ * registers on the card after completing the sequencer download.  This
+ * allows the actual sequencer download to be verified.  It is possible
+ * to use this option and still boot up and run your system.  This is
+ * only intended for debugging purposes.
+ */
+static int aic7xxx_dump_sequencer = 0;
+/*
+ * Certain newer motherboards have put new PCI based devices into the
+ * IO spaces that used to typically be occupied by VLB or EISA cards.
+ * This overlap can cause these newer motherboards to lock up when scanned
+ * for older EISA and VLB devices.  Setting this option to non-0 will
+ * cause the driver to skip scanning for any VLB or EISA controllers and
+ * only support the PCI controllers.  NOTE: this means that if the kernel
+ * os compiled with PCI support disabled, then setting this to non-0
+ * would result in never finding any devices :)
+ */
+static int aic7xxx_no_probe = 0;
+
 /*
  * So that insmod can find the variable and make it point to something
  */
 #ifdef MODULE
 static char * aic7xxx = NULL;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,18)
+MODULE_PARM(aic7xxx, "s");
+#endif
 
 /*
  * Just in case someone uses commas to separate items on the insmod
@@ -1138,9 +1455,9 @@ static adapter_tag_info_t aic7xxx_tag_info[] =
 #define VERBOSE_SCSIINT        0x0004
 #define VERBOSE_PROBE          0x0008
 #define VERBOSE_PROBE2         0x0010
-#define VERBOSE_QUEUE          0x0020
+#define VERBOSE_NEGOTIATION2   0x0020
 #define VERBOSE_MINOR_ERROR    0x0040
-#define VERBOSE_QUEUE_FULL     0x0080
+#define VERBOSE_TRACING        0x0080
 #define VERBOSE_ABORT          0x0f00
 #define VERBOSE_ABORT_MID      0x0100
 #define VERBOSE_ABORT_FIND     0x0200
@@ -1157,49 +1474,95 @@ static int aic7xxx_verbose = VERBOSE_NORMAL | VERBOSE_NEGOTIATION |
 
 /****************************************************************************
  *
- * These functions are not used yet, but when we do memory mapped
- * IO, we'll use them then.
+ * We're going to start putting in function declarations so that order of
+ * functions is no longer important.  As needed, they are added here.
+ *
+ ***************************************************************************/
+
+static void aic7xxx_panic_abort(struct aic7xxx_host *p, Scsi_Cmnd *cmd);
+static void aic7xxx_print_card(struct aic7xxx_host *p);
+static void aic7xxx_print_scratch_ram(struct aic7xxx_host *p);
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+static void aic7xxx_print_sequencer(struct aic7xxx_host *p, int downloaded);
+static void aic7xxx_check_scbs(struct aic7xxx_host *p, char *buffer);
+#endif
+
+/****************************************************************************
+ *
+ * These functions are now used.  They happen to be wrapped in useless
+ * inb/outb port read/writes around the real reads and writes because it
+ * seems that certain very fast CPUs have a problem dealing with us when
+ * going at full speed.
  *
  ***************************************************************************/
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0)
+static inline void
+mdelay(int milliseconds)
+{
+  int i;
+
+  for(i=0; i<milliseconds; i++)
+    udelay(1000);
+}
+#endif
 
 static inline unsigned char
 aic_inb(struct aic7xxx_host *p, long port)
 {
+#ifdef MMAPIO
   unsigned char x;
   if(p->maddr)
+  {
     x = p->maddr[port];
+  }
   else
+  {
     x = inb(p->base + port);
+  }
   mb();
   return(x);
+#else
+  return(inb(p->base + port));
+#endif
 }
 
 static inline void
 aic_outb(struct aic7xxx_host *p, unsigned char val, long port)
 {
+#ifdef MMAPIO
   if(p->maddr)
+  {
     p->maddr[port] = val;
+  }
   else
+  {
     outb(val, p->base + port);
+  }
   mb();
+#else
+  outb(val, p->base + port);
+#endif
 }
 
-static inline void
+static void
 aic_outsb(struct aic7xxx_host *p, long port, unsigned char *valp, size_t size)
 {
+#ifdef MMAPIO
   if(p->maddr)
   {
     int i;
-
     for (i=0; i < size; i++)
     {
       p->maddr[port] = valp[i];
     }
+    mb();
   }
   else
     outsb(p->base + port, valp, size);
-  mb();
+#else
+  outsb(p->base + port, valp, size);
+#endif
 }
 
 /*+F*************************************************************************
@@ -1227,10 +1590,13 @@ aic7xxx_setup(char *s, int *dummy)
     { "irq_trigger", &aic7xxx_irq_trigger },
     { "verbose",     &aic7xxx_verbose },
     { "reverse_scan",&aic7xxx_reverse_scan },
-    { "7895_irq_hack", &aic7xxx_7895_irq_hack },
     { "override_term", &aic7xxx_override_term },
+    { "stpwlev", &aic7xxx_stpwlev },
+    { "no_probe", &aic7xxx_no_probe },
     { "panic_on_abort", &aic7xxx_panic_on_abort },
     { "pci_parity", &aic7xxx_pci_parity },
+    { "dump_card", &aic7xxx_dump_card },
+    { "dump_sequencer", &aic7xxx_dump_sequencer },
     { "tag_info",    NULL }
   };
 
@@ -1327,7 +1693,7 @@ aic7xxx_setup(char *s, int *dummy)
         }
         else if (!strncmp(p, "verbose", n))
         {
-          *(options[i].flag) = 0xff69;
+          *(options[i].flag) = 0xff09;
         }
         else
         {
@@ -1387,54 +1753,64 @@ unpause_sequencer(struct aic7xxx_host *p, int unpause_always)
 static inline void
 restart_sequencer(struct aic7xxx_host *p)
 {
-  /* Set the sequencer address to 0. */
-  aic_outb(p, 0, SEQADDR0);
-  aic_outb(p, 0, SEQADDR1);
-
-  /*
-   * Reset and unpause the sequencer.  The reset is suppose to
-   * start the sequencer running, so we immediately do a pause_sequencer
-   * since some of our code expects the sequencer paused after a restart
-   */
-  aic_outb(p, SEQRESET | FASTMODE, SEQCTL);
-  pause_sequencer(p);
+  aic_outb(p, FASTMODE|SEQRESET, SEQCTL);
 }
 
+/*
+ * We include the aic7xxx_seq.c file here so that the other defines have
+ * already been made, and so that it comes before the code that actually
+ * downloads the instructions (since we don't typically use function
+ * prototype, our code has to be ordered that way, it's a left-over from
+ * the original driver days.....I should fix it some time DL).
+ */
+#include "aic7xxx_seq.c"
 
 /*+F*************************************************************************
  * Function:
- *   aic7xxx_next_patch
+ *   aic7xxx_check_patch
  *
  * Description:
- *   Find the next patch to download.
+ *   See if the next patch to download should be downloaded.
  *-F*************************************************************************/
-static struct sequencer_patch *
-aic7xxx_next_patch(struct sequencer_patch *cur_patch, int options, int instrptr)
+static int
+aic7xxx_check_patch(struct aic7xxx_host *p,
+  struct sequencer_patch **start_patch, int start_instr, int *skip_addr)
 {
-  while (cur_patch != NULL)
+  struct sequencer_patch *cur_patch;
+  struct sequencer_patch *last_patch;
+  int num_patches;
+
+  num_patches = sizeof(sequencer_patches)/sizeof(struct sequencer_patch);
+  last_patch = &sequencer_patches[num_patches];
+  cur_patch = *start_patch;
+
+  while ((cur_patch < last_patch) && (start_instr == cur_patch->begin))
   {
-    if ((((cur_patch->options & options) != 0) && (cur_patch->negative == FALSE))
-      || (((cur_patch->options & options) == 0) && (cur_patch->negative == TRUE))
-      || (instrptr >= cur_patch->end))
+    if (cur_patch->patch_func(p) == 0)
     {
       /*
-       * Either we want to keep this section of code, or we have consumed
-       * this patch.  Skip to the next patch.
+       * Start rejecting code.
        */
-      cur_patch++;
-      if (cur_patch->options == 0)
-      {
-        /* Out of patches. */
-        cur_patch = NULL;
-      }
+      *skip_addr = start_instr + cur_patch->skip_instr;
+      cur_patch += cur_patch->skip_patch;
     }
     else
     {
-      /* Found an OK patch. */
-      break;
+      /*
+       * Found an OK patch.  Advance the patch pointer to the next patch
+       * and wait for our instruction pointer to get here.
+       */
+      cur_patch++;
     }
   }
-  return (cur_patch);
+
+  *start_patch = cur_patch;
+  if (start_instr < *skip_addr)
+    /*
+     * Still skipping
+     */
+    return (0);
+  return(1);
 }
 
 
@@ -1446,15 +1822,21 @@ aic7xxx_next_patch(struct sequencer_patch *cur_patch, int options, int instrptr)
  *   Find the next patch to download.
  *-F*************************************************************************/
 static void
-aic7xxx_download_instr(struct aic7xxx_host *p, int options, int instrptr)
+aic7xxx_download_instr(struct aic7xxx_host *p, int instrptr,
+  unsigned char *dconsts)
 {
+  union ins_formats instr;
+  struct ins_format1 *fmt1_ins;
+  struct ins_format3 *fmt3_ins;
   unsigned char opcode;
-  struct ins_format3 instr;
-  unsigned char dconsts[4] = { 0, 0, 0, 0 };
 
-  instr = *(struct ins_format3 *) &seqprog[instrptr * 4];
+  instr = *(union ins_formats*) &seqprog[instrptr * 4];
+
+  fmt1_ins = &instr.format1;
+  fmt3_ins = NULL;
+
   /* Pull the opcode */
-  opcode = (instr.opcode_addr & ~DOWNLOAD_CONST_IMMEDIATE) >> 1;
+  opcode = instr.format1.opcode;
   switch (opcode)
   {
     case AIC_OP_JMP:
@@ -1466,44 +1848,86 @@ aic7xxx_download_instr(struct aic7xxx_host *p, int options, int instrptr)
     case AIC_OP_JE:
     case AIC_OP_JZ:
     {
+      struct sequencer_patch *cur_patch;
       int address_offset;
       unsigned int address;
-      struct sequencer_patch *patch;
+      int skip_addr;
       int i;
 
+      fmt3_ins = &instr.format3;
       address_offset = 0;
-      address = instr.address;
-      address |= (instr.opcode_addr & ADDR_HIGH_BIT) << 8;
-      for (i = 0; i < NUMBER(sequencer_patches); i++)
+      address = fmt3_ins->address;
+      cur_patch = sequencer_patches;
+      skip_addr = 0;
+
+      for (i = 0; i < address;)
       {
-        patch = &sequencer_patches[i];
-        if ((((patch->options & options) == 0) && (patch->negative == FALSE)) ||
-            (((patch->options & options) != 0) && (patch->negative == TRUE)))
+        aic7xxx_check_patch(p, &cur_patch, i, &skip_addr);
+        if (skip_addr > i)
         {
-          if (address >= patch->end)
-          {
-            address_offset += patch->end - patch->begin;
-          }
+          int end_addr;
+
+          end_addr = MIN(address, skip_addr);
+          address_offset += end_addr - i;
+          i = skip_addr;
+        }
+        else
+        {
+          i++;
         }
       }
       address -= address_offset;
-      instr.address = address & 0xFF;
-      instr.opcode_addr &= ~ADDR_HIGH_BIT;
-      instr.opcode_addr |= (address >> 8) & ADDR_HIGH_BIT;
+      fmt3_ins->address = address;
+      /* Fall Through to the next code section */
     }
-       /*  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)
+    case AIC_OP_BMOV:
+      if (fmt1_ins->parity != 0)
       {
-        instr.immediate = dconsts[instr.immediate];
+        fmt1_ins->immediate = dconsts[fmt1_ins->immediate];
       }
-      instr.opcode_addr &= ~DOWNLOAD_CONST_IMMEDIATE;
+      fmt1_ins->parity = 0;
+      /* Fall Through to the next code section */
     case AIC_OP_ROL:
-      aic_outsb(p, SEQRAM, &instr.immediate, 4);
+      if ((p->features & AHC_ULTRA2) != 0)
+      {
+        int i, count;
+
+        /* Calculate odd parity for the instruction */
+        for ( i=0, count=0; i < 31; i++)
+        {
+          unsigned int mask;
+
+          mask = 0x01 << i;
+          if ((instr.integer & mask) != 0)
+            count++;
+        }
+        if (!(count & 0x01))
+          instr.format1.parity = 1;
+      }
+      else
+      {
+        if (fmt3_ins != NULL)
+        {
+          instr.integer =  fmt3_ins->immediate |
+                          (fmt3_ins->source << 8) |
+                          (fmt3_ins->address << 16) |
+                          (fmt3_ins->opcode << 25);
+        }
+        else
+        {
+          instr.integer =  fmt1_ins->immediate |
+                          (fmt1_ins->source << 8) |
+                          (fmt1_ins->destination << 16) |
+                          (fmt1_ins->ret << 24) |
+                          (fmt1_ins->opcode << 25);
+        }
+      }
+      aic_outsb(p, SEQRAM, instr.bytes, 4);
       break;
 
     default:
@@ -1523,104 +1947,100 @@ aic7xxx_download_instr(struct aic7xxx_host *p, int options, int instrptr)
 static void
 aic7xxx_loadseq(struct aic7xxx_host *p)
 {
-  int options;
   struct sequencer_patch *cur_patch;
   int i;
   int downloaded;
+  int skip_addr;
+  unsigned char download_consts[4] = {0, 0, 0, 0};
 
   if (aic7xxx_verbose & VERBOSE_PROBE)
   {
     printk(KERN_INFO "(scsi%d) Downloading sequencer code...", p->host_no);
   }
-  if (aic7xxx_verbose & VERBOSE_PROBE2)
-    printk("\n");
-  options = 1;  /* Code for all options. */
+  download_consts[TMODE_NUMCMDS] = p->num_targetcmds;
+  cur_patch = &sequencer_patches[0];
   downloaded = 0;
-  if (p->type & AHC_ULTRA)
-  {
-    options |= ULTRA;
-    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 (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;
-  }
+  skip_addr = 0;
 
-
-  cur_patch = sequencer_patches;
-  aic_outb(p, PERRORDIS | LOADRAM, SEQCTL);
+  aic_outb(p, PERRORDIS|LOADRAM|FAILDIS|FASTMODE, SEQCTL);
   aic_outb(p, 0, SEQADDR0);
   aic_outb(p, 0, SEQADDR1);
 
   for (i = 0; i < sizeof(seqprog) / 4;  i++)
   {
-    cur_patch = aic7xxx_next_patch(cur_patch, options, i);
-    if (cur_patch && (cur_patch->begin <= i) && (cur_patch->end > i))
+    if (aic7xxx_check_patch(p, &cur_patch, i, &skip_addr) == 0)
     {
       /* Skip this instruction for this configuration. */
       continue;
     }
-    aic7xxx_download_instr(p, options, i);
+    aic7xxx_download_instr(p, i, &download_consts[0]);
     downloaded++;
   }
 
-  aic_outb(p, FASTMODE, SEQCTL);
+  aic_outb(p, FASTMODE|SEQRESET, SEQCTL);
+  if (aic7xxx_verbose & VERBOSE_PROBE)
+  {
+    printk(" %d instructions downloaded\n", downloaded);
+  }
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+  if (aic7xxx_dump_sequencer)
+    aic7xxx_print_sequencer(p, downloaded);
+#endif
+}
+
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_print_sequencer
+ *
+ * Description:
+ *   Print the contents of the sequencer memory to the screen.
+ *-F*************************************************************************/
+static void
+aic7xxx_print_sequencer(struct aic7xxx_host *p, int downloaded)
+{
+  int i, k, temp;
+  
+  aic_outb(p, PERRORDIS|LOADRAM|FAILDIS|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 & VERBOSE_PROBE)
+  k = 0;
+  for (i=0; i < downloaded; i++)
   {
-    printk(" %d instructions downloaded\n", downloaded);
+    if ( k == 0 )
+      printk("%03x: ", i);
+    temp = aic_inb(p, SEQRAM);
+    temp |= (aic_inb(p, SEQRAM) << 8);
+    temp |= (aic_inb(p, SEQRAM) << 16);
+    temp |= (aic_inb(p, SEQRAM) << 24);
+    printk("%08x", temp);
+    if ( ++k == 8 )
+    {
+      printk("\n");
+      k = 0;
+    }
+    else
+      printk(" ");
   }
+  aic_outb(p, FASTMODE|SEQRESET, SEQCTL);
+  printk("\n");
 }
+#endif
 
 /*+F*************************************************************************
  * Function:
  *   aic7xxx_delay
  *
  * Description:
- *   Delay for specified amount of time.  We use udelay because the timer
+ *   Delay for specified amount of time.  We use mdelay because the timer
  *   interrupt is not guaranteed to be enabled.  This will cause an
  *   infinite loop since jiffies (clock ticks) is not updated.
  *-F*************************************************************************/
 static void
 aic7xxx_delay(int seconds)
 {
-  udelay(seconds*1000000);
+  mdelay(seconds * 1000);
 }
 
 /*+F*************************************************************************
@@ -1652,146 +2072,321 @@ aic7xxx_info(struct Scsi_Host *dooh)
   return(bp);
 }
 
-
 /*+F*************************************************************************
  * Function:
- *   aic7xxx_scsirate
+ *   aic7xxx_find_syncrate
  *
  * Description:
  *   Look up the valid period to SCSIRATE conversion in our table
  *-F*************************************************************************/
-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 struct aic7xxx_syncrate *
+aic7xxx_find_syncrate(struct aic7xxx_host *p, unsigned int *period,
+  unsigned int maxsync)
 {
-  int i = num_aic7xxx_syncrates;
-  unsigned char response_period;
-  unsigned char tindex;
-  unsigned short target_mask;
-  unsigned char lun;
-
-  tindex = target | (channel << 3);
-  target_mask = 0x01 << tindex;
-  lun = aic_inb(p, SCB_TCL) & 0x07;
+  struct aic7xxx_syncrate *syncrate;
 
-  response_period = *period;
-
-  /*
-   * If the offset is 0, then the device is requesting asynchronous
-   * transfers.
-   */
-  if ((*period != 0) && (*offset != 0))
+  syncrate = &aic7xxx_syncrates[maxsync];
+  while ( (syncrate->rate[0] != NULL) &&
+         (!(p->features & AHC_ULTRA2) || syncrate->sxfr_ultra2) )
   {
-    for (i = 0; i < num_aic7xxx_syncrates; i++)
+    if ( *period <= syncrate->period )
     {
-      if (*period <= aic7xxx_syncrates[i].period)
+      /*
+       * When responding to a target that requests sync, the requested rate
+       * may fall between two rates that we can output, but still be a rate
+       * that we can receive.  Because of this, we want to respond with the
+       * same rate that it sent to us even if the persiod we use to send
+       * data to it is lower.  Only lower the response period if we must.
+       */
+      if(syncrate == &aic7xxx_syncrates[maxsync])
       {
-        /*
-         * Watch out for Ultra speeds when ultra is not enabled and
-         * vice-versa.
-         */
-        if (!(p->type & AHC_ULTRA) &&
-            (aic7xxx_syncrates[i].rate & ULTRA_SXFR))
-        {
-          /*
-           * This should only happen if the drive is the first to negotiate
-           * and chooses a high rate.   We'll just move down the table until
-           * we hit a non ultra speed.
-           */
-          continue;
-        }
-        *scsirate = (aic7xxx_syncrates[i].rate & 0xF0) | (*offset & 0x0F);
-        *period = aic7xxx_syncrates[i].period;
-
-        /*
-         * 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(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;
+        *period = syncrate->period;
       }
+      break;
     }
+    syncrate++;
   }
-
-  if (i >= num_aic7xxx_syncrates)
+  if ( (*period == 0) || (syncrate->rate[0] == NULL) ||
+       ((p->features & AHC_ULTRA2) && (syncrate->sxfr_ultra2 == 0)) )
   {
     /*
-     * Use asynchronous transfers.
+     * Use async transfers for this target
      */
-    *scsirate = 0;
     *period = 0;
-    *offset = 0;
-    response_period = 0;
-    if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
-         (p->dev_flags[tindex] & DEVICE_PRINT_SDTR) )
-    {
-      printk(INFO_LEAD "Using asynchronous transfers.\n",
-             p->host_no, channel, target, lun);
-      p->dev_flags[tindex] &= ~DEVICE_PRINT_SDTR;
-    }
+    syncrate = NULL;
   }
+  return (syncrate);
+}
 
-  /*
-   * Ensure Ultra mode is set properly for this target.
-   */
-  if ( (*scsirate != 0) && 
-       (aic7xxx_syncrates[i].rate & ULTRA_SXFR) )
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_find_period
+ *
+ * Description:
+ *   Look up the valid SCSIRATE to period conversion in our table
+ *-F*************************************************************************/
+static unsigned int
+aic7xxx_find_period(struct aic7xxx_host *p, unsigned int scsirate,
+  unsigned int maxsync)
+{
+  struct aic7xxx_syncrate *syncrate;
+
+  if ((p->features & AHC_ULTRA2) != 0)
   {
-    p->ultraenb |= target_mask;
+    scsirate &= SXFR_ULTRA2;
   }
   else
   {
-    p->ultraenb &= ~target_mask;
+    scsirate &= SXFR;
   }
-  if (set)
-  {
-    unsigned char sxfrctl0;
 
-    sxfrctl0 = aic_inb(p, SXFRCTL0);
-    sxfrctl0 &= ~FAST20;
-    if (p->ultraenb & target_mask)
+  syncrate = &aic7xxx_syncrates[maxsync];
+  while (syncrate->rate[0] != NULL)
+  {
+    if ((p->features & AHC_ULTRA2) != 0)
+    {
+      if (syncrate->sxfr_ultra2 == 0)
+        break;
+      else if (scsirate == syncrate->sxfr_ultra2)
+        return (syncrate->period);
+    }
+    else if (scsirate == (syncrate->sxfr & ~ULTRA_SXFR))
     {
-      sxfrctl0 |= FAST20;
+      return (syncrate->period);
     }
-    aic_outb(p, p->ultraenb & 0xff, ULTRA_ENB);
-    aic_outb(p, (p->ultraenb >> 8) & 0xff, ULTRA_ENB + 1);
-    aic_outb(p, sxfrctl0, SXFRCTL0);
+    syncrate++;
   }
-  return(response_period);
+  return (0); /* async */
 }
 
 /*+F*************************************************************************
  * Function:
- *   scbq_init
+ *   aic7xxx_validate_offset
  *
  * Description:
- *   SCB queue initialization.
- *
+ *   Set a valid offset value for a particular card in use and transfer
+ *   settings in use.
  *-F*************************************************************************/
-static inline void
-scbq_init(volatile scb_queue_type *queue)
+static void
+aic7xxx_validate_offset(struct aic7xxx_host *p,
+  struct aic7xxx_syncrate *syncrate, unsigned int *offset, int wide)
+{
+  unsigned int maxoffset;
+
+  /* Limit offset to what the card (and device) can do */
+  if (syncrate == NULL)
+  {
+    maxoffset = 0;
+  }
+  else if (p->features & AHC_ULTRA2)
+  {
+    maxoffset = MAX_OFFSET_ULTRA2;
+  }
+  else
+  {
+    if (wide)
+      maxoffset = MAX_OFFSET_16BIT;
+    else
+      maxoffset = MAX_OFFSET_8BIT;
+  }
+  *offset = MIN(*offset, maxoffset);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_set_syncrate
+ *
+ * Description:
+ *   Set the actual syncrate down in the card and in our host structs
+ *-F*************************************************************************/
+static void
+aic7xxx_set_syncrate(struct aic7xxx_host *p, struct aic7xxx_syncrate *syncrate,
+    int target, int channel, unsigned int period, unsigned int offset,
+    unsigned int type)
+{
+  unsigned char tindex;
+  unsigned short target_mask;
+  unsigned char lun;
+  unsigned int old_period, old_offset;
+
+  tindex = target | (channel << 3);
+  target_mask = 0x01 << tindex;
+  lun = aic_inb(p, SCB_TCL) & 0x07;
+
+  if (syncrate == NULL)
+  {
+    period = 0;
+    offset = 0;
+  }
+
+  old_period = p->transinfo[tindex].cur_period;
+  old_offset = p->transinfo[tindex].cur_offset;
+
+  
+  if (type & AHC_TRANS_CUR)
+  {
+    unsigned int scsirate;
+
+    scsirate = aic_inb(p, TARG_SCSIRATE + tindex);
+    if (p->features & AHC_ULTRA2)
+    {
+      scsirate &= ~SXFR_ULTRA2;
+      if (syncrate != NULL)
+      {
+        scsirate |= syncrate->sxfr_ultra2;
+      }
+      if (type & AHC_TRANS_ACTIVE)
+      {
+        aic_outb(p, offset, SCSIOFFSET);
+      }
+      aic_outb(p, offset, TARG_OFFSET + tindex);
+    }
+    else /* Not an Ultra2 controller */
+    {
+      scsirate &= ~(SXFR|SOFS);
+      p->ultraenb &= ~target_mask;
+      if (syncrate != NULL)
+      {
+        if (syncrate->sxfr & ULTRA_SXFR)
+        {
+          p->ultraenb |= target_mask;
+        }
+        scsirate |= (syncrate->sxfr & SXFR);
+        scsirate |= (offset & SOFS);
+      }
+      if (type & AHC_TRANS_ACTIVE)
+      {
+        unsigned char sxfrctl0;
+
+        sxfrctl0 = aic_inb(p, SXFRCTL0);
+        sxfrctl0 &= ~FAST20;
+        if (p->ultraenb & target_mask)
+          sxfrctl0 |= FAST20;
+        aic_outb(p, sxfrctl0, SXFRCTL0);
+      }
+      aic_outb(p, p->ultraenb & 0xff, ULTRA_ENB);
+      aic_outb(p, (p->ultraenb >> 8) & 0xff, ULTRA_ENB + 1 );
+    }
+    if (type & AHC_TRANS_ACTIVE)
+    {
+      aic_outb(p, scsirate, SCSIRATE);
+    }
+    aic_outb(p, scsirate, TARG_SCSIRATE + tindex);
+    p->transinfo[tindex].cur_period = period;
+    p->transinfo[tindex].cur_offset = offset;
+    if ( !(type & AHC_TRANS_QUITE) &&
+         (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
+         (p->dev_flags[tindex] & DEVICE_PRINT_SDTR) )
+    {
+      if (offset)
+      {
+        int rate_mod = (scsirate & WIDEXFER) ? 1 : 0;
+      
+        printk(INFO_LEAD "Synchronous at %s Mbyte/sec, "
+               "offset %d.\n", p->host_no, channel, target, lun,
+               syncrate->rate[rate_mod], offset);
+      }
+      else
+      {
+        printk(INFO_LEAD "Using asynchronous transfers.\n",
+               p->host_no, channel, target, lun);
+      }
+      p->dev_flags[tindex] &= ~DEVICE_PRINT_SDTR;
+    }
+  }
+
+  if (type & AHC_TRANS_GOAL)
+  {
+    p->transinfo[tindex].goal_period = period;
+    p->transinfo[tindex].goal_offset = offset;
+  }
+
+  if (type & AHC_TRANS_USER)
+  {
+    p->transinfo[tindex].user_period = period;
+    p->transinfo[tindex].user_offset = offset;
+  }
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_set_width
+ *
+ * Description:
+ *   Set the actual width down in the card and in our host structs
+ *-F*************************************************************************/
+static void
+aic7xxx_set_width(struct aic7xxx_host *p, int target, int channel, int lun,
+    unsigned int width, unsigned int type)
+{
+  unsigned char tindex;
+  unsigned short target_mask;
+  unsigned int old_width, new_offset;
+
+  tindex = target | (channel << 3);
+  target_mask = 1 << tindex;
+  
+  old_width = p->transinfo[tindex].cur_width;
+
+  if (p->features & AHC_ULTRA2)
+    new_offset = MAX_OFFSET_ULTRA2;
+  else if (width == MSG_EXT_WDTR_BUS_16_BIT)
+    new_offset = MAX_OFFSET_16BIT;
+  else
+    new_offset = MAX_OFFSET_8BIT;
+  
+  if (type & AHC_TRANS_CUR) 
+  {
+    unsigned char scsirate;
+
+    scsirate = aic_inb(p, TARG_SCSIRATE + tindex);
+
+    scsirate &= ~WIDEXFER;
+    if (width == MSG_EXT_WDTR_BUS_16_BIT)
+      scsirate |= WIDEXFER;
+
+    aic_outb(p, scsirate, TARG_SCSIRATE + tindex);
+
+    if (type & AHC_TRANS_ACTIVE)
+      aic_outb(p, scsirate, SCSIRATE);
+
+    p->transinfo[tindex].cur_width = width;
+
+    if ((aic7xxx_verbose & VERBOSE_NEGOTIATION2) && 
+        (p->dev_flags[tindex] & DEVICE_PRINT_WDTR))
+    {
+      printk(INFO_LEAD "Using %s transfers\n", p->host_no, channel, target,
+        lun, (scsirate & WIDEXFER) ? "Wide(16bit)" : "Narrow(8bit)" );
+      p->dev_flags[tindex] &= ~DEVICE_PRINT_WDTR;
+    }
+  }
+
+  if (type & AHC_TRANS_GOAL)
+    p->transinfo[tindex].goal_width = width;
+  if (type & AHC_TRANS_USER)
+    p->transinfo[tindex].user_width = width;
+
+  /*
+   * Having just set the width, the SDTR should come next, and we need a valid
+   * offset for the SDTR.  So, we make sure we put a valid one in here now as
+   * the goal_offset.
+   */
+  if (p->transinfo[tindex].goal_offset)
+    p->transinfo[tindex].goal_offset = new_offset;
+
+}
+      
+/*+F*************************************************************************
+ * Function:
+ *   scbq_init
+ *
+ * Description:
+ *   SCB queue initialization.
+ *
+ *-F*************************************************************************/
+static void
+scbq_init(volatile scb_queue_type *queue)
 {
   queue->head = NULL;
   queue->tail = NULL;
@@ -1828,7 +2423,7 @@ scbq_insert_head(volatile scb_queue_type *queue, struct aic7xxx_scb *scb)
  *   Remove an SCB from the head of the list.
  *
  *-F*************************************************************************/
-static __inline struct aic7xxx_scb *
+static inline struct aic7xxx_scb *
 scbq_remove_head(volatile scb_queue_type *queue)
 {
   struct aic7xxx_scb * scbp;
@@ -2021,7 +2616,7 @@ aic7xxx_rem_scb_from_disc_list(struct aic7xxx_host *p, unsigned char scbptr)
  * Description:
  *   Set the specified target busy.
  *-F*************************************************************************/
-static __inline void
+static inline void
 aic7xxx_busy_target(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
 {
   p->untagged_scbs[scb->hscb->target_channel_lun] = scb->hscb->tag;
@@ -2035,7 +2630,7 @@ aic7xxx_busy_target(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
  *   Returns the index of the busy target, and optionally sets the
  *   target inactive.
  *-F*************************************************************************/
-static __inline unsigned char
+static inline unsigned char
 aic7xxx_index_busy_target(struct aic7xxx_host *p, unsigned char tcl,
     int unbusy)
 {
@@ -2091,47 +2686,47 @@ aic7xxx_find_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
  * Description:
  *   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, int force_alloc)
+static int
+aic7xxx_allocate_scb(struct aic7xxx_host *p)
 {
   struct aic7xxx_scb   *scbp = NULL;
   int scb_size = sizeof(struct aic7xxx_scb) +
                  sizeof (struct hw_scatterlist) * AIC7XXX_MAX_SG;
   int i;
+  int step = PAGE_SIZE / 1024;
   unsigned long scb_count = 0;
   struct hw_scatterlist *hsgp;
   struct aic7xxx_scb *scb_ap;
+  unsigned long temp;
 
 
-  if (force_alloc == FALSE)
-  {
-    scbp = scbq_remove_head(&p->scb_data->free_scbs);
-    if (scbp != NULL)
-      return(scbp);
-  }
-  /*
-   * Either there wasn't an SCB or this is a strictly allocation call
-   */
-
   if (p->scb_data->numscbs < p->scb_data->maxscbs)
   {
-
     /*
-     * 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.
+     * Calculate the optimal number of SCBs to allocate.
+     *
+     * NOTE: This formula works because the sizeof(sg_array) is always
+     * 1024.  Therefore, scb_size * i would always be > PAGE_SIZE *
+     * (i/step).  The (i-1) allows the left hand side of the equation
+     * to grow into the right hand side to a point of near perfect
+     * efficiency since scb_size * (i -1) is growing slightly faster
+     * than the right hand side.  If the number of SG array elements
+     * is changed, this function may not be near so efficient any more.
      */
-    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);
-    
+    for ( i=step;; i *= 2 )
+    {
+      if ( (scb_size * (i-1)) >= ( (PAGE_SIZE * (i/step)) - 64 ) )
+      {
+        i /= 2;
+        break;
+      }
+    }
+    scb_count = MIN( (i-1), 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)
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+      if (aic7xxx_verbose > 0xffff)
       {
         if (p->scb_data->numscbs == 0)
           printk(INFO_LEAD "Allocating initial %ld SCB structures.\n",
@@ -2140,8 +2735,12 @@ aic7xxx_allocate_scb(struct aic7xxx_host *p, int force_alloc)
           printk(INFO_LEAD "Allocating %ld additional SCB structures.\n",
             p->host_no, -1, -1, -1, scb_count);
       }
+#endif
       memset(scb_ap, 0, scb_count * scb_size);
-      hsgp = (struct hw_scatterlist *) &scb_ap[scb_count];
+      temp = (unsigned long) &scb_ap[scb_count];
+      temp += 1023;
+      temp &= ~1023;
+      hsgp = (struct hw_scatterlist *)temp;
       for (i=0; i < scb_count; i++)
       {
         scbp = &scb_ap[i];
@@ -2155,20 +2754,14 @@ aic7xxx_allocate_scb(struct aic7xxx_host *p, int force_alloc)
         p->scb_data->scb_array[p->scb_data->numscbs++] = scbp;
         scbq_insert_head(&p->scb_data->free_scbs, scbp);
       }
+      scbp->kmalloc_ptr = scb_ap;
     }
     else
     {
-      return(NULL);
+      return(0);
     }
   }
-  if (force_alloc == TRUE)
-  {
-    return((struct aic7xxx_scb *)scb_count);
-  }
-  else
-  {
-    return(scbq_remove_head(&p->scb_data->free_scbs));
-  }
+  return(scb_count);
 }
 
 /*+F*************************************************************************
@@ -2180,7 +2773,7 @@ aic7xxx_allocate_scb(struct aic7xxx_host *p, int force_alloc)
  *   to queue completed commands, then call scsi_done() on them when
  *   we're finished.  This function queues the completed commands.
  *-F*************************************************************************/
-static inline void
+static void
 aic7xxx_queue_cmd_complete(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
 {
   cmd->host_scribble = (char *)p->completeq.head;
@@ -2194,7 +2787,7 @@ aic7xxx_queue_cmd_complete(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
  * Description:
  *   Process the completed command queue.
  *-F*************************************************************************/
-static inline void
+static void
 aic7xxx_done_cmds_complete(struct aic7xxx_host *p)
 {
   Scsi_Cmnd *cmd;
@@ -2267,17 +2860,15 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
   }
   if (scb->flags & SCB_RESET)
   {
-      cmd->result = (DID_RESET << 16) | (SUGGEST_RETRY << 24) | 
-        (cmd->result & 0xffff);
+      cmd->result = (DID_RESET << 16) | (cmd->result & 0xffff);
   }
   else if (scb->flags & SCB_ABORT)
   {
-      cmd->result = (DID_RESET << 16) | (SUGGEST_RETRY << 24) | 
-        (cmd->result & 0xffff);
+      cmd->result = (DID_RESET << 16) | (cmd->result & 0xffff);
   }
-  if (!(p->dev_flags[tindex] & DEVICE_SCANNED))
+  else if (!(p->dev_flags[tindex] & DEVICE_SCANNED))
   {
-    if(cmd->cmnd[0] == INQUIRY)
+    if ( (cmd->cmnd[0] == INQUIRY) && (cmd->result == DID_OK) )
     {
       char *buffer;
       
@@ -2295,35 +2886,65 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
 #define WIDE_INQUIRY_BITS 0x60
 #define SYNC_INQUIRY_BITS 0x10
       if ( (buffer[7] & WIDE_INQUIRY_BITS) &&
-           (p->needwdtr_copy & (1<<tindex)) &&
-           (p->type & AHC_WIDE) )
+           (p->features & AHC_WIDE) )
       {
         p->needwdtr |= (1<<tindex);
         p->needwdtr_copy |= (1<<tindex);
-        p->syncinfo[tindex].offset = MAX_OFFSET_16BIT;
+        if ( (p->flags & AHC_SEEPROM_FOUND) &&
+             (p->transinfo[tindex].user_width != MSG_EXT_WDTR_BUS_16_BIT) )
+          p->transinfo[tindex].goal_width = MSG_EXT_WDTR_BUS_8_BIT;
+        else
+          p->transinfo[tindex].goal_width = MSG_EXT_WDTR_BUS_16_BIT;
       }
       else
       {
         p->needwdtr &= ~(1<<tindex);
         p->needwdtr_copy &= ~(1<<tindex);
-        p->syncinfo[tindex].offset = MAX_OFFSET_8BIT;
+        pause_sequencer(p);
+        aic7xxx_set_width(p, cmd->target, cmd->channel, cmd->lun,
+                          MSG_EXT_WDTR_BUS_8_BIT, (AHC_TRANS_ACTIVE |
+                                                   AHC_TRANS_GOAL |
+                                                   AHC_TRANS_CUR) );
+        unpause_sequencer(p, FALSE);
       }
       if (buffer[7] & SYNC_INQUIRY_BITS)
       {
         p->needsdtr |= (1<<tindex);
         p->needsdtr_copy |= (1<<tindex);
+
+        if (p->flags & AHC_SEEPROM_FOUND)
+          p->transinfo[tindex].goal_period = p->transinfo[tindex].user_period;
+        else if (p->features & AHC_ULTRA2)
+          p->transinfo[tindex].goal_period =
+            aic7xxx_syncrates[AHC_SYNCRATE_ULTRA2].period;
+        else if (p->features & AHC_ULTRA)
+          p->transinfo[tindex].goal_period =
+            aic7xxx_syncrates[AHC_SYNCRATE_ULTRA].period;
+        else
+          p->transinfo[tindex].goal_period =
+            aic7xxx_syncrates[AHC_SYNCRATE_FAST].period;
+
+        if (p->features & AHC_ULTRA2)
+          p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
+        else if (p->transinfo[tindex].goal_width == MSG_EXT_WDTR_BUS_16_BIT)
+          p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT;
+        else
+          p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
       }
       else
       {
         p->needsdtr &= ~(1<<tindex);
         p->needsdtr_copy &= ~(1<<tindex);
+        p->transinfo[tindex].goal_period = 0;
+        p->transinfo[tindex].goal_offset = 0;
       }
       p->dev_flags[tindex] |= DEVICE_SCANNED;
+      p->dev_flags[tindex] |= DEVICE_PRINT_WDTR | DEVICE_PRINT_SDTR;
 #undef WIDE_INQUIRY_BITS
 #undef SYNC_INQUIRY_BITS
     }
   }
-  if ((scb->flags & (SCB_MSGOUT_WDTR | SCB_MSGOUT_SDTR)) != 0)
+  else if ((scb->flags & (SCB_MSGOUT_WDTR | SCB_MSGOUT_SDTR)) != 0)
   {
     unsigned short mask;
     int message_error = FALSE;
@@ -2346,7 +2967,7 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
       p->wdtr_pending &= ~mask;
       if (message_error)
       {
-        if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
+        if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
              (p->dev_flags[tindex] & DEVICE_PRINT_WDTR) )
         {
           printk(INFO_LEAD "Device failed to complete Wide Negotiation "
@@ -2366,7 +2987,7 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
       p->sdtr_pending &= ~mask;
       if (message_error)
       {
-        if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
+        if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
              (p->dev_flags[tindex] & DEVICE_PRINT_SDTR) )
         {
           printk(INFO_LEAD "Device failed to complete Sync Negotiation "
@@ -2402,12 +3023,17 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
       {
         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);
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+      if (aic7xxx_verbose > 0xffff)
+        printk(INFO_LEAD "Moving SCB from delayed to waiting queue.\n",
+               p->host_no, CTL_OF_SCB(scbp));
+#endif
+      if (queue_depth > p->dev_active_cmds[tindex])
+      {
+        scbp = scbq_remove_head(&p->delayed_scbs[tindex]);
+        if (scbp)
+          scbq_insert_tail(&p->waiting_scbs, scbp);
+      }
     }
   }
   if ( !(scb->tag_action) && (p->tagenable & (1<<tindex)) )
@@ -2427,7 +3053,6 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
     aic7xxx_index_busy_target(p, scb->hscb->target_channel_lun, TRUE);
   }
 
-#ifdef AIC7XXX_PROC_STATS
   {
     int actual;
 
@@ -2445,11 +3070,17 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
     if ((actual >= 512) && (((cmd->result >> 16) & 0xf) == DID_OK))
     {
       struct aic7xxx_xferstats *sp;
+#ifdef AIC7XXX_PROC_STATS
       long *ptr;
       int x;
+#endif /* AIC7XXX_PROC_STATS */
 
       sp = &p->stats[TARGET_INDEX(cmd)][cmd->lun & 0x7];
       sp->xfers++;
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+      if ( (sp->xfers > 16) && (aic7xxx_verbose > 0xffff) )
+        aic7xxx_verbose &= 0xffff;
+#endif
 
       /*
        * For block devices, cmd->request.cmd is always == either READ or
@@ -2462,14 +3093,19 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
       {
         sp->w_total++;
         sp->w_total512 += (actual >> 9);
+#ifdef AIC7XXX_PROC_STATS
         ptr = sp->w_bins;
+#endif /* AIC7XXX_PROC_STATS */
       }
       else
       {
         sp->r_total++;
         sp->r_total512 += (actual >> 9);
+#ifdef AIC7XXX_PROC_STATS
         ptr = sp->r_bins;
+#endif /* AIC7XXX_PROC_STATS */
       }
+#ifdef AIC7XXX_PROC_STATS
       for (x = 9; x <= 17; x++)
       {
         if (actual < (1 << x))
@@ -2482,10 +3118,9 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
       {
         ptr[x - 9]++;
       }
+#endif /* AIC7XXX_PROC_STATS */
     }
   }
-#endif /* AIC7XXX_PROC_STATS */
-
   aic7xxx_free_scb(p, scb);
   aic7xxx_queue_cmd_complete(p, cmd);
 
@@ -2667,7 +3302,10 @@ aic7xxx_search_qinfifo(struct aic7xxx_host *p, int target, int channel,
   {
     p->qinfifo[qinpos++] = SCB_LIST_NULL;
   }
-  aic_outb(p, p->qinfifonext, KERNEL_QINPOS);
+  if (p->features & AHC_QUEUE_REGS)
+    aic_outb(p, p->qinfifonext, HNSCB_QOFF);
+  else
+    aic_outb(p, p->qinfifonext, KERNEL_QINPOS);
 
   return (found);
 }
@@ -2740,7 +3378,7 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, int channel,
       {
         case 0:
                  min_target = 0;
-                 max_target = (p->type & AHC_WIDE) ? 15 : 7;
+                 max_target = (p->features & AHC_WIDE) ? 15 : 7;
                  break;
         case 1:
                  min_target = 8;
@@ -2749,7 +3387,7 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, int channel,
         case ALL_CHANNELS:
         default:
                  min_target = 0;
-                 max_target = (p->type & (AHC_TWIN|AHC_WIDE)) ? 15 : 7;
+                 max_target = (p->features & (AHC_TWIN|AHC_WIDE)) ? 15 : 7;
                  break;
       }
     }
@@ -2812,7 +3450,7 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, int channel,
       j = 0; 
       prev_scbp = NULL; 
       scbp = p->delayed_scbs[i].head;
-      while ( (scbp != NULL) && (j++ <= p->scb_data->numscbs) )
+      while ( (scbp != NULL) && (j++ <= (p->scb_data->numscbs + 1)) )
       {
         prev_scbp = scbp;
         scbp = scbp->q_next;
@@ -2837,7 +3475,7 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, int channel,
           prev_scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
         }
       }
-      if ( j > p->scb_data->numscbs )
+      if ( j > (p->scb_data->maxscbs + 1) )
       {
         if (aic7xxx_verbose & (VERBOSE_ABORT | VERBOSE_RESET))
           printk(WARN_LEAD "Yikes!! There's a loop in the "
@@ -2871,7 +3509,7 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, int channel,
     j = 0; 
     prev_scbp = NULL; 
     scbp = p->waiting_scbs.head;
-    while ( (scbp != NULL) && (j++ <= p->scb_data->numscbs) )
+    while ( (scbp != NULL) && (j++ <= (p->scb_data->numscbs + 1)) )
     {
       prev_scbp = scbp;
       scbp = scbp->q_next;
@@ -2896,7 +3534,7 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, int channel,
         prev_scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
       }
     }
-    if ( j > p->scb_data->numscbs )
+    if ( j > (p->scb_data->maxscbs + 1) )
     {
       if (aic7xxx_verbose & (VERBOSE_ABORT | VERBOSE_RESET))
         printk(WARN_LEAD "Yikes!! There's a loop in the "
@@ -2918,7 +3556,7 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, int channel,
     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) )
+    while ( (next != SCB_LIST_NULL) && (j++ <= (p->scb_data->maxscbs + 1)) )
     {
       aic_outb(p, next, SCBPTR);
       scb_index = aic_inb(p, SCB_TAG);
@@ -2966,7 +3604,7 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, int channel,
         }
       }
     }
-    if ( j > p->scb_data->maxhscbs )
+    if ( j > (p->scb_data->maxscbs + 1) )
     {
       printk(WARN_LEAD "Yikes!!  There is a loop in the waiting for "
         "selection list!\n", p->host_no, channel, target, lun);
@@ -2981,13 +3619,14 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, int channel,
   if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
     printk(INFO_LEAD "Cleaning disconnected scbs "
       "list.\n", p->host_no, channel, target, lun);
+  if (p->features & AHC_PAGESCBS)
   {
     unsigned char next, prev, scb_index;
 
     next = aic_inb(p, DISCONNECTED_SCBH);
     prev = SCB_LIST_NULL;
     j = 0;
-    while ( (next != SCB_LIST_NULL) && (j++ <= p->scb_data->maxhscbs) )
+    while ( (next != SCB_LIST_NULL) && (j++ <= (p->scb_data->maxscbs + 1)) )
     {
       aic_outb(p, next, SCBPTR);
       scb_index = aic_inb(p, SCB_TAG);
@@ -3020,7 +3659,7 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, int channel,
         }
       }
     }
-    if ( j > p->scb_data->maxhscbs )
+    if ( j > (p->scb_data->maxscbs + 1) )
     {
       printk(WARN_LEAD "Yikes!!  There is a loop in the disconnected list!\n",
         p->host_no, channel, target, lun);
@@ -3032,15 +3671,23 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, int channel,
    * Walk the free list making sure no entries on the free list have
    * a valid SCB_TAG value or SCB_CONTROL byte.
    */
+  if (p->features & AHC_PAGESCBS)
   {
     unsigned char next;
 
     j = 0;
     next = aic_inb(p, FREE_SCBH);
-    while ( (next != SCB_LIST_NULL) && (j++ < p->scb_data->maxhscbs) )
+    if ( (next >= p->scb_data->maxhscbs) && (next != SCB_LIST_NULL) )
+    {
+      printk(WARN_LEAD "Bogus FREE_SCBH!.\n", p->host_no, channel,
+        target, lun);
+      init_lists = TRUE;
+      next = SCB_LIST_NULL;
+    }
+    while ( (next != SCB_LIST_NULL) && (j++ <= (p->scb_data->maxscbs + 1)) )
     {
       aic_outb(p, next, SCBPTR);
-      if ( aic_inb(p, SCB_TAG) < p->scb_data->numscbs )
+      if (aic_inb(p, SCB_TAG) < p->scb_data->numscbs)
       {
         printk(WARN_LEAD "Free list inconsistency!.\n", p->host_no, channel,
           target, lun);
@@ -3054,7 +3701,7 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, int channel,
         next = aic_inb(p, SCB_NEXT);
       }
     }
-    if ( j > p->scb_data->maxhscbs )
+    if ( j > (p->scb_data->maxscbs + 1) )
     {
       printk(WARN_LEAD "Yikes!!  There is a loop in the free list!\n",
         p->host_no, channel, target, lun);
@@ -3072,7 +3719,7 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, int channel,
     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)
+  for (i = p->scb_data->maxhscbs - 1; i >= 0; i--)
   {
     unsigned char scbid;
 
@@ -3148,7 +3795,7 @@ aic7xxx_clear_intstat(struct aic7xxx_host *p)
   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);
+  aic_outb(p, CLRSCSIINT | CLRSEQINT | CLRBRKADRINT | CLRPARERR, CLRINT);
 }
 
 /*+F*************************************************************************
@@ -3161,21 +3808,26 @@ aic7xxx_clear_intstat(struct aic7xxx_host *p)
 static void
 aic7xxx_reset_current_bus(struct aic7xxx_host *p)
 {
-  unsigned char scsiseq;
 
   /* Disable reset interrupts. */
   aic_outb(p, aic_inb(p, SIMODE1) & ~ENSCSIRST, SIMODE1);
 
+  /* Turn off the bus' current operations, after all, we shouldn't have any
+   * valid commands left to cause a RSELI and SELO once we've tossed the
+   * bus away with this reset, so we might as well shut down the sequencer
+   * until the bus is restarted as oppossed to saving the current settings
+   * and restoring them (which makes no sense to me). */
+
   /* Turn on the bus reset. */
-  scsiseq = aic_inb(p, SCSISEQ);
-  aic_outb(p, scsiseq | SCSIRSTO, SCSISEQ);
+  aic_outb(p, aic_inb(p, SCSISEQ) | SCSIRSTO, SCSISEQ);
+  while ( (aic_inb(p, SCSISEQ) & SCSIRSTO) == 0)
+    mdelay(5);
 
-  udelay(5000);
+  mdelay(10);
 
   /* Turn off the bus reset. */
-  aic_outb(p, scsiseq & ~SCSIRSTO, SCSISEQ);
-
-  udelay(2000);
+  aic_outb(p, 0, SCSISEQ);
+  mdelay(5);
 
   aic7xxx_clear_intstat(p);
   /* Re-enable reset interrupts. */
@@ -3193,7 +3845,7 @@ aic7xxx_reset_current_bus(struct aic7xxx_host *p)
 static void
 aic7xxx_reset_channel(struct aic7xxx_host *p, int channel, int initiate_reset)
 {
-  unsigned long offset, offset_max;
+  unsigned long offset_min, offset_max;
   unsigned char sblkctl;
   int cur_channel;
 
@@ -3206,48 +3858,52 @@ aic7xxx_reset_channel(struct aic7xxx_host *p, int channel, int initiate_reset)
   {
     p->needsdtr |= (p->needsdtr_copy & 0xFF00);
     p->sdtr_pending &= 0x00FF;
-    offset = TARG_SCRATCH + 8;
-    offset_max = TARG_SCRATCH + 16;
+    offset_min = 8;
+    offset_max = 16;
   }
   else
   {
-    if (p->type & AHC_WIDE)
+    if (p->features & AHC_WIDE)
     {
       p->needsdtr = p->needsdtr_copy;
       p->needwdtr = p->needwdtr_copy;
       p->sdtr_pending = 0x0;
       p->wdtr_pending = 0x0;
-      offset = TARG_SCRATCH;
-      offset_max = TARG_SCRATCH + 16;
+      offset_min = 0;
+      offset_max = 16;
     }
     else
     {
       /* Channel A */
       p->needsdtr |= (p->needsdtr_copy & 0x00FF);
       p->sdtr_pending &= 0xFF00;
-      offset = TARG_SCRATCH;
-      offset_max = TARG_SCRATCH + 8;
+      offset_min = 0;
+      offset_max = 8;
     }
   }
 
-  while (offset < offset_max)
+  while (offset_min < offset_max)
   {
     /*
      * Revert to async/narrow transfers until we renegotiate.
      */
-    u_char targ_scratch;
-
-    targ_scratch = aic_inb(p, offset);
-    targ_scratch &= SXFR;
-    aic_outb(p, targ_scratch, offset++);
+    aic_outb(p, 0, TARG_SCSIRATE + offset_min);
+    if (p->features & AHC_ULTRA2)
+    {
+      aic_outb(p, 0, TARG_OFFSET + offset_min);
+    }
+    offset_min++;
   }
 
   /*
    * Reset the bus and unpause/restart the controller
    */
   sblkctl = aic_inb(p, SBLKCTL);
-  cur_channel = (sblkctl & SELBUSB) >> 3;
-  if (cur_channel != channel)
+  if ( (p->chip & AHC_CHIPID_MASK) == AHC_AIC7770 )
+    cur_channel = (sblkctl & SELBUSB) >> 3;
+  else
+    cur_channel = 0;
+  if ( (cur_channel != channel) && (p->features & AHC_TWIN) )
   {
     /*
      * Case 1: Command for another bus is active
@@ -3264,7 +3920,7 @@ aic7xxx_reset_channel(struct aic7xxx_host *p, int channel, int initiate_reset)
     {
       aic7xxx_reset_current_bus(p);
     }
-    aic_outb(p, 0, SCSISEQ);
+    aic_outb(p, aic_inb(p, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP), SCSISEQ);
     aic7xxx_clear_intstat(p);
     aic_outb(p, sblkctl, SBLKCTL);
   }
@@ -3285,7 +3941,7 @@ aic7xxx_reset_channel(struct aic7xxx_host *p, int channel, int initiate_reset)
     {
       aic7xxx_reset_current_bus(p);
     }
-    aic_outb(p, 0, SCSISEQ);
+    aic_outb(p, aic_inb(p, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP), SCSISEQ);
     aic7xxx_clear_intstat(p);
   }
   if (aic7xxx_verbose & VERBOSE_RESET_RETURN)
@@ -3296,7 +3952,13 @@ aic7xxx_reset_channel(struct aic7xxx_host *p, int channel, int initiate_reset)
    */
   aic7xxx_reset_device(p, ALL_TARGETS, channel, ALL_LUNS, SCB_LIST_NULL);
 
-  if ( !(p->type & AHC_TWIN) )
+  /*
+   * Convince Mid Level SCSI code to leave us be for a little bit...
+   */
+  p->last_reset = jiffies;
+  p->host->last_reset = (jiffies + (HZ * AIC7XXX_RESET_DELAY));
+
+  if ( !(p->features & AHC_TWIN) )
   {
     restart_sequencer(p);
   }
@@ -3312,7 +3974,7 @@ aic7xxx_reset_channel(struct aic7xxx_host *p, int channel, int initiate_reset)
  *   Scan the awaiting_scbs queue downloading and starting as many
  *   scbs as we can.
  *-F*************************************************************************/
-static inline void
+static void
 aic7xxx_run_waiting_queues(struct aic7xxx_host *p)
 {
   struct aic7xxx_scb *scb;
@@ -3337,23 +3999,38 @@ aic7xxx_run_waiting_queues(struct aic7xxx_host *p)
     tindex = TARGET_INDEX(scb->cmd);
     if ( !scb->tag_action && (p->tagenable & (1<<tindex)) )
     {
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+      if (aic7xxx_verbose > 0xffff)
+        printk(INFO_LEAD "Reducing Queue depth for untagged command.\n",
+               p->host_no, CTL_OF_SCB(scb));
+#endif
       p->dev_temp_queue_depth[tindex] = 1;
     }
     if ( (p->dev_active_cmds[tindex] >=
           p->dev_temp_queue_depth[tindex]) ||
          (p->dev_last_reset[tindex] >= (jiffies - (4 * HZ))) )
     {
-        scbq_insert_tail(&p->delayed_scbs[tindex], scb);
-        if ( !(p->dev_timer[tindex].expires) &&
-             !(p->dev_active_cmds[tindex]) )
-        {
-          p->dev_timer[tindex].expires = p->dev_last_reset[tindex] + (4 * HZ);
-          add_timer(&p->dev_timer[tindex]);
-        }
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+      if (aic7xxx_verbose > 0xffff)
+        printk(INFO_LEAD "Moving SCB to Delayed Queue.\n",
+               p->host_no, CTL_OF_SCB(scb));
+#endif
+      scbq_insert_tail(&p->delayed_scbs[tindex], scb);
+      if ( !(p->dev_timer[tindex].expires) &&
+           !(p->dev_active_cmds[tindex]) )
+      {
+        p->dev_timer[tindex].expires = p->dev_last_reset[tindex] + (4 * HZ);
+        add_timer(&p->dev_timer[tindex]);
+      }
     }
     else
     {
         scb->flags &= ~SCB_WAITINGQ;
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+        if (aic7xxx_verbose > 0xffff)
+          printk(INFO_LEAD "Sending command %d/0x%x to QINFIFO\n", p->host_no,
+                 CTL_OF_SCB(scb), scb->hscb->tag, scb->flags);
+#endif
         p->dev_active_cmds[tindex]++;
         p->activescbs++;
         if ( !(scb->tag_action) )
@@ -3366,62 +4043,142 @@ aic7xxx_run_waiting_queues(struct aic7xxx_host *p)
   }
   if (sent)
   {
-    pause_sequencer(p);
-    aic_outb(p, p->qinfifonext, KERNEL_QINPOS);
-    unpause_sequencer(p, FALSE);
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+    if (aic7xxx_verbose > 0xffff)
+    {
+      printk(INFO_LEAD "Sending commands to QINFIFO\n", p->host_no,
+             -1, -1, -1);
+      if ( (p->isr_count < 16) && (aic7xxx_panic_on_abort) &&
+           (p->flags & AHC_PAGESCBS) )
+        aic7xxx_check_scbs(p, "While sending commands to QINFIFO");
+    }
+#endif
+    if (p->features & AHC_QUEUE_REGS)
+      aic_outb(p, p->qinfifonext, HNSCB_QOFF);
+    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
 }
 
+#ifdef CONFIG_PCI
+
+#define  DPE 0x80
+#define  SSE 0x40
+#define  RMA 0x20
+#define  RTA 0x10
+#define  STA 0x08
+#define  DPR 0x01
 
 /*+F*************************************************************************
  * Function:
- *   aic7xxx_timer
+ *   aic7xxx_pci_intr
  *
  * Description:
- *   Take expired extries off of delayed queues and place on waiting queue
- *   then run waiting queue to start commands.
- ***************************************************************************/
+ *   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_timer(struct aic7xxx_host *p)
+aic7xxx_pci_intr(struct aic7xxx_host *p)
 {
-  int i, j;
-  unsigned long cpu_flags = 0;
-  struct aic7xxx_scb *scb;
+  unsigned char status1;
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)   
-  DRIVER_LOCK
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
+  pci_read_config_byte(p->pdev, PCI_STATUS + 1, &status1);
 #else
-  spin_lock_irqsave(&io_request_lock, cpu_flags);
+  pcibios_read_config_byte(p->pci_bus, p->pci_device_fn,
+                           PCI_STATUS + 1, &status1);
 #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];
-      j = 0;
-      while ( ((scb = scbq_remove_head(&p->delayed_scbs[i])) != NULL) &&
-              (j++ < p->scb_data->numscbs) )
-      {
-        scbq_insert_tail(&p->waiting_scbs, scb);
-      }
-      if (j == p->scb_data->numscbs)
-      {
-        printk(INFO_LEAD "timer: Yikes, loop in delayed_scbs list.\n",
-          p->host_no, 0, i, -1);
-        scbq_init(&p->delayed_scbs[i]);
-        scbq_init(&p->waiting_scbs);
-        /*
-         * Well, things are screwed now, wait for a reset to clean the junk
+
+  if ( (status1 & DPE) && (aic7xxx_verbose & VERBOSE_MINOR_ERROR) )
+    printk(WARN_LEAD "Data Parity Error during PCI address or PCI write"
+      "phase.\n", p->host_no, -1, -1, -1);
+  if ( (status1 & SSE) && (aic7xxx_verbose & VERBOSE_MINOR_ERROR) )
+    printk(WARN_LEAD "Signal System Error Detected\n", p->host_no,
+      -1, -1, -1);
+  if ( (status1 & RMA) && (aic7xxx_verbose & VERBOSE_MINOR_ERROR) )
+    printk(WARN_LEAD "Received a PCI Master Abort\n", p->host_no,
+      -1, -1, -1);
+  if ( (status1 & RTA) && (aic7xxx_verbose & VERBOSE_MINOR_ERROR) )
+    printk(WARN_LEAD "Received a PCI Target Abort\n", p->host_no,
+      -1, -1, -1);
+  if ( (status1 & STA) && (aic7xxx_verbose & VERBOSE_MINOR_ERROR) )
+    printk(WARN_LEAD "Signaled a PCI Target Abort\n", p->host_no,
+      -1, -1, -1);
+  if ( (status1 & DPR) && (aic7xxx_verbose & VERBOSE_MINOR_ERROR) )
+    printk(WARN_LEAD "Data Parity Error has been reported via PCI pin "
+      "PERR#\n", p->host_no, -1, -1, -1);
+  
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
+  pci_write_config_byte(p->pdev, PCI_STATUS + 1, status1);
+#else
+  pcibios_write_config_byte(p->pci_bus, p->pci_device_fn,
+                            PCI_STATUS + 1, status1);
+#endif
+  if (status1 & (DPR|RMA|RTA))
+    aic_outb(p,  CLRPARERR, CLRINT);
+
+  if ( (aic7xxx_panic_on_abort) && (p->spurious_int > 500) )
+    aic7xxx_panic_abort(p, NULL);
+
+}
+#endif /* CONFIG_PCI */
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_timer
+ *
+ * Description:
+ *   Take expired extries off of delayed queues and place on waiting queue
+ *   then run waiting queue to start commands.
+ ***************************************************************************/
+static void
+aic7xxx_timer(struct aic7xxx_host *p)
+{
+  int i, j;
+  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];
+      j = 0;
+      while ( ((scb = scbq_remove_head(&p->delayed_scbs[i])) != NULL) &&
+              (j++ < p->scb_data->numscbs) )
+      {
+        scbq_insert_tail(&p->waiting_scbs, scb);
+      }
+      if (j == p->scb_data->numscbs)
+      {
+        printk(INFO_LEAD "timer: Yikes, loop in delayed_scbs list.\n",
+          p->host_no, 0, i, -1);
+        scbq_init(&p->delayed_scbs[i]);
+        scbq_init(&p->waiting_scbs);
+        /*
+         * Well, things are screwed now, wait for a reset to clean the junk
          * out.
          */
       }
@@ -3545,12 +4302,11 @@ static void
 aic7xxx_handle_device_reset(struct aic7xxx_host *p, int target, int channel)
 {
   unsigned short targ_mask;
-  unsigned char  targ_scratch;
-  int scratch_offset = target;
+  unsigned char tindex = target;
 
-  scratch_offset += channel << 3;
+  tindex |= ((channel & 0x01) << 3);
 
-  targ_mask = (0x01 << scratch_offset);
+  targ_mask = (0x01 << tindex);
   /*
    * Go back to async/narrow transfers and renegotiate.
    */
@@ -3558,9 +4314,9 @@ aic7xxx_handle_device_reset(struct aic7xxx_host *p, int target, int channel)
   p->needwdtr |= (p->needwdtr_copy & targ_mask);
   p->sdtr_pending &= ~targ_mask;
   p->wdtr_pending &= ~targ_mask;
-  targ_scratch = aic_inb(p, TARG_SCRATCH + scratch_offset);
-  targ_scratch &= SXFR;
-  aic_outb(p, targ_scratch, TARG_SCRATCH + scratch_offset);
+  aic_outb(p, 0, TARG_SCSIRATE + tindex);
+  if (p->features & AHC_ULTRA2)
+    aic_outb(p, 0, TARG_OFFSET + tindex);
   aic7xxx_reset_device(p, target, channel, ALL_LUNS, SCB_LIST_NULL);
   if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
     printk(INFO_LEAD "Bus Device Reset delivered.\n", p->host_no, channel,
@@ -3580,20 +4336,30 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
 {
   struct aic7xxx_scb *scb;
   unsigned short target_mask;
-  unsigned char target, scratch_offset, lun;
+  unsigned char target, lun, tindex;
   unsigned char queue_flag = FALSE;
   char channel;
 
   target = ((aic_inb(p, SAVED_TCL) >> 4) & 0x0f);
-  channel = (aic_inb(p, SBLKCTL) >> 3) & 0x01;
-  scratch_offset = target + (channel << 3);
+  if ( (p->chip & AHC_CHIPID_MASK) == AHC_AIC7770 )
+    channel = (aic_inb(p, SBLKCTL) & SELBUSB) >> 3;
+  else
+    channel = 0;
+  tindex = target + (channel << 3);
   lun = aic_inb(p, SAVED_TCL) & 0x07;
-  target_mask = (0x01 << scratch_offset);
+  target_mask = (0x01 << tindex);
 
+  /*
+   * Go ahead and clear the SEQINT now, that avoids any interrupt race
+   * conditions later on in case we enable some other interrupt.
+   */
+  aic_outb(p, CLRSEQINT, CLRINT);
   switch (intstat & SEQINT_MASK)
   {
     case NO_MATCH:
       {
+        aic_outb(p, aic_inb(p, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP),
+                 SCSISEQ);
         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",
@@ -3654,12 +4420,11 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
         p->msg_len = 0;
         p->msg_index = 0;
 
-       /*
-        * 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);
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+        if (aic7xxx_verbose > 0xffff)
+          printk(INFO_LEAD "Enabling REQINITs for MSG_IN\n", p->host_no,
+                 channel, target, lun);
+#endif
 
        /*      
         * To actually receive the message, simply turn on
@@ -3682,13 +4447,11 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
          * 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;
 
         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) &&
@@ -3696,7 +4459,7 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
             !(scb->flags & SCB_MSGOUT_BITS) )
         {
           if ((scb->tag_action == MSG_ORDERED_Q_TAG) &&
-              (p->dev_flags[scratch_offset] & DEVICE_TAGGED_SUCCESS))
+              (p->dev_flags[tindex] & DEVICE_TAGGED_SUCCESS))
           {
             /*
              * OK...the device seems able to accept tagged commands, but
@@ -3718,7 +4481,7 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
             aic_outb(p, aic_inb(p, SCSISIGI) | ATNO, SCSISIGO);
           }
           else if ( (scb->tag_action == MSG_SIMPLE_Q_TAG) &&
-                   !(p->dev_flags[scratch_offset] & DEVICE_TAGGED_SUCCESS) )
+                   !(p->dev_flags[tindex] & DEVICE_TAGGED_SUCCESS) )
           {
             unsigned char i, reset = 0;
             struct aic7xxx_scb *scbp;
@@ -3733,8 +4496,8 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
              */
             p->tagenable &= ~target_mask;
             p->orderedtag &= ~target_mask;
-            p->dev_max_queue_depth[scratch_offset] =
-               p->dev_temp_queue_depth[scratch_offset] = 1;
+            p->dev_max_queue_depth[tindex] =
+               p->dev_temp_queue_depth[tindex] = 1;
             /*
              * 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
@@ -3783,40 +4546,34 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
           /*
            * note 8bit xfers and clear flag
            */
-          targ_scratch &= 0x7F;
           p->needwdtr &= ~target_mask;
           p->needwdtr_copy &= ~target_mask;
           p->wdtr_pending &= ~target_mask;
-          if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
-               (p->dev_flags[scratch_offset] & DEVICE_PRINT_WDTR) )
+          scb->flags &= ~SCB_MSGOUT_BITS;
+          aic7xxx_set_width(p, target, channel, lun, MSG_EXT_WDTR_BUS_8_BIT,
+            (AHC_TRANS_ACTIVE|AHC_TRANS_GOAL|AHC_TRANS_CUR));
+          aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0,
+                               AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE);
+          if ( (p->needsdtr_copy & target_mask) &&
+               !(p->sdtr_pending & target_mask) )
           {
-            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;
+            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);
           }
-          scb->flags &= ~SCB_MSGOUT_WDTR_16BIT;
-          p->syncinfo[scratch_offset].offset = MAX_OFFSET_8BIT;
-          if (p->needsdtr_copy & target_mask)
-            p->needsdtr |= target_mask;
         }
         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;
-          }
+          scb->flags &= ~SCB_MSGOUT_SDTR;
+          aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0,
+            (AHC_TRANS_CUR|AHC_TRANS_ACTIVE|AHC_TRANS_GOAL));
         }
         else if (aic7xxx_verbose & VERBOSE_SEQINT)
         {
@@ -3826,8 +4583,6 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
           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;
 
@@ -3842,11 +4597,15 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
          * 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.
+         *
+         * 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);
         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;
@@ -3854,12 +4613,6 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
         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,"
@@ -3928,7 +4681,6 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
 
                 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
@@ -3936,12 +4688,67 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
                  * 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.
-                 *
-                 * 1998/04/23 - We also don't want to set the flag if the
-                 *   original command was a TEST_UNIT_READY since that
-                 *   implies a SEND_SENSE anyway.
                  */
-                if (scb->cmd->cmnd[0] != TEST_UNIT_READY)
+#ifdef AIC7XXX_FAKE_NEGOTIATION_CMDS
+                if ( (scb->cmd->cmnd[0] != TEST_UNIT_READY) &&
+                     (p->dev_flags[tindex] & DEVICE_SCANNED) &&
+                     !(p->wdtr_pending & target_mask) && 
+                     !(p->sdtr_pending & target_mask) )
+                {
+                  p->needwdtr |= (p->needwdtr_copy & target_mask);
+                  p->needsdtr |= (p->needsdtr_copy & target_mask);
+                }
+                else if ( (scb->cmd == p->dev_wdtr_cmnd[tindex]) ||
+                          (scb->cmd == p->dev_sdtr_cmnd[tindex]) )
+                {
+                  /*
+                   * This is already a negotiation command, so we must have
+                   * already done either WDTR or SDTR (or maybe both).  So
+                   * we simply check sdtr_pending and needsdtr to see if we
+                   * should throw out SDTR on this command.
+                   *
+                   * Note: Don't check the needsdtr_copy here, instead just
+                   * check to see if WDTR wiped out our SDTR and set needsdtr.
+                   * Even if WDTR did wipe out SDTR and set needsdtr, if
+                   * parse_msg() then turned around and started our SDTR
+                   * in back to back fasion, then conclusion of that should
+                   * have negated any needsdtr setting.  That's why we only
+                   * check needsdtr and sdtr_pending.
+                   */
+                  scb->flags &= ~SCB_MSGOUT_BITS;
+                  if ( (scb->cmd == p->dev_wdtr_cmnd[tindex]) &&
+                       !(p->sdtr_pending & target_mask) &&
+                       (p->needsdtr & target_mask) )
+                  {
+                    p->sdtr_pending |= target_mask;
+                    hscb->control |= MK_MESSAGE;
+                    scb->flags |= SCB_MSGOUT_SDTR;
+                  }
+
+                  /*
+                   * This is the important part though.  We are getting sense
+                   * info back from this device.  It's going into a fake
+                   * command.  We need to put that into the real command
+                   * instead so that the mid level SCSI code can act upon it.
+                   * So, when we set up these fake commands, the next pointer
+                   * is used to point to the real command.  Use that to change
+                   * the address of our sense_buffer[] to the real command.
+                   * However, don't do this if the real command is also a
+                   * TEST_UNIT_READY as it will most likely pull down its own
+                   * SENSE information anyway.
+                   */
+                  if (cmd->next->cmnd[0] != TEST_UNIT_READY)
+                  {
+                    scb->sg_list[0].address = 
+                      cpu_to_le32(VIRT_TO_BUS(&cmd->next->sense_buffer[0]));
+                    hscb->data_pointer = scb->sg_list[0].address;
+                  }
+                }
+#else
+                if (  (scb->cmd->cmnd[0] != TEST_UNIT_READY) &&
+                     !(scb->flags & SCB_MSGOUT_BITS) && 
+                      (scb->cmd->lun == 0) &&
+                      (p->dev_flags[TARGET_INDEX(scb->cmd)] & DEVICE_SCANNED) )
                 {
                   if ( (p->needwdtr_copy & target_mask) &&
                       !(p->wdtr_pending & target_mask) &&
@@ -3950,7 +4757,7 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
                     p->needwdtr |= target_mask;
                     p->wdtr_pending |= target_mask;
                     hscb->control |= MK_MESSAGE;
-                    scb->flags |= SCB_MSGOUT_WDTR_16BIT;
+                    scb->flags |= SCB_MSGOUT_WDTR;
                   }
                   if ( p->needsdtr_copy & target_mask )
                   {
@@ -3964,12 +4771,26 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
                     }
                   }
                 }
-
+                else
+                  scb->flags &= ~SCB_MSGOUT_BITS;
+#endif /* AIC7XXX_FAKE_NEGOTIATION_CMDS */
                 scb->flags |= SCB_SENSE;
                 /*
                  * Ensure the target is busy since this will be an
                  * an untagged request.
                  */
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+                if (aic7xxx_verbose > 0xffff)
+                {
+                  if (scb->flags & SCB_MSGOUT_BITS)
+                    printk(INFO_LEAD "Requesting SENSE with %s\n", p->host_no,
+                           CTL_OF_SCB(scb), (scb->flags & SCB_MSGOUT_SDTR) ?
+                           "SDTR" : "WDTR");
+                  else
+                    printk(INFO_LEAD "Requesting SENSE, no MSG\n", p->host_no,
+                           CTL_OF_SCB(scb));
+                }
+#endif
                 aic7xxx_busy_target(p, scb);
                 aic_outb(p, SEND_SENSE, RETURN_1);
                 aic7xxx_error(cmd) = DID_OK;
@@ -3994,7 +4815,7 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
                */
               aic7xxx_search_qinfifo(p, target, channel, lun,
                 SCB_LIST_NULL, 0, TRUE,
-                &p->delayed_scbs[scratch_offset]);
+                &p->delayed_scbs[tindex]);
               next_scbp = p->waiting_scbs.head;
               while ( next_scbp != NULL )
               {
@@ -4004,7 +4825,7 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
                      SCB_LIST_NULL) )
                 {
                   scbq_remove(&p->waiting_scbs, prev_scbp);
-                  scbq_insert_tail(&p->delayed_scbs[scratch_offset],
+                  scbq_insert_tail(&p->delayed_scbs[tindex],
                     prev_scbp);
                 }
               }
@@ -4024,15 +4845,15 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
                   {
                     if (next_scbp->flags & SCB_WAITINGQ)
                     {
-                      p->dev_active_cmds[scratch_offset]++;
+                      p->dev_active_cmds[tindex]++;
                       p->activescbs--;
-                      scbq_remove(&p->delayed_scbs[scratch_offset], next_scbp);
+                      scbq_remove(&p->delayed_scbs[tindex], next_scbp);
                       scbq_remove(&p->waiting_scbs, next_scbp);
                     }
-                    scbq_insert_head(&p->delayed_scbs[scratch_offset],
+                    scbq_insert_head(&p->delayed_scbs[tindex],
                       next_scbp);
                     next_scbp->flags |= SCB_WAITINGQ;
-                    p->dev_active_cmds[scratch_offset]--;
+                    p->dev_active_cmds[tindex]--;
                     p->activescbs--;
                     next_hscb = aic_inb(p, SCB_NEXT);
                     aic_outb(p, 0, SCB_CONTROL);
@@ -4065,65 +4886,67 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
               aic_outb(p, active_hscb, SCBPTR);
               if (scb->flags & SCB_WAITINGQ)
               {
-                scbq_remove(&p->delayed_scbs[scratch_offset], scb);
+                scbq_remove(&p->delayed_scbs[tindex], scb);
                 scbq_remove(&p->waiting_scbs, scb);
-                p->dev_active_cmds[scratch_offset]++;
+                p->dev_active_cmds[tindex]++;
                 p->activescbs++;
               }
-              scbq_insert_head(&p->delayed_scbs[scratch_offset], scb);
-              p->dev_active_cmds[scratch_offset]--;
+              scbq_insert_head(&p->delayed_scbs[tindex], scb);
+              p->dev_active_cmds[tindex]--;
               p->activescbs--;
               scb->flags |= SCB_WAITINGQ | SCB_WAS_BUSY;
                   
-              if (p->dev_timer[scratch_offset].expires == 0) 
+              if (p->dev_timer[tindex].expires == 0) 
               {
-                if ( p->dev_active_cmds[scratch_offset] )
+                if ( p->dev_active_cmds[tindex] )
                 {
-                  p->dev_timer[scratch_offset].expires = jiffies + (HZ * 2);
-                  add_timer(&p->dev_timer[scratch_offset]);
+                  p->dev_timer[tindex].expires = jiffies + (HZ * 2);
+                  add_timer(&p->dev_timer[tindex]);
                 }
                 else
                 {
-                  p->dev_timer[scratch_offset].expires = jiffies + (HZ / 2);
-                  add_timer(&p->dev_timer[scratch_offset]);
+                  p->dev_timer[tindex].expires = jiffies + (HZ / 2);
+                  add_timer(&p->dev_timer[tindex]);
                 }
               }
-              if (aic7xxx_verbose & VERBOSE_QUEUE_FULL)
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+              if (aic7xxx_verbose & VERBOSE_MINOR_ERROR)
               {
                 if (queue_flag)
                   printk(INFO_LEAD "Queue full received; queue depth %d, "
                     "active %d\n", p->host_no, CTL_OF_SCB(scb),
-                    p->dev_max_queue_depth[scratch_offset],
-                    p->dev_active_cmds[scratch_offset]);
+                    p->dev_max_queue_depth[tindex],
+                    p->dev_active_cmds[tindex]);
                 else
                   printk(INFO_LEAD "Target busy\n", p->host_no, CTL_OF_SCB(scb));
 
               }
+#endif
               if (queue_flag)
               {
-                p->dev_temp_queue_depth[scratch_offset] = 
-                  p->dev_active_cmds[scratch_offset];
-                if ( p->dev_last_queue_full[scratch_offset] !=
-                     p->dev_active_cmds[scratch_offset] )
+                p->dev_temp_queue_depth[tindex] = 
+                  p->dev_active_cmds[tindex];
+                if ( p->dev_last_queue_full[tindex] !=
+                     p->dev_active_cmds[tindex] )
                 {
-                  p->dev_last_queue_full[scratch_offset] = 
-                      p->dev_active_cmds[scratch_offset];
-                  p->dev_last_queue_full_count[scratch_offset] = 0;
+                  p->dev_last_queue_full[tindex] = 
+                      p->dev_active_cmds[tindex];
+                  p->dev_last_queue_full_count[tindex] = 0;
                 }
                 else
                 {
-                  p->dev_last_queue_full_count[scratch_offset]++;
+                  p->dev_last_queue_full_count[tindex]++;
                 }
-                if ( (p->dev_last_queue_full_count[scratch_offset] > 14) &&
-                     (p->dev_active_cmds[scratch_offset] > 4) )
+                if ( (p->dev_last_queue_full_count[tindex] > 14) &&
+                     (p->dev_active_cmds[tindex] > 4) )
                 {
-                  if (aic7xxx_verbose & VERBOSE_NEGOTIATION)
+                  if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
                     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;
+                      CTL_OF_SCB(scb), p->dev_active_cmds[tindex]);
+                  p->dev_max_queue_depth[tindex] = 
+                      p->dev_active_cmds[tindex];
+                  p->dev_last_queue_full[tindex] = 0;
+                  p->dev_last_queue_full_count[tindex] = 0;
                 }
               }
               break;
@@ -4157,6 +4980,15 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
          * this target.
          */
 
+        if ( !(scb->flags & SCB_DEVICE_RESET) &&
+              (aic_inb(p, MSG_OUT) == MSG_IDENTIFYFLAG) &&
+              (scb->hscb->control & TAG_ENB) )
+        {
+          p->msg_buf[p->msg_index++] = scb->tag_action;
+          p->msg_buf[p->msg_index++] = scb->hscb->tag;
+          p->msg_len += 2;
+        }
+
         if (scb->flags & SCB_DEVICE_RESET)
         {
           p->msg_buf[p->msg_index++] = MSG_BUS_DEV_RESET;
@@ -4169,12 +5001,6 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
         {
           if (scb->tag_action)
           {
-            if (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
@@ -4188,23 +5014,67 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
         }
         else if (scb->flags & SCB_MSGOUT_WDTR)
         {
-          aic7xxx_construct_wdtr(p, (scb->flags & SCB_WDTR_16BIT));
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+          if (aic7xxx_verbose > 0xffff)
+            printk(INFO_LEAD "Sending WDTR message.\n", p->host_no,
+                   CTL_OF_SCB(scb));
+#endif
+          aic7xxx_construct_wdtr(p,
+            p->transinfo[TARGET_INDEX(scb->cmd)].goal_width);
         }
         else if (scb->flags & SCB_MSGOUT_SDTR)
         {
-          unsigned char period, offset;
-
+          unsigned int max_sync, period;
+          /*
+           * We need to set an accurate goal_offset instead of
+           * the ridiculously high one we default to.  We should
+           * now know if we are wide.  Plus, the WDTR code will 
+           * set our goal_offset for us as well.
+           */
+          if (p->transinfo[tindex].goal_offset)
+          {
+            if (p->features & AHC_ULTRA2)
+              p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
+            else if (p->transinfo[tindex].cur_width == MSG_EXT_WDTR_BUS_16_BIT)
+              p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT;
+            else
+              p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
+          }
           /*
-           * Pull the user defined setting from scratch RAM.
+           * Now that the device is selected, use the bits in SBLKCTL and
+           * SSTAT2 to determine the max sync rate for this device.
            */
-          period = p->syncinfo[scratch_offset].period;
-          offset = p->syncinfo[scratch_offset].offset;
-          if ( (p->needsdtr_copy & target_mask) == 0)
+          if (p->features & AHC_ULTRA2)
+          {
+            if ( (aic_inb(p, SBLKCTL) & ENAB40) &&
+                !(aic_inb(p, SSTAT2) & EXP_ACTIVE) )
+            {
+              max_sync = AHC_SYNCRATE_ULTRA2;
+            }
+            else
+            {
+              max_sync = AHC_SYNCRATE_ULTRA;
+            }
+          }
+          else if (p->features & AHC_ULTRA)
+          {
+            max_sync = AHC_SYNCRATE_ULTRA;
+          }
+          else
           {
-            period = 0;
-            offset = 0;
+            max_sync = AHC_SYNCRATE_FAST;
           }
-          aic7xxx_construct_sdtr(p, period, offset);
+          period = p->transinfo[tindex].goal_period;
+          aic7xxx_find_syncrate(p, &period, max_sync);
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+          if (aic7xxx_verbose > 0xffff)
+            printk(INFO_LEAD "Sending SDTR %d/%d message.\n", p->host_no,
+                   CTL_OF_SCB(scb),
+                   p->transinfo[tindex].goal_period,
+                   p->transinfo[tindex].goal_offset);
+#endif
+          aic7xxx_construct_sdtr(p, period,
+            p->transinfo[tindex].goal_offset);
         }
         else 
         {
@@ -4224,7 +5094,7 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
          * have this problem since they continually interrupt the kernel
          * until we take care of the situation.
          */
-        aic_outb(p, CLRSEQINT, CLRINT);
+        scb->flags |= SCB_MSGOUT_SENT;
         p->msg_index = 0;
         p->msg_type = MSG_TYPE_INITIATOR_MSGOUT;
         p->flags |= AHC_HANDLING_REQINITS;
@@ -4273,6 +5143,7 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
       }
       break;
 
+#if AIC7XXX_NOT_YET 
     case TRACEPOINT:
       {
         printk(INFO_LEAD "Tracepoint #1 reached.\n", p->host_no, channel,
@@ -4287,7 +5158,6 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
       }
       break;
 
-#if AIC7XXX_NOT_YET 
     /* XXX Fill these in later */
     case MSG_BUFFER_BUSY:
       printk("aic7xxx: Message buffer busy.\n");
@@ -4307,7 +5177,6 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
   /*
    * Clear the sequencer interrupt and unpause the sequencer.
    */
-  aic_outb(p, CLRSEQINT, CLRINT);
   unpause_sequencer(p, /* unpause always */ TRUE);
 }
 
@@ -4322,14 +5191,18 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
 static int
 aic7xxx_parse_msg(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
 {
-  int reject, done;
-  unsigned char target_scratch, scratch_offset;
+  int reject, reply, done;
+  unsigned char target_scsirate, tindex;
   unsigned short target_mask;
+  unsigned char target, channel, lun;
 
-  reject = done = FALSE;
-  scratch_offset = TARGET_INDEX(scb->cmd);
-  target_scratch = aic_inb(p, TARG_SCRATCH + scratch_offset);
-  target_mask = (0x01 << scratch_offset);
+  target = scb->cmd->target;
+  channel = scb->cmd->channel;
+  lun = scb->cmd->lun;
+  reply = reject = done = FALSE;
+  tindex = TARGET_INDEX(scb->cmd);
+  target_scsirate = aic_inb(p, TARG_SCSIRATE + tindex);
+  target_mask = (0x01 << tindex);
 
   /*
    * Parse as much of the message as is availible,
@@ -4355,9 +5228,10 @@ aic7xxx_parse_msg(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
     {
       case MSG_EXT_SDTR:
       {
-        unsigned char period, response_period, offset;
-        unsigned char max_offset, saved_offset, rate;
-
+        unsigned int period, offset;
+        unsigned char maxsync, saved_offset;
+        struct aic7xxx_syncrate *syncrate;
+        
         if (p->msg_buf[1] != MSG_EXT_SDTR_LEN)
         {
           reject = TRUE;
@@ -4370,51 +5244,114 @@ aic7xxx_parse_msg(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
         }
 
         period = p->msg_buf[3];
-        saved_offset = p->msg_buf[4];
+        saved_offset = offset = p->msg_buf[4];
 
-        if (target_scratch & WIDEXFER)
+        if (p->features & AHC_ULTRA2)
+        {
+          if ( (aic_inb(p, SBLKCTL) & ENAB40) &&
+               !(aic_inb(p, SSTAT2) & EXP_ACTIVE) )
+          {
+            maxsync = AHC_SYNCRATE_ULTRA2;
+          }
+          else
+          {
+            maxsync = AHC_SYNCRATE_ULTRA;
+          }
+        }
+        else if (p->features & AHC_ULTRA)
         {
-          max_offset = MAX_OFFSET_16BIT;
+          maxsync = AHC_SYNCRATE_ULTRA;
         }
         else
         {
-          max_offset = MAX_OFFSET_8BIT;
+          maxsync = AHC_SYNCRATE_FAST;
         }
-        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;
+  
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+        if (aic7xxx_verbose > 0xffff)
+        {
+          printk(INFO_LEAD "Finished receipt of SDTR, parsing %d/%d\n",
+                 p->host_no, CTL_OF_SCB(scb), period, offset);
+          syncrate = aic7xxx_find_syncrate(p, &period, maxsync);
+          printk(INFO_LEAD "After find_syncrate() %d/%d\n",
+                 p->host_no, CTL_OF_SCB(scb), period, offset);
+          aic7xxx_validate_offset(p, syncrate, &offset,
+                                  target_scsirate & WIDEXFER);
+          printk(INFO_LEAD "After validate_offset() %d/%d\n",
+                 p->host_no, CTL_OF_SCB(scb), period, offset);
+          aic7xxx_set_syncrate(p, syncrate, target, channel, period,
+                               offset, AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+          printk(INFO_LEAD "Final values of Period/Offset as set: %d/%d\n",
+                 p->host_no, CTL_OF_SCB(scb), period, offset);
+        }
+        else
+        {
+          syncrate = aic7xxx_find_syncrate(p, &period, maxsync);
+          aic7xxx_validate_offset(p, syncrate, &offset,
+                                  target_scsirate & WIDEXFER);
+          aic7xxx_set_syncrate(p, syncrate, target, channel, period,
+                               offset, AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+        }
+#else
+        syncrate = aic7xxx_find_syncrate(p, &period, maxsync);
+        aic7xxx_validate_offset(p, syncrate, &offset,
+                                target_scsirate & WIDEXFER);
+        aic7xxx_set_syncrate(p, syncrate, target, channel, period,
+                             offset, AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+#endif
 
+        if (offset == 0)
+        {
+          /*
+           * Uhh ohh, things fell through to async....update the goal
+           * items and the needsdtr_copy to reflect this...
+           */
+          aic7xxx_set_syncrate(p, syncrate, target, channel, period,
+                 offset, AHC_TRANS_GOAL|AHC_TRANS_QUITE);
+          p->needsdtr_copy &= ~target_mask;
+        }
         /*
          * 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)
+        p->sdtr_pending &= ~target_mask;
+        if ( ((scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) ==
+              (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) &&
+             (offset == saved_offset) )
         {
-          if (saved_offset != offset)
-          {
-            p->needsdtr_copy &= ~target_mask;
-            reject = TRUE; 
-          }
-          scb->flags &= ~SCB_MSGOUT_SDTR;
-          p->sdtr_pending &= ~target_mask;
+          scb->flags &= ~SCB_MSGOUT_BITS;
         }
         else
         {
+          /*
+           * Send a reply SDTR back.  Even if we sent the first one, it
+           * is valid to send another one out immediately to re-negotiate
+           * things, and a few devices don't like getting rejects after
+           * we already sent them one SDTR.  Just send an SDTR for async
+           * this time if need be (or for the correct params if we didn't
+           * start all of this).  If this is a Reject Reply type message,
+           * then we've put the async settings into the goal area for
+           * future reference (when we get the AWAITING_MSG interrupt).
+           * If this is a case where we are responding to the target's
+           * initiated SDTR, then leave our own goal and user values in
+           * place (unless the device hasn't been scanned yet, in which
+           * case, put the user values into the goal values so we don't
+           * send out an Async message).
+           */
+          if ( !(p->dev_flags[tindex] & DEVICE_SCANNED) )
+          {
+            p->transinfo[tindex].goal_width =
+              p->transinfo[tindex].user_width;
+            p->transinfo[tindex].goal_period =
+              p->transinfo[tindex].user_period;
+            p->transinfo[tindex].goal_offset =
+              p->transinfo[tindex].user_offset;
+            p->needwdtr_copy |= target_mask;
+            p->needsdtr_copy |= target_mask;
+          }
           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);
         }
@@ -4437,112 +5374,111 @@ aic7xxx_parse_msg(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
         }
 
         bus_width = p->msg_buf[3];
-        p->needwdtr &= ~target_mask;
-        if (scb->flags & SCB_MSGOUT_WDTR)
+        if ( (scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_WDTR)) ==
+             (SCB_MSGOUT_SENT|SCB_MSGOUT_WDTR) )
         {
           switch(bus_width)
           {
             default:
             {
               reject = TRUE;
-              if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
-                   (p->dev_flags[scratch_offset] & DEVICE_PRINT_WDTR) )
+              if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
+                   ((p->dev_flags[tindex] & DEVICE_PRINT_WDTR) ||
+                    (aic7xxx_verbose > 0xffff)) )
               {
                 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;
+                p->dev_flags[tindex] &= ~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;
+          scb->flags &= ~SCB_MSGOUT_BITS;
           p->wdtr_pending &= ~target_mask;
-          /*
-           * By virtue of the SCSI spec, a WDTR message negates any existing
-           * SDTR negotiations.  So, even if needsdtr isn't marked for this
-           * device, we still have to do a new SDTR message if the device
-           * supports SDTR at all.  Therefore, we check needsdtr_copy instead
-           * of needstr.
-           */
-          if ( (p->needsdtr_copy & target_mask) &&
-              !(p->sdtr_pending & target_mask))
-          {
-            p->needsdtr |= target_mask;
-          }
+          p->needwdtr &= ~target_mask;
         }
         else
         {
           scb->flags &= ~SCB_MSGOUT_BITS;
+          scb->flags |= SCB_MSGOUT_WDTR;
+          reply = TRUE;
+          if ( !(p->dev_flags[tindex] & DEVICE_SCANNED) )
+          {
+            /* 
+             * Well, we now know the WDTR and SYNC caps of this device since
+             * it contacted us first, mark it as such and copy the user stuff
+             * over to the goal stuff.
+             */
+            p->transinfo[tindex].goal_width =
+              p->transinfo[tindex].user_width;
+            p->transinfo[tindex].goal_period =
+              p->transinfo[tindex].user_period;
+            p->transinfo[tindex].goal_offset =
+              p->transinfo[tindex].user_offset;
+            p->needwdtr_copy |= target_mask;
+            p->needsdtr_copy |= target_mask;
+          }
           switch(bus_width)
           {
             default:
             {
-              if (p->type & AHC_WIDE)
+              if ( (p->features & AHC_WIDE) &&
+                   (p->transinfo[tindex].goal_width ==
+                    MSG_EXT_WDTR_BUS_16_BIT) )
               {
                 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;
-              }
+              bus_width = MSG_EXT_WDTR_BUS_8_BIT;
               break;
             }
           }
+          p->needwdtr &= ~target_mask;
+          p->wdtr_pending &= ~target_mask;
           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;
+        aic7xxx_set_width(p, target, channel, lun, bus_width,
+                          AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+        
+        /*
+         * By virtue of the SCSI spec, a WDTR message negates any existing
+         * SDTR negotiations.  So, even if needsdtr isn't marked for this
+         * device, we still have to do a new SDTR message if the device
+         * supports SDTR at all.  Therefore, we check needsdtr_copy instead
+         * of needstr.
+         */
+        aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0,
+                             AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE);
+        if ( (p->needsdtr_copy & target_mask) &&
+            !(p->sdtr_pending & target_mask))
+        {
+          p->needsdtr |= target_mask;
+          if ( !reject && !reply )
+          {
+            scb->flags &= ~SCB_MSGOUT_WDTR;
+            if (p->transinfo[tindex].goal_period)
+            {
+              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;
       }
@@ -4558,10 +5494,12 @@ aic7xxx_parse_msg(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
   {
     aic_outb(p, MSG_MESSAGE_REJECT, MSG_OUT);
     aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
+    done = TRUE;
   }
   return(done);
 }
 
+
 /*+F*************************************************************************
  * Function:
  *   aic7xxx_handle_reqinit
@@ -4605,10 +5543,20 @@ aic7xxx_handle_reqinit(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
           {
             aic_outb(p, p->msg_buf[p->msg_index], SINDEX);
             aic_outb(p, 0, RETURN_1);
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+            if (aic7xxx_verbose > 0xffff)
+              printk(INFO_LEAD "Completed sending of REQINIT message.\n",
+                     p->host_no, CTL_OF_SCB(scb));
+#endif
           }
           else
           {
             aic_outb(p, MSGOUT_PHASEMIS, RETURN_1);
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+            if (aic7xxx_verbose > 0xffff)
+              printk(INFO_LEAD "PHASEMIS while sending REQINIT message.\n",
+                     p->host_no, CTL_OF_SCB(scb));
+#endif
           }
           unpause_sequencer(p, TRUE);
         }
@@ -4642,12 +5590,23 @@ aic7xxx_handle_reqinit(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
         }
         if (phasemis || done)
         {
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+          if (aic7xxx_verbose > 0xffff)
+          {
+            if (phasemis)
+              printk(INFO_LEAD "PHASEMIS while receiving REQINIT message.\n",
+                     p->host_no, CTL_OF_SCB(scb));
+            else
+              printk(INFO_LEAD "Completed receipt of REQINIT message.\n",
+                     p->host_no, CTL_OF_SCB(scb));
+          }
+#endif
           /* 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);
+          p->flags &= ~AHC_HANDLING_REQINITS;
           unpause_sequencer(p, TRUE);
         }
         break;
@@ -4691,30 +5650,14 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
   }
 
 
-  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 ( (p->chip & AHC_CHIPID_MASK) == AHC_AIC7770 )
+      channel = (aic_inb(p, SBLKCTL) & SELBUSB) >> 3;
+    else
+      channel = 0;
 
     if (aic7xxx_verbose & VERBOSE_RESET)
       printk(WARN_LEAD "Someone else reset the channel!!\n",
@@ -4737,10 +5680,16 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
     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 channel;
     int printerror = TRUE;
 
-    aic_outb(p, 0, SCSISEQ);
+    if ( (p->chip & AHC_CHIPID_MASK) == AHC_AIC7770 )
+      channel = (aic_inb(p, SBLKCTL) & SELBUSB) >> 3;
+    else
+      channel = 0;
+
+    aic_outb(p, aic_inb(p, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP),
+             SCSISEQ);
     if (lastphase == P_MESGOUT)
     {
       unsigned char message;
@@ -4782,20 +5731,16 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
         aic7xxx_reset_device(p, target, channel, ALL_LUNS, tag);
         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    */
-        aic7xxx_add_curscb_to_free_list(p);
-      }
       printk(INFO_LEAD "Unexpected busfree, LASTPHASE = 0x%x, "
              "SEQADDR = 0x%x\n", p->host_no, channel, target, -1, lastphase,
              (aic_inb(p, SEQADDR1) << 8) | aic_inb(p, SEQADDR0));
       scb = NULL;
     }
+    aic_outb(p, MSG_NOOP, MSG_OUT);
     aic_outb(p, aic_inb(p, SIMODE1) & ~(ENBUSFREE|ENREQINIT),
       SIMODE1);
     p->flags &= ~AHC_HANDLING_REQINITS;
-    aic_outb(p, CLRBUSFREE | CLRREQINIT, CLRSINT1);
+    aic_outb(p, CLRBUSFREE, CLRSINT1);
     aic_outb(p, CLRSCSIINT, CLRINT);
     restart_sequencer(p);
     unpause_sequencer(p, TRUE);
@@ -4807,6 +5752,24 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
     Scsi_Cmnd *cmd;
 
     scbptr = aic_inb(p, WAITING_SCBH);
+    if (scbptr > p->scb_data->maxhscbs)
+    {
+      /*
+       * I'm still trying to track down exactly how this happens, but until
+       * I find it, this code will make sure we aren't passing bogus values
+       * into the SCBPTR register, even if that register will just wrap
+       * things around, we still don't like having out of range variables.
+       *
+       * NOTE: Don't check the aic7xxx_verbose variable, I want this message
+       * to always be displayed.
+       */
+      printk(INFO_LEAD "Invalid WAITING_SCBH value %d, improvising.\n",
+             p->host_no, -1, -1, -1, scbptr);
+      if (p->scb_data->maxhscbs > 4)
+        scbptr &= (p->scb_data->maxhscbs - 1);
+      else
+        scbptr &= 0x03;
+    }
     aic_outb(p, scbptr, SCBPTR);
     scb_index = aic_inb(p, SCB_TAG);
 
@@ -4827,6 +5790,8 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
              "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));
+      if (aic7xxx_panic_on_abort)
+        aic7xxx_panic_abort(p, NULL);
     }
     else
     {
@@ -4863,6 +5828,10 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
        * What we need to do then is to let the command timeout again so
        * we get a reset since this abort just failed.
        */
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+      if (aic7xxx_verbose > 0xffff)
+        printk(INFO_LEAD "Selection Timeout.\n", p->host_no, CTL_OF_SCB(scb));
+#endif
       if (p->flags & SCB_QUEUED_ABORT)
       {
         cmd->result = 0;
@@ -4875,9 +5844,9 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
      * are allowed to reselect in.
      */
     aic_outb(p, 0, SCSISEQ);
-    aic_outb(p, aic_inb(p, SIMODE1) & ~ENREQINIT, SIMODE1);
+    aic_outb(p, aic_inb(p, SIMODE1) & ~(ENREQINIT|ENBUSFREE), SIMODE1);
     p->flags &= ~AHC_HANDLING_REQINITS;
-    aic_outb(p, CLRSELTIMEO | CLRBUSFREE | CLRREQINIT, CLRSINT1);
+    aic_outb(p, CLRSELTIMEO | CLRBUSFREE, CLRSINT1);
     aic_outb(p, CLRSCSIINT, CLRINT);
     restart_sequencer(p);
     unpause_sequencer(p, TRUE);
@@ -4942,7 +5911,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(WARN_LEAD "Parity error during phase %s.\n",
+    printk(WARN_LEAD "Parity error during %s phase.\n",
            p->host_no, CTL_OF_SCB(scb), phase);
 
     /*
@@ -4960,6 +5929,17 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
     aic_outb(p, CLRSCSIINT, CLRINT);
     unpause_sequencer(p, /* unpause_always */ TRUE);
   }
+  else if ( (status & REQINIT) &&
+            (p->flags & AHC_HANDLING_REQINITS) )
+  {
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+    if (aic7xxx_verbose > 0xffff)
+      printk(INFO_LEAD "Handling REQINIT, SSTAT1=0x%x.\n", p->host_no,
+             CTL_OF_SCB(scb), aic_inb(p, SSTAT1));
+#endif
+    aic7xxx_handle_reqinit(p, scb);
+    return;
+  }
   else
   {
     /*
@@ -4980,66 +5960,151 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
   }
 }
 
-#ifdef CONFIG_PCI
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+static void
+aic7xxx_check_scbs(struct aic7xxx_host *p, char *buffer)
+{
+  unsigned char saved_scbptr, free_scbh, dis_scbh, wait_scbh, temp;
+  int i, bogus, lost;
+  static unsigned char scb_status[AIC7XXX_MAXSCB];
 
-#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;
+#define SCB_NO_LIST 0
+#define SCB_FREE_LIST 1
+#define SCB_WAITING_LIST 2
+#define SCB_DISCONNECTED_LIST 4
+#define SCB_CURRENTLY_ACTIVE 8
 
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
-  pci_read_config_byte(p->pdev, PCI_STATUS, &status1);
-#else
-  pcibios_read_config_byte(p->pci_bus, p->pci_device_fn,
-                                            PCI_STATUS, &status1);
-#endif
+  /*
+   * Note, these checks will fail on a regular basis once the machine moves
+   * beyond the bus scan phase.  The problem is race conditions concerning
+   * the scbs and where they are linked in.  When you have 30 or so commands
+   * outstanding on the bus, and run this twice with every interrupt, the
+   * chances get pretty good that you'll catch the sequencer with an SCB
+   * only partially linked in.  Therefore, once we pass the scan phase
+   * of the bus, we really should disable this function.
+   */
+  bogus = FALSE;
+  memset(&scb_status[0], 0, sizeof(scb_status));
+  pause_sequencer(p);
+  saved_scbptr = aic_inb(p, SCBPTR);
+  if (saved_scbptr >= p->scb_data->maxhscbs)
+  {
+    printk("Bogus SCBPTR %d\n", saved_scbptr);
+    bogus = TRUE;
+  }
+  scb_status[saved_scbptr] = SCB_CURRENTLY_ACTIVE;
+  free_scbh = aic_inb(p, FREE_SCBH);
+  if ( (free_scbh != SCB_LIST_NULL) &&
+       (free_scbh >= p->scb_data->maxhscbs) )
+  {
+    printk("Bogus FREE_SCBH %d\n", free_scbh);
+    bogus = TRUE;
+  }
+  else
+  {
+    temp = free_scbh;
+    while( (temp != SCB_LIST_NULL) && (temp < p->scb_data->maxhscbs) )
+    {
+      if(scb_status[temp] & 0x07)
+      {
+        printk("HSCB %d on multiple lists, status 0x%02x", temp,
+               scb_status[temp] | SCB_FREE_LIST);
+        bogus = TRUE;
+      }
+      scb_status[temp] |= SCB_FREE_LIST;
+      aic_outb(p, temp, SCBPTR);
+      temp = aic_inb(p, SCB_NEXT);
+    }
+  }
 
-  if ( (status1 & DPE) && (aic7xxx_verbose & VERBOSE_MINOR_ERROR) )
-    printk(WARN_LEAD "Data Parity Error during PCI address or PCI write"
-      "phase.\n", p->host_no, -1, -1, -1);
-  if ( (status1 & SSE) && (aic7xxx_verbose & VERBOSE_MINOR_ERROR) )
-    printk(WARN_LEAD "Signal System Error Detected\n", p->host_no,
-      -1, -1, -1);
-  if ( (status1 & RMA) && (aic7xxx_verbose & VERBOSE_MINOR_ERROR) )
-    printk(WARN_LEAD "Received a PCI Master Abort\n", p->host_no,
-      -1, -1, -1);
-  if ( (status1 & RTA) && (aic7xxx_verbose & VERBOSE_MINOR_ERROR) )
-    printk(WARN_LEAD "Received a PCI Target Abort\n", p->host_no,
-      -1, -1, -1);
-  if ( (status1 & STA) && (aic7xxx_verbose & VERBOSE_MINOR_ERROR) )
-    printk(WARN_LEAD "Signaled a PCI Target Abort\n", p->host_no,
-      -1, -1, -1);
-  if ( (status1 & DPR) && (aic7xxx_verbose & VERBOSE_MINOR_ERROR) )
-    printk(WARN_LEAD "Data Parity Error has been reported via PCI pin "
-      "PERR#\n", p->host_no, -1, -1, -1);
+  dis_scbh = aic_inb(p, DISCONNECTED_SCBH);
+  if ( (dis_scbh != SCB_LIST_NULL) &&
+       (dis_scbh >= p->scb_data->maxhscbs) )
+  {
+    printk("Bogus DISCONNECTED_SCBH %d\n", dis_scbh);
+    bogus = TRUE;
+  }
+  else
+  {
+    temp = dis_scbh;
+    while( (temp != SCB_LIST_NULL) && (temp < p->scb_data->maxhscbs) )
+    {
+      if(scb_status[temp] & 0x07)
+      {
+        printk("HSCB %d on multiple lists, status 0x%02x", temp,
+               scb_status[temp] | SCB_DISCONNECTED_LIST);
+        bogus = TRUE;
+      }
+      scb_status[temp] |= SCB_DISCONNECTED_LIST;
+      aic_outb(p, temp, SCBPTR);
+      temp = aic_inb(p, SCB_NEXT);
+    }
+  }
   
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
-  pci_write_config_byte(p->pdev, PCI_STATUS, status1);
-#else
-  pcibios_write_config_byte(p->pci_bus, p->pci_device_fn,
-                                            PCI_STATUS, status1);
-#endif
-  if (status1 & (DPR|RMA|RTA))
-    aic_outb(p,  CLRPARERR, CLRINT);
+  wait_scbh = aic_inb(p, WAITING_SCBH);
+  if ( (wait_scbh != SCB_LIST_NULL) &&
+       (wait_scbh >= p->scb_data->maxhscbs) )
+  {
+    printk("Bogus WAITING_SCBH %d\n", wait_scbh);
+    bogus = TRUE;
+  }
+  else
+  {
+    temp = wait_scbh;
+    while( (temp != SCB_LIST_NULL) && (temp < p->scb_data->maxhscbs) )
+    {
+      if(scb_status[temp] & 0x07)
+      {
+        printk("HSCB %d on multiple lists, status 0x%02x", temp,
+               scb_status[temp] | SCB_WAITING_LIST);
+        bogus = TRUE;
+      }
+      scb_status[temp] |= SCB_WAITING_LIST;
+      aic_outb(p, temp, SCBPTR);
+      temp = aic_inb(p, SCB_NEXT);
+    }
+  }
 
+  lost=0;
+  for(i=0; i < p->scb_data->maxhscbs; i++)
+  {
+    aic_outb(p, i, SCBPTR);
+    temp = aic_inb(p, SCB_NEXT);
+    if ( ((temp != SCB_LIST_NULL) &&
+          (temp >= p->scb_data->maxhscbs)) )
+    {
+      printk("HSCB %d bad, SCB_NEXT invalid(%d).\n", i, temp);
+      bogus = TRUE;
+    }
+    if ( temp == i )
+    {
+      printk("HSCB %d bad, SCB_NEXT points to self.\n", i);
+      bogus = TRUE;
+    }
+    temp = aic_inb(p, SCB_PREV);
+    if ((temp != SCB_LIST_NULL) &&
+        (temp >= p->scb_data->maxhscbs))
+    {
+      printk("HSCB %d bad, SCB_PREV invalid(%d).\n", i, temp);
+      bogus = TRUE;
+    }
+    if (scb_status[i] == 0)
+      lost++;
+    if (lost > 1)
+    {
+      printk("Too many lost scbs.\n");
+      bogus=TRUE;
+    }
+  }
+  aic_outb(p, saved_scbptr, SCBPTR);
+  unpause_sequencer(p, FALSE);
+  if (bogus)
+  {
+    printk("Bogus parameters found in card SCB array structures.\n");
+    printk("%s\n", buffer);
+    aic7xxx_panic_abort(p, NULL);
+  }
+  return;
 }
 #endif
 
@@ -5066,7 +6131,8 @@ aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
   if (!((intstat = aic_inb(p, INTSTAT)) & INT_PEND))
   {
 #ifdef CONFIG_PCI
-    if ((p->type & AHC_AIC78x0) && (p->spurious_int > 500))
+    if ( (p->chip & AHC_PCI) && (p->spurious_int > 500) &&
+        !(p->flags & AHC_HANDLING_REQINITS) )
     {
       if ( aic_inb(p, ERROR) & PCIERRSTAT )
       {
@@ -5074,7 +6140,7 @@ aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
       }
       p->spurious_int = 0;
     }
-    else
+    else if ( !(p->flags & AHC_HANDLING_REQINITS) )
     {
       p->spurious_int++;
     }
@@ -5089,6 +6155,12 @@ aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
    */
   p->isr_count++;
 
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+  if ( (p->isr_count < 16) && (aic7xxx_verbose > 0xffff) &&
+       (aic7xxx_panic_on_abort) && (p->flags & AHC_PAGESCBS) )
+    aic7xxx_check_scbs(p, "Bogus settings at start of interrupt.");
+#endif
+
   /*
    * Handle all the interrupt sources - especially for SCSI
    * interrupts, we won't get a second chance at them.
@@ -5099,6 +6171,11 @@ aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
     Scsi_Cmnd *cmd;
     unsigned char scb_index;
 
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+    if(aic7xxx_verbose > 0xffff)
+      printk(INFO_LEAD "Command Complete Int.\n", p->host_no, -1, -1, -1);
+#endif
+    
     /*
      * Clear interrupt status before running the completion loop.
      * This eliminates a race condition whereby a command could
@@ -5152,6 +6229,14 @@ aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
           SCB_QUEUED_ABORT);
         unpause_sequencer(p, FALSE);
       }
+      else if (scb->flags & SCB_ABORT)
+      {
+        /*
+         * We started to abort this, but it completed on us, let it
+         * through as successful
+         */
+        scb->flags &= ~(SCB_ABORT|SCB_RESET);
+      }
       switch (status_byte(scb->hscb->target_status))
       {
         case QUEUE_FULL:
@@ -5192,16 +6277,33 @@ aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
         printk(KERN_ERR "  %s\n", hard_error[i].errmesg);
       }
     }
-    printk(KERN_ERR "(scsi%d)   LINE=%d\n", p->host_no,
+    printk(KERN_ERR "(scsi%d)   SEQADDR=0x%x\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 )
+    if (aic7xxx_panic_on_abort)
+      aic7xxx_panic_abort(p, NULL);
+    if (errno & PCIERRSTAT)
+      aic7xxx_pci_intr(p);
+    if (errno & (SQPARERR | ILLOPCODE | ILLSADDR))
     {
-      aic7xxx_reset_channel(p, 1, TRUE);
-      restart_sequencer(p);
+      sti();
+      panic("aic7xxx: unrecoverable BRKADRINT.\n");
     }
-    aic7xxx_run_done_queue(p, FALSE);
-    aic_outb(p, CLRBRKADRINT, CLRINT);
+    if (errno & ILLHADDR)
+    {
+      printk(KERN_ERR "(scsi%d) BUG! Driver accessed chip without first "
+             "pausing controller!\n", p->host_no);
+    }
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+    if (errno & DPARERR)
+    {
+      if (aic_inb(p, DMAPARAMS) & DIRECTION)
+        printk("(scsi%d) while DMAing SCB from host to card.\n", p->host_no);
+      else
+        printk("(scsi%d) while DMAing SCB from card to host.\n", p->host_no);
+    }
+#endif
+    aic_outb(p, CLRPARERR | CLRBRKADRINT, CLRINT);
+    unpause_sequencer(p, FALSE);
   }
 
   if (intstat & SEQINT)
@@ -5213,6 +6315,13 @@ aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
   {
     aic7xxx_handle_scsiint(p, intstat);
   }
+
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+  if ( (p->isr_count < 16) && (aic7xxx_verbose > 0xffff) &&
+       (aic7xxx_panic_on_abort) && (p->flags & AHC_PAGESCBS) )
+    aic7xxx_check_scbs(p, "Bogus settings at end of interrupt.");
+#endif
+
 }
 
 /*+F*************************************************************************
@@ -5229,49 +6338,34 @@ do_aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
 {
   unsigned long cpu_flags;
   struct aic7xxx_host *p;
-  static unsigned int re_entry_counter = 0;
   
   p = (struct aic7xxx_host *)dev_id;
   if(!p)
     return;
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,95)
+  spin_lock_irqsave(&io_request_lock, cpu_flags);
   if(test_and_set_bit(AHC_IN_ISR_BIT, &p->flags))
   {
-    if(re_entry_counter++ > 100000UL)
-    {
-      /*
-       * Hmmm...we seem to be looping here.  This usually means that our
-       * interrupt routine got killed by a NULL pointer deref.  Panic.
-       */
-      sti();
-      panic("aic7xxx: The interrupt routine appears to have seg faulted.\n");
-    }
     return;
   }
-  re_entry_counter = 0;
-  spin_lock_irqsave(&io_request_lock, cpu_flags);
-  aic7xxx_isr(irq, dev_id, regs);
+  do
+  {
+    aic7xxx_isr(irq, dev_id, regs);
+  } while ( (aic_inb(p, INTSTAT) & INT_PEND) );
   aic7xxx_done_cmds_complete(p);
   aic7xxx_run_waiting_queues(p);
-  spin_unlock_irqrestore(&io_request_lock, cpu_flags);
   clear_bit(AHC_IN_ISR_BIT, &p->flags);
+  spin_unlock_irqrestore(&io_request_lock, cpu_flags);
 #else
   if(set_bit(AHC_IN_ISR_BIT, (int *)&p->flags))
   {
-    if(re_entry_counter++ > 100000UL)
-    {
-      /*
-       * Hmmm...we seem to be looping here.  This usually means that our
-       * interrupt routine got killed by a NULL pointer deref.  Panic.
-       */
-      sti();
-      panic("aic7xxx: The interrupt routine appears to have seg faulted.\n");
-    }
     return;
   }
-  re_entry_counter = 0;
   DRIVER_LOCK
-  aic7xxx_isr(irq, dev_id, regs);
+  do
+  {
+    aic7xxx_isr(irq, dev_id, regs);
+  } while ( (aic_inb(p, INTSTAT) & INT_PEND) );
   DRIVER_UNLOCK
   aic7xxx_done_cmds_complete(p);
   aic7xxx_run_waiting_queues(p);
@@ -5324,7 +6418,7 @@ aic7xxx_device_queue_depth(struct aic7xxx_host *p, Scsi_Device *device)
  
     if (!(p->discenable & target_mask))
     {
-      if (aic7xxx_verbose & VERBOSE_QUEUE)
+      if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
         printk(INFO_LEAD "Disconnection disabled, unable to "
              "enable tagged queueing.\n",
              p->host_no, device->channel, device->id, device->lun);
@@ -5364,7 +6458,7 @@ aic7xxx_device_queue_depth(struct aic7xxx_host *p, Scsi_Device *device)
       }
       if ((device->tagged_queue == 0) && tag_enabled)
       {
-        if (aic7xxx_verbose & VERBOSE_QUEUE)
+        if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
         {
               printk(INFO_LEAD "Enabled tagged queuing, queue depth %d.\n",
                 p->host_no, device->channel, device->id,
@@ -5418,7 +6512,7 @@ aic7xxx_select_queue_depth(struct Scsi_Host *host,
      * 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 )
+    if ( aic7xxx_allocate_scb(p) == 0 )
       return;
   }
 }
@@ -5451,7 +6545,7 @@ aic7xxx_select_queue_depth(struct Scsi_Host *host,
  *   an unused function.
  *-F*************************************************************************/
 #if defined(__i386__) || defined(__alpha__)
-static ahc_type
+static int
 aic7xxx_probe(int slot, int base, ahc_flag_type *flags)
 {
   int i;
@@ -5460,13 +6554,17 @@ aic7xxx_probe(int slot, int base, ahc_flag_type *flags)
   static struct {
     int n;
     unsigned char signature[sizeof(buf)];
-    ahc_type type;
+    ahc_chip type;
     int bios_disabled;
   } AIC7xxx[] = {
-    { 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 */
+    { 4, { 0x04, 0x90, 0x77, 0x70 },
+      AHC_AIC7770|AHC_EISA, FALSE },  /* mb 7770  */
+    { 4, { 0x04, 0x90, 0x77, 0x71 },
+      AHC_AIC7770|AHC_EISA, FALSE }, /* host adapter 274x */
+    { 4, { 0x04, 0x90, 0x77, 0x56 },
+      AHC_AIC7770|AHC_VL, FALSE }, /* 284x BIOS enabled */
+    { 4, { 0x04, 0x90, 0x77, 0x57 },
+      AHC_AIC7770|AHC_VL, TRUE }   /* 284x BIOS disabled */
   };
 
   /*
@@ -5496,7 +6594,7 @@ aic7xxx_probe(int slot, int base, ahc_flag_type *flags)
         {
           *flags |= AHC_BIOS_ENABLED;
         }
-        return (AIC7xxx[i].type);
+        return (i);
       }
 
       printk("aic7xxx: <Adaptec 7770 SCSI Host Adapter> "
@@ -5504,7 +6602,7 @@ aic7xxx_probe(int slot, int base, ahc_flag_type *flags)
     }
   }
 
-  return (AHC_NONE);
+  return (-1);
 }
 #endif /* (__i386__) || (__alpha__) */
 
@@ -5661,7 +6759,7 @@ read_284x_seeprom(struct aic7xxx_host *p, struct seeprom_config *sc)
  * Description:
  *   Acquires access to the memory port on PCI controllers.
  *-F*************************************************************************/
-static inline int
+static int
 acquire_seeprom(struct aic7xxx_host *p)
 {
   int wait;
@@ -5678,7 +6776,7 @@ acquire_seeprom(struct aic7xxx_host *p)
   while ((wait > 0) && ((aic_inb(p, SEECTL) & SEERDY) == 0))
   {
     wait--;
-    udelay(1000);  /* 1 msec */
+    mdelay(1);  /* 1 msec */
   }
   if ((aic_inb(p, SEECTL) & SEERDY) == 0)
   {
@@ -5695,7 +6793,7 @@ acquire_seeprom(struct aic7xxx_host *p)
  * Description:
  *   Releases access to the memory port on PCI controllers.
  *-F*************************************************************************/
-static inline void
+static void
 release_seeprom(struct aic7xxx_host *p)
 {
   aic_outb(p, 0, SEECTL);
@@ -5895,19 +6993,38 @@ read_seeprom(struct aic7xxx_host *p, int offset,
  * Description:
  *   Writes a value to the BRDCTL register.
  *-F*************************************************************************/
-static inline void
+static void
 write_brdctl(struct aic7xxx_host *p, unsigned char value)
 {
   unsigned char brdctl;
 
-  brdctl = BRDCS | BRDSTB;
+  if ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895)
+  {
+    brdctl = BRDSTB;
+    if (p->flags & AHC_CHNLB)
+      brdctl |= BRDCS;
+  }
+  else if (p->features & AHC_ULTRA2)
+    brdctl = 0;
+  else
+    brdctl = BRDSTB | BRDCS;
   aic_outb(p, brdctl, BRDCTL);
+  udelay(1);
   brdctl |= value;
   aic_outb(p, brdctl, BRDCTL);
-  brdctl &= ~BRDSTB;
+  udelay(1);
+  if (p->features & AHC_ULTRA2)
+    brdctl |= BRDSTB_ULTRA2;
+  else
+    brdctl &= ~BRDSTB;
   aic_outb(p, brdctl, BRDCTL);
-  brdctl &= ~BRDCS;
+  udelay(1);
+  if (p->features & AHC_ULTRA2)
+    brdctl = 0;
+  else
+    brdctl &= ~BRDCS;
   aic_outb(p, brdctl, BRDCTL);
+  udelay(1);
 }
 
 /*+F*************************************************************************
@@ -5917,11 +7034,27 @@ write_brdctl(struct aic7xxx_host *p, unsigned char value)
  * Description:
  *   Reads the BRDCTL register.
  *-F*************************************************************************/
-static inline unsigned char
+static unsigned char
 read_brdctl(struct aic7xxx_host *p)
 {
-  aic_outb(p, BRDRW | BRDCS, BRDCTL);
-  return (aic_inb(p, BRDCTL));
+  unsigned char brdctl, value;
+
+  if ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895)
+  {
+    brdctl = BRDRW;
+    if (p->flags & AHC_CHNLB)
+      brdctl |= BRDCS;
+  }
+  else if (p->features & AHC_ULTRA2)
+    brdctl = BRDRW_ULTRA2;
+  else
+    brdctl = BRDRW | BRDCS;
+  aic_outb(p, brdctl, BRDCTL);
+  udelay(1);
+  value = aic_inb(p, BRDCTL);
+  aic_outb(p, 0, BRDCTL);
+  udelay(1);
+  return (value);
 }
 
 /*+F*************************************************************************
@@ -5938,11 +7071,14 @@ aic785x_cable_detect(struct aic7xxx_host *p, int *int_50,
   unsigned char brdctl;
 
   aic_outb(p, BRDRW | BRDCS, BRDCTL);
+  udelay(1);
   aic_outb(p, 0, BRDCTL);
+  udelay(1);
   brdctl = aic_inb(p, BRDCTL);
+  udelay(1);
   *int_50 = !(brdctl & BRDDAT5);
   *ext_present = !(brdctl & BRDDAT6);
-  *eeprom = ( aic_inb(p, SPIOCAP) & EEPROM ) != 0;
+  *eeprom = (aic_inb(p, SPIOCAP) & EEPROM);
 }
 
 /*+F*************************************************************************
@@ -5985,12 +7121,37 @@ aic787x_cable_detect(struct aic7xxx_host *p, int *int_50, int *int_68,
   brdctl = read_brdctl(p);
 
   *ext_present = !(brdctl & BRDDAT6);
-  *eeprom = (brdctl & BRDDAT7);
+  *eeprom = !(brdctl & BRDDAT7);
 
   /*
    * We're done, the calling function will release the SEEPROM for us
    */
-  
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic787x_ultra2_term_detect
+ *
+ * Description:
+ *   Detect the termination settings present on ultra2 class controllers
+ *
+ * NOTE: This functions assumes the SEEPROM will have already been aquired
+ *       prior to invocation of this function.
+ *-F*************************************************************************/
+static void
+aic7xxx_ultra2_term_detect(struct aic7xxx_host *p, int *enableSE_low,
+                           int *enableSE_high, int *enableLVD_low,
+                           int *enableLVD_high, int *eprom_present)
+{
+  unsigned char brdctl;
+
+  brdctl = read_brdctl(p);
+
+  *eprom_present  = (brdctl & BRDDAT7);
+  *enableSE_high  = (brdctl & BRDDAT6);
+  *enableSE_low   = (brdctl & BRDDAT5);
+  *enableLVD_high = (brdctl & BRDDAT4);
+  *enableLVD_low  = (brdctl & BRDDAT3);
 }
 
 /*+F*************************************************************************
@@ -6002,146 +7163,192 @@ aic787x_cable_detect(struct aic7xxx_host *p, int *int_50, int *int_68,
  *   SEEPROMs available.
  *-F*************************************************************************/
 static void
-configure_termination(struct aic7xxx_host *p, unsigned char *sxfrctl1,
-    unsigned short adapter_control, unsigned char max_targ)
+configure_termination(struct aic7xxx_host *p)
 {
-  int internal50_present;
+  int internal50_present = 0;
   int internal68_present = 0;
   int external_present = 0;
-  int eprom_present;
-  int high_on;
-  int low_on;
+  int eprom_present = 0;
+  int enableSE_low = 0;
+  int enableSE_high = 0;
+  int enableLVD_low = 0;
+  int enableLVD_high = 0;
+  unsigned char brddat = 0;
+  unsigned char max_target = 0;
+  unsigned char sxfrctl1 = aic_inb(p, SXFRCTL1);
 
   if (acquire_seeprom(p))
   {
-    if (adapter_control & CFAUTOTERM)
+    if (p->features & (AHC_WIDE|AHC_TWIN))
+      max_target = 16;
+    else
+      max_target = 8;
+    aic_outb(p, SEEMS | SEECS, SEECTL);
+    sxfrctl1 &= ~STPWEN;
+    if ( (p->adapter_control & CFAUTOTERM) ||
+         (p->features & AHC_ULTRA2) )
     {
-      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)
+      if ( (p->adapter_control & CFAUTOTERM) && !(p->features & AHC_ULTRA2) )
       {
-        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 "(scsi%d) Warning - detected auto-termination\n",
+               p->host_no);
+        printk(KERN_INFO "(scsi%d) Please verify driver detected settings are "
+          "correct.\n", p->host_no);
+        printk(KERN_INFO "(scsi%d) If not, then please properly set the device "
+          "termination\n", p->host_no);
+        printk(KERN_INFO "(scsi%d) in the Adaptec SCSI BIOS by hitting CTRL-A "
+          "when prompted\n", p->host_no);
+        printk(KERN_INFO "(scsi%d) during machine bootup.\n", p->host_no);
       }
-      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. */
-      aic_outb(p, SEECS | SEEMS, SEECTL);
 
-      if ( (p->type & AHC_AIC7860) == AHC_AIC7860 )
+      if (p->features & AHC_ULTRA2)
       {
-        aic785x_cable_detect(p, &internal50_present, &external_present,
-          &eprom_present);
+        if (aic7xxx_override_term == -1)
+          aic7xxx_ultra2_term_detect(p, &enableSE_low, &enableSE_high,
+                                     &enableLVD_low, &enableLVD_high,
+                                     &eprom_present);
+        if (!(p->adapter_control & CFSEAUTOTERM))
+        {
+          enableSE_low = (p->adapter_control & CFSTERM);
+          enableSE_high = (p->adapter_control & CFWSTERM);
+        }
+        if (!(p->adapter_control & CFAUTOTERM))
+        {
+          enableLVD_low = enableLVD_high = (p->adapter_control & CFLVDSTERM);
+        }
+        internal50_present = 0;
+        internal68_present = 1;
+        external_present = 1;
       }
-      else
+      else if ( (p->chip & AHC_CHIPID_MASK) >= AHC_AIC7870 )
       {
         aic787x_cable_detect(p, &internal50_present, &internal68_present,
           &external_present, &eprom_present);
       }
-      if (max_targ > 8)
-      {
-        printk(KERN_INFO "aic7xxx: Cables present (Int-50 %s, Int-68 %s, "
-               "Ext-68 %s)\n",
-               internal50_present ? "YES" : "NO",
-               internal68_present ? "YES" : "NO",
-               external_present ? "YES" : "NO");
-      }
       else
       {
-        printk(KERN_INFO "aic7xxx: Cables present (Int-50 %s, Ext-50 %s)\n",
-               internal50_present ? "YES" : "NO",
-               external_present ? "YES" : "NO");
+        aic785x_cable_detect(p, &internal50_present, &external_present,
+          &eprom_present);
+      }
+      
+      if (max_target <= 8)
         internal68_present = 0;
+
+      if ( !(p->features & AHC_ULTRA2) )
+      {
+        if (max_target > 8)
+        {
+          printk(KERN_INFO "(scsi%d) Cables present (Int-50 %s, Int-68 %s, "
+                 "Ext-68 %s)\n", p->host_no,
+                 internal50_present ? "YES" : "NO",
+                 internal68_present ? "YES" : "NO",
+                 external_present ? "YES" : "NO");
+        }
+        else
+        {
+          printk(KERN_INFO "(scsi%d) Cables present (Int-50 %s, Ext-50 %s)\n",
+                 p->host_no,
+                 internal50_present ? "YES" : "NO",
+                 external_present ? "YES" : "NO");
+        }
       }
       if (aic7xxx_verbose & VERBOSE_PROBE2)
-        printk(KERN_INFO "aic7xxx: EEPROM %s present.\n",
+        printk(KERN_INFO "(scsi%d) EEPROM %s present.\n", p->host_no,
              eprom_present ? "is" : "is not");
 
       /*
        * Now set the termination based on what we found.  BRDDAT6
        * controls wide termination enable.
+       * Flash Enable = BRDDAT7
+       * SE High Term Enable = BRDDAT6
+       * SE Low Term Enable = BRDDAT5 (7890)
+       * LVD High Term Enable = BRDDAT4 (7890)
        */
-      high_on = FALSE;
-      low_on = FALSE;
-      if ((max_targ > 8) &&
-          ((external_present == 0) || (internal68_present == 0)))
+      if ( !(p->features & AHC_ULTRA2) &&
+           (internal50_present && internal68_present && external_present) )
       {
-        high_on = TRUE;
+        printk(KERN_INFO "(scsi%d) Illegal cable configuration!!  Only two\n",
+               p->host_no);
+        printk(KERN_INFO "(scsi%d) connectors on the SCSI controller may be "
+               "in use at a time!\n", p->host_no);
+        /*
+         * Force termination (low and high byte) on.  This is safer than
+         * leaving it completely off, especially since this message comes
+         * most often from motherboard controllers that don't even have 3
+         * connectors, but instead are failing the cable detection.
+         */
+        internal50_present = external_present = 0;
+        enableSE_high = enableSE_low = 1;
       }
 
-      if ( ( (internal50_present ? 1 : 0) +
-             (internal68_present ? 1 : 0) +
-             (external_present   ? 1 : 0) ) <= 1)
+      if ((max_target > 8) &&
+          ((external_present == 0) || (internal68_present == 0) ||
+           (enableSE_high != 0)))
       {
-        low_on = TRUE;
+        brddat |= BRDDAT6;
+        p->flags |= AHC_TERM_ENB_SE_HIGH;
+        if (aic7xxx_verbose & VERBOSE_PROBE2)
+          printk(KERN_INFO "(scsi%d) SE High byte termination Enabled\n",
+                 p->host_no);
       }
-          
-      if (internal50_present && internal68_present && external_present)
+
+      if ( (((internal50_present ? 1 : 0) +
+             (internal68_present ? 1 : 0) +
+             (external_present   ? 1 : 0)) <= 1) ||
+           (enableSE_low != 0) )
       {
-        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 (p->features & AHC_ULTRA2)
+          brddat |= BRDDAT5;
+        else
+          sxfrctl1 |= STPWEN;
+        p->flags |= AHC_TERM_ENB_SE_LOW;
+        if (aic7xxx_verbose & VERBOSE_PROBE2)
+          printk(KERN_INFO "(scsi%d) SE Low byte termination Enabled\n",
+                 p->host_no);
       }
 
-      if (high_on == TRUE)
-        write_brdctl(p, BRDDAT6);
-      else
-        write_brdctl(p, 0);
-
-      if (low_on == TRUE)
-        *sxfrctl1 |= STPWEN;
-
-      if (max_targ > 8)
+      if (enableLVD_low != 0)
       {
-        printk(KERN_INFO "aic7xxx: Termination (Low %s, High %s)\n",
-              low_on ? "ON" : "OFF", high_on ? "ON" : "OFF");
+        sxfrctl1 |= STPWEN;
+        p->flags |= AHC_TERM_ENB_LVD;
+        if (aic7xxx_verbose & VERBOSE_PROBE2)
+          printk(KERN_INFO "(scsi%d) LVD Low byte termination Enabled\n",
+                 p->host_no);
       }
-      else
+          
+      if (enableLVD_high != 0)
       {
-        printk(KERN_INFO "aic7xxx: Termination %s\n",
-          low_on ? "Enabled" : "Disabled");
+        brddat |= BRDDAT4;
+        if (aic7xxx_verbose & VERBOSE_PROBE2)
+          printk(KERN_INFO "(scsi%d) LVD High byte termination Enabled\n",
+                 p->host_no);
       }
     }
     else
     {
-      if (adapter_control & CFSTERM)
-        *sxfrctl1 |= STPWEN;
-
-      aic_outb(p, SEEMS | SEECS, SEECTL);
-      /*
-       * Configure high byte termination.
-       */
-      if (adapter_control & CFWSTERM)
+      if (p->adapter_control & CFSTERM)
       {
-        write_brdctl(p, BRDDAT6);
-      }
-      else
-      {
-        write_brdctl(p, 0);
+        if (p->features & AHC_ULTRA2)
+          brddat |= BRDDAT5;
+        else
+          sxfrctl1 |= STPWEN;
+        if (aic7xxx_verbose & VERBOSE_PROBE2)
+          printk(KERN_INFO "(scsi%d) SE Low byte termination Enabled\n",
+                 p->host_no);
       }
-      if (aic7xxx_verbose & VERBOSE_PROBE2)
+
+      if (p->adapter_control & CFWSTERM)
       {
-        printk(KERN_INFO "aic7xxx: Termination (Low %s, High %s)\n",
-               (adapter_control & CFSTERM) ? "ON" : "OFF",
-               (adapter_control & CFWSTERM) ? "ON" : "OFF");
+        brddat |= BRDDAT6;
+        if (aic7xxx_verbose & VERBOSE_PROBE2)
+          printk(KERN_INFO "(scsi%d) SE High byte termination Enabled\n",
+                 p->host_no);
       }
     }
+    write_brdctl(p, brddat);
     release_seeprom(p);
+    aic_outb(p, sxfrctl1, SXFRCTL1);
   }
 }
 
@@ -6183,7 +7390,12 @@ detect_maxscb(struct aic7xxx_host *p)
       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, i - 1, SCB_PREV);  /* Set the prev pointer. */
       aic_outb(p, SCB_LIST_NULL, SCB_TAG);  /* Make the tag invalid. */
+      aic_outb(p, SCB_LIST_NULL, SCB_BUSYTARGETS);  /* no busy untagged */
+      aic_outb(p, SCB_LIST_NULL, SCB_BUSYTARGETS+1);/* targets active yet */
+      aic_outb(p, SCB_LIST_NULL, SCB_BUSYTARGETS+2);
+      aic_outb(p, SCB_LIST_NULL, SCB_BUSYTARGETS+3);
     }
 
     /* Make sure the last SCB terminates the free list. */
@@ -6195,6 +7407,11 @@ detect_maxscb(struct aic7xxx_host *p)
     aic_outb(p, 0, SCB_CONTROL);
 
     p->scb_data->maxhscbs = i;
+    /*
+     * Use direct indexing instead for speed
+     */
+    if ( i == AIC7XXX_MAXSCB )
+      p->flags &= ~AHC_PAGESCBS;
   }
 
 }
@@ -6213,9 +7430,7 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p,
   int i, result;
   int max_targets;
   int found = 1;
-  unsigned char target_settings;
-  unsigned char term, scsi_conf, sxfrctl1;
-  unsigned short ultraenable = 0;
+  unsigned char term, scsi_conf;
   struct Scsi_Host *host;
 
   /*
@@ -6236,11 +7451,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->type & AHC_WIDE)
+  if (p->features & AHC_WIDE)
   {
     host->max_id = 16;
   }
-  if (p->type & AHC_TWIN)
+  if (p->features & AHC_TWIN)
   {
     host->max_channel = 1;
   }
@@ -6248,6 +7463,7 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p,
   p->host = host;
   p->last_reset = 0;
   p->host_no = host->host_no;
+  host->unique_id = p->instance;
   p->isr_count = 0;
   p->next = NULL;
   p->completeq.head = NULL;
@@ -6270,7 +7486,7 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p,
   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_flags[i] = 0;
     p->dev_active_cmds[i] = 0;
     p->dev_last_reset[i] = 0;
     p->dev_last_queue_full[i] = 0;
@@ -6283,19 +7499,16 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p,
     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)
+  switch(p->chip)
   {
-    case AHC_AIC7770:
-    case AHC_274:
+    case (AHC_AIC7770|AHC_EISA):
       printk("EISA slot %d\n", p->pci_device_fn);
       break;
-    case AHC_284:
+    case (AHC_AIC7770|AHC_VL):
       printk("VLB slot %d\n", p->pci_device_fn);
       break;
     default:
@@ -6303,7 +7516,7 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p,
         PCI_FUNC(p->pci_device_fn));
       break;
   }
-  if (p->type & AHC_TWIN)
+  if (p->features & 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);
@@ -6314,7 +7527,7 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p,
 
     channel = "";
 
-    if ((p->type & AHC_39x) != 0)
+    if ((p->flags & AHC_MULTI_CHANNEL) != 0)
     {
       channel = " A";
 
@@ -6323,7 +7536,7 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p,
         channel = (p->flags & AHC_CHNLB) ? " B" : " C";
       }
     }
-    if (p->type & AHC_WIDE)
+    if (p->features & AHC_WIDE)
     {
       printk(KERN_INFO "(scsi%d) Wide ", p->host_no);
     }
@@ -6340,129 +7553,159 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p,
    */
   detect_maxscb(p);
   printk("%d/%d SCBs\n", p->scb_data->maxhscbs, p->scb_data->maxscbs);
-  printk(KERN_INFO "(scsi%d) BIOS %sabled, IO Port 0x%lx, IRQ %d\n",
-    p->host_no, (p->flags & AHC_BIOS_ENABLED) ? "en" : "dis",
-    p->base, p->irq);
-  printk(KERN_INFO "(scsi%d) IO Memory at 0x%lx, MMAP Memory at 0x%lx\n",
-    p->host_no, p->mbase, (unsigned long)p->maddr);
-
-
-
-  /*
-   * Register IRQ with the kernel.  Only allow sharing IRQs with
-   * PCI devices.
-   */
-  if ((p->type & AHC_AIC7770) == AHC_AIC7770)
-  {
-    result = (request_irq(p->irq, do_aic7xxx_isr, 0, "aic7xxx", p));
-  }
-  else
-  {
-    result = (request_irq(p->irq, do_aic7xxx_isr, SA_SHIRQ,
-              "aic7xxx", p));
-    if (result < 0)
-    {
-      result = (request_irq(p->irq, do_aic7xxx_isr, SA_INTERRUPT | SA_SHIRQ,
-              "aic7xxx", p));
-    }
-  }
-  if (result < 0)
+  if (aic7xxx_verbose & VERBOSE_PROBE2)
   {
-    printk(KERN_WARNING "(scsi%d) Couldn't register IRQ %d, ignoring.\n",
-           p->host_no, p->irq);
-    return (0);
+    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);
   }
 
   /*
-   * Set the SCSI Id, SXFRCTL0, SXFRCTL1, and SIMODE1, for both channels
+   * Now that we know our instance number, we can set the flags we need to
+   * force termination if need be.
    */
-  if (p->type & AHC_TWIN)
+  if (aic7xxx_stpwlev != -1)
   {
     /*
-     * The controller is gated to channel B after a chip reset; set
-     * bus B values first.
+     * This option only applies to PCI controllers.
      */
-    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)
+    if ( (p->chip & ~AHC_CHIPID_MASK) == AHC_PCI)
     {
-      aic_outb(p, DFON | SPIOEN | FAST20, SXFRCTL0);
-    }
-    else
-    {
-      aic_outb(p, DFON | SPIOEN, SXFRCTL0);
-    }
-    if ( (p->type & AHC_AIC7770) == AHC_AIC7770 )
-    {
-      scsi_conf &= ~0x07;
-      scsi_conf |= p->scsi_id_b;
-      aic_outb(p, scsi_conf | (term) ? TERM_ENB : 0, SCSICONF + 1);
-    }
-    if ( (scsi_conf & RESET_SCSI) && !(aic7xxx_no_reset) )
-    {
-      /* Reset SCSI bus B. */
-      if (aic7xxx_verbose & VERBOSE_PROBE)
-        printk(KERN_INFO "(scsi%d) Resetting channel B\n", p->host_no);
+      unsigned char devconfig;
 
-      aic7xxx_reset_current_bus(p);
+#if LINUX_KERNEL_VERSION > KERNEL_VERSION(2,1,92)
+      pci_read_config_byte(p->pdev, DEVCONFIG, &devconfig);
+#else
+      pcibios_read_config_byte(p->pci_bus, p->pci_device_fn,
+                               DEVCONFIG, &devconfig);
+#endif
+      if ( (aic7xxx_stpwlev >> p->instance) & 0x01 )
+      {
+        devconfig |= 0x02;
+        if (aic7xxx_verbose & VERBOSE_PROBE2)
+          printk("(scsi%d) Force setting STPWLEV bit\n", p->host_no);
+      }
+      else
+      {
+        devconfig &= ~0x02;
+        if (aic7xxx_verbose & VERBOSE_PROBE2)
+          printk("(scsi%d) Force clearing STPWLEV bit\n", p->host_no);
+      }
+#if LINUX_KERNEL_VERSION > KERNEL_VERSION(2,1,92)
+      pci_write_config_byte(p->pdev, DEVCONFIG, devconfig);
+#else
+      pcibios_write_config_byte(p->pci_bus, p->pci_device_fn,
+                                DEVCONFIG, devconfig);
+#endif
     }
-
-    /* Select channel A */
-    aic_outb(p, SELNARROW, SBLKCTL);
   }
 
-  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)
+  /*
+   * That took care of devconfig and stpwlev, now for the actual termination
+   * settings.
+   */
+  if (aic7xxx_override_term != -1)
   {
-    aic_outb(p, DFON | SPIOEN | FAST20, SXFRCTL0);
+    /*
+     * Again, this only applies to PCI controllers.  We don't have problems
+     * with the termination on 274x controllers to the best of my knowledge.
+     */
+    if ( (p->chip & ~AHC_CHIPID_MASK) == AHC_PCI)
+    {
+      unsigned char term_override;
+
+      term_override = ( (aic7xxx_override_term >> (p->instance * 4)) & 0x0f);
+      p->adapter_control &= 
+        ~(CFSTERM|CFWSTERM|CFLVDSTERM|CFAUTOTERM|CFSEAUTOTERM);
+      if ( (p->features & AHC_ULTRA2) && (term_override & 0x0c) )
+      {
+        p->adapter_control |= CFLVDSTERM;
+      }
+      if (term_override & 0x02)
+      {
+        p->adapter_control |= CFWSTERM;
+      }
+      if (term_override & 0x01)
+      {
+        p->adapter_control |= CFSTERM;
+      }
+    }
   }
-  else
+
+  if ( (p->flags & AHC_SEEPROM_FOUND) || (aic7xxx_override_term != -1) )
   {
-    aic_outb(p, DFON | SPIOEN, SXFRCTL0);
+    if (p->features & AHC_SPIOCAP)
+    {
+      if ( aic_inb(p, SPIOCAP) & SSPIOCPS )
+      /*
+       * Update the settings in sxfrctl1 to match the termination
+       * settings.
+       */
+        configure_termination(p);
+    }
+    else if ((p->chip & AHC_CHIPID_MASK) >= AHC_AIC7870)
+    {
+      configure_termination(p);
+    }
   }
-  if ( (p->type & AHC_AIC7770) == AHC_AIC7770 )
+
+  /*
+   * Load the sequencer program, then re-enable the board -
+   * resetting the AIC-7770 disables it, leaving the lights
+   * on with nobody home.
+   */
+  aic7xxx_loadseq(p);
+
+  if ( (p->chip & AHC_CHIPID_MASK) == AHC_AIC7770 )
   {
-    scsi_conf &= ~0x07;
-    scsi_conf |= p->scsi_id;
-    aic_outb(p, scsi_conf | (term) ? TERM_ENB : 0, SCSICONF);
+    aic_outb(p, ENABLE, BCTL);  /* Enable the boards BUS drivers. */
   }
+  aic_outb(p, aic_inb(p, SBLKCTL) & ~AUTOFLUSHDIS, SBLKCTL);
 
+  /*
+   * Clear out any possible pending interrupts.
+   */
+  aic7xxx_clear_intstat(p);
 
-  if ( (scsi_conf & RESET_SCSI) && !(aic7xxx_no_reset) )
+  /*
+   * Set the SCSI Id, SXFRCTL0, SXFRCTL1, and SIMODE1, for both channels
+   */
+  if (p->features & AHC_TWIN)
   {
-    /* Reset SCSI bus A. */
-    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);
-    }
+    /* Select channel B */
+    aic_outb(p, aic_inb(p, SBLKCTL) | SELBUSB, SBLKCTL);
 
-    aic7xxx_reset_current_bus(p);
+    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);
+    aic_outb(p, DFON | SPIOEN, SXFRCTL0);
+    aic_outb(p, (scsi_conf & ENSPCHK) | term | 
+         ENSTIMER | ACTNEGEN, SXFRCTL1);
+    aic_outb(p, 0, SIMODE0);
+    aic_outb(p, ENSELTIMO | ENSCSIRST | ENSCSIPERR, SIMODE1);
+    aic_outb(p, 0, SCSIRATE);
 
-    /*
-     * Delay for the reset delay.
-     */
-    if (!reset_delay)
-      aic7xxx_delay(AIC7XXX_RESET_DELAY);
+    /* Select channel A */
+    aic_outb(p, aic_inb(p, SBLKCTL) & ~SELBUSB, SBLKCTL);
   }
 
+  term = ((p->flags & AHC_TERM_ENB_SE_LOW) != 0) ? STPWEN : 0;
+  if (p->features & AHC_ULTRA2)
+    aic_outb(p, p->scsi_id, SCSIID_ULTRA2);
+  else
+    aic_outb(p, p->scsi_id, SCSIID);
+  scsi_conf = aic_inb(p, SCSICONF);
+  aic_outb(p, DFON | SPIOEN, SXFRCTL0);
+  aic_outb(p, (scsi_conf & ENSPCHK) | term | 
+       ENSTIMER | ACTNEGEN, SXFRCTL1);
+  aic_outb(p, 0, SIMODE0);
+  aic_outb(p, ENSELTIMO | ENSCSIRST | ENSCSIPERR, SIMODE1);
+  aic_outb(p, 0, SCSIRATE);
+  if ( p->features & AHC_ULTRA2)
+    aic_outb(p, 0, SCSIOFFSET);
+
   /*
    * Look at the information that board initialization or the board
    * BIOS has left us. In the lower four bits of each target's
@@ -6471,14 +7714,7 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p,
    * BIOS has decided to disable synchronous negotiation to that
    * target so we don't activate the needsdtr flag.
    */
-  p->needsdtr_copy = 0x0;
-  p->sdtr_pending = 0x0;
-  p->needwdtr_copy = 0x0;
-  p->wdtr_pending = 0x0;
-  p->tagenable = 0x0;
-  p->ultraenb = 0x0;
-  p->discenable = 0xffff;
-  if ((p->type & (AHC_TWIN|AHC_WIDE)) == 0)
+  if ((p->features & (AHC_TWIN|AHC_WIDE)) == 0)
   {
     max_targets = 8;
   }
@@ -6487,110 +7723,31 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p,
     max_targets = 16;
   }
 
-  /*
-   * Grab the disconnection disable table and invert it for our needs
-   */
-  if (p->flags & AHC_USEDEFAULTS)
-  {
-    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 = ~((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 (!(aic7xxx_no_reset))
   {
-    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->type & AHC_ULTRA)
-        ultraenable |= (0x01 << i);
-    }
-    else
-    {
-      target_settings = aic_inb(p, TARG_SCRATCH + i);
-      if (target_settings & 0x0F)
-      {
-        p->needsdtr_copy |= (0x01 << i);
-        /*
-         * Default to asynchronous transfers (0 offset)
-         */
-        target_settings &= 0xF0;
-      }
-      if (target_settings & 0x80)
-      {
-        p->needwdtr_copy |= (0x01 << i);
-        /*
-         * Clear the wide flag. When wide negotiation is successful,
-         * we'll enable it.
-         */
-        target_settings &= 0x7F;
-      }
-    }
-
     /*
-     * If we reset the bus, then clear the transfer ssettings, else leave
+     * If we reset the bus, then clear the transfer settings, else leave
      * them be
      */
-    if ( (scsi_conf & RESET_SCSI) && !(aic7xxx_no_reset) )
-      aic_outb(p, target_settings, TARG_SCRATCH + i);
-    if (p->needsdtr_copy & (0x01 << i))
+    for (i = 0; i < max_targets; i++)
     {
-      short sxfr, j;
-
-      sxfr = target_settings & SXFR;
-      if ((p->ultraenb & (1 << i)) != 0)
-      {
-        /* Want an ultra speed in the table */
-        sxfr |= 0x100;
-      }
-      for (j = 0; j < NUMBER(aic7xxx_syncrates); j++)
+      aic_outb(p, 0, TARG_SCSIRATE + i);
+      if (p->features & AHC_ULTRA2)
       {
-        if (sxfr == aic7xxx_syncrates[j].rate)
-          break;
+        aic_outb(p, 0, TARG_OFFSET + i);
       }
-      p->syncinfo[i].period = aic7xxx_syncrates[j].period;
-      p->syncinfo[i].offset =
-       (p->type & AHC_WIDE) ? MAX_OFFSET_16BIT : MAX_OFFSET_8BIT;
+      p->transinfo[i].cur_offset = 0;
+      p->transinfo[i].cur_period = 0;
+      p->transinfo[i].cur_width = MSG_EXT_WDTR_BUS_8_BIT;
     }
-    else
-    {
-      p->syncinfo[i].period = 0;
-      p->syncinfo[i].offset = 0;
-    }
-  }
-
-  /*
-   * If we are not wide, forget WDTR. This makes the driver
-   * work on some cards that don't leave these fields cleared
-   * when BIOS is not installed.
-   */
-  if ( !(p->type & AHC_WIDE))
-  {
-    p->needwdtr_copy = 0;
-  }
-  p->needsdtr = p->needsdtr_copy;
-  p->needwdtr = p->needwdtr_copy;
 
-  /*
-   * If we reset the bus, then clear the transfer ssettings, else leave
-   * them be
-   */
-  if ( (scsi_conf & RESET_SCSI) && !(aic7xxx_no_reset) )
-  {
+    /*
+     * If we reset the bus, then clear the transfer settings, else leave
+     * them be.
+     */
     aic_outb(p, 0, ULTRA_ENB);
     aic_outb(p, 0, ULTRA_ENB + 1);
+    p->ultraenb = 0;
   }
 
   /*
@@ -6600,21 +7757,35 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p,
    * routine should only allocate contiguous memory, but note that
    * this could be a problem if kmalloc() is changed.
    */
-  if (p->scb_data->hscbs == NULL)
   {
     size_t array_size;
     unsigned int hscb_physaddr;
+    unsigned long temp;
 
     array_size = p->scb_data->maxscbs * sizeof(struct aic7xxx_hwscb);
-    p->scb_data->hscbs = kmalloc(array_size, GFP_ATOMIC);
+    if (p->scb_data->hscbs == NULL)
+    {
+      /*
+       * A little padding so we can align thing the way we want
+       */
+      p->scb_data->hscbs = kmalloc(array_size + 0x1f, GFP_ATOMIC);
+    }
     if (p->scb_data->hscbs == NULL)
     {
       printk("(scsi%d) Unable to allocate hardware SCB array; "
              "failing detection.\n", p->host_no);
-      release_region(p->base, MAXREG - MINREG);
-      free_irq(p->irq, p);
+      p->irq = 0;
       return(0);
     }
+    /*
+     * Save the actual kmalloc buffer pointer off, then align our
+     * buffer to a 32 byte boundary
+     */
+    p->scb_data->hscb_kmalloc_ptr = p->scb_data->hscbs;
+    temp = (unsigned long)p->scb_data->hscbs;
+    temp += 0x1f;
+    temp &= ~0x1f;
+    p->scb_data->hscbs = (struct aic7xxx_hwscb *)temp;
     /* At least the control byte of each SCB needs to be 0. */
     memset(p->scb_data->hscbs, 0, array_size);
 
@@ -6631,12 +7802,19 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p,
     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);
+  /* 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);
 
+  if(p->features & AHC_QUEUE_REGS)
+  {
+    aic_outb(p, SCB_QSIZE_256, QOFF_CTLSTA);
+    aic_outb(p, 0, SDSCB_QOFF);
+    aic_outb(p, 0, SNSCB_QOFF);
+    aic_outb(p, 0, HNSCB_QOFF);
   }
 
   /*
@@ -6649,20 +7827,19 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p,
    * Message out buffer starts empty
    */
   aic_outb(p, MSG_NOOP, MSG_OUT);
+  aic_outb(p, MSG_NOOP, LAST_MSG);
 
   /*
-   * Load the sequencer program, then re-enable the board -
-   * resetting the AIC-7770 disables it, leaving the lights
-   * on with nobody home. On the PCI bus you *may* be home,
-   * but then your mailing address is dynamically assigned
-   * so no one can find you anyway :-)
+   * Set all the other asundry items that haven't been set yet.
+   * This includes just dumping init values to a lot of registers simply
+   * to make sure they've been touched and are ready for use parity wise
+   * speaking.
    */
-  aic7xxx_loadseq(p);
-
-  if ( (p->type & AHC_AIC7770) == AHC_AIC7770 )
-  {
-    aic_outb(p, ENABLE, BCTL);  /* Enable the boards BUS drivers. */
-  }
+  aic_outb(p, 0, TMODE_CMDADDR);
+  aic_outb(p, 0, TMODE_CMDADDR + 1);
+  aic_outb(p, 0, TMODE_CMDADDR + 2);
+  aic_outb(p, 0, TMODE_CMDADDR + 3);
+  aic_outb(p, 0, TMODE_CMDADDR_NEXT);
 
   /*
    * Link us into the list of valid hosts
@@ -6671,10 +7848,104 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p,
   first_aic7xxx = p;
 
   /*
-   * Unpause the sequencer before returning and enable
-   * interrupts - we shouldn't get any until the first
-   * command is sent to us by the high-level SCSI code.
+   * Clear out any possible pending interrupts, again.
+   */
+  aic7xxx_clear_intstat(p);
+
+  /*
+   * Allocate the first set of scbs for this controller.  This is to stream-
+   * line code elsewhere in the driver.  If we have to check for the existence
+   * of scbs in certain code sections, it slows things down.  However, as
+   * soon as we register the IRQ for this card, we could get an interrupt that
+   * includes possibly the SCSI_RSTI interrupt.  If we catch that interrupt
+   * then we are likely to segfault if we don't have at least one chunk of
+   * SCBs allocated or add checks all through the reset code to make sure
+   * that the SCBs have been allocated which is an invalid running condition
+   * and therefore I think it's preferable to simply pre-allocate the first
+   * chunk of SCBs.
    */
+  aic7xxx_allocate_scb(p);
+
+  if ( !(aic7xxx_no_reset) )
+  {
+    if (p->features & AHC_TWIN)
+    {
+      if (aic7xxx_verbose & VERBOSE_PROBE2)
+        printk(KERN_INFO "(scsi%d) Resetting channel B\n", p->host_no);
+      aic_outb(p, aic_inb(p, SBLKCTL) | SELBUSB, SBLKCTL);
+      aic7xxx_reset_current_bus(p);
+      aic_outb(p, aic_inb(p, SBLKCTL) & ~SELBUSB, SBLKCTL);
+    }
+    /* Reset SCSI bus A. */
+    if (aic7xxx_verbose & VERBOSE_PROBE2)
+    {  /* 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);
+    }
+    
+    /*
+     * Some of the new Ultra2 chipsets need a longer delay after a chip
+     * reset than just the init setup creates, so we have to delay here
+     * before we go into a reset in order to make the chips happy.
+     */
+    if (p->features & AHC_ULTRA2)
+      mdelay(250);
+    aic7xxx_reset_current_bus(p);
+
+    /*
+     * Delay for the reset delay.
+     */
+    if (!reset_delay)
+      aic7xxx_delay(AIC7XXX_RESET_DELAY);
+  }
+  else
+  {
+    if (!reset_delay)
+    {
+      printk(KERN_INFO "(scsi%d) Not resetting SCSI bus.  Note: Don't use "
+             "the no_reset\n", p->host_no);
+      printk(KERN_INFO "(scsi%d) option unless you have a verifiable need "
+             "for it.\n", p->host_no);
+      printk(KERN_INFO "(scsi%d) The no_reset option is known to break some "
+             "systems,\n", p->host_no);
+      printk(KERN_INFO "(scsi%d) and is not supported by the driver author\n",
+             p->host_no);
+      aic7xxx_delay(AIC7XXX_RESET_DELAY);
+    }
+  }
+  
+  /*
+   * Register IRQ with the kernel.  Only allow sharing IRQs with
+   * PCI devices.
+   */
+  if (!(p->chip & AHC_PCI))
+  {
+    result = (request_irq(p->irq, do_aic7xxx_isr, 0, "aic7xxx", p));
+  }
+  else
+  {
+    result = (request_irq(p->irq, do_aic7xxx_isr, SA_SHIRQ,
+              "aic7xxx", p));
+    if (result < 0)
+    {
+      result = (request_irq(p->irq, do_aic7xxx_isr, SA_INTERRUPT | SA_SHIRQ,
+              "aic7xxx", p));
+    }
+  }
+  if (result < 0)
+  {
+    printk(KERN_WARNING "(scsi%d) Couldn't register IRQ %d, ignoring "
+           "controller.\n", p->host_no, p->irq);
+    p->irq = 0;
+    return (0);
+  }
+
   unpause_sequencer(p, /* unpause_always */ TRUE);
 
   return (found);
@@ -6691,12 +7962,9 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p,
 int
 aic7xxx_chip_reset(struct aic7xxx_host *p)
 {
-  unsigned char hcntrl;
+  unsigned char sblkctl;
   int wait;
 
-  /* Retain the IRQ type across the chip reset. */
-  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.
@@ -6707,29 +7975,26 @@ aic7xxx_chip_reset(struct aic7xxx_host *p)
    * 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) && ((aic_inb(p, HCNTRL) & CHIPRSTACK) == 0))
+  wait = 1000;  /* 1 second (1000 * 1 msec) */
+  while (--wait && !(aic_inb(p, HCNTRL) & CHIPRSTACK))
   {
-    udelay(1000);  /* 1 msec = 1000 usec */
-    wait = wait - 1;
+    mdelay(1);  /* 1 msec */
   }
 
-  if ((aic_inb(p, HCNTRL) & CHIPRSTACK) == 0)
-  {
-    printk(KERN_INFO "aic7xxx: Chip reset not cleared; clearing manually.\n");
-  }
-
-  aic_outb(p, hcntrl | PAUSE, HCNTRL);
+  pause_sequencer(p);
 
-  switch( aic_inb(p, SBLKCTL) & 0x0a )
+  sblkctl = aic_inb(p, SBLKCTL) & (SELBUSB|SELWIDE);
+  if (p->chip & AHC_PCI)
+    sblkctl &= ~SELBUSB;
+  switch( sblkctl )
   {
     case 0:  /* normal narrow card */
       break;
     case 2:  /* Wide card */
-      p->type |= AHC_WIDE;
+      p->features |= AHC_WIDE;
       break;
     case 8:  /* Twin card */
-      p->type |= AHC_TWIN;
+      p->features |= AHC_TWIN;
       p->flags |= AHC_MULTI_CHANNEL;
       break;
     default: /* hmmm...we don't know what this is */
@@ -6753,6 +8018,7 @@ aic7xxx_alloc(Scsi_Host_Template *sht, struct aic7xxx_host *temp)
 {
   struct aic7xxx_host *p = NULL;
   struct Scsi_Host *host;
+  int i;
 
   /*
    * Allocate a storage area by registering us with the mid-level
@@ -6764,6 +8030,7 @@ aic7xxx_alloc(Scsi_Host_Template *sht, struct aic7xxx_host *temp)
   {
     p = (struct aic7xxx_host *) host->hostdata;
     memset(p, 0, sizeof(struct aic7xxx_host));
+    *p = *temp;
     p->host = host;
 
     p->scb_data = kmalloc(sizeof(scb_data_type), GFP_ATOMIC);
@@ -6778,34 +8045,20 @@ aic7xxx_alloc(Scsi_Host_Template *sht, struct aic7xxx_host *temp)
        * For some reason we don't have enough memory.  Free the
        * allocated memory for the aic7xxx_host struct, and return NULL.
        */
+      release_region(p->base, MAXREG - MINREG);
       scsi_unregister(host);
-      p = NULL;
-    }
-    if (p != NULL)
-    {
-      p->host_no = host->host_no;
-      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(NULL);
     }
+    p->host_no = host->host_no;
+    p->tagenable = 0;
+    p->orderedtag = 0;
+    for (i=0; i<MAX_TARGETS; i++)
+    {
+      p->transinfo[i].goal_period = 0;
+      p->transinfo[i].goal_offset = 0;
+      p->transinfo[i].goal_width = MSG_EXT_WDTR_BUS_8_BIT;
+    }
+    DRIVER_LOCK_INIT
   }
   return (p);
 }
@@ -6821,28 +8074,35 @@ aic7xxx_alloc(Scsi_Host_Template *sht, struct aic7xxx_host *temp)
 static void
 aic7xxx_free(struct aic7xxx_host *p)
 {
-  int i, jump;
+  int i;
 
   /*
    * Free the allocated hardware SCB space.
    */
-  if (p->scb_data->hscbs != NULL)
+  if (p->scb_data != NULL)
   {
-    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]);
+    if (p->scb_data->hscbs != NULL)
+    {
+      kfree(p->scb_data->hscb_kmalloc_ptr);
+      p->scb_data->hscbs = p->scb_data->hscb_kmalloc_ptr = NULL;
+    }
+    /*
+     * Free the driver SCBs.  These were allocated on an as-need
+     * basis.  We allocated these in groups depending on how many
+     * we could fit into a given amount of RAM.  The tail SCB for
+     * these allocations has a pointer to the alloced area.
+     */
+    for (i = 0; i < p->scb_data->numscbs; i++)
+    {
+      if (p->scb_data->scb_array[i]->kmalloc_ptr != NULL)
+        kfree(p->scb_data->scb_array[i]->kmalloc_ptr);
+      p->scb_data->scb_array[i] = NULL;
+    }
+  
+    /*
+     * Free the SCB data area.
+     */
+    kfree(p->scb_data);
   }
 
   /*
@@ -6857,10 +8117,6 @@ aic7xxx_free(struct aic7xxx_host *p)
       kfree(p->dev_sdtr_cmnd[i]);
   }
 
-  /*
-   * Free the SCB data area.
-   */
-  kfree(p->scb_data);
 }
 
 /*+F*************************************************************************
@@ -6871,12 +8127,12 @@ aic7xxx_free(struct aic7xxx_host *p)
  *   Load the seeprom and configure adapter and target settings.
  *   Returns 1 if the load was successful and 0 otherwise.
  *-F*************************************************************************/
-static int
-load_seeprom (struct aic7xxx_host *p, unsigned char *sxfrctl1)
+static void
+aic7xxx_load_seeprom(struct aic7xxx_host *p, unsigned char *sxfrctl1)
 {
   int have_seeprom = 0;
-  int i, max_targets;
-  unsigned char target_settings, scsi_conf;
+  int i, max_targets, mask;
+  unsigned char scsirate, scsi_conf;
   unsigned short scarray[128];
   struct seeprom_config *sc = (struct seeprom_config *) scarray;
 
@@ -6884,42 +8140,31 @@ load_seeprom (struct aic7xxx_host *p, unsigned char *sxfrctl1)
   {
     printk(KERN_INFO "aic7xxx: Loading serial EEPROM...");
   }
-  switch (p->type & 0x00001ff1)
+  switch (p->chip)
   {
-    case AHC_AIC7770:  /* None of these adapters have seeproms. */
-    case AHC_274:
+    case (AHC_AIC7770|AHC_EISA):  /* None of these adapters have seeproms. */
+      if (aic_inb(p, SCSICONF) & TERM_ENB)
+        p->flags |= AHC_TERM_ENB_A;
+      if ( (p->features & AHC_TWIN) && (aic_inb(p, SCSICONF + 1) & TERM_ENB) )
+        p->flags |= AHC_TERM_ENB_B;
       break;
 
-    case AHC_284:
+    case (AHC_AIC7770|AHC_VL):
       have_seeprom = read_284x_seeprom(p, (struct seeprom_config *) scarray);
       break;
 
-    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:
+    default:
       have_seeprom = read_seeprom(p, (p->flags & (AHC_CHNLB|AHC_CHNLC)),
-                                  scarray, sizeof(*sc)/2, C46);
+                                  scarray, p->sc_size, p->sc_type);
       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;
-
-    default:
+      {
+        if(p->sc_type == C46)
+          have_seeprom = read_seeprom(p, (p->flags & (AHC_CHNLB|AHC_CHNLC)),
+                                      scarray, p->sc_size, C56_66);
+        else
+          have_seeprom = read_seeprom(p, (p->flags & (AHC_CHNLB|AHC_CHNLC)),
+                                      scarray, p->sc_size, C46);
+      }
       break;
   }
 
@@ -6927,10 +8172,31 @@ load_seeprom (struct aic7xxx_host *p, unsigned char *sxfrctl1)
   {
     if (aic7xxx_verbose & VERBOSE_PROBE2)
     {
-      printk("\naic7xxx: No SEEPROM available; using defaults.\n");
+      printk("\naic7xxx: No SEEPROM available.\n");
+    }
+    p->flags |= AHC_NEWEEPROM_FMT;
+    if (aic_inb(p, SCSISEQ) == 0)
+    {
+      p->flags |= AHC_USEDEFAULTS;
+      p->flags &= ~AHC_BIOS_ENABLED;
+      p->scsi_id = p->scsi_id_b = 7;
+      *sxfrctl1 |= STPWEN;
+      if (aic7xxx_verbose & VERBOSE_PROBE2)
+      {
+        printk("aic7xxx: Using default values.\n");
+      }
     }
-    p->flags |= AHC_USEDEFAULTS;
-    p->flags &= ~AHC_BIOS_ENABLED;
+    else if (aic7xxx_verbose & VERBOSE_PROBE2)
+    {
+      printk("aic7xxx: Using leftover BIOS values.\n");
+    }
+    if ( *sxfrctl1 & STPWEN )
+    {
+      p->flags |= AHC_TERM_ENB_SE_LOW | AHC_TERM_ENB_SE_HIGH;
+      sc->adapter_control &= ~CFAUTOTERM;
+      sc->adapter_control |= CFSTERM | CFWSTERM | CFLVDSTERM;
+    }
+    p->flags |= AHC_EXTEND_TRANS_A | AHC_EXTEND_TRANS_B;
   }
   else
   {
@@ -6939,16 +8205,26 @@ load_seeprom (struct aic7xxx_host *p, unsigned char *sxfrctl1)
       printk("done\n");
     }
 
+    /*
+     * Note things in our flags
+     */
+    p->flags |= AHC_SEEPROM_FOUND;
+
     /*
      * Update the settings in sxfrctl1 to match the termination settings.
      */
     *sxfrctl1 = 0;
 
+    /*
+     * Get our SCSI ID from the SEEPROM setting...
+     */
+    p->scsi_id = (sc->brtime_id & CFSCSIID);
+
     /*
      * First process the settings that are different between the VLB
      * and PCI adapter seeproms.
      */
-    if (p->type & AHC_284)
+    if ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7770)
     {
       /* VLB adapter seeproms */
       if (sc->bios_control & CF284XEXTEND)
@@ -6957,42 +8233,42 @@ load_seeprom (struct aic7xxx_host *p, unsigned char *sxfrctl1)
       if (sc->adapter_control & CF284XSTERM)
       {
         *sxfrctl1 |= STPWEN;
-        p->flags |= AHC_TERM_ENB_A;
+        p->flags |= AHC_TERM_ENB_SE_LOW | AHC_TERM_ENB_SE_HIGH;
       }
-      /*
-       * The 284x SEEPROM doesn't have a max targets field.  We
-       * set it to 16 to make sure we take care of the 284x-wide
-       * adapters.  For narrow adapters, going through the extra
-       * 8 target entries will not cause any harm since they will
-       * will not be used.
-       *
-       * XXX - We should probably break out the bus detection
-       *       from the register function so we can use it here
-       *       to tell us how many targets there really are.
-       */
-      max_targets = 16;
     }
     else
     {
       /* PCI adapter seeproms */
       if (sc->bios_control & CFEXTEND)
         p->flags |= AHC_EXTEND_TRANS_A;
+      if (sc->bios_control & CFBIOSEN)
+        p->flags |= AHC_BIOS_ENABLED;
+      else
+        p->flags &= ~AHC_BIOS_ENABLED;
 
       if (sc->adapter_control & CFSTERM)
       {
         *sxfrctl1 |= STPWEN;
-        p->flags |= AHC_TERM_ENB_A;
+        p->flags |= AHC_TERM_ENB_SE_LOW | AHC_TERM_ENB_SE_HIGH;
       }
-
-      /* Limit to 16 targets just in case. */
-      max_targets = MIN(sc->max_targets & CFMAXTARG, 16);
     }
+    p->sc = *sc;
+  }
 
-    p->discenable = 0;
+  p->discenable = 0;
+    
+  /*
+   * Limit to 16 targets just in case.  The 2842 for one is known to
+   * blow the max_targets setting, future cards might also.
+   */
+  max_targets = MIN(sc->max_targets & CFMAXTARG,
+                   ((p->features & (AHC_TWIN | AHC_WIDE)) ? 16 : 8));
 
+  if (have_seeprom)
+  {
     for (i = 0; i < max_targets; i++)
     {
-      if( (p->type & AHC_ULTRA) &&
+      if( (p->features & AHC_ULTRA) &&
          !(sc->adapter_control & CFULTRAEN) &&
           (sc->device_flags[i] & CFSYNCHISULTRA) )
       {
@@ -7000,114 +8276,203 @@ load_seeprom (struct aic7xxx_host *p, unsigned char *sxfrctl1)
         break;
       }
     }
+  }
 
-    for (i = 0; i < max_targets; i++)
+  for (i = 0; i < max_targets; i++)
+  {
+    mask = (0x01 << i);
+    if (!have_seeprom)
     {
-      target_settings = (sc->device_flags[i] & CFXFER) << 4;
-      if (sc->device_flags[i] & CFSYNCH)
+      if(aic_inb(p, SCSISEQ) != 0)
       {
-        target_settings |= SOFS;
+        /*
+         * OK...the BIOS set things up and left behind the settings we need.
+         * Just make our sc->device_flags[i] entry match what the card has
+         * set for this device.
+         */
+        p->discenable = 
+          ~(aic_inb(p, DISC_DSB) | (aic_inb(p, DISC_DSB + 1) << 8) );
+        p->ultraenb =
+          (aic_inb(p, ULTRA_ENB) | (aic_inb(p, ULTRA_ENB + 1) << 8) );
+        sc->device_flags[i] = (p->discenable & mask) ? CFDISC : 0;
+        if (aic_inb(p, TARG_SCSIRATE + i) & WIDEXFER)
+          sc->device_flags[i] |= CFWIDEB;
+        if (p->features & AHC_ULTRA2)
+        {
+          if (aic_inb(p, TARG_OFFSET + i))
+          {
+            sc->device_flags[i] |= CFSYNCH;
+            sc->device_flags[i] |= (aic_inb(p, TARG_SCSIRATE + i) & 0x07);
+            if ( (aic_inb(p, TARG_SCSIRATE + i) & 0x18) == 0x18 )
+              sc->device_flags[i] |= CFSYNCHISULTRA;
+          }
+        }
+        else
+        {
+          if (aic_inb(p, TARG_SCSIRATE + i) & ~WIDEXFER)
+          {
+            sc->device_flags[i] |= CFSYNCH;
+            if (p->features & AHC_ULTRA)
+              sc->device_flags[i] |= ((p->ultraenb & mask) ?
+                                      CFSYNCHISULTRA : 0);
+          }
+        }
       }
-      if (sc->device_flags[i] & CFWIDEB)
+      else
       {
-        target_settings |= WIDEXFER;
+        /*
+         * Assume the BIOS has NOT been run on this card and nothing between
+         * the card and the devices is configured yet.
+         */
+        sc->device_flags[i] = CFDISC;
+        if (p->features & AHC_WIDE)
+          sc->device_flags[i] |= CFWIDEB;
+        if (p->features & AHC_ULTRA2)
+          sc->device_flags[i] |= 3;
+        else if (p->features & AHC_ULTRA)
+          sc->device_flags[i] |= CFSYNCHISULTRA;
+        sc->device_flags[i] |= CFSYNCH;
+        aic_outb(p, 0, TARG_SCSIRATE + i);
+        if (p->features & AHC_ULTRA2)
+          aic_outb(p, 0, TARG_OFFSET + i);
       }
-      if (sc->device_flags[i] & CFDISC)
+    }
+    if (sc->device_flags[i] & CFDISC)
+    {
+      p->discenable |= mask;
+    }
+    if (p->flags & AHC_NEWEEPROM_FMT)
+    {
+      if (sc->device_flags[i] & CFSYNCHISULTRA)
+      {
+        p->ultraenb |= mask;
+      }
+    }
+    else if (sc->adapter_control & CFULTRAEN)
+    {
+      p->ultraenb |= mask;
+    }
+    if ( (sc->device_flags[i] & CFSYNCH) == 0)
+    {
+      sc->device_flags[i] &= ~CFXFER;
+      p->ultraenb &= ~mask;
+      p->transinfo[i].user_offset = 0;
+      p->transinfo[i].user_period = 0;
+      p->transinfo[i].cur_offset = 0;
+      p->transinfo[i].cur_period = 0;
+      p->needsdtr_copy &= ~mask;
+    }
+    else
+    {
+      if (p->features & AHC_ULTRA2)
       {
-        p->discenable |= (0x01 << i);
+        p->transinfo[i].user_offset = MAX_OFFSET_ULTRA2;
+        p->transinfo[i].cur_offset = aic_inb(p, TARG_OFFSET + i);
+        scsirate = (sc->device_flags[i] & CFXFER) |
+                   ((p->ultraenb & mask) ? 0x18 : 0x10);
+        p->transinfo[i].user_period = aic7xxx_find_period(p, scsirate,
+                                       AHC_SYNCRATE_ULTRA2);
+        p->transinfo[i].cur_period = aic7xxx_find_period(p,
+                                       aic_inb(p, TARG_SCSIRATE + i),
+                                       AHC_SYNCRATE_ULTRA2);
       }
-      if (p->flags & AHC_NEWEEPROM_FMT)
+      else
       {
-        if (sc->device_flags[i] & CFSYNCHISULTRA)
+        scsirate = (sc->device_flags[i] & CFXFER) << 4;
+        if (sc->device_flags[i] & CFWIDEB)
+          p->transinfo[i].user_offset = MAX_OFFSET_16BIT;
+        else
+          p->transinfo[i].user_offset = MAX_OFFSET_8BIT;
+        if (p->features & AHC_ULTRA)
         {
-          p->ultraenb |= (0x01 << i);
+          short ultraenb;
+          ultraenb = aic_inb(p, ULTRA_ENB) |
+            (aic_inb(p, ULTRA_ENB + 1) << 8);
+          p->transinfo[i].user_period = aic7xxx_find_period(p,
+                                          scsirate,
+                                          (p->ultraenb & mask) ?
+                                          AHC_SYNCRATE_ULTRA :
+                                          AHC_SYNCRATE_FAST);
+          p->transinfo[i].cur_period = aic7xxx_find_period(p,
+                                         aic_inb(p, TARG_SCSIRATE + i),
+                                         (ultraenb & mask) ? 
+                                         AHC_SYNCRATE_ULTRA :
+                                         AHC_SYNCRATE_FAST);
         }
+        else
+          p->transinfo[i].user_period = aic7xxx_find_period(p,
+                                          scsirate, AHC_SYNCRATE_FAST);
       }
-      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);
-      }
-      /*
-       * Don't output these settings if we aren't resetting the bus, instead,
-       * leave the devices current settings in place
-       */
-      if (!(aic7xxx_no_reset))
-        aic_outb(p, target_settings, TARG_SCRATCH + i);
+      p->needsdtr_copy |= mask;
     }
-    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)
+    if ( (sc->device_flags[i] & CFWIDEB) && (p->features & AHC_WIDE) )
     {
-      p->flags &= ~AHC_USEDEFAULTS;
-      p->flags |= AHC_BIOS_ENABLED;
+      p->transinfo[i].user_width = MSG_EXT_WDTR_BUS_16_BIT;
+      p->needwdtr_copy |= mask;
     }
     else
     {
-      p->flags &= ~AHC_BIOS_ENABLED;
-      p->flags |= AHC_USEDEFAULTS;
+      p->transinfo[i].user_width = MSG_EXT_WDTR_BUS_8_BIT;
+      p->needwdtr_copy &= ~mask;
     }
+    p->transinfo[i].cur_width =
+      (aic_inb(p, TARG_SCSIRATE + i) & WIDEXFER) ?
+      MSG_EXT_WDTR_BUS_16_BIT : MSG_EXT_WDTR_BUS_8_BIT;
+  }
+  aic_outb(p, ~(p->discenable & 0xFF), DISC_DSB);
+  aic_outb(p, ~((p->discenable >> 8) & 0xFF), DISC_DSB + 1);
+  p->needwdtr = p->needwdtr_copy;
+  p->needsdtr = p->needsdtr_copy;
+  p->wdtr_pending = p->sdtr_pending = 0;
+
+  /*
+   * We set the p->ultraenb from the SEEPROM to begin with, but now we make
+   * it match what is already down in the card.  If we are doing a reset
+   * on the card then this will get put back to a default state anyway.
+   * This allows us to not have to pre-emptively negotiate when using the
+   * no_reset option.
+   */
+  if (p->features & AHC_ULTRA)
+    p->ultraenb = aic_inb(p, ULTRA_ENB) | (aic_inb(p, ULTRA_ENB + 1) << 8);
+
+  
+  scsi_conf = (p->scsi_id & HSCSIID);
+
+  if(have_seeprom)
+  {
+    p->adapter_control = sc->adapter_control;
+    p->bios_control = sc->bios_control;
 
-    if ((p->type & 0x1ff1) == AHC_AIC7895)
+    switch (p->chip & AHC_CHIPID_MASK)
     {
-      if (p->adapter_control & CFBPRIMARY)
-        p->flags |= AHC_CHANNEL_B_PRIMARY;
+      case AHC_AIC7895:
+      case AHC_AIC7896:
+        if (p->adapter_control & CFBPRIMARY)
+          p->flags |= AHC_CHANNEL_B_PRIMARY;
+      default:
+        break;
     }
 
-    scsi_conf = (p->scsi_id & 0x7);
     if (sc->adapter_control & CFSPARITY)
       scsi_conf |= ENSPCHK;
-    /*
-     * 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)
-      scsi_conf |= RESET_SCSI;
-    /*
-     * 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;
+  }
+  else
+  {
+    scsi_conf |= ENSPCHK | RESET_SCSI;
+  }
 
+  /*
+   * Only set the SCSICONF and SCSICONF + 1 registers if we are a PCI card.
+   * The 2842 and 2742 cards already have these registers set and we don't
+   * want to muck with them since we don't set all the bits they do.
+   */
+  if ( (p->chip & ~AHC_CHIPID_MASK) == AHC_PCI )
+  {
     /* Set the host ID */
     aic_outb(p, scsi_conf, SCSICONF);
     /* In case we are a wide card */
     aic_outb(p, p->scsi_id, SCSICONF + 1);
-
-    if ((p->type & AHC_AIC7860) == AHC_AIC7860)
-    {
-      if ( aic_inb(p, SPIOCAP) & SSPIOCPS )
-      /*
-       * Update the settings in sxfrctl1 to match the termination
-       * settings.
-       */
-        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);
 }
 
 /*+F*************************************************************************
@@ -7130,7 +8495,7 @@ aic7xxx_detect(Scsi_Host_Template *template)
   struct aic7xxx_host *list_p = NULL;
   int found = 0;
   ahc_flag_type flags = 0;
-  ahc_type type;
+  int type;
   unsigned char sxfrctl1;
 #if defined(__i386__) || defined(__alpha__)
   unsigned char hcntrl, hostconf;
@@ -7164,7 +8529,7 @@ aic7xxx_detect(Scsi_Host_Template *template)
    * EISA/VL-bus card signature probe.
    */
   slot = MINSLOT;
-  while (slot <= MAXSLOT)
+  while ( (slot <= MAXSLOT) && !(aic7xxx_no_probe) )
   {
     base = SLOTBASE(slot) + MINREG;
 
@@ -7178,27 +8543,11 @@ aic7xxx_detect(Scsi_Host_Template *template)
       continue; /* back to the beginning of the for loop */
     }
     flags = 0;
-    type = aic7xxx_probe(slot, base + HID0, &flags);
-    switch (type)
+    type = aic7xxx_probe(slot, base + AHC_HID0, &flags);
+    if (type == -1)
     {
-      case AHC_AIC7770:
-        if (aic7xxx_verbose & VERBOSE_PROBE2)
-          printk("aic7xxx: <%s> at EISA %d\n",
-               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[4], slot);
-        break;
-      default:
-        slot++;
-        continue; /* back to the beginning of the while loop */
+      slot++;
+      continue;
     }
     temp_p = kmalloc(sizeof(struct aic7xxx_host), GFP_ATOMIC);
     if (temp_p == NULL)
@@ -7221,8 +8570,6 @@ aic7xxx_detect(Scsi_Host_Template *template)
     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;
@@ -7233,6 +8580,8 @@ aic7xxx_detect(Scsi_Host_Template *template)
       temp_p->irq = 0;
     else
       temp_p->irq = aic_inb(temp_p, INTDEF) & 0x0F;
+    temp_p->flags |= AHC_PAGESCBS;
+
     switch (temp_p->irq)
     {
       case 9:
@@ -7255,6 +8604,7 @@ aic7xxx_detect(Scsi_Host_Template *template)
      * 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
      */
@@ -7276,12 +8626,18 @@ aic7xxx_detect(Scsi_Host_Template *template)
         temp_p->flags |= AHC_EXTEND_TRANS_B;
     }
 
-    switch (temp_p->type & 0x1ff1)
+    switch (type)
     {
-      case AHC_AIC7770:
+      case 0:
         temp_p->board_name_index = 2;
-      case AHC_274:
+        if (aic7xxx_verbose & VERBOSE_PROBE2)
+          printk("aic7xxx: <%s> at EISA %d\n",
+               board_names[2], slot);
+        /* FALLTHROUGH */
+      case 1:
       {
+        temp_p->chip = AHC_AIC7770 | AHC_EISA;
+        temp_p->features |= AHC_AIC7770_FE;
         temp_p->bios_control = aic_inb(temp_p, HA_274_BIOSCTRL);
 
         /*
@@ -7290,7 +8646,12 @@ aic7xxx_detect(Scsi_Host_Template *template)
          * the mid-level SCSI code which channel is primary.
          */
         if (temp_p->board_name_index == 0)
+        {
           temp_p->board_name_index = 3;
+          if (aic7xxx_verbose & VERBOSE_PROBE2)
+            printk("aic7xxx: <%s> at EISA %d\n",
+                 board_names[3], slot);
+        }
         if (temp_p->bios_control & CHANNEL_B_PRIMARY)
         {
           temp_p->flags |= AHC_CHANNEL_B_PRIMARY;
@@ -7298,7 +8659,6 @@ aic7xxx_detect(Scsi_Host_Template *template)
 
         if ((temp_p->bios_control & BIOSMODE) == BIOSDISABLED)
         {
-          temp_p->flags |= AHC_USEDEFAULTS;
           temp_p->flags &= ~AHC_BIOS_ENABLED;
         }
         else
@@ -7307,79 +8667,46 @@ aic7xxx_detect(Scsi_Host_Template *template)
           temp_p->flags |= AHC_BIOS_ENABLED;
           if ( (temp_p->bios_control & 0x20) == 0 )
           {
-            switch(temp_p->bios_control & 0x07)
-            {
-              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 */
-            }
+            temp_p->bios_address = 0xcc000;
+            temp_p->bios_address += (0x4000 * (temp_p->bios_control & 0x07));
           }
           else
           {
-            switch(temp_p->bios_control & 0x06)
-            {
-              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 */
-            }
+            temp_p->bios_address = 0xd0000;
+            temp_p->bios_address += (0x8000 * (temp_p->bios_control & 0x06));
           }
         }
         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)
+        if (temp_p->features & AHC_WIDE)
         {
-          temp_p->scsi_id = temp_p->scsi_id_b = 7;
-          temp_p->flags |= AHC_TERM_ENB_A | AHC_TERM_ENB_B;
+          temp_p->scsi_id = temp_p->adapter_control & HWSCSIID;
+          temp_p->scsi_id_b = temp_p->scsi_id;
         }
         else
         {
-          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;
         }
+        aic7xxx_load_seeprom(temp_p, &sxfrctl1);
         break;
       }
 
-      case AHC_284:
-        load_seeprom(temp_p, &sxfrctl1);
+      case 2:
+      case 3:
+        temp_p->chip = AHC_AIC7770 | AHC_VL;
+        temp_p->features |= AHC_AIC7770_FE;
+        if (type == 2)
+          temp_p->flags |= AHC_BIOS_ENABLED;
+        else
+          temp_p->flags &= ~AHC_BIOS_ENABLED;
+        if (aic_inb(temp_p, SCSICONF) & TERM_ENB)
+          sxfrctl1 = STPWEN;
+        aic7xxx_load_seeprom(temp_p, &sxfrctl1);
         temp_p->board_name_index = 4;
+        if (aic7xxx_verbose & VERBOSE_PROBE2)
+          printk("aic7xxx: <%s> at VLB %d\n",
+               board_names[2], slot);
         switch( aic_inb(temp_p, STATUS_2840) & BIOS_SEL )
         {
           case 0x00:
@@ -7438,42 +8765,84 @@ aic7xxx_detect(Scsi_Host_Template *template)
     {
       unsigned short      vendor_id;
       unsigned short      device_id;
-      ahc_type            type;
+      ahc_chip            chip;
       ahc_flag_type       flags;
+      ahc_feature         features;
       int                 board_name_index;
-    } const aic7xxx_pci_devices[] = {
+      unsigned short      seeprom_size;
+      unsigned short      seeprom_type;
+    } const aic_pdevs[] = {
       {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7810, AHC_NONE,
-       AHC_FNONE,                                            1 },
+       AHC_FNONE, AHC_FENONE,                                1,
+       32, C46 },
       {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7850, AHC_AIC7850,
-       AHC_PAGESCBS | AHC_USEDEFAULTS,                       5 },
+       AHC_PAGESCBS, AHC_AIC7850_FE,                         5,
+       32, C46 },
       {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7855, AHC_AIC7850,
-       AHC_PAGESCBS | AHC_USEDEFAULTS,                       6 },
+       AHC_PAGESCBS, AHC_AIC7850_FE,                         6,
+       32, C46 },
       {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 },
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+       AHC_AIC7860_FE,                                       7,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7861, AHC_AIC7860,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+       AHC_AIC7860_FE,                                       8,
+       32, C46 },
       {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 },
+       AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7870_FE,      9,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7871, AHC_AIC7870,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7870_FE,     10,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7872, AHC_AIC7870,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
+       AHC_AIC7870_FE,                                      11,
+       32, C56_66 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7873, AHC_AIC7870,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
+       AHC_AIC7870_FE,                                      12,
+       32, C56_66 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7874, AHC_AIC7870,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7870_FE,     13,
+       32, C46 },
       {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 },
+       AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE,     14,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7881, AHC_AIC7880,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE,     15,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7882, AHC_AIC7880,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
+       AHC_AIC7880_FE,                                      16,
+       32, C56_66 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7883, AHC_AIC7880,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
+       AHC_AIC7880_FE,                                      17,
+       32, C56_66 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7884, AHC_AIC7880,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE,     18,
+       32, C46 },
       {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7895, AHC_AIC7895,
-       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, 19 }
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
+       AHC_AIC7895_FE,                                      19,
+       32, C56_66 },
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7890, AHC_AIC7890,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+       AHC_AIC7890_FE,                                      20,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_2940U2, AHC_AIC7890,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+       AHC_AIC7890_FE,                                      21,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7896, AHC_AIC7896,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
+       AHC_AIC7896_FE,                                      22,
+       32, C56_66 },
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_3940U2, AHC_AIC7896,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
+       AHC_AIC7896_FE,                                      23,
+       32, C56_66 },
     };
 
     unsigned short command;
@@ -7481,7 +8850,6 @@ aic7xxx_detect(Scsi_Host_Template *template)
 #ifdef MMAPIO
     unsigned long page_offset, base;
 #endif
-    struct aic7xxx_host *first_7895 = NULL;
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
     struct pci_dev *pdev = NULL;
 #else
@@ -7490,17 +8858,17 @@ aic7xxx_detect(Scsi_Host_Template *template)
     unsigned char pci_bus, pci_devfn, pci_irq;
 #endif
 
-    for (i = 0; i < NUMBER(aic7xxx_pci_devices); i++)
+    for (i = 0; i < NUMBER(aic_pdevs); i++)
     {
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
       pdev = NULL;
-      while ((pdev = pci_find_device(aic7xxx_pci_devices[i].vendor_id,
-                                     aic7xxx_pci_devices[i].device_id,
+      while ((pdev = pci_find_device(aic_pdevs[i].vendor_id,
+                                     aic_pdevs[i].device_id,
                                      pdev)))
 #else
       index = 0;
-      while (!(pcibios_find_device(aic7xxx_pci_devices[i].vendor_id,
-                                   aic7xxx_pci_devices[i].device_id,
+      while (!(pcibios_find_device(aic_pdevs[i].vendor_id,
+                                   aic_pdevs[i].device_id,
                                    index++, &pci_bus, &pci_devfn)) )
 #endif
       {
@@ -7517,9 +8885,12 @@ aic7xxx_detect(Scsi_Host_Template *template)
                                     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;
+          temp_p->chip = aic_pdevs[i].chip | AHC_PCI;
+          temp_p->flags = aic_pdevs[i].flags;
+          temp_p->features = aic_pdevs[i].features;
+          temp_p->board_name_index = aic_pdevs[i].board_name_index;
+          temp_p->sc_size = aic_pdevs[i].seeprom_size;
+          temp_p->sc_type = aic_pdevs[i].seeprom_type;
 
           /*
            * Read sundry information from PCI BIOS.
@@ -7531,19 +8902,29 @@ aic7xxx_detect(Scsi_Host_Template *template)
           temp_p->pci_device_fn = pdev->devfn;
           temp_p->base = pdev->base_address[0];
           temp_p->mbase = pdev->base_address[1];
+          if (aic7xxx_verbose & VERBOSE_PROBE2)
+            printk("aic7xxx: <%s> at PCI %d/%d\n", 
+              board_names[aic_pdevs[i].board_name_index],
+              PCI_SLOT(temp_p->pdev->devfn),
+              PCI_FUNC(temp_p->pdev->devfn));
           pci_read_config_word(pdev, PCI_COMMAND, &command);
           if (aic7xxx_verbose & VERBOSE_PROBE2)
           {
             printk("aic7xxx: Initial PCI_COMMAND value was 0x%x\n",
               (int)command);
           }
+#ifdef AIC7XXX_STRICT_PCI_SETUP
           command |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY |
             PCI_COMMAND_INVALIDATE | PCI_COMMAND_MASTER |
             PCI_COMMAND_MEMORY | PCI_COMMAND_IO;
+#else
+          command |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO;
+#endif
           if (aic7xxx_pci_parity == 0)
             command &= ~(PCI_COMMAND_SERR | PCI_COMMAND_PARITY);
           pci_write_config_word(pdev, PCI_COMMAND, command);
-          pci_read_config_dword(pdev, PCI_COMMAND, &devconfig);
+#ifdef AIC7XXX_STRICT_PCI_SETUP
+          pci_read_config_dword(pdev, DEVCONFIG, &devconfig);
           if (aic7xxx_verbose & VERBOSE_PROBE2)
           {
             printk("aic7xxx: Initial DEVCONFIG value was 0x%x\n", devconfig);
@@ -7557,15 +8938,16 @@ aic7xxx_detect(Scsi_Host_Template *template)
           {
             devconfig |= 0x00000008;
           }
-          pci_write_config_dword(pdev, PCI_COMMAND, devconfig);
-          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->pdev->devfn),
-              PCI_FUNC(temp_p->pdev->devfn));
-#else
+          pci_write_config_dword(pdev, DEVCONFIG, devconfig);
+#endif /* AIC7XXX_STRICT_PCI_SETUP */
+#else  /* LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92) */
           temp_p->pci_bus = pci_bus;
           temp_p->pci_device_fn = pci_devfn;
+          if (aic7xxx_verbose & VERBOSE_PROBE2)
+            printk("aic7xxx: <%s> at PCI %d/%d\n", 
+              board_names[aic_pdevs[i].board_name_index],
+              PCI_SLOT(temp_p->pci_device_fn),
+              PCI_FUNC(temp_p->pci_device_fn));
           pcibios_read_config_byte(pci_bus, pci_devfn, PCI_INTERRUPT_LINE,
             &pci_irq);
           temp_p->irq = pci_irq;
@@ -7581,12 +8963,17 @@ aic7xxx_detect(Scsi_Host_Template *template)
             printk("aic7xxx: Initial PCI_COMMAND value was 0x%x\n",
               (int)command);
           }
+#ifdef AIC7XXX_STRICT_PCI_SETUP
           command |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY |
             PCI_COMMAND_INVALIDATE | PCI_COMMAND_MASTER |
             PCI_COMMAND_MEMORY | PCI_COMMAND_IO;
+#else
+          command |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO;
+#endif
           if (aic7xxx_pci_parity == 0)
             command &= ~(PCI_COMMAND_SERR | PCI_COMMAND_PARITY);
           pcibios_write_config_word(pci_bus, pci_devfn, PCI_COMMAND, command);
+#ifdef AIC7XXX_STRICT_PCI_SETUP
           pcibios_read_config_dword(pci_bus, pci_devfn, DEVCONFIG, &devconfig);
           if (aic7xxx_verbose & VERBOSE_PROBE2)
           {
@@ -7602,12 +8989,8 @@ aic7xxx_detect(Scsi_Host_Template *template)
             devconfig |= 0x00000008;
           }
           pcibios_write_config_dword(pci_bus, pci_devfn, DEVCONFIG, devconfig);
-          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));
-#endif
+#endif /* AIC7XXX_STRICT_PCI_SETUP */
+#endif /* LINUIX_VERSION_CODE > KERNEL_VERSION(2,1,92) */
 
           /*
            * The first bit (LSB) of PCI_BASE_ADDRESS_0 is always set, so
@@ -7615,49 +8998,24 @@ aic7xxx_detect(Scsi_Host_Template *template)
            */
           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->unpause = INTEN;
           temp_p->pause = temp_p->unpause | PAUSE;
 
 #ifdef MMAPIO
-          if((temp_p->type & AHC_AIC7850) != AHC_AIC7850)
-          {
-            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);
-             */
+          base = temp_p->mbase & PAGE_MASK;
+          page_offset = temp_p->mbase - base;
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
-            temp_p->maddr = ioremap(base, page_offset + 256);
+          temp_p->maddr = ioremap_nocache(base, page_offset + 256);
 #else
-            temp_p->maddr = vremap(base, page_offset + 256);
+          temp_p->maddr = vremap(base, page_offset + 256);
 #endif
-            if(temp_p->maddr)
-            {
-              temp_p->maddr += page_offset;
-            }
-          }
-          else
+          if(temp_p->maddr)
           {
-#ifdef __i386__
-            /*
-             * Resort to PIO mode on these controllers and Intel hardware.
-             * For other hardware we need to either disable these controllers
-             * or do without MMAPed IO.  However, for PPC, we can't do
-             * MMAPed IO (according to what I've heard) so we may be forced
-             * to just fail detection on those cards.
-             */
-            temp_p->maddr = NULL;
-#else
-            kfree(temp_p);
-            temp_p = NULL;
-            continue;
-#endif /* __i386__ */
+            temp_p->maddr += page_offset;
           }
 #endif
 
-          aic_outb(temp_p, temp_p->pause, HCNTRL);
-          while( (aic_inb(temp_p, HCNTRL) & PAUSE) == 0 ) ;
+          pause_sequencer(temp_p);
 
           /*
            * Clear out any pending PCI error status messages.  Also set
@@ -7674,7 +9032,10 @@ aic7xxx_detect(Scsi_Host_Template *template)
           /*
            * Remember how the card was setup in case there is no seeprom.
            */
-          temp_p->scsi_id = aic_inb(temp_p, SCSIID) & OID;
+          if (temp_p->features & AHC_ULTRA2)
+            temp_p->scsi_id = aic_inb(temp_p, SCSIID_ULTRA2) & OID;
+          else
+            temp_p->scsi_id = aic_inb(temp_p, SCSIID) & OID;
           /*
            * Get current termination setting
            */
@@ -7687,11 +9048,17 @@ aic7xxx_detect(Scsi_Host_Template *template)
             continue;
           }
 
-          switch (temp_p->type & 0x1ff1)
+          /*
+           * Doing a switch based upon i is really gross, but since Justin
+           * changed around the chip ID stuff, we can't use that any more.
+           * Since we don't scan the devices the same way as FreeBSD, we end
+           * up doing this gross hack in order to avoid totally splitting
+           * away from Justin's init code in ahc_pci.c
+           */
+          switch (i)
           {
-            case AHC_394:   /* 3940 */
-            case AHC_394U:  /* 3940-Ultra */
-              temp_p->flags |= AHC_MULTI_CHANNEL;
+            case 7:   /* 3940 */
+            case 12:  /* 3940-Ultra */
               switch(PCI_SLOT(temp_p->pci_device_fn))
               {
                 case 5:
@@ -7702,9 +9069,8 @@ aic7xxx_detect(Scsi_Host_Template *template)
               }
               break;
 
-            case AHC_398:   /* 3985 */
-            case AHC_398U:  /* 3985-Ultra */
-              temp_p->flags |= AHC_MULTI_CHANNEL;
+            case 8:   /* 3985 */
+            case 13:  /* 3985-Ultra */
               switch(PCI_SLOT(temp_p->pci_device_fn))
               {
                 case 8:
@@ -7718,54 +9084,44 @@ aic7xxx_detect(Scsi_Host_Template *template)
               }
               break;
 
-            case AHC_AIC7895:
-              temp_p->flags |= AHC_MULTI_CHANNEL;
+            case 15:
+            case 18:
+            case 19:
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
               if (PCI_FUNC(temp_p->pdev->devfn) != 0)
               {
                 temp_p->flags |= AHC_CHNLB;
               }
-              pci_read_config_dword(pdev, DEVCONFIG, &devconfig);
-              devconfig = le32_to_cpu(devconfig);
-              devconfig |= SCBSIZE32;
-              devconfig = cpu_to_le32(devconfig);
-              pci_write_config_dword(pdev, DEVCONFIG, devconfig);
+              /*
+               * The 7895 is the only chipset that sets the SCBSIZE32 param
+               * in the DEVCONFIG register.  The Ultra2 chipsets use
+               * the DSCOMMAND0 register instead.
+               */
+              if ((temp_p->chip & AHC_CHIPID_MASK) == AHC_AIC7895)
+              {
+                pci_read_config_dword(pdev, DEVCONFIG, &devconfig);
+                devconfig |= SCBSIZE32;
+                pci_write_config_dword(pdev, DEVCONFIG, devconfig);
+              }
 #else
               if (PCI_FUNC(temp_p->pci_device_fn) != 0)
               {
                 temp_p->flags |= AHC_CHNLB;
               }
-              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)
+              /*
+               * The 7895 is the only chipset that sets the SCBSIZE32 param
+               * in the DEVCONFIG register.  The Ultra2 chipsets use
+               * the DSCOMMAND0 register instead.
+               */
+              if ((temp_p->chip & AHC_CHIPID_MASK) == AHC_AIC7895)
               {
-                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;
-                }
+                pcibios_read_config_dword(pci_bus, pci_devfn, DEVCONFIG,
+                  &devconfig);
+                devconfig |= SCBSIZE32;
+                pcibios_write_config_dword(pci_bus, pci_devfn, DEVCONFIG,
+                  devconfig);
               }
+#endif
               break;
             default:
               break;
@@ -7777,21 +9133,74 @@ aic7xxx_detect(Scsi_Host_Template *template)
            * on 394x and 398x cards we'll end up reading the wrong settings
            * for channels B and C
            */
-          if ( !(load_seeprom(temp_p, &sxfrctl1)) )
+          switch (temp_p->chip & AHC_CHIPID_MASK)
           {
-            temp_p->flags |= AHC_USEDEFAULTS;
-            if (sxfrctl1 & STPWEN)
-              temp_p->flags |= AHC_TERM_ENB_A | AHC_TERM_ENB_B;
+            case AHC_AIC7890:
+            case AHC_AIC7896:
+              aic_outb(temp_p, 0, SCAMCTL);
+              /*
+               * We used to set DPARCKEN in this register, but after talking
+               * to a tech from Adaptec, I found out they don't use that
+               * particular bit in their own register settings, and when you
+               * combine that with the fact that I determined that we were
+               * seeing Data-Path Parity Errors on things we shouldn't see
+               * them on, I think there is a bug in the silicon and the way
+               * to work around it is to disable this particular check.  Also
+               * This bug only showed up on certain commands, so it seems to
+               * be pattern related or some such.  The commands we would
+               * typically send as a linux TEST_UNIT_READY or INQUIRY command
+               * could cause it to be triggered, while regular commands that
+               * actually made reasonable use of the SG array capabilities
+               * seemed not to cause the problem.
+               */
+              /*
+              aic_outb(temp_p, aic_inb(temp_p, DSCOMMAND0) |
+                               CACHETHEN | DPARCKEN | MPARCKEN |
+                               USCBSIZE32 | CIOPARCKEN,
+                               DSCOMMAND0);
+               */
+              aic_outb(temp_p, (aic_inb(temp_p, DSCOMMAND0) |
+                                CACHETHEN | MPARCKEN | USCBSIZE32 |
+                                CIOPARCKEN) & ~DPARCKEN, DSCOMMAND0);
+              /* FALLTHROUGH */
+            default:
+              /*
+               * We attempt to read a SEEPROM on *everything*.  If we fail,
+               * then we fail, but this covers things like 2910c cards that
+               * now have SEEPROMs with their 7856 chipset that we would
+               * otherwise ignore.  They still don't have a BIOS, but they
+               * have a SEEPROM that the SCSISelect utility on the Adaptec
+               * diskettes can configure.
+               */
+              aic7xxx_load_seeprom(temp_p, &sxfrctl1);
+              break;
+            case AHC_AIC7850:
+            case AHC_AIC7860:
+              /*
+               * Set the DSCOMMAND0 register on these cards different from
+               * on the 789x cards.  Also, read the SEEPROM as well.
+               */
+              aic_outb(temp_p, (aic_inb(temp_p, DSCOMMAND0) |
+                                CACHETHEN | MPARCKEN) & ~DPARCKEN,
+                       DSCOMMAND0);
+              aic7xxx_load_seeprom(temp_p, &sxfrctl1);
+              break;
           }
+          
 
           /*
            * 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!!!
+           * controllers....Arrrgggghhh!!!  We also have to catch the fact
+           * that when you disable the BIOS on the 7895 on the Intel DK440LX
+           * motherboard, and possibly others, it only sets the BIOS disabled
+           * bit on the A channel...I think I'm starting to lean towards
+           * going postal....
            */
-          switch(temp_p->type & 0x1ff1)
+          switch(temp_p->chip & AHC_CHIPID_MASK)
           {
             case AHC_AIC7895:
+            case AHC_AIC7896:
               current_p = list_p;
               while(current_p != NULL)
               {
@@ -7800,11 +9209,21 @@ aic7xxx_detect(Scsi_Host_Template *template)
                       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);
+                    temp_p->flags &= ~(AHC_BIOS_ENABLED|AHC_USEDEFAULTS);
+                    temp_p->flags |=
+                      (current_p->flags & (AHC_BIOS_ENABLED|AHC_USEDEFAULTS));
+                  }
                   else
+                  {
                     current_p->flags |=
                       (temp_p->flags & AHC_CHANNEL_B_PRIMARY);
+                    current_p->flags &= ~(AHC_BIOS_ENABLED|AHC_USEDEFAULTS);
+                    current_p->flags |=
+                      (temp_p->flags & (AHC_BIOS_ENABLED|AHC_USEDEFAULTS));
+                  }
                 }
                 current_p = current_p->next;
               }
@@ -7813,6 +9232,56 @@ aic7xxx_detect(Scsi_Host_Template *template)
               break;
           }
 
+          /*
+           * We do another switch based on i so that we can exclude all
+           * 3895 devices from the next option since the 3895 cards use
+           * shared external SCB RAM while all other cards have dedicated
+           * external SCB RAM per channel.  Also exclude the 7850 and
+           * 7860 based stuff since they can have garbage in the bit
+           * that indicates external RAM and get some of this stuff
+           * wrong as a result.
+           */
+          switch(temp_p->chip & AHC_CHIPID_MASK)
+          {
+            default:
+              break;
+            case AHC_AIC7895:
+            case AHC_AIC7896:
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
+              pci_read_config_dword(pdev, DEVCONFIG, &devconfig);
+#else
+              pcibios_read_config_dword(pci_bus, pci_devfn, DEVCONFIG,
+                                        &devconfig);
+#endif
+              if (temp_p->features & AHC_ULTRA2)
+              {
+                if (aic_inb(temp_p, DSCOMMAND0) & RAMPSM_ULTRA2)
+                {
+                  aic_outb(temp_p,
+                           aic_inb(temp_p, DSCOMMAND0) & ~SCBRAMSEL_ULTRA2,
+                           DSCOMMAND0);
+                  temp_p->flags |= AHC_EXTERNAL_SRAM;
+                  devconfig |= EXTSCBPEN;
+                }
+              }
+              else if (devconfig & RAMPSM)
+              {
+                devconfig &= ~SCBRAMSEL;
+                devconfig |= EXTSCBPEN;
+                temp_p->flags |= AHC_EXTERNAL_SRAM;
+              }
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
+              pci_write_config_dword(pdev, DEVCONFIG, devconfig);
+#else
+              pcibios_write_config_dword(pci_bus, pci_devfn, DEVCONFIG,
+                                         devconfig);
+#endif
+              if ( (temp_p->flags & AHC_EXTERNAL_SRAM) &&
+                   (temp_p->flags & AHC_CHNLB) )
+                aic_outb(temp_p, 1, CCSCBBADDR);
+              break;
+          }
+
           /*
            * Take the LED out of diagnostic mode
            */
@@ -7822,75 +9291,21 @@ aic7xxx_detect(Scsi_Host_Template *template)
 
           /*
            * We don't know where this is set in the SEEPROM or by the
-           * BIOS, so we default to 100%.
+           * BIOS, so we default to 100%.  On Ultra2 controllers, use 75%
+           * instead.
            */
-          aic_outb(temp_p, DFTHRSH_100, DSPCISTATUS);
-
-          if (temp_p->flags & AHC_USEDEFAULTS)
+          if (temp_p->features & AHC_ULTRA2)
           {
-            int j;
-            unsigned char k;
-            /*
-             * Default setup; should only be used if the adapter does
-             * not have a SEEPROM.
-             */
-            /*
-             * Check the target scratch area to see if someone set us
-             * up already.  We are previously set up if the scratch
-             * area contains something other than all zeroes and ones.
-             */
-            for (j = TARG_SCRATCH; j < 0x60; j++)
-            {
-              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 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))
-            {
-              temp_p->flags &= ~AHC_USEDEFAULTS;
-              if (aic7xxx_verbose & VERBOSE_PROBE2)
-              {
-                printk(KERN_INFO "aic7xxx: Using leftover BIOS values.\n");
-              }
-            }
-            else
-            {
-              /*
-               * 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;
-              temp_p->scsi_id = 7;
-            }
-            aic_outb(temp_p, (temp_p->scsi_id & HSCSIID) | ENSPCHK | RESET_SCSI,
-                 SCSICONF);
-            /* In case we are a wide card. */
-            aic_outb(temp_p, temp_p->scsi_id, SCSICONF + 1);
+            aic_outb(temp_p, RD_DFTHRSH_75 | WR_DFTHRSH_75, DFF_THRSH);
           }
-          else /* not using defaults */
+          else
           {
-            if (sxfrctl1 & STPWEN)
-              temp_p->flags |= AHC_TERM_ENB_A;
+            aic_outb(temp_p, DFTHRSH_100, DSPCISTATUS);
           }
 
           if (aic7xxx_extended)
             temp_p->flags |= AHC_EXTEND_TRANS_A;
 
-          /*
-           * Put our termination setting into sxfrctl1 now that the
-           * generic initialization is complete.
-           */
-          sxfrctl1 |= aic_inb(temp_p, SXFRCTL1);
-          aic_outb(temp_p, sxfrctl1, SXFRCTL1);
           if ( list_p == NULL )
           {
             list_p = current_p = temp_p;
@@ -7908,7 +9323,7 @@ aic7xxx_detect(Scsi_Host_Template *template)
         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]);
+            board_names[aic_pdevs[i].board_name_index]);
           printk(KERN_INFO "aic7xxx: Unable to allocate device memory, "
             "skipping.\n");
         }
@@ -7929,87 +9344,74 @@ aic7xxx_detect(Scsi_Host_Template *template)
    */
 
   {
-    struct aic7xxx_host *vlb_enab, *vlb_disab, *pci;
+    struct aic7xxx_host *sort_list[4] = { NULL, NULL, NULL, NULL };
+    struct aic7xxx_host *vlb, *pci;
     struct aic7xxx_host *prev_p;
     struct aic7xxx_host *p;
     unsigned char left;
 
-    prev_p = vlb_enab = vlb_disab = pci = NULL;
+    prev_p = vlb = pci = NULL;
 
     temp_p = list_p;
     while (temp_p != NULL)
     {
-      switch(temp_p->type)
+      switch(temp_p->chip & ~AHC_CHIPID_MASK)
       {
-        case AHC_AIC7770:
-        case AHC_274:
-        case AHC_284:
-          if (temp_p->flags & AHC_BIOS_ENABLED)
+        case AHC_EISA:
+        case AHC_VL:
+        {
+          p = temp_p;
+          if (p->flags & AHC_BIOS_ENABLED)
+            vlb = sort_list[0];
+          else
+            vlb = sort_list[2];
+
+          if (vlb == NULL)
           {
-            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;
-              }
-            }
+            vlb = temp_p;
+            temp_p = temp_p->next;
+            vlb->next = NULL;
           }
           else
           {
-            if (vlb_disab == NULL)
+            current_p = vlb;
+            prev_p = NULL;
+            while ( (current_p != NULL) &&
+                    (current_p->bios_address < temp_p->bios_address))
             {
-              vlb_disab = temp_p;
-              temp_p = temp_p->next;
-              vlb_disab->next = NULL;
+              prev_p = current_p;
+              current_p = current_p->next;
             }
-            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;
-              }
+            if (prev_p != NULL)
+            {
+              prev_p->next = temp_p;
+              temp_p = temp_p->next;
+              prev_p->next->next = current_p;
+            }
+            else
+            {
+              vlb = temp_p;
+              temp_p = temp_p->next;
+              vlb->next = current_p;
             }
           }
+          
+          if (p->flags & AHC_BIOS_ENABLED)
+            sort_list[0] = vlb;
+          else
+            sort_list[2] = vlb;
+          
           break;
+        }
         default:  /* All PCI controllers fall through to default */
+        {
+
+          p = temp_p;
+          if (p->flags & AHC_BIOS_ENABLED) 
+            pci = sort_list[1];
+          else
+            pci = sort_list[3];
+
           if (pci == NULL)
           {
             pci = temp_p;
@@ -8084,75 +9486,60 @@ aic7xxx_detect(Scsi_Host_Template *template)
               pci->next = current_p;
             }
           }
+
+          if (p->flags & AHC_BIOS_ENABLED)
+            sort_list[1] = pci;
+          else
+            sort_list[3] = pci;
+
           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);
-          scsi_unregister(p->host);
-        }
-      }
-      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);
-          scsi_unregister(p->host);
-        }
-      }
-      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)
+      int i;
+      
+      left = found;
+      for (i=0; i<NUMBER(sort_list); i++)
       {
-        p->instance = found - left;
-        if (aic7xxx_register(template, p, (--left)) == 0)
+        temp_p = sort_list[i];
+        while(temp_p != NULL)
         {
-          found--;
-          aic7xxx_free(p);
-          scsi_unregister(p->host);
+          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_release(p->host);
+              scsi_unregister(p->host);
+            }
+            else if (aic7xxx_dump_card)
+            {
+              pause_sequencer(p);
+              aic7xxx_print_card(p);
+              aic7xxx_print_scratch_ram(p);
+              unpause_sequencer(p, TRUE);
+            }
+          }
+          current_p = temp_p;
+          temp_p = (struct aic7xxx_host *)temp_p->next;
+          kfree(current_p);
         }
       }
-      current_p = temp_p;
-      temp_p = (struct aic7xxx_host *)temp_p->next;
-      kfree(current_p);
     }
   }
   return (found);
 }
 
+#ifdef AIC7XXX_FAKE_NEGOTIATION_CMDS
+
 /*+F*************************************************************************
  * Function:
  *   aic7xxx_negotiation_complete
@@ -8164,7 +9551,7 @@ aic7xxx_detect(Scsi_Host_Template *template)
 static void
 aic7xxx_negotiation_complete(Scsi_Cmnd *cmd)
 {
-  memset(&cmd->sense_buffer[0], 0, sizeof(cmd->sense_buffer));
+  return;
 }
 
 /*+F*************************************************************************
@@ -8204,10 +9591,19 @@ aic7xxx_build_negotiation_cmnd(struct aic7xxx_host *p, Scsi_Cmnd *old_cmd,
       cmd->underflow = 0;
       cmd->cmd_len = 6;
     }
+    /*
+     * Before sending this thing out, we also amke the cmd->next pointer
+     * point to the real command so we can stuff any possible SENSE data
+     * intp the real command instead of this fake command.  This has to be
+     * done each time the command is built, not just the first time, hence
+     * it's outside of the above if()...
+     */
+    p->dev_wdtr_cmnd[tindex]->next = old_cmd;
     aic7xxx_queue(p->dev_wdtr_cmnd[tindex], 
                   aic7xxx_negotiation_complete);
   }
-  else if ( (p->needsdtr & (1<<tindex)) && !(p->sdtr_pending & (1<<tindex)) )
+  else if ( (p->needsdtr & (1<<tindex)) && !(p->sdtr_pending & (1<<tindex)) &&
+            !(p->wdtr_pending & (1<<tindex)) )
   {
     if(p->dev_sdtr_cmnd[tindex] == NULL)
     {
@@ -8231,11 +9627,45 @@ aic7xxx_build_negotiation_cmnd(struct aic7xxx_host *p, Scsi_Cmnd *old_cmd,
       cmd->underflow = 0;
       cmd->cmd_len = 6;
     }
+    /*
+     * Before sending this thing out, we also amke the cmd->next pointer
+     * point to the real command so we can stuff any possible SENSE data
+     * intp the real command instead of this fake command.  This has to be
+     * done each time the command is built, not just the first time, hence
+     * it's outside of the above if()...
+     */
+    p->dev_sdtr_cmnd[tindex]->next = old_cmd;
     aic7xxx_queue(p->dev_sdtr_cmnd[tindex], 
                   aic7xxx_negotiation_complete);
   }
 }
 
+#endif
+
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_print_scb
+ *
+ * Description:
+ *   Dump the byte codes for an about to be sent SCB.
+ *-F*************************************************************************/
+static void
+aic7xxx_print_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
+{
+  int i;
+  unsigned char *x;  
+
+  x = (unsigned char *)&scb->hscb->control;
+
+  for(i=0; i<32; i++)
+  {
+    printk("%02x ", x[i]);
+  }
+  printk("\n");
+}
+#endif
+
 /*+F*************************************************************************
  * Function:
  *   aic7xxx_buildscb
@@ -8289,12 +9719,13 @@ aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
   }
   if (p->dev_flags[TARGET_INDEX(cmd)] & DEVICE_SCANNED)
   {
+#ifdef AIC7XXX_FAKE_NEGOTIATION_CMDS
     if ( (p->needwdtr & mask) && !(p->wdtr_pending & mask) )
     {
       if (cmd == p->dev_wdtr_cmnd[TARGET_INDEX(cmd)])
       {
         p->wdtr_pending |= mask;
-        scb->flags |= SCB_MSGOUT_WDTR_16BIT;
+        scb->flags |= SCB_MSGOUT_WDTR;
         hscb->control &= DISCENB;
         hscb->control |= MK_MESSAGE;
         scb->tag_action = 0;
@@ -8304,7 +9735,8 @@ aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
         aic7xxx_build_negotiation_cmnd(p, cmd, TARGET_INDEX(cmd));
       }
     }
-    if ( (p->needsdtr & mask) && !(p->sdtr_pending & mask) )
+    else if ( (p->needsdtr & mask) && !(p->sdtr_pending & mask) &&
+              !(p->wdtr_pending & mask) )
     {
       if (cmd == p->dev_sdtr_cmnd[TARGET_INDEX(cmd)])
       {
@@ -8319,6 +9751,36 @@ aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
         aic7xxx_build_negotiation_cmnd(p, cmd, TARGET_INDEX(cmd));
       }
     }
+#else
+    if ( (p->needwdtr & mask) && !(p->wdtr_pending & mask) &&
+         !(p->sdtr_pending & mask) && (cmd->lun == 0) )
+    {
+      p->wdtr_pending |= mask;
+      scb->flags |= SCB_MSGOUT_WDTR;
+      hscb->control &= DISCENB;
+      hscb->control |= MK_MESSAGE;
+      scb->tag_action = 0;
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+      if (aic7xxx_verbose > 0xffff)
+        printk(INFO_LEAD "Building WDTR command.\n", p->host_no,
+               CTL_OF_CMD(cmd));
+#endif
+    }
+    else if ( (p->needsdtr & mask) && !(p->wdtr_pending & mask) &&
+              !(p->sdtr_pending & mask) && (cmd->lun == 0) )
+    {
+      p->sdtr_pending |= mask;
+      scb->flags |= SCB_MSGOUT_SDTR;
+      hscb->control &= DISCENB;
+      hscb->control |= MK_MESSAGE;
+      scb->tag_action = 0;
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+      if (aic7xxx_verbose > 0xffff)
+        printk(INFO_LEAD "Building SDTR command.\n", p->host_no,
+               CTL_OF_CMD(cmd));
+#endif
+    }
+#endif
   }
   hscb->target_channel_lun = ((cmd->target << 4) & 0xF0) |
         ((cmd->channel & 0x01) << 3) | (cmd->lun & 0x07);
@@ -8351,19 +9813,26 @@ aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
 
     sg = (struct scatterlist *)cmd->request_buffer;
     scb->sg_length = 0;
+    /*
+     * Copy the segments into the SG array.  NOTE!!! - We used to
+     * have the first entry both in the data_pointer area and the first
+     * SG element.  That has changed somewhat.  We still have the first
+     * entry in both places, but now we download the address of
+     * scb->sg_list[1] instead of 0 to the sg pointer in the hscb.
+     */
     for (i = 0; i < cmd->use_sg; i++)
     {
       scb->sg_list[i].address = cpu_to_le32(VIRT_TO_BUS(sg[i].address));
       scb->sg_list[i].length = cpu_to_le32(sg[i].length);
       scb->sg_length += sg[i].length;
     }
-    hscb->SG_list_pointer = cpu_to_le32(VIRT_TO_BUS(scb->sg_list));
-    hscb->SG_segment_count = cmd->use_sg;
-    scb->sg_count = 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->sg_count = cmd->use_sg;
+    hscb->SG_segment_count = cmd->use_sg;
+    hscb->SG_list_pointer = cpu_to_le32(VIRT_TO_BUS(&scb->sg_list[1]));
+
   }
   else
   {
@@ -8388,6 +9857,12 @@ aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
       hscb->data_pointer = 0;
     }
   }
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+  if((cmd->cmnd[0] == TEST_UNIT_READY) && (aic7xxx_verbose & VERBOSE_PROBE2))
+  {
+    aic7xxx_print_scb(p, scb);
+  }
+#endif
 }
 
 /*+F*************************************************************************
@@ -8402,7 +9877,9 @@ aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
 {
   struct aic7xxx_host *p;
   struct aic7xxx_scb *scb;
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
   int tindex = TARGET_INDEX(cmd);
+#endif
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
   unsigned long cpu_flags = 0;
 #endif
@@ -8411,18 +9888,22 @@ aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
   /*
    * Check to see if channel was scanned.
    */
+  
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
   if (!(p->flags & AHC_A_SCANNED) && (cmd->channel == 0))
   {
-    printk(INFO_LEAD "Scanning channel for devices.\n",
-      p->host_no, 0, -1, -1);
+    if (aic7xxx_verbose & VERBOSE_PROBE2)
+      printk(INFO_LEAD "Scanning channel for devices.\n",
+        p->host_no, 0, -1, -1);
     p->flags |= AHC_A_SCANNED;
   }
   else
   {
     if (!(p->flags & AHC_B_SCANNED) && (cmd->channel == 1))
     {
-      printk(INFO_LEAD "Scanning channel for devices.\n",
-        p->host_no, 1, -1, -1);
+      if (aic7xxx_verbose & VERBOSE_PROBE2)
+        printk(INFO_LEAD "Scanning channel for devices.\n",
+          p->host_no, 1, -1, -1);
       p->flags |= AHC_B_SCANNED;
     }
   }
@@ -8436,12 +9917,25 @@ aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
     if ( p->dev_active_cmds[tindex] > 220 )
       p->dev_active_cmds[tindex] = 0;
   }
-  DRIVER_LOCK
-  scb = aic7xxx_allocate_scb(p, FALSE);
-  DRIVER_UNLOCK
+#endif
+
+  scb = scbq_remove_head(&p->scb_data->free_scbs);
+  if (scb == NULL)
+  {
+    DRIVER_LOCK
+    aic7xxx_allocate_scb(p);
+    DRIVER_UNLOCK
+    scb = scbq_remove_head(&p->scb_data->free_scbs);
+  }
   if (scb == NULL)
   {
-    panic("(scsi%d) aic7xxx_queue:Couldn't get a free SCB.\n", p->host_no);
+    printk(WARN_LEAD "Couldn't get a free SCB.\n", p->host_no,
+           CTL_OF_CMD(cmd));
+    cmd->result = (DID_BUS_BUSY << 16);
+    DRIVER_LOCK
+    aic7xxx_queue_cmd_complete(p, cmd);
+    DRIVER_UNLOCK
+    return 0;
   }
   else
   {
@@ -8460,23 +9954,16 @@ aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
      * the SCB to the sequencer and watch the fun begin.
      */
     cmd->scsi_done = fn;
+    cmd->result = DID_OK;
+    memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
     aic7xxx_error(cmd) = DID_OK;
     aic7xxx_status(cmd) = 0;
-    cmd->result = 0;
     cmd->host_scribble = NULL;
-    memset(&cmd->sense_buffer[0], 0, sizeof(cmd->sense_buffer));
 
     scb->flags |= SCB_ACTIVE | SCB_WAITINGQ;
 
     DRIVER_LOCK
-    if (p->delayed_scbs[tindex].head != NULL) 
-    {
-        scbq_insert_tail(&p->delayed_scbs[tindex], scb);
-    }
-    else
-    {
-        scbq_insert_tail(&p->waiting_scbs, scb);
-    }
+    scbq_insert_tail(&p->waiting_scbs, scb);
     if ( (p->flags & (AHC_IN_ISR | AHC_IN_ABORT | AHC_IN_RESET)) == 0)
     {
       aic7xxx_run_waiting_queues(p);
@@ -8664,7 +10151,10 @@ aic7xxx_bus_device_reset(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
       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);
+    if (p->features & AHC_QUEUE_REGS)
+      aic_outb(p, p->qinfifonext, HNSCB_QOFF);
+    else
+      aic_outb(p, p->qinfifonext, KERNEL_QINPOS);
     scb->flags |= SCB_QUEUED_ABORT;
     result = SCSI_RESET_PENDING;
   }
@@ -8685,30 +10175,142 @@ aic7xxx_bus_device_reset(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
  *   Abort the current SCSI command(s).
  *-F*************************************************************************/
 void
-aic7xxx_panic_abort(struct aic7xxx_host *p)
+aic7xxx_panic_abort(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
 {
-  int i;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0)
+  int i, mask, found, need_tag;
+  struct aic7xxx_scb *scb;
+  unsigned char qinpos, hscbp;
+
+  found = FALSE;
+#endif
 
-  printk("aic7xxx driver version %s\n", AIC7XXX_C_VERSION);
+  printk("aic7xxx driver version %s/%s\n", AIC7XXX_C_VERSION,
+         UTS_RELEASE);
   printk("Controller type:\n    %s\n", board_names[p->board_name_index]);
+  printk("p->flags=0x%x, p->chip=0x%x, p->features=0x%x, "
+         "sequencer %s paused\n",
+     p->flags, p->chip, p->features,
+    (aic_inb(p, HCNTRL) & PAUSE) ? "is" : "isn't" );
+  pause_sequencer(p);
+  disable_irq(p->irq);
+  aic7xxx_print_card(p);
+  aic7xxx_print_scratch_ram(p);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0)
   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",
+      mask = (0x01 << i);
+      printk(INFO_LEAD "dev_flags=0x%x, WDTR:%c/%c/%c, SDTR:%c/%c/%c,"
+             " q_depth=%d:%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->wdtr_pending & mask) ? 'Y' : 'N',
+        (p->needwdtr & mask) ? 'Y' : 'N',
+        (p->needwdtr_copy & mask) ? 'Y' : 'N',
+        (p->sdtr_pending & mask) ? 'Y' : 'N',
+        (p->needsdtr & mask) ? 'Y' : 'N',
+        (p->needsdtr_copy & mask) ? 'Y' : 'N',
+        p->dev_active_cmds[i],
         p->dev_max_queue_depth[i], p->dev_mid_level_queue_depth[i]);
+      printk(INFO_LEAD "targ_scsirate=0x%x", p->host_no, 0, i, 0,
+             aic_inb(p, TARG_SCSIRATE + i));
+      if (p->features & AHC_ULTRA2)
+        printk(", targ_offset=%d", aic_inb(p, TARG_OFFSET + i));
+      printk("\n");
     }
   }
-  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");
+  /*
+   * Search for this command and see if we can't track it down, it's the
+   * one causing the timeout.  Print out this command first, then all other
+   * active commands afterwords.
+   */
+  need_tag = -1;
+  if ( cmd )
+  {
+    scb = p->scb_data->scb_array[aic7xxx_position(cmd)];
+    if ( (scb->flags & SCB_ACTIVE) && (scb->cmd == cmd) )
+    {
+      printk("Timed out command is scb #%d:\n", scb->hscb->tag);
+      printk("Tag%d: flags=0x%x, control=0x%x, TCL=0x%x, %s\n", scb->hscb->tag,
+             scb->flags, scb->hscb->control, scb->hscb->target_channel_lun,
+             (scb->flags & SCB_WAITINGQ) ? "WAITINGQ" : "Sent" );
+      need_tag = scb->hscb->tag;
+      if (scb->flags & SCB_WAITINGQ) found=TRUE;
+    }
+  }
+  printk("QINFIFO: (TAG) ");
+  qinpos = aic_inb(p, QINPOS);
+  while ( qinpos != p->qinfifonext )
+  {
+    if (p->qinfifo[qinpos] == need_tag)
+      found=TRUE;
+    printk("%d ", p->qinfifo[qinpos++]);
+  }  
+  printk("\n");
+  printk("Current SCB: (SCBPTR/TAG/CONTROL) %d/%d/0x%x\n", aic_inb(p, SCBPTR),
+         aic_inb(p, SCB_TAG), aic_inb(p, SCB_CONTROL) );
+  if (aic_inb(p, SCB_TAG) == need_tag)  found=TRUE;
+  printk("WAITING_SCBS: (SCBPTR/TAG/CONTROL) %d->",
+         hscbp = aic_inb(p, WAITING_SCBH));
+  while (hscbp != SCB_LIST_NULL)
+  {
+    aic_outb(p, hscbp, SCBPTR);
+    printk("%d/%d/0x%x ", hscbp, aic_inb(p, SCB_TAG), aic_inb(p, SCB_CONTROL));
+    hscbp = aic_inb(p, SCB_NEXT);
+    if (aic_inb(p, SCB_TAG) == need_tag)  found=TRUE;
+  }
+  printk("\n");
+  printk("DISCONNECTED_SCBS: (SCBPTR/TAG/CONTROL) %d->",
+         hscbp = aic_inb(p, DISCONNECTED_SCBH));
+  while (hscbp != SCB_LIST_NULL)
+  {
+    aic_outb(p, hscbp, SCBPTR);
+    printk("%d/%d/0x%x ", hscbp, aic_inb(p, SCB_TAG), aic_inb(p, SCB_CONTROL));
+    hscbp = aic_inb(p, SCB_NEXT);
+    if (aic_inb(p, SCB_TAG) == need_tag)  found=TRUE;
+  }
+  printk("\n");
+  printk("FREE_SCBS: (SCBPTR/TAG/CONTROL) %d->",
+         hscbp = aic_inb(p, FREE_SCBH));
+  while (hscbp != SCB_LIST_NULL)
+  {
+    aic_outb(p, hscbp, SCBPTR);
+    printk("%d/%d/0x%x ", hscbp, aic_inb(p, SCB_TAG), aic_inb(p, SCB_CONTROL));
+    hscbp = aic_inb(p, SCB_NEXT);
+  }
+  printk("\n");
+
+  if (found == FALSE)
+  {
+    /*
+     * We haven't found the offending SCB yet, and it should be around
+     * somewhere, so go look for it in the cards SCBs.
+     */
+    printk("SCBPTR CONTROL TAG PREV NEXT\n");
+    for(i=0; i<p->scb_data->maxhscbs; i++)
+    {
+      aic_outb(p, i, SCBPTR);
+      printk("   %3d      %02x  %02x   %02x   %02x\n", i,
+             aic_inb(p, SCB_CONTROL), aic_inb(p, SCB_TAG),
+             aic_inb(p, SCB_PREV), aic_inb(p, SCB_NEXT));
+    }
+  }
+  
+
+  for (i=0; i < p->scb_data->numscbs; i++)
+  {
+    scb = p->scb_data->scb_array[i];
+    if ( (scb->flags & SCB_ACTIVE) && (scb->cmd != cmd) )
+    {
+      printk("Tag%d: flags=0x%x, control=0x%x, TCL=0x%x, %s\n", scb->hscb->tag,
+             scb->flags, scb->hscb->control, scb->hscb->target_channel_lun,
+             (scb->flags & SCB_WAITINGQ) ? "WAITINGQ" : "Sent" );
+    }
+  }
+#endif
+  sti();
+  for(;;) barrier();
 }
 
 /*+F*************************************************************************
@@ -8742,7 +10344,7 @@ aic7xxx_abort(Scsi_Cmnd *cmd)
    * code.
    */
   if (aic7xxx_panic_on_abort)
-    aic7xxx_panic_abort(p);
+    aic7xxx_panic_abort(p, cmd);
 
   DRIVER_LOCK
 
@@ -8797,7 +10399,7 @@ aic7xxx_abort(Scsi_Cmnd *cmd)
           p->completeq.head = (Scsi_Cmnd *)cmd_next->host_scribble;
         else
           cmd_prev->host_scribble = cmd_next->host_scribble;
-        cmd_next->done(cmd_next);
+        cmd_next->scsi_done(cmd_next);
         unpause_sequencer(p, FALSE);
         DRIVER_UNLOCK
         return(SCSI_ABORT_NOT_RUNNING); /* It's already back as a successful
@@ -8821,7 +10423,12 @@ aic7xxx_abort(Scsi_Cmnd *cmd)
  *     command held by the scb pointer and is a valid abort request.
  *   Now, we just have to figure out what to do from here.  Current plan is:
  *     if we have already been here on this command, escalate to a reset
- *     if scb is on waiting list or QINFIFO, send it back as aborted
+ *     if scb is on waiting list or QINFIFO, send it back as aborted, but
+ *       we also need to be aware of the possibility that we could be using
+ *       a faked negotiation command that is holding this command up,  if
+ *       so we need to take care of that command instead, which means we
+ *       would then treat this one like it was sitting around disconnected
+ *       instead.
  *     if scb is on WAITING_SCB list in sequencer, free scb and send back
  *     if scb is disconnected and not completed, abort with abort message
  *     if scb is currently running, then it may be causing the bus to hang
@@ -8901,18 +10508,55 @@ aic7xxx_abort(Scsi_Cmnd *cmd)
 
   if ((found == 0) && (scb->flags & SCB_WAITINGQ))
   {
-      int tindex = TARGET_INDEX(cmd);
-     
-      if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS) 
-        printk(INFO_LEAD "SCB found on waiting list and "
-            "aborted.\n", p->host_no, CTL_OF_SCB(scb));
-      scbq_remove(&p->waiting_scbs, scb);
-      scbq_remove(&p->delayed_scbs[tindex], scb);
-      p->dev_active_cmds[tindex]++;
-      p->activescbs++;
-      scb->flags &= ~(SCB_WAITINGQ | SCB_ACTIVE);
-      scb->flags |= SCB_ABORT | SCB_QUEUED_FOR_DONE;
+    int tindex = TARGET_INDEX(cmd);
+#ifdef AIC7XXX_FAKE_NEGOTIATION_CMDS
+    unsigned short mask;
+
+    mask = (1 << tindex);
+
+    if (p->wdtr_pending & mask)
+    {
+      if (p->dev_wdtr_cmnd[tindex]->next != cmd)
+        found = 1;
+      else
+        found = 0;
+    }
+    else if (p->sdtr_pending & mask)
+    {
+      if (p->dev_sdtr_cmnd[tindex]->next != cmd)
+        found = 1;
+      else
+        found = 0;
+    }
+    else
+    {
       found = 1;
+    }
+    if (found == 0)
+    {
+      /*
+       * OK..this means the command we are currently getting an abort
+       * for has an outstanding negotiation command in front of it.
+       * We don't really have a way to tie back into the negotiation
+       * commands, so we just send this back as pending, then it
+       * will get reset in 2 seconds.
+       */
+      unpause_sequencer(p, TRUE);
+      scb->flags |= SCB_ABORT;
+      DRIVER_UNLOCK
+      return(SCSI_ABORT_PENDING);
+    }
+#endif
+    if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS) 
+      printk(INFO_LEAD "SCB found on waiting list and "
+          "aborted.\n", p->host_no, CTL_OF_SCB(scb));
+    scbq_remove(&p->waiting_scbs, scb);
+    scbq_remove(&p->delayed_scbs[tindex], scb);
+    p->dev_active_cmds[tindex]++;
+    p->activescbs++;
+    scb->flags &= ~(SCB_WAITINGQ | SCB_ACTIVE);
+    scb->flags |= SCB_ABORT | SCB_QUEUED_FOR_DONE;
+    found = 1;
   }
 
 /*
@@ -9005,7 +10649,10 @@ aic7xxx_abort(Scsi_Cmnd *cmd)
       printk(INFO_LEAD "SCB disconnected.  Queueing Abort"
         " SCB.\n", p->host_no, CTL_OF_SCB(scb));
     p->qinfifo[p->qinfifonext++] = scb->hscb->tag;
-    aic_outb(p, p->qinfifonext, KERNEL_QINPOS);
+    if (p->features & AHC_QUEUE_REGS)
+      aic_outb(p, p->qinfifonext, HNSCB_QOFF);
+    else
+      aic_outb(p, p->qinfifonext, KERNEL_QINPOS);
   }
   if (found)
   {
@@ -9082,7 +10729,7 @@ aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags)
    * code.
    */
   if (aic7xxx_panic_on_abort)
-    aic7xxx_panic_abort(p);
+    aic7xxx_panic_abort(p, cmd);
 
   DRIVER_LOCK
 
@@ -9202,7 +10849,7 @@ aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags)
         "other action has failed.\n", p->host_no, CTL_OF_CMD(cmd));
     action = BUS_RESET;
   }
-  if ( (action & BUS_RESET) && !(p->type & AHC_TWIN) )
+  if ( (action & BUS_RESET) && !(p->features & AHC_TWIN) )
   {
     action = HOST_RESET;
   }
@@ -9269,16 +10916,11 @@ aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags)
       p->reset_start = jiffies;
       p->flags |= AHC_IN_RESET;
       aic7xxx_reset_channel(p, cmd->channel, TRUE);
-      if ( (p->type & AHC_TWIN) && (action & HOST_RESET) )
+      if ( (p->features & AHC_TWIN) && (action & HOST_RESET) )
       {
         aic7xxx_reset_channel(p, cmd->channel ^ 0x01, TRUE);
         restart_sequencer(p);
       }
-      if (scb == NULL)
-      {
-        cmd->result = DID_RESET << 16;
-        cmd->done(cmd);
-      }
       p->last_reset = jiffies;
       if (action != HOST_RESET)
         result = SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET;
@@ -9391,6 +11033,207 @@ aic7xxx_release(struct Scsi_Host *host)
   return(0);
 }
 
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_print_card
+ *
+ * Description:
+ *   Print out all of the control registers on the card
+ *
+ *   NOTE: This function is not yet safe for use on the VLB and EISA
+ *   controllers, so it isn't used on those controllers at all.
+ *-F*************************************************************************/
+static void
+aic7xxx_print_card(struct aic7xxx_host *p)
+{
+  int i, j, k, chip;
+  static struct register_ranges {
+    int num_ranges;
+    int range_val[32];
+  } cards_ds[] = {
+    { 0, {0,} }, /* none */
+    {10, {0x00, 0x05, 0x08, 0x11, 0x18, 0x19, 0x1f, 0x1f, 0x60, 0x60, /*7771*/
+          0x62, 0x66, 0x80, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9b, 0x9f} },
+    { 9, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1f, 0x60, 0x60, 0x62, 0x66, /*7850*/
+          0x80, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9f} },
+    { 9, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1f, 0x60, 0x60, 0x62, 0x66, /*7860*/
+          0x80, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9f} },
+    {10, {0x00, 0x05, 0x08, 0x11, 0x18, 0x19, 0x1c, 0x1f, 0x60, 0x60, /*7870*/
+          0x62, 0x66, 0x80, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9f} },
+    {10, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1a, 0x1c, 0x1f, 0x60, 0x60, /*7880*/
+          0x62, 0x66, 0x80, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9f} },
+    {16, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1f, 0x60, 0x60, 0x62, 0x66, /*7890*/
+          0x84, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9a, 0x9f, 0x9f,
+          0xe0, 0xf1, 0xf4, 0xf4, 0xf6, 0xf6, 0xf8, 0xf8, 0xfa, 0xfc,
+          0xfe, 0xff} },
+    {12, {0x00, 0x05, 0x08, 0x11, 0x18, 0x19, 0x1b, 0x1f, 0x60, 0x60, /*7895*/
+          0x62, 0x66, 0x80, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9a,
+          0x9f, 0x9f, 0xe0, 0xf1} },
+    {16, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1f, 0x60, 0x60, 0x62, 0x66, /*7896*/
+          0x84, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9a, 0x9f, 0x9f,
+          0xe0, 0xf1, 0xf4, 0xf4, 0xf6, 0xf6, 0xf8, 0xf8, 0xfa, 0xfc,
+          0xfe, 0xff} },
+  };
+#ifdef CONFIG_PCI
+  static struct register_ranges cards_ns[] = {
+    { 0, {0,} }, /* none */
+    { 0, {0,} }, /* 7771 */
+    { 7, {0x04, 0x08, 0x0c, 0x0e, 0x10, 0x17, 0x28, 0x2b, 0x30, 0x33,
+          0x3c, 0x41, 0x43, 0x47} },
+    { 7, {0x04, 0x08, 0x0c, 0x0e, 0x10, 0x17, 0x28, 0x2b, 0x30, 0x33,
+          0x3c, 0x41, 0x43, 0x47} },
+    { 5, {0x04, 0x08, 0x0c, 0x0e, 0x10, 0x17, 0x30, 0x33, 0x3c, 0x41} },
+    { 5, {0x04, 0x08, 0x0c, 0x0e, 0x10, 0x17, 0x30, 0x34, 0x3c, 0x47} },
+    { 5, {0x04, 0x08, 0x0c, 0x1b, 0x30, 0x34, 0x3c, 0x43, 0xdc, 0xe3} },
+    { 6, {0x04, 0x08, 0x0c, 0x0e, 0x10, 0x17, 0x30, 0x34, 0x3c, 0x47,
+          0xdc, 0xe3} },
+    { 6, {0x04, 0x08, 0x0c, 0x1b, 0x30, 0x34, 0x3c, 0x43, 0xdc, 0xe3,
+          0xff, 0xff} }
+  };
+#endif
+  chip = p->chip & AHC_CHIPID_MASK;
+  /*
+   * Let's run through the PCI space first....
+   */
+  printk("%s at ",
+         board_names[p->board_name_index]);
+  switch(p->chip & ~AHC_CHIPID_MASK)
+  {
+    case AHC_VL:
+      printk("VLB Slot %d.\n", p->pci_device_fn);
+      break;
+    case AHC_EISA:
+      printk("EISA Slot %d.\n", p->pci_device_fn);
+      break;
+    case AHC_PCI:
+    default:
+      printk("PCI %d/%d.\n", PCI_SLOT(p->pci_device_fn),
+             PCI_FUNC(p->pci_device_fn));
+      break;
+  }
+
+#ifdef CONFIG_PCI
+  {
+    unsigned char temp;
+    
+    printk("PCI Dump:\n");
+    k=0;
+    for(i=0; i<cards_ns[chip].num_ranges; i++)
+    {
+      for(j  = cards_ns[chip].range_val[ i * 2 ];
+          j <= cards_ns[chip].range_val[ i * 2 + 1 ] ;
+          j++)
+      {
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
+        pci_read_config_byte(p->pdev, j, &temp);
+#else
+        pcibios_read_config_byte(p->pci_bus, p->pci_device_fn, j, &temp);
+#endif
+        printk("%02x:%02x ", j, temp);
+        if(++k == 13)
+        {
+          printk("\n");
+          k = 0;
+        }
+      }
+    }
+  }
+  if(k != 0)
+    printk("\n");
+#endif /* CONFIG_PCI */
+
+  /*
+   * Now the registers on the card....
+   */
+  printk("Card Dump:\n");
+  k = 0;
+  for(i=0; i<cards_ds[chip].num_ranges; i++)
+  {
+    for(j  = cards_ds[chip].range_val[ i * 2 ];
+        j <= cards_ds[chip].range_val[ i * 2 + 1 ] ;
+        j++)
+    {
+      printk("%02x:%02x ", j, aic_inb(p, j));
+      if(++k == 13)
+      {
+        printk("\n");
+        k=0;
+      }
+    }
+  }
+  if(k != 0)
+    printk("\n");
+  if (p->flags & AHC_SEEPROM_FOUND)
+  {
+    unsigned short *sc1;
+    sc1 = (unsigned short *)&p->sc;
+    
+    printk("SEEPROM dump.\n");
+    for(i=1; i<=32; i++)
+    {
+      printk("0x%04x", sc1[i-1]);
+      if ( (i % 8) == 0 )
+        printk("\n");
+      else
+        printk("  ");
+    }
+  }
+
+  /*
+   * If this was an Ultra2 controller, then we just hosed the card in terms
+   * of the QUEUE REGS.  This function is only called at init time or by
+   * the panic_abort function, so it's safe to assume a generic init time
+   * setting here
+   */
+
+  if(p->features & AHC_QUEUE_REGS)
+  {
+    aic_outb(p, 0, SDSCB_QOFF);
+    aic_outb(p, 0, SNSCB_QOFF);
+    aic_outb(p, 0, HNSCB_QOFF);
+  }
+
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_print_scratch_ram
+ *
+ * Description:
+ *   Print out the scratch RAM values on the card.
+ *-F*************************************************************************/
+static void
+aic7xxx_print_scratch_ram(struct aic7xxx_host *p)
+{
+  int i, k;
+
+  k = 0;
+  printk("Scratch RAM:\n");
+  for(i = SRAM_BASE; i < SEQCTL; i++)
+  {
+    printk("%02x:%02x ", i, aic_inb(p, i));
+    if(++k == 13)
+    {
+      printk("\n");
+      k=0;
+    }
+  }
+  if (p->features & AHC_MORE_SRAM)
+  {
+    for(i = TARG_OFFSET; i < 0x80; i++)
+    {
+      printk("%02x:%02x ", i, aic_inb(p, i));
+      if(++k == 13)
+      {
+        printk("\n");
+        k=0;
+      }
+    }
+  }
+  printk("\n");
+}
+
+
 #include "aic7xxx_proc.c"
 
 #ifdef MODULE
index 6dffebc8bf1cf20ede945c18ce04d7847ed633d6..7cb4dbaa379190af3f3dc736469647af6aecd9e8 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Aic7xxx register and scratch ram definitions.
  *
- * Copyright (c) 1994-1997 Justin Gibbs.
+ * Copyright (c) 1994-1998 Justin Gibbs.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -161,6 +161,7 @@ register SCSIRATE {
        access_mode RW
        bit     WIDEXFER        0x80            /* Wide transfer control */
        mask    SXFR            0x70            /* Sync transfer rate */
+       mask    SXFR_ULTRA2     0x7f            /* Sync transfer rate */
        mask    SOFS            0x0f            /* Sync offset */
 }
 
@@ -174,6 +175,13 @@ register SCSIID    {
        access_mode RW
        mask    TID             0xf0            /* Target ID mask */
        mask    OID             0x0f            /* Our ID mask */
+       /*
+        * SCSI Maximum Offset (p. 4-61 aic7890/91 Data Book)
+        * The aic7890/91 allow an offset of up to 127 transfers in both wide
+        * and narrow mode.
+        */
+       alias   SCSIOFFSET
+       mask    SOFS_ULTRA2     0x7f            /* Sync offset U2 chips */
 }
 
 /*
@@ -227,14 +235,15 @@ register CLRSINT0 {
 register SSTAT0        {
        address                 0x00b
        access_mode RO
-       bit     TARGET          0x80            /* Board acting as target */
-       bit     SELDO           0x40            /* Selection Done */
-       bit     SELDI           0x20            /* Board has been selected */
-       bit     SELINGO         0x10            /* Selection In Progress */
-       bit     SWRAP           0x08            /* 24bit counter wrap */
-       bit     SDONE           0x04            /* STCNT = 0x000000 */
-       bit     SPIORDY         0x02            /* SCSI PIO Ready */
-       bit     DMADONE         0x01            /* DMA transfer completed */
+       bit     TARGET          0x80    /* Board acting as target */
+       bit     SELDO           0x40    /* Selection Done */
+       bit     SELDI           0x20    /* Board has been selected */
+       bit     SELINGO         0x10    /* Selection In Progress */
+       bit     SWRAP           0x08    /* 24bit counter wrap */
+       bit     IOERR           0x08    /* LVD Tranceiver mode changed */
+       bit     SDONE           0x04    /* STCNT = 0x000000 */
+       bit     SPIORDY         0x02    /* SCSI PIO Ready */
+       bit     DMADONE         0x01    /* DMA transfer completed */
 }
 
 /*
@@ -276,6 +285,7 @@ register SSTAT2 {
        address                 0x00d
        access_mode RO
        bit     OVERRUN         0x80
+       bit     EXP_ACTIVE      0x10    /* SCSI Expander Active */
        mask    SFCNT           0x1f
 }
 
@@ -290,14 +300,13 @@ register SSTAT3 {
 }
 
 /*
- * SCSI Test Control (p. 3-27)
+ * SCSI ID for the aic7890/91 chips
  */
-register SCSITEST {
+register SCSIID_ULTRA2 {
        address                 0x00f
        access_mode RW
-       bit     RQAKCNT         0x04
-       bit     CNTRTEST        0x02
-       bit     CMODE           0x01
+       mask    TID             0xf0            /* Target ID mask */
+       mask    OID             0x0f            /* Our ID mask */
 }
 
 /*
@@ -312,6 +321,7 @@ register SIMODE0 {
        bit     ENSELDI         0x20
        bit     ENSELINGO       0x10
        bit     ENSWRAP         0x08
+       bit     ENIOERR         0x08    /* LVD Tranceiver mode changes */
        bit     ENSDONE         0x04
        bit     ENSPIORDY       0x02
        bit     ENDMADONE       0x01
@@ -424,7 +434,10 @@ register SBLKCTL {
        bit     DIAGLEDON       0x40    /* Aic78X0 only */
        bit     AUTOFLUSHDIS    0x20
        bit     SELBUSB         0x08
+       bit     ENAB40          0x08    /* LVD transceiver active */
+       bit     ENAB20          0x04    /* SE/HVD transceiver active */
        bit     SELWIDE         0x02
+       bit     XCVR            0x01    /* External transceiver active */
 }
 
 /*
@@ -547,6 +560,19 @@ register BCTL {
        bit     ENABLE          0x01
 }
 
+register DSCOMMAND0 {
+       address                 0x084
+       access_mode RW
+       bit     CACHETHEN       0x80
+       bit     DPARCKEN        0x40
+       bit     MPARCKEN        0x20
+       bit     EXTREQLCK       0x10
+       bit     INTSCBRAMSEL    0x08
+       bit     RAMPS           0x04
+       bit     USCBSIZE32      0x02
+       bit     CIOPARCKEN      0x01
+}
+
 /*
  * On the aic78X0 chips, Board Control is replaced by the DSCommand
  * register (p. 4-64)
@@ -676,6 +702,7 @@ register INTSTAT {
 register ERROR {
        address                 0x092
        access_mode RO
+       bit     CIOPARERR       0x80    /* Ultra2 only */
        bit     PCIERRSTAT      0x40    /* PCI only */
        bit     MPARERR         0x20    /* PCI only */
        bit     DPARERR         0x10    /* PCI only */
@@ -701,6 +728,7 @@ register CLRINT {
 register DFCNTRL {
        address                 0x093
        access_mode RW
+       bit     PRELOADEN       0x80    /* aic7890 only */
        bit     WIDEODD         0x40
        bit     SCSIEN          0x20
        bit     SDMAEN          0x10
@@ -715,6 +743,7 @@ register DFCNTRL {
 register DFSTATUS {
        address                 0x094
        access_mode RO
+       bit     PRELOAD_AVAIL   0x80
        bit     DWORDEMP        0x20
        bit     MREQPEND        0x10
        bit     HDONE           0x08
@@ -776,6 +805,14 @@ register QOUTCNT {
        access_mode RO
 }
 
+/*
+ * Special Function
+ */
+register SFUNCT {
+       address                 0x09f
+       access_mode RW
+}
+
 /*
  * SCB Definition (p. 5-4)
  */
@@ -865,6 +902,109 @@ register STATUS_2840 {
 
 register DSPCISTATUS {
        address                 0x086
+       mask    DFTHRSH_100     0xc0
+}
+
+register CCHADDR {
+       address                 0x0E0
+       size 8
+}
+
+register CCHCNT {
+       address                 0x0E8
+}
+
+register CCSGRAM {
+       address                 0x0E9
+}
+
+register CCSGADDR {
+       address                 0x0EA
+}
+
+register CCSGCTL {
+       address                 0x0EB
+       bit     CCSGDONE        0x80
+       bit     CCSGEN          0x08
+       bit     FLAG            0x02
+       bit     CCSGRESET       0x01
+}
+
+register CCSCBCNT {
+       address                 0xEF
+}
+
+register CCSCBCTL {
+       address                 0x0EE
+       bit     CCSCBDONE       0x80
+       bit     ARRDONE         0x40    /* SCB Array prefetch done */
+       bit     CCARREN         0x10
+       bit     CCSCBEN         0x08
+       bit     CCSCBDIR        0x04
+       bit     CCSCBRESET      0x01
+}
+
+register CCSCBADDR {
+       address                 0x0ED
+}
+
+register CCSCBRAM {
+       address                 0xEC
+}
+
+register CCSCBPTR {
+       address                 0x0F1
+}
+
+register HNSCB_QOFF {
+       address                 0x0F4
+}
+
+register SNSCB_QOFF {
+       address                 0x0F6
+}
+
+register SDSCB_QOFF {
+       address                 0x0F8
+}
+
+register QOFF_CTLSTA {
+       address                 0x0FA
+       bit     SCB_AVAIL       0x40
+       bit     SNSCB_ROLLOVER  0x20
+       bit     SDSCB_ROLLOVER  0x10
+       mask    SCB_QSIZE       0x07
+       mask    SCB_QSIZE_256   0x06
+}
+
+register DFF_THRSH {
+       address                 0x0FB
+       mask    WR_DFTHRSH      0x70
+       mask    RD_DFTHRSH      0x07
+       mask    RD_DFTHRSH_MIN  0x00
+       mask    RD_DFTHRSH_25   0x01
+       mask    RD_DFTHRSH_50   0x02
+       mask    RD_DFTHRSH_63   0x03
+       mask    RD_DFTHRSH_75   0x04
+       mask    RD_DFTHRSH_85   0x05
+       mask    RD_DFTHRSH_90   0x06
+       mask    RD_DFTHRSH_MAX  0x07
+       mask    WR_DFTHRSH_MIN  0x00
+       mask    WR_DFTHRSH_25   0x10
+       mask    WR_DFTHRSH_50   0x20
+       mask    WR_DFTHRSH_63   0x30
+       mask    WR_DFTHRSH_75   0x40
+       mask    WR_DFTHRSH_85   0x50
+       mask    WR_DFTHRSH_90   0x60
+       mask    WR_DFTHRSH_MAX  0x70
+}
+
+register SG_CACHEPTR {
+       access_mode RW
+       address                 0x0fc
+       mask    SG_USER_DATA    0xfc
+       bit     LAST_SEG        0x02
+       bit     LAST_SEG_DONE   0x01
 }
 
 register BRDCTL        {
@@ -877,6 +1017,12 @@ register BRDCTL   {
        bit     BRDRW           0x04
        bit     BRDCTL1         0x02
        bit     BRDCTL0         0x01
+       /* 7890 Definitions */
+       bit     BRDDAT4         0x10
+       bit     BRDDAT3         0x08
+       bit     BRDDAT2         0x04
+       bit     BRDRW_ULTRA2    0x02
+       bit     BRDSTB_ULTRA2   0x01
 }
 
 /*
@@ -935,7 +1081,7 @@ scratch_ram {
        /*
         * 1 byte per target starting at this address for configuration values
         */
-       TARG_SCRATCH {
+       TARG_SCSIRATE {
                size            16
        }
        /*
@@ -960,6 +1106,7 @@ scratch_ram {
        /* Parameters for DMA Logic */
        DMAPARAMS {
                size            1
+               bit     PRELOADEN       0x80
                bit     WIDEODD         0x40
                bit     SCSIEN          0x20
                bit     SDMAEN          0x10
@@ -1078,12 +1225,27 @@ scratch_ram {
                mask    MSGOUT_PHASEMIS 0x10
                alias   RETURN_1
        }
+       ARG_2 {
+               size            1
+               alias   RETURN_2
+       }
+
        /*
         * Snapshot of MSG_OUT taken after each message is sent.
         */
        LAST_MSG {
                size            1
        }
+
+       /*
+        * Number of times we have filled the CCSGRAM with prefetched
+        * SG elements.
+        */
+       PREFETCH_CNT {
+               size            1
+       }
+
+
        /*
         * These are reserved registers in the card's scratch ram.  Some of
         * the values are specified in the AHA2742 technical reference manual
@@ -1108,22 +1270,35 @@ scratch_ram {
                mask    BIOSDISABLED            0x30    
                bit     CHANNEL_B_PRIMARY       0x08
        }
+       /*
+        * Per target SCSI offset values for Ultra2 controllers.
+        */
+       TARG_OFFSET {
+               address         0x070
+               size            16
+       }
 }
 
 const SCB_LIST_NULL    0xff
 
+const CCSGADDR_MAX     0x80
+const CCSGRAM_MAXSEGS  16
+
 /* 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
+const BUS_8_BIT                        0x00
 const BUS_16_BIT               0x01
 const BUS_32_BIT               0x02
+
+/* Offset maximums */
 const MAX_OFFSET_8BIT          0x0f
-const MAX_OFFSET_16BIT 0x08
-const HOST_MSG         0xFF
+const MAX_OFFSET_16BIT         0x08
+const MAX_OFFSET_ULTRA2                0x7f
+const HOST_MSG                 0xff
 
 /* Target mode command processing constants */
 const CMD_GROUP_CODE_SHIFT     0x05
@@ -1135,11 +1310,7 @@ 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.
  */
index b4613387f2a913c6650bca1124cc5c92475be518..60a718a3a6796abc4983efcc03d517e9db04e054 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Adaptec 274x/284x/294x device driver firmware for Linux and FreeBSD.
  *
- * Copyright (c) 1994-1997 Justin Gibbs.
+ * Copyright (c) 1994-1998 Justin Gibbs.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -14,7 +14,7 @@
  *    derived from this software without specific prior written permission.
  *
  * Where this Software is combined with software released under the terms of 
- * the GNU Public License ("GPL") and the terms of the GPL would require the 
+ * the GNU Public License (GPL) and the terms of the GPL would require the 
  * combined work to also be released under the terms of the GPL, the terms
  * and conditions of this License will apply in addition to those of the
  * GPL with the exception of any terms or conditions of this License that
@@ -32,7 +32,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- *     $Id: aic7xxx.seq,v 1.74 1997/06/27 19:38:42 gibbs Exp $
+ *     $Id: aic7xxx.seq,v 1.77 1998/06/28 02:58:57 gibbs Exp $
  */
 
 #include "aic7xxx.reg"
 reset:
        clr     SCSISIGO;               /* De-assert BSY */
        /* Always allow reselection */
-.if ( TARGET_MODE )
-       mvi     SCSISEQ, ENSELI|ENRSELI|ENAUTOATNP;
-.else
-       mvi     SCSISEQ, ENRSELI|ENAUTOATNP;
-.endif
+       if ((p->flags & AHC_TARGETMODE) != 0) {
+               mvi     SCSISEQ, ENSELI|ENRSELI|ENAUTOATNP;
+       } else {
+               mvi     SCSISEQ, ENRSELI|ENAUTOATNP;
+       }
+
+       if ((p->features & AHC_CMD_CHAN) != 0) {
+               /* Ensure that no DMA operations are in progress */
+               clr     CCSGCTL;
+               clr     CCSCBCTL;
+       }
+
        call    clear_target_state;
        and     SXFRCTL0, ~SPIOEN;
 poll_for_work:
-       mov     A, QINPOS;
+       if ((p->features & AHC_QUEUE_REGS) == 0) {
+               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 )
-       /*
-        * Twin channel devices cannot handle things like SELTO
-        * interrupts on the "background" channel.  So, if we
-        * are selecting, keep polling the current channel util
-        * either a selection or reselection occurs.
-        */
-       xor     SBLKCTL,SELBUSB;        /* Toggle to the other bus */
+       if ((p->features & AHC_QUEUE_REGS) == 0) {
+               and     SEQCTL, ~PAUSEDIS;
+       }
        test    SSTAT0, SELDO|SELDI     jnz selection;
        test    SCSISEQ, ENSELO jnz poll_for_work;
-       xor     SBLKCTL,SELBUSB;        /* Toggle back */
-.endif
+       if ((p->features & AHC_TWIN) != 0) {
+               /*
+                * Twin channel devices cannot handle things like SELTO
+                * interrupts on the "background" channel.  So, if we
+                * are selecting, keep polling the current channel util
+                * either a selection or reselection occurs.
+                */
+               xor     SBLKCTL,SELBUSB;        /* Toggle to the other bus */
+               test    SSTAT0, SELDO|SELDI     jnz selection;
+               test    SCSISEQ, ENSELO jnz poll_for_work;
+               xor     SBLKCTL,SELBUSB;        /* Toggle back */
+       }
        cmp     WAITING_SCBH,SCB_LIST_NULL jne start_waiting;
 test_queue:
        /* Has the driver posted any work for us? */
-       or      SEQCTL, PAUSEDIS;
-       cmp     KERNEL_QINPOS, A je poll_for_work_loop;
-       inc     QINPOS;
-       and     SEQCTL, ~PAUSEDIS;
+       if ((p->features & AHC_QUEUE_REGS) != 0) {
+               test    QOFF_CTLSTA, SCB_AVAIL jz poll_for_work_loop;
+               mov     NONE, SNSCB_QOFF;
+               inc     QINPOS;
+       } else {
+               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 
@@ -98,26 +115,24 @@ test_queue:
  * any SCBs available for use, pull the tag from the QINFIFO
  * and get to work on it.
  */
-.if ( SCB_PAGING )
-       mov     ALLZEROS        call    get_free_or_disc_scb;
-.endif
+       if ((p->flags & AHC_PAGESCBS) != 0) {
+               mov     ALLZEROS        call    get_free_or_disc_scb;
+       }
+
 dequeue_scb:
        add     A, -1, QINPOS;
-       mvi     QINFIFO_OFFSET call set_SCBID_host_addr_and_cnt;
-       mvi     DFCNTRL, HDMAEN|DIRECTION|FIFORESET;
+       mvi     QINFIFO_OFFSET call fetch_byte;
 
-       call    dma_finish;
-       mov     SINDEX, DFDAT;
-.if !( SCB_PAGING )
-       /* In the non-paging case, the SCBID == hardware SCB index */
-       mov     SCBPTR, SINDEX;
-.endif
+       if ((p->flags & AHC_PAGESCBS) == 0) {
+               /* In the non-paging case, the SCBID == hardware SCB index */
+               mov     SCBPTR, RETURN_2;
+       }
 dma_queued_scb:
 /*
  * DMA the SCB from host ram into the current SCB location.
  */
        mvi     DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
-       call    dma_scb;
+       mov     RETURN_2         call dma_scb;
 
 start_scb:
        /*
@@ -135,16 +150,22 @@ start_waiting:
        jmp     poll_for_work;
 
 start_selection:
-.if ( TWIN_CHANNEL )
-       and     SINDEX,~SELBUSB,SBLKCTL;/* Clear the channel select bit */
-       and     A,SELBUSB,SCB_TCL;      /* Get new channel bit */
-       or      SINDEX,A;
-       mov     SBLKCTL,SINDEX;         /* select channel */
-.endif
+       if ((p->features & AHC_TWIN) != 0) {
+               and     SINDEX,~SELBUSB,SBLKCTL;/* Clear channel select bit */
+               and     A,SELBUSB,SCB_TCL;      /* Get new channel bit */
+               or      SINDEX,A;
+               mov     SBLKCTL,SINDEX;         /* select channel */
+       }
 initialize_scsiid:
-       and     A, TID, SCB_TCL;        /* Get target ID */
-       and     SCSIID, OID;            /* Clear old target */
-       or      SCSIID, A;
+       if ((p->features & AHC_ULTRA2) != 0) {
+               and     A, TID, SCB_TCL;        /* Get target ID */
+               and     SCSIID_ULTRA2, OID;     /* Clear old target */
+               or      SCSIID_ULTRA2, A;
+       } else {
+               and     A, TID, SCB_TCL;        /* Get target ID */
+               and     SCSIID, OID;            /* Clear old target */
+               or      SCSIID, A;
+       }
        mvi     SCSISEQ, ENSELO|ENAUTOATNO|ENRSELI|ENAUTOATNP ret;
 
 /*
@@ -155,143 +176,154 @@ initialize_scsiid:
 initialize_channel:
        or      A, CLRSTCNT|CLRCHN, SINDEX;
        or      SXFRCTL0, A;
-.if ( ULTRA )
+       if ((p->features & AHC_ULTRA) != 0) {
 ultra:
-       mvi     SINDEX, ULTRA_ENB+1;
-       test    SAVED_TCL, 0x80         jnz ultra_2;    /* Target ID > 7 */
-       dec     SINDEX;
+               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
+               mov     FUNCTION1,SAVED_TCL;
+               mov     A,FUNCTION1;
+               test    SINDIR, A       jz ndx_dtr;
+               or      SXFRCTL0, FAST20;
+       } 
 /*
  * Initialize SCSIRATE with the appropriate value for this target.
  * The SCSIRATE settings for each target are stored in an array
- * based at TARG_SCRATCH.
+ * based at TARG_SCSIRATE.
  */
 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 */
+       if ((p->features & AHC_TWIN) != 0) {
+               test    SBLKCTL,SELBUSB jz ndx_dtr_2;
+               or      SAVED_TCL, SELBUSB; 
+               or      A,0x08;                 /* Channel B entries add 8 */
 ndx_dtr_2:
-       add     SINDEX,TARG_SCRATCH,A;
+       }
+
+       if ((p->features & AHC_ULTRA2) != 0) {
+               add     SINDEX, TARG_OFFSET, A;
+               mov     SCSIOFFSET, SINDIR;
+       }
+
+       add     SINDEX,TARG_SCSIRATE,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 */
+       if ((p->flags & AHC_TARGETMODE) != 0) {
+               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     DINDEX, HADDR;
+               mvi     TMODE_CMDADDR call set_32byte_addr;
+               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 */
+               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;
+               add     HCNT[0], 1, A;
+               clr     HCNT[1];
+               clr     HCNT[2];
+               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;
+               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;
+               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;
+               call    dma_finish;
 
-       test    ARG_1, MSG_IDENTIFY_DISCFLAG jz selectin_post;
+               test    ARG_1, MSG_IDENTIFY_DISCFLAG jz selectin_post;
 
-       mvi     SCSISIGO, P_MESGIN|BSYO;
+               mvi     SCSISIGO, P_MESGIN|BSYO;
 
-       or      SXFRCTL0, SPIOEN;
+               or      SXFRCTL0, SPIOEN;
 
-       mvi     MSG_DISCONNECT call target_outb;
+               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;
+               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;
+               test    ARG_1, MSG_IDENTIFY_DISCFLAG jnz target_busfree;
 
-       /* Busy loop on something then go to data or status phase */
+               /* Busy loop on something then go to data or status phase */
 
 target_busfree:
-       clr     SCSISIGO;
-       jmp     poll_for_work;
+               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.
@@ -396,26 +428,41 @@ data_phase_reinit:
        jmp     data_phase_loop;
 
 p_data:
-       mvi     DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|FIFORESET;
+       if ((p->features & AHC_ULTRA2) != 0) {
+               mvi     DMAPARAMS, PRELOADEN|SCSIEN|HDMAEN;
+       } else {
+               mvi     DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|FIFORESET;
+       }
        test    LASTPHASE, IOI jnz . + 2;
        or      DMAPARAMS, DIRECTION;
        call    assert;                 /*
                                         * Ensure entering a data
                                         * phase is okay - seen identify, etc.
                                         */
-
+       if ((p->features & AHC_CMD_CHAN) != 0) {
+               mvi     CCSGADDR, CCSGADDR_MAX;
+       }
        test    SEQ_FLAGS, DPHASE       jnz data_phase_reinit;
 
+       /* We have seen a data phase */
+       or      SEQ_FLAGS, DPHASE;
+
        /*
         * Initialize the DMA address and counter from the SCB.
         * Also set SG_COUNT and SG_NEXT in memory since we cannot
         * modify the values in the SCB itself until we see a
         * save data pointers message.
         */
-       mvi     DINDEX, HADDR;
-       mvi     SCB_DATAPTR     call bcopy_7;
+       if ((p->features & AHC_CMD_CHAN) != 0) {
+               bmov    HADDR, SCB_DATAPTR, 7;
+       } else {
+               mvi     DINDEX, HADDR;
+               mvi     SCB_DATAPTR     call bcopy_7;
+       }
 
-       call    set_stcnt_from_hcnt;
+       if ((p->features & AHC_ULTRA2) == 0) {
+               call    set_stcnt_from_hcnt;
+       }
 
        mov     SG_COUNT,SCB_SGCOUNT;
 
@@ -432,19 +479,38 @@ data_phase_loop:
  * had an overrun.
  */
        or      SXFRCTL1,BITBUCKET;
-       mvi     HCNT[0], 0xff;
-       mvi     HCNT[1], 0xff;
-       mvi     HCNT[2], 0xff;
-       call    set_stcnt_from_hcnt;
        and     DMAPARAMS, ~(HDMAEN|SDMAEN);
-
+       if ((p->features & AHC_ULTRA2) != 0) {
+               bmov    HCNT, ALLONES, 3;
+       } else {
+               mvi     STCNT[0], 0xFF;
+               mvi     STCNT[1], 0xFF;
+               mvi     STCNT[2], 0xFF;
+       }
 data_phase_inbounds:
-/* If we are the last SG block, ensure wideodd is off. */
+/* If we are the last SG block, tell the hardware. */
        cmp     SG_COUNT,0x01 jne data_phase_wideodd;
-       and     DMAPARAMS, ~WIDEODD;
+       if ((p->features & AHC_ULTRA2) != 0) {
+               or      SG_CACHEPTR, LAST_SEG;
+       } else {
+               and     DMAPARAMS, ~WIDEODD;
+       }
 data_phase_wideodd:
-       mov     DMAPARAMS  call dma;
-
+       if ((p->features & AHC_ULTRA2) != 0) {
+               mov     SINDEX, ALLONES;
+               mov     DFCNTRL, DMAPARAMS;
+               test    SSTAT0, SDONE jnz .;/* Wait for preload to complete */
+data_phase_dma_loop:
+               test    SSTAT0, SDONE jnz data_phase_dma_done;
+               test    SSTAT1,PHASEMIS jz data_phase_dma_loop; /* ie. underrun */
+data_phase_dma_phasemis:
+               test    SSTAT0,SDONE    jnz . + 2;
+               mov     SINDEX,ALLZEROS;        /* Remeber the phasemiss */
+       } else {
+               mov     DMAPARAMS  call dma;
+       }
+
+data_phase_dma_done:
 /* Go tell the host about any overruns */
        test    SXFRCTL1,BITBUCKET jnz data_phase_overrun;
 
@@ -458,11 +524,6 @@ sg_advance:
        dec     SG_COUNT;       /* one less segment to go */
 
        test    SG_COUNT, 0xff  jz data_phase_finish; /* Are we done? */
-
-       clr     A;                      /* add sizeof(struct scatter) */
-       add     SG_NEXT[0],SG_SIZEOF;
-       adc     SG_NEXT[1],A;
-
 /*
  * Load a struct scatter and set up the data address and length.
  * If the working value of the SG count is nonzero, then
@@ -471,33 +532,71 @@ sg_advance:
  * This, like all DMA's, assumes little-endian host data storage.
  */
 sg_load:
-       mvi     DINDEX, HADDR;
-       mvi     SG_NEXT call bcopy_4;
-
-       mvi     HCNT[0],SG_SIZEOF;
-       clr     HCNT[1];
-       clr     HCNT[2];
-
-       or      DFCNTRL, HDMAEN|DIRECTION|FIFORESET;
-
-       call    dma_finish;
-
-/*
- * Copy data from FIFO into SCB data pointer and data count.  This assumes
- * that the SG segments are of the form:
- *
- * struct ahc_dma_seg {
- *     u_int32_t       addr;           four bytes, little-endian order
- *     u_int32_t       len;            four bytes, little endian order
- * };
- */
-       mvi     HADDR   call dfdat_in_7;
+       if ((p->features & AHC_CMD_CHAN) != 0) {
+               /*
+                * Do we have any prefetch left???
+                */
+               cmp     CCSGADDR, CCSGADDR_MAX jne prefetched_segs_avail;
+
+               /*
+                * Fetch MIN(CCSGADDR_MAX, (SG_COUNT * 8)) bytes.
+                */
+               add     A, -(CCSGRAM_MAXSEGS + 1), SG_COUNT;
+               mvi     A, CCSGADDR_MAX;
+               jc      . + 2;
+               shl     A, 3, SG_COUNT;
+               mov     CCHCNT, A;
+               bmov    CCHADDR, SG_NEXT, 4;
+               mvi     CCSGCTL, CCSGEN|CCSGRESET;
+               test    CCSGCTL, CCSGDONE jz .;
+               and     CCSGCTL, ~CCSGEN;
+               test    CCSGCTL, CCSGEN jnz .;
+               mvi     CCSGCTL, CCSGRESET;
+prefetched_segs_avail:
+               bmov    HADDR, CCSGRAM, 8;
+       } else {
+               mvi     DINDEX, HADDR;
+               mvi     SG_NEXT call bcopy_4;
+
+               mvi     HCNT[0],SG_SIZEOF;
+               clr     HCNT[1];
+               clr     HCNT[2];
+
+               or      DFCNTRL, HDMAEN|DIRECTION|FIFORESET;
+
+               call    dma_finish;
+
+               /*
+                * Copy data from FIFO into SCB data pointer and data count.
+                * This assumes that the SG segments are of the form:
+                * struct ahc_dma_seg {
+                *      u_int32_t       addr;   four bytes, little-endian order
+                *      u_int32_t       len;    four bytes, little endian order
+                * };
+                */
+               mvi     HADDR   call dfdat_in_7;
+       }
+
+       if ((p->features & AHC_ULTRA2) == 0) {
+               /* Load STCNT as well.  It is a mirror of HCNT */
+               call    set_stcnt_from_hcnt;
+       }
+
+/* Advance the SG pointer */
+       clr     A;                      /* add sizeof(struct scatter) */
+       add     SG_NEXT[0],SG_SIZEOF;
+       adc     SG_NEXT[1],A;
 
-/* Load STCNT as well.  It is a mirror of HCNT */
-       call    set_stcnt_from_hcnt;
        test    SSTAT1,PHASEMIS jz data_phase_loop;
+       /* Ensure the last seg is visable at the shaddow layer */
+       if ((p->features & AHC_ULTRA2) != 0) {
+               or      DFCNTRL, PRELOADEN;
+       }
 
 data_phase_finish:
+       if ((p->features & AHC_ULTRA2) != 0) {
+               call    ultra2_dmafinish;
+       }
 /*
  * After a DMA finishes, save the SG and STCNT residuals back into the SCB
  * We use STCNT instead of HCNT, since it's a reflection of how many bytes 
@@ -508,12 +607,17 @@ data_phase_finish:
        mov     SCB_RESID_DCNT[2],STCNT[2];
        mov     SCB_RESID_SGCNT, SG_COUNT;
 
-       /* We have seen a data phase */
-       or      SEQ_FLAGS, DPHASE;
+       if ((p->features & AHC_ULTRA2) != 0) {
+               or      SXFRCTL0, CLRSTCNT|CLRCHN;
+       }
 
        jmp     ITloop;
 
 data_phase_overrun:
+       if ((p->features & AHC_ULTRA2) != 0) {
+               call    ultra2_dmafinish;
+               or      SXFRCTL0, CLRSTCNT|CLRCHN;
+       }
 /*
  * Turn off BITBUCKET mode and notify the host
  */
@@ -521,6 +625,19 @@ data_phase_overrun:
        mvi     INTSTAT,DATA_OVERRUN;
        jmp     ITloop;
 
+ultra2_dmafinish:
+       if ((p->features & AHC_ULTRA2) != 0) {
+               test    DFCNTRL, DIRECTION jnz ultra2_dmahalt;
+               and     DFCNTRL, ~SCSIEN;
+               test    DFCNTRL, SCSIEN jnz .;
+               or      DFCNTRL, FIFOFLUSH;
+               test    DFSTATUS, FIFOEMP jz . - 1;
+ultra2_dmahalt:
+               and     DFCNTRL, ~(SCSIEN|HDMAEN);
+               test    DFCNTRL, HDMAEN jnz .;
+               ret;
+       }
+
 /*
  * Command phase.  Set up the DMA registers and let 'er rip.
  */
@@ -530,14 +647,26 @@ p_command:
 /*
  * Load HADDR and HCNT.
  */
-       mvi     DINDEX, HADDR;
-       mvi     SCB_CMDPTR      call bcopy_5;
-       clr     HCNT[1];
-       clr     HCNT[2];
-
-       call    set_stcnt_from_hcnt;
-
-       mvi     (SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET) call dma;
+       if ((p->features & AHC_ULTRA2) != 0) {
+               or      SG_CACHEPTR, LAST_SEG;
+       }
+
+       if ((p->features & AHC_CMD_CHAN) != 0) {
+               bmov    HADDR, SCB_CMDPTR, 5;
+               bmov    HCNT[1], ALLZEROS, 2;
+       } else {
+               mvi     DINDEX, HADDR;
+               mvi     SCB_CMDPTR      call bcopy_5;
+               clr     HCNT[1];
+               clr     HCNT[2];
+       }
+
+       if ((p->features & AHC_ULTRA2) == 0) {
+               call    set_stcnt_from_hcnt;
+               mvi     (SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET) call dma;
+       } else {
+               mvi     (PRELOADEN|SCSIEN|HDMAEN|DIRECTION) call dma;
+       }
        jmp     ITloop;
 
 /*
@@ -562,7 +691,6 @@ p_status:
  * 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).
  *
@@ -574,11 +702,11 @@ p_mesgout:
        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
+       if ((p->features & AHC_WIDE) != 0) {
+               and     SINDEX,0xf,SCB_TCL;     /* lun */
+       } else {
+               and     SINDEX,0x7,SCB_TCL;     /* lun */
+       }
        and     A,DISCENB,SCB_CONTROL;  /* mask off disconnect privledge */
        or      SINDEX,A;               /* or in disconnect privledge */
        or      SINDEX,MSG_IDENTIFYFLAG;
@@ -606,6 +734,7 @@ p_mesgout_tag:
 p_mesgout_from_host:
        cmp     SINDEX, HOST_MSG        jne p_mesgout_onebyte;
        mvi     INTSTAT,AWAITING_MSG;
+       nop;
        /*
         * Did the host detect a phase change?
         */
@@ -692,6 +821,7 @@ upload_scb:
 check_status:
        test    SCB_TARGET_STATUS,0xff  jz complete;    /* Just a residual? */
        mvi     INTSTAT,BAD_STATUS;                     /* let driver know */
+       nop;
        cmp     RETURN_1, SEND_SENSE    jne complete;
        /* This SCB becomes the next to execute as it will retrieve sense */
        mvi     DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
@@ -710,21 +840,21 @@ 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;
+       mvi     UNTAGGEDSCB_OFFSET call post_byte_setup;
+       mvi     SCB_LIST_NULL call post_byte;
 
 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;
+       if ((p->features & AHC_QUEUE_REGS) != 0) {
+               mov     A, SDSCB_QOFF;
+       } else {
+               mov     A, QOUTPOS;
+       }
+       mvi     QOUTFIFO_OFFSET call post_byte_setup;
+       mov     SCB_TAG call post_byte;
+       if ((p->features & AHC_QUEUE_REGS) == 0) {
+               inc     QOUTPOS;
+       }
        mvi     INTSTAT,CMDCMPLT;
 
 add_to_free_list:
@@ -796,18 +926,19 @@ mesgin_rdptrs:
  * clearing the "disconnected" bit so we don't "find" it by accident later.
  */
 mesgin_identify:
-.if ( WIDE )
-       and     A,0x0f;                 /* lun in lower four bits */
-.else
-       and     A,0x07;                 /* lun in lower three bits */
-.endif
+       
+       if ((p->features & AHC_WIDE) != 0) {
+               and     A,0x0f;         /* lun in lower four bits */
+       } else {
+               and     A,0x07;         /* lun in lower three bits */
+       }
        or      SAVED_TCL,A;            /* SAVED_TCL should be complete now */
 
        call    get_untagged_SCBID;
        cmp     ARG_1, SCB_LIST_NULL    je snoop_tag;
-.if ( SCB_PAGING )
-       test    SEQ_FLAGS, SCBPTR_VALID jz use_retrieveSCB;
-.endif
+       if ((p->flags & AHC_PAGESCBS) != 0) {
+               test    SEQ_FLAGS, SCBPTR_VALID jz use_retrieveSCB;
+       }
        /*
         * If the SCB was found in the disconnected list (as is
         * always the case in non-paging scenarios), SCBPTR is already
@@ -833,19 +964,19 @@ snoop_tag_loop:
 get_tag:
        mvi     ARG_1   call inb_next;  /* tag value */
 
-.if ! ( SCB_PAGING )
+       if ((p->flags & AHC_PAGESCBS) == 0) {
 index_by_tag:
-       mov     SCBPTR,ARG_1;
-       test    SCB_CONTROL,TAG_ENB     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.
- */
+               mov     SCBPTR,ARG_1;
+               test    SCB_CONTROL,TAG_ENB     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_retrieveSCB:
-       call    retrieveSCB;
-.endif
+               call    retrieveSCB;
+       }
 setup_SCB:
        mov     A, SAVED_TCL;
        cmp     SCB_TCL, A      jne not_found_cleanup_scb;
@@ -924,16 +1055,16 @@ 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.
- */
+if ((p->flags & AHC_TARGETMODE) != 0) {
+       /*
       * 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:
 /*
@@ -980,7 +1111,17 @@ dma_fifoempty:
 dma_dmadone:
        and     DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN);
 dma_halt:
-       test    DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz dma_halt; 
+       /*
+        * Some revisions of the aic7880 have a problem where, if the
+        * data fifo is full, but the PCI input latch is not empty, 
+        * HDMAEN cannot be cleared.  The fix used here is to attempt
+        * to drain the data fifo until there is space for the input
+        * latch to drain and HDMAEN de-asserts.
+        */
+       if ((p->features & AHC_ULTRA2) == 0) {
+               mov     NONE, DFDAT;
+       }
+       test    DFCNTRL, HDMAEN jnz dma_halt;
 return:
        ret;
 
@@ -1079,18 +1220,67 @@ get_untagged_SCBID:
        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;
+/*
+ * Fetch a byte from host memory given an index of (A + (256 * SINDEX))
+ * and a base address of SCBID_ADDR.  The byte is returned in RETURN_2.
+ */
+fetch_byte:
+       mov     ARG_2, SINDEX;
+       if ((p->features & AHC_CMD_CHAN) != 0) {
+               mvi     DINDEX, CCHADDR;
+               mvi     SCBID_ADDR call set_1byte_addr;
+               mvi     CCHCNT, 1;
+               mvi     CCSGCTL, CCSGEN|CCSGRESET;
+               test    CCSGCTL, CCSGDONE jz .;
+               mvi     CCSGCTL, CCSGRESET;
+               bmov    RETURN_2, CCSGRAM, 1 ret;
+       } else {
+               mvi     DINDEX, HADDR;
+               mvi     SCBID_ADDR call set_1byte_addr;
+               mvi     HCNT[0], 1;
+               clr     HCNT[1];
+               clr     HCNT[2];
+               mvi     DFCNTRL, HDMAEN|DIRECTION|FIFORESET;
+               call    dma_finish;
+               mov     RETURN_2, DFDAT ret;
+       }
+
+/*
+ * Prepare the hardware to post a byte to host memory given an
+ * index of (A + (256 * SINDEX)) and a base address of SCBID_ADDR.
+ */
+post_byte_setup:
+       mov     ARG_2, SINDEX;
+       if ((p->features & AHC_CMD_CHAN) != 0) {
+               mvi     DINDEX, CCHADDR;
+               mvi     SCBID_ADDR call set_1byte_addr;
+               mvi     CCHCNT, 1;
+               mvi     CCSCBCTL, CCSCBRESET ret;
+       } else {
+               mvi     DINDEX, HADDR;
+               mvi     SCBID_ADDR call set_1byte_addr;
+               mvi     HCNT[0], 1;
+               clr     HCNT[1];
+               clr     HCNT[2];
+               mvi     DFCNTRL, FIFORESET ret;
+       }
+
+post_byte:
+       if ((p->features & AHC_CMD_CHAN) != 0) {
+               bmov    CCSCBRAM, SINDEX, 1;
+               or      CCSCBCTL, CCSCBEN|CCSCBRESET;
+               test    CCSCBCTL, CCSCBDONE jz .;
+               clr     CCSCBCTL ret;
+       } else {
+               mov     DFDAT, SINDEX;
+               or      DFCNTRL, HDMAEN|FIFOFLUSH;
+               jmp     dma_finish;
+       }
 
 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;
+       mvi     UNTAGGEDSCB_OFFSET call fetch_byte;
+       mov     RETURN_1,  RETURN_2 ret;
 
 phase_lock:     
        test    SSTAT1, REQINIT jz phase_lock;
@@ -1116,65 +1306,102 @@ bcopy_3:
        mov     DINDIR, SINDIR ret;
 
 /*
- * Setup haddr and count assuming that A is an
- * index into an array of 32byte objects.
+ * Setup addr assuming that A is an index into
+ * an array of 32byte objects, SINDEX contains
+ * the base address of that array, and DINDEX
+ * contains the base address of the location
+ * to store the indexed address.
  */
-set_32byte_haddr_and_clrcnt:
-       shr     DINDEX, 3, A;
+set_32byte_addr:
+       shr     ARG_2, 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;
+/*
+ * Setup addr assuming that A + (ARG_1 * 256) is an
+ * index into an array of 1byte objects, SINDEX contains
+ * the base address of that array, and DINDEX contains
+ * the base address of the location to store the computed
+ * address.
+ */
+set_1byte_addr:
+       add     DINDIR, A, SINDIR;
+       mov     A, ARG_2;
+       adc     DINDIR, A, SINDIR;
        clr     A;
-       adc     HADDR[2], A, SINDIR;
-       adc     HADDR[3], A, SINDIR;
-       /* Clear Count */
-       clr     HCNT[1];
-       clr     HCNT[2] ret;
+       adc     DINDIR, A, SINDIR;
+       adc     DINDIR, A, SINDIR ret;
 
+/*
+ * Either post or fetch and SCB from host memory based on the
+ * DIRECTION bit in DMAPARAMS. The host SCB index is in SINDEX.
+ */
 dma_scb:
-       /*
-        * SCB index is in SINDEX.  Determine the physical address in
-        * the host where this SCB is located and load HADDR with it.
-        */
        mov     A, SINDEX;
-       mvi     HSCB_ADDR call set_32byte_haddr_and_clrcnt;
-       mvi     HCNT[0], 28;
-       mov     DFCNTRL, DMAPARAMS;
-       test    DMAPARAMS, DIRECTION    jnz dma_scb_fromhost;
-       /* Fill it with the SCB data */
+       if ((p->features & AHC_CMD_CHAN) != 0) {
+               mvi     DINDEX, CCHADDR;
+               mvi     HSCB_ADDR call set_32byte_addr;
+               mov     CCSCBPTR, SCBPTR;
+               mvi     CCHCNT, 32;
+               test    DMAPARAMS, DIRECTION jz dma_scb_tohost;
+               mvi     CCSCBCTL, CCARREN|CCSCBEN|CCSCBDIR|CCSCBRESET;
+               cmp     CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN|CCSCBDIR jne .;
+               jmp     dma_scb_finish;
+dma_scb_tohost:
+               if ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) {
+                       mvi     CCSCBCTL, CCSCBRESET;
+                       bmov    CCSCBRAM, SCB_CONTROL, 32;
+                       or      CCSCBCTL, CCSCBEN|CCSCBRESET;
+                       test    CCSCBCTL, CCSCBDONE jz .;
+               } else {
+                       mvi     CCSCBCTL, CCARREN|CCSCBEN|CCSCBRESET;
+                       cmp     CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN jne .;
+               }
+dma_scb_finish:
+               clr     CCSCBCTL;
+               test    CCSCBCTL, CCARREN|CCSCBEN jnz .;
+               ret;
+       } else {
+               mvi     DINDEX, HADDR;
+               mvi     HSCB_ADDR call set_32byte_addr;
+               mvi     HCNT[0], 32;
+               clr     HCNT[1];
+               clr     HCNT[2];
+               mov     DFCNTRL, DMAPARAMS;
+               test    DMAPARAMS, DIRECTION    jnz dma_scb_fromhost;
+               /* Fill it with the SCB data */
 copy_scb_tofifo:
-       mvi     SINDEX, SCB_CONTROL;
-       add     A, 28, SINDEX;
+               mvi     SINDEX, SCB_CONTROL;
+               add     A, 32, SINDEX;
 copy_scb_tofifo_loop:
-       mov     DFDAT,SINDIR;
-       mov     DFDAT,SINDIR;
-       mov     DFDAT,SINDIR;
-       mov     DFDAT,SINDIR;
-       mov     DFDAT,SINDIR;
-       mov     DFDAT,SINDIR;
-       mov     DFDAT,SINDIR;
-       cmp     SINDEX, A jne copy_scb_tofifo_loop;
-       or      DFCNTRL, HDMAEN|FIFOFLUSH;
+               mov     DFDAT,SINDIR;
+               mov     DFDAT,SINDIR;
+               mov     DFDAT,SINDIR;
+               mov     DFDAT,SINDIR;
+               mov     DFDAT,SINDIR;
+               mov     DFDAT,SINDIR;
+               mov     DFDAT,SINDIR;
+               mov     DFDAT,SINDIR;
+               cmp     SINDEX, A jne copy_scb_tofifo_loop;
+               or      DFCNTRL, HDMAEN|FIFOFLUSH;
 dma_scb_fromhost:
-       call    dma_finish;
-       /* If we were putting the SCB, we are done */
-       test    DMAPARAMS, DIRECTION    jz      return;
-       mvi     SCB_CONTROL  call dfdat_in_7;
-       call    dfdat_in_7_continued;
-       call    dfdat_in_7_continued;
-       jmp     dfdat_in_7_continued;
+               call    dma_finish;
+               /* If we were putting the SCB, we are done */
+               test    DMAPARAMS, DIRECTION    jz      return;
+               mvi     SCB_CONTROL  call dfdat_in_7;
+               call    dfdat_in_7_continued;
+               call    dfdat_in_7_continued;
+               jmp     dfdat_in_7_continued;
 dfdat_in_7:
-       mov     DINDEX,SINDEX;
+               mov     DINDEX,SINDEX;
 dfdat_in_7_continued:
-       mov     DINDIR,DFDAT;
-       mov     DINDIR,DFDAT;
-       mov     DINDIR,DFDAT;
-       mov     DINDIR,DFDAT;
-       mov     DINDIR,DFDAT;
-       mov     DINDIR,DFDAT;
-       mov     DINDIR,DFDAT ret;
+               mov     DINDIR,DFDAT;
+               mov     DINDIR,DFDAT;
+               mov     DINDIR,DFDAT;
+               mov     DINDIR,DFDAT;
+               mov     DINDIR,DFDAT;
+               mov     DINDIR,DFDAT;
+               mov     DINDIR,DFDAT ret;
+       }
+
 
 /*
  * Wait for DMA from host memory to data FIFO to complete, then disable
@@ -1188,13 +1415,13 @@ dma_finish:
        ret;
 
 add_scb_to_free_list:
-.if ( SCB_PAGING )
-       mov     SCB_NEXT, FREE_SCBH;
-       mov     FREE_SCBH, SCBPTR;
-.endif
+       if ((p->flags & AHC_PAGESCBS) != 0) {
+               mov     SCB_NEXT, FREE_SCBH;
+               mov     FREE_SCBH, SCBPTR;
+       }
        mvi     SCB_TAG, SCB_LIST_NULL ret;
 
-.if ( SCB_PAGING )
+if ((p->flags & AHC_PAGESCBS) != 0) {
 get_free_or_disc_scb:
        cmp     FREE_SCBH, SCB_LIST_NULL jne dequeue_free_scb;
        cmp     DISCONNECTED_SCBH, SCB_LIST_NULL jne dequeue_disc_scb;
@@ -1211,7 +1438,7 @@ unlink_disc_scb:
 dequeue_free_scb:
        mov     SCBPTR, FREE_SCBH;
        mov     FREE_SCBH, SCB_NEXT ret;
-.endif
+}
 
 add_scb_to_disc_list:
 /*
diff --git a/drivers/scsi/aic7xxx/bsd_q.h b/drivers/scsi/aic7xxx/bsd_q.h
new file mode 100644 (file)
index 0000000..042fc39
--- /dev/null
@@ -0,0 +1,507 @@
+/*
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 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. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)queue.h     8.5 (Berkeley) 8/20/94
+ * $Id: queue.h,v 1.21 1998/05/12 03:55:25 gibbs Exp $
+ */
+
+#ifndef _SYS_QUEUE_H_
+#define        _SYS_QUEUE_H_
+
+/*
+ * This file defines five types of data structures: singly-linked lists,
+ * slingly-linked tail queues, lists, tail queues, and circular queues.
+ *
+ * A singly-linked list is headed by a single forward pointer. The elements
+ * are singly linked for minimum space and pointer manipulation overhead at
+ * the expense of O(n) removal for arbitrary elements. New elements can be
+ * added to the list after an existing element or at the head of the list.
+ * Elements being removed from the head of the list should use the explicit
+ * macro for this purpose for optimum efficiency. A singly-linked list may
+ * only be traversed in the forward direction.  Singly-linked lists are ideal
+ * for applications with large datasets and few or no removals or for
+ * implementing a LIFO queue.
+ *
+ * A singly-linked tail queue is headed by a pair of pointers, one to the
+ * head of the list and the other to the tail of the list. The elements are
+ * singly linked for minimum space and pointer manipulation overhead at the
+ * expense of O(n) removal for arbitrary elements. New elements can be added
+ * to the list after an existing element, at the head of the list, or at the
+ * end of the list. Elements being removed from the head of the tail queue
+ * should use the explicit macro for this purpose for optimum efficiency.
+ * A singly-linked tail queue may only be traversed in the forward direction.
+ * Singly-linked tail queues are ideal for applications with large datasets
+ * and few or no removals or for implementing a FIFO queue.
+ *
+ * A list is headed by a single forward pointer (or an array of forward
+ * pointers for a hash table header). The elements are doubly linked
+ * so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before
+ * or after an existing element or at the head of the list. A list
+ * may only be traversed in the forward direction.
+ *
+ * A tail queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or
+ * after an existing element, at the head of the list, or at the end of
+ * the list. A tail queue may only be traversed in the forward direction.
+ *
+ * A circle queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or after
+ * an existing element, at the head of the list, or at the end of the list.
+ * A circle queue may be traversed in either direction, but has a more
+ * complex end of list detection.
+ *
+ * For details on the use of these macros, see the queue(3) manual page.
+ *
+ *
+ *                     SLIST   LIST    STAILQ  TAILQ   CIRCLEQ
+ * _HEAD               +       +       +       +       +
+ * _ENTRY              +       +       +       +       +
+ * _INIT               +       +       +       +       +
+ * _EMPTY              +       +       +       +       +
+ * _FIRST              +       +       -       +       +
+ * _NEXT               +       +       -       +       +
+ * _PREV               -       -       -       +       +
+ * _LAST               -       -       -       +       +
+ * _FOREACH            +       +       -       +       -
+ * _INSERT_HEAD                +       +       +       +       +
+ * _INSERT_BEFORE      -       +       -       +       +
+ * _INSERT_AFTER       +       +       +       +       +
+ * _INSERT_TAIL                -       -       +       +       +
+ * _REMOVE_HEAD                +       -       +       -       -
+ * _REMOVE             +       +       +       +       +
+ *
+ */
+
+/*
+ * Singly-linked List definitions.
+ */
+#define SLIST_HEAD(name, type)                                         \
+struct name {                                                          \
+       struct type *slh_first; /* first element */                     \
+}
+#define SLIST_ENTRY(type)                                              \
+struct {                                                               \
+       struct type *sle_next;  /* next element */                      \
+}
+/*
+ * Singly-linked List functions.
+ */
+#define        SLIST_EMPTY(head)       ((head)->slh_first == NULL)
+
+#define        SLIST_FIRST(head)       ((head)->slh_first)
+
+#define SLIST_FOREACH(var, head, field)                                        \
+       for((var) = (head)->slh_first; (var); (var) = (var)->field.sle_next)
+
+#define SLIST_INIT(head) {                                             \
+       (head)->slh_first = NULL;                                       \
+}
+
+#define SLIST_INSERT_AFTER(slistelm, elm, field) do  {                 \
+       (elm)->field.sle_next = (slistelm)->field.sle_next;             \
+       (slistelm)->field.sle_next = (elm);                             \
+} while (0)
+
+#define SLIST_INSERT_HEAD(head, elm, field) do {                       \
+       (elm)->field.sle_next = (head)->slh_first;                      \
+       (head)->slh_first = (elm);                                      \
+} while (0)
+
+#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
+
+#define SLIST_REMOVE_HEAD(head, field) do {                            \
+       (head)->slh_first = (head)->slh_first->field.sle_next;          \
+} while (0)
+
+#define SLIST_REMOVE(head, elm, type, field) do {                      \
+       if ((head)->slh_first == (elm)) {                               \
+               SLIST_REMOVE_HEAD((head), field);                       \
+       }                                                               \
+       else {                                                          \
+               struct type *curelm = (head)->slh_first;                \
+               while( curelm->field.sle_next != (elm) )                \
+                       curelm = curelm->field.sle_next;                \
+               curelm->field.sle_next =                                \
+                   curelm->field.sle_next->field.sle_next;             \
+       }                                                               \
+} while (0)
+
+/*
+ * Singly-linked Tail queue definitions.
+ */
+#define STAILQ_HEAD(name, type)                                                \
+struct name {                                                          \
+       struct type *stqh_first;/* first element */                     \
+       struct type **stqh_last;/* addr of last next element */         \
+}
+
+#define STAILQ_ENTRY(type)                                             \
+struct {                                                               \
+       struct type *stqe_next; /* next element */                      \
+}
+
+/*
+ * Singly-linked Tail queue functions.
+ */
+#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL)
+
+#define        STAILQ_INIT(head) do {                                          \
+       (head)->stqh_first = NULL;                                      \
+       (head)->stqh_last = &(head)->stqh_first;                        \
+} while (0)
+
+#define STAILQ_FIRST(head)     ((head)->stqh_first)
+#define STAILQ_LAST(head)      (*(head)->stqh_last)
+
+#define STAILQ_INSERT_HEAD(head, elm, field) do {                      \
+       if (((elm)->field.stqe_next = (head)->stqh_first) == NULL)      \
+               (head)->stqh_last = &(elm)->field.stqe_next;            \
+       (head)->stqh_first = (elm);                                     \
+} while (0)
+
+#define STAILQ_INSERT_TAIL(head, elm, field) do {                      \
+       (elm)->field.stqe_next = NULL;                                  \
+       *(head)->stqh_last = (elm);                                     \
+       (head)->stqh_last = &(elm)->field.stqe_next;                    \
+} while (0)
+
+#define STAILQ_INSERT_AFTER(head, tqelm, elm, field) do {              \
+       if (((elm)->field.stqe_next = (tqelm)->field.stqe_next) == NULL)\
+               (head)->stqh_last = &(elm)->field.stqe_next;            \
+       (tqelm)->field.stqe_next = (elm);                               \
+} while (0)
+
+#define STAILQ_NEXT(elm, field)        ((elm)->field.stqe_next)
+
+#define STAILQ_REMOVE_HEAD(head, field) do {                           \
+       if (((head)->stqh_first =                                       \
+            (head)->stqh_first->field.stqe_next) == NULL)              \
+               (head)->stqh_last = &(head)->stqh_first;                \
+} while (0)
+
+#define STAILQ_REMOVE(head, elm, type, field) do {                     \
+       if ((head)->stqh_first == (elm)) {                              \
+               STAILQ_REMOVE_HEAD(head, field);                        \
+       }                                                               \
+       else {                                                          \
+               struct type *curelm = (head)->stqh_first;               \
+               while( curelm->field.stqe_next != (elm) )               \
+                       curelm = curelm->field.stqe_next;               \
+               if((curelm->field.stqe_next =                           \
+                   curelm->field.stqe_next->field.stqe_next) == NULL)  \
+                       (head)->stqh_last = &(curelm)->field.stqe_next; \
+       }                                                               \
+} while (0)
+
+/*
+ * List definitions.
+ */
+
+#define LIST_ENTRY(type)                                               \
+struct {                                                               \
+       struct type *le_next;   /* next element */                      \
+       struct type **le_prev;  /* address of previous next element */  \
+}
+
+/*
+ * List functions.
+ */
+
+#define        LIST_EMPTY(head) ((head)->lh_first == NULL)
+
+#define LIST_FIRST(head)       ((head)->lh_first)
+
+#define LIST_FOREACH(var, head, field)                                 \
+       for((var) = (head)->lh_first; (var); (var) = (var)->field.le_next)
+
+#define        LIST_INIT(head) do {                                            \
+       (head)->lh_first = NULL;                                        \
+} while (0)
+
+#define LIST_INSERT_AFTER(listelm, elm, field) do {                    \
+       if (((elm)->field.le_next = (listelm)->field.le_next) != NULL)  \
+               (listelm)->field.le_next->field.le_prev =               \
+                   &(elm)->field.le_next;                              \
+       (listelm)->field.le_next = (elm);                               \
+       (elm)->field.le_prev = &(listelm)->field.le_next;               \
+} while (0)
+
+#define LIST_INSERT_BEFORE(listelm, elm, field) do {                   \
+       (elm)->field.le_prev = (listelm)->field.le_prev;                \
+       (elm)->field.le_next = (listelm);                               \
+       *(listelm)->field.le_prev = (elm);                              \
+       (listelm)->field.le_prev = &(elm)->field.le_next;               \
+} while (0)
+
+#define LIST_INSERT_HEAD(head, elm, field) do {                                \
+       if (((elm)->field.le_next = (head)->lh_first) != NULL)          \
+               (head)->lh_first->field.le_prev = &(elm)->field.le_next;\
+       (head)->lh_first = (elm);                                       \
+       (elm)->field.le_prev = &(head)->lh_first;                       \
+} while (0)
+
+#define LIST_NEXT(elm, field)  ((elm)->field.le_next)
+
+#define LIST_REMOVE(elm, field) do {                                   \
+       if ((elm)->field.le_next != NULL)                               \
+               (elm)->field.le_next->field.le_prev =                   \
+                   (elm)->field.le_prev;                               \
+       *(elm)->field.le_prev = (elm)->field.le_next;                   \
+} while (0)
+
+/*
+ * Tail queue definitions.
+ */
+#define TAILQ_HEAD(name, type)                                         \
+struct name {                                                          \
+       struct type *tqh_first; /* first element */                     \
+       struct type **tqh_last; /* addr of last next element */         \
+}
+
+#define TAILQ_HEAD_INITIALIZER(head)                                   \
+       { NULL, &(head).tqh_first }
+
+#define TAILQ_ENTRY(type)                                              \
+struct {                                                               \
+       struct type *tqe_next;  /* next element */                      \
+       struct type **tqe_prev; /* address of previous next element */  \
+}
+
+/*
+ * Tail queue functions.
+ */
+#define        TAILQ_EMPTY(head) ((head)->tqh_first == NULL)
+
+#define TAILQ_FOREACH(var, head, field)                                        \
+       for (var = TAILQ_FIRST(head); var; var = TAILQ_NEXT(var, field))
+
+#define        TAILQ_FIRST(head) ((head)->tqh_first)
+
+#define        TAILQ_LAST(head, headname) \
+       (*(((struct headname *)((head)->tqh_last))->tqh_last))
+
+#define        TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
+
+#define TAILQ_PREV(elm, headname, field) \
+       (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
+
+#define        TAILQ_INIT(head) do {                                           \
+       (head)->tqh_first = NULL;                                       \
+       (head)->tqh_last = &(head)->tqh_first;                          \
+} while (0)
+
+#define TAILQ_INSERT_HEAD(head, elm, field) do {                       \
+       if (((elm)->field.tqe_next = (head)->tqh_first) != NULL)        \
+               (head)->tqh_first->field.tqe_prev =                     \
+                   &(elm)->field.tqe_next;                             \
+       else                                                            \
+               (head)->tqh_last = &(elm)->field.tqe_next;              \
+       (head)->tqh_first = (elm);                                      \
+       (elm)->field.tqe_prev = &(head)->tqh_first;                     \
+} while (0)
+
+#define TAILQ_INSERT_TAIL(head, elm, field) do {                       \
+       (elm)->field.tqe_next = NULL;                                   \
+       (elm)->field.tqe_prev = (head)->tqh_last;                       \
+       *(head)->tqh_last = (elm);                                      \
+       (head)->tqh_last = &(elm)->field.tqe_next;                      \
+} while (0)
+
+#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do {             \
+       if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
+               (elm)->field.tqe_next->field.tqe_prev =                 \
+                   &(elm)->field.tqe_next;                             \
+       else                                                            \
+               (head)->tqh_last = &(elm)->field.tqe_next;              \
+       (listelm)->field.tqe_next = (elm);                              \
+       (elm)->field.tqe_prev = &(listelm)->field.tqe_next;             \
+} while (0)
+
+#define TAILQ_INSERT_BEFORE(listelm, elm, field) do {                  \
+       (elm)->field.tqe_prev = (listelm)->field.tqe_prev;              \
+       (elm)->field.tqe_next = (listelm);                              \
+       *(listelm)->field.tqe_prev = (elm);                             \
+       (listelm)->field.tqe_prev = &(elm)->field.tqe_next;             \
+} while (0)
+
+#define TAILQ_REMOVE(head, elm, field) do {                            \
+       if (((elm)->field.tqe_next) != NULL)                            \
+               (elm)->field.tqe_next->field.tqe_prev =                 \
+                   (elm)->field.tqe_prev;                              \
+       else                                                            \
+               (head)->tqh_last = (elm)->field.tqe_prev;               \
+       *(elm)->field.tqe_prev = (elm)->field.tqe_next;                 \
+} while (0)
+
+/*
+ * Circular queue definitions.
+ */
+#define CIRCLEQ_HEAD(name, type)                                       \
+struct name {                                                          \
+       struct type *cqh_first;         /* first element */             \
+       struct type *cqh_last;          /* last element */              \
+}
+
+#define CIRCLEQ_ENTRY(type)                                            \
+struct {                                                               \
+       struct type *cqe_next;          /* next element */              \
+       struct type *cqe_prev;          /* previous element */          \
+}
+
+/*
+ * Circular queue functions.
+ */
+#define CIRCLEQ_EMPTY(head) ((head)->cqh_first == (void *)(head))
+
+#define CIRCLEQ_FIRST(head) ((head)->cqh_first)
+
+#define CIRCLEQ_FOREACH(var, head, field)                              \
+       for((var) = (head)->cqh_first;                                  \
+           (var) != (void *)(head);                                    \
+           (var) = (var)->field.cqe_next)
+
+#define        CIRCLEQ_INIT(head) do {                                         \
+       (head)->cqh_first = (void *)(head);                             \
+       (head)->cqh_last = (void *)(head);                              \
+} while (0)
+
+#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do {           \
+       (elm)->field.cqe_next = (listelm)->field.cqe_next;              \
+       (elm)->field.cqe_prev = (listelm);                              \
+       if ((listelm)->field.cqe_next == (void *)(head))                \
+               (head)->cqh_last = (elm);                               \
+       else                                                            \
+               (listelm)->field.cqe_next->field.cqe_prev = (elm);      \
+       (listelm)->field.cqe_next = (elm);                              \
+} while (0)
+
+#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do {          \
+       (elm)->field.cqe_next = (listelm);                              \
+       (elm)->field.cqe_prev = (listelm)->field.cqe_prev;              \
+       if ((listelm)->field.cqe_prev == (void *)(head))                \
+               (head)->cqh_first = (elm);                              \
+       else                                                            \
+               (listelm)->field.cqe_prev->field.cqe_next = (elm);      \
+       (listelm)->field.cqe_prev = (elm);                              \
+} while (0)
+
+#define CIRCLEQ_INSERT_HEAD(head, elm, field) do {                     \
+       (elm)->field.cqe_next = (head)->cqh_first;                      \
+       (elm)->field.cqe_prev = (void *)(head);                         \
+       if ((head)->cqh_last == (void *)(head))                         \
+               (head)->cqh_last = (elm);                               \
+       else                                                            \
+               (head)->cqh_first->field.cqe_prev = (elm);              \
+       (head)->cqh_first = (elm);                                      \
+} while (0)
+
+#define CIRCLEQ_INSERT_TAIL(head, elm, field) do {                     \
+       (elm)->field.cqe_next = (void *)(head);                         \
+       (elm)->field.cqe_prev = (head)->cqh_last;                       \
+       if ((head)->cqh_first == (void *)(head))                        \
+               (head)->cqh_first = (elm);                              \
+       else                                                            \
+               (head)->cqh_last->field.cqe_next = (elm);               \
+       (head)->cqh_last = (elm);                                       \
+} while (0)
+
+#define CIRCLEQ_LAST(head) ((head)->cqh_last)
+
+#define CIRCLEQ_NEXT(elm,field) ((elm)->field.cqe_next)
+
+#define CIRCLEQ_PREV(elm,field) ((elm)->field.cqe_prev)
+
+#define        CIRCLEQ_REMOVE(head, elm, field) do {                           \
+       if ((elm)->field.cqe_next == (void *)(head))                    \
+               (head)->cqh_last = (elm)->field.cqe_prev;               \
+       else                                                            \
+               (elm)->field.cqe_next->field.cqe_prev =                 \
+                   (elm)->field.cqe_prev;                              \
+       if ((elm)->field.cqe_prev == (void *)(head))                    \
+               (head)->cqh_first = (elm)->field.cqe_next;              \
+       else                                                            \
+               (elm)->field.cqe_prev->field.cqe_next =                 \
+                   (elm)->field.cqe_next;                              \
+} while (0)
+
+#ifdef KERNEL
+
+/*
+ * XXX insque() and remque() are an old way of handling certain queues.
+ * They bogusly assumes that all queue heads look alike.
+ */
+
+struct quehead {
+       struct quehead *qh_link;
+       struct quehead *qh_rlink;
+};
+
+#ifdef __GNUC__
+
+static __inline void
+insque(void *a, void *b)
+{
+       struct quehead *element = a, *head = b;
+
+       element->qh_link = head->qh_link;
+       element->qh_rlink = head;
+       head->qh_link = element;
+       element->qh_link->qh_rlink = element;
+}
+
+static __inline void
+remque(void *a)
+{
+       struct quehead *element = a;
+
+       element->qh_link->qh_rlink = element->qh_rlink;
+       element->qh_rlink->qh_link = element->qh_link;
+       element->qh_rlink = 0;
+}
+
+#else /* !__GNUC__ */
+
+void   insque __P((void *a, void *b));
+void   remque __P((void *a));
+
+#endif /* __GNUC__ */
+
+#endif /* KERNEL */
+
+#endif /* !_SYS_QUEUE_H_ */
index 875283fc8dbcbfdad99120378d5f4a24039b4175..27f839365499a8f01d82eedd9227db3ac61cde0f 100644 (file)
@@ -2,7 +2,7 @@
  * Instruction formats for the sequencer program downloaded to
  * Aic7xxx SCSI host adapters
  *
- * Copyright (c) 1997 Justin T. Gibbs.
+ * Copyright (c) 1997, 1998 Justin T. Gibbs.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  */
 
 struct ins_format1 {
-       unsigned char immediate;
-       unsigned char source;
-       unsigned char destination;
-       unsigned char opcode_ret;
-#define DOWNLOAD_CONST_IMMEDIATE 0x80
+       unsigned int    immediate       : 8,
+                       source          : 9,
+                       destination     : 9,
+                       ret             : 1,
+                       opcode          : 4,
+                       parity          : 1;
 };
 
 struct ins_format2 {
-       unsigned char shift_control;
-       unsigned char source;
-       unsigned char destination;
-       unsigned char opcode_ret;
-#define RETURN_BIT 0x01
+       unsigned int    shift_control   : 8,
+                       source          : 9,
+                       destination     : 9,
+                       ret             : 1,
+                       opcode          : 4,
+                       parity          : 1;
 };
 
 struct ins_format3 {
-       unsigned char immediate;
-       unsigned char source;
-       unsigned char address;
-       unsigned char opcode_addr;
-#define ADDR_HIGH_BIT 0x01
+       unsigned int    immediate       : 8,
+                       source          : 9,
+                       address         : 10,
+                       opcode          : 4,
+                       parity          : 1;
 };
 
-#ifndef __KERNEL__
-struct instruction {
-       union {
+union ins_formats {
                struct ins_format1 format1;
                struct ins_format2 format2;
                struct ins_format3 format3;
                unsigned char      bytes[4];
-       } format;
-       u_int   srcline;
+               unsigned int       integer;
+};
+struct instruction {
+       union   ins_formats format;
+       unsigned int    srcline;
        struct symbol *patch_label;
        STAILQ_ENTRY(instruction) links;
 };
-#endif
 
 #define        AIC_OP_OR       0x0
 #define        AIC_OP_AND      0x1
@@ -80,6 +82,7 @@ struct instruction {
 #define        AIC_OP_ADD      0x3
 #define        AIC_OP_ADC      0x4
 #define        AIC_OP_ROL      0x5
+#define        AIC_OP_BMOV     0x6
 
 #define        AIC_OP_JMP      0x8
 #define AIC_OP_JC      0x9
index 44ac9d5f9c8961d181defb5d028b51ffb77a6c59..d3d1b1ea36a324cb4ed16e5f15095d3c46161067 100644 (file)
@@ -85,10 +85,8 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length,
   struct aic7xxx_host *p;
   int    size = 0;
   unsigned char i;
-#ifdef AIC7XXX_PROC_STATS
   struct aic7xxx_xferstats *sp;
   unsigned char target, lun;
-#endif
 
   HBAptr = NULL;
 
@@ -130,16 +128,18 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length,
    */
 
   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)
+#ifdef AIC7XXX_PROC_STATS
         size += 512;
+#else
+        size += 256;
+#endif
     }
   }
-#endif
   if (aic7xxx_buffer_size != size)
   {
     if (aic7xxx_buffer != NULL) 
@@ -195,9 +195,11 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length,
       if (p->flags & (AHC_CHNLB|AHC_CHNLC))
         channel = (p->flags & AHC_CHNLB) ? " Channel B" : " Channel C";
     }
-    if (p->type & AHC_WIDE)
+    if (p->features & AHC_WIDE)
       wide = "Wide ";
-    if (p->type & AHC_ULTRA)
+    if (p->features & AHC_ULTRA2)
+      ultra = "Ultra2-LVD/SE ";
+    else if (p->features & AHC_ULTRA)
       ultra = "Ultra ";
     size += sprintf(BLS, "                           %s%sController%s\n",
       ultra, wide, channel);
@@ -210,25 +212,26 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length,
   {
     size += sprintf(BLS, "    PCI MMAPed I/O Base: 0x%lx\n", p->mbase);
   }
-  if( !(p->type & AHC_AIC78x0) )
+  if( (p->chip & (AHC_VL | AHC_EISA)) )
   {
     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, " Adapter SEEPROM Config: %s\n",
+          (p->flags & AHC_SEEPROM_FOUND) ? "SEEPROM found and used." :
+         ((p->flags & AHC_USEDEFAULTS) ? "SEEPROM not found, using defaults." :
+           "SEEPROM not found, using leftover BIOS values.") );
+  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: 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);
+  if (p->flags & AHC_EXTERNAL_SRAM)
+    size += sprintf(BLS, "                         Using External SCB SRAM\n");
   size += sprintf(BLS, "             Interrupts: %ld", p->isr_count);
-  if (p->type & AHC_AIC7770)
+  if (p->chip & AHC_EISA)
   {
     size += sprintf(BLS, " %s\n",
         (p->pause & IRQMS) ? "(Level Sensitive)" : "(Edge Triggered)");
@@ -244,7 +247,7 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length,
   size += sprintf(BLS, "   Extended Translation: %sabled\n",
       (p->flags & AHC_EXTEND_TRANS_A) ? "En" : "Dis");
   size += sprintf(BLS, "Disconnect Enable Flags: 0x%04x\n", p->discenable);
-  if (p->type & AHC_ULTRA)
+  if (p->features & (AHC_ULTRA | AHC_ULTRA2))
   {
     size += sprintf(BLS, "     Ultra Enable Flags: 0x%04x\n", p->ultraenb);
   }
@@ -268,7 +271,6 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length,
     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");
   for (target = 0; target < MAX_TARGETS; target++)
@@ -280,7 +282,7 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length,
       {
         continue;
       }
-      if (p->type & AHC_TWIN)
+      if (p->features & AHC_TWIN)
       {
         size += sprintf(BLS, "(scsi%d:%d:%d:%d)\n",
             p->host_no, (target >> 3), (target & 0x7), lun);
@@ -290,10 +292,50 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length,
         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",
+      size += sprintf(BLS, "  Device using %s/%s\n",
+            (p->transinfo[target].cur_width == MSG_EXT_WDTR_BUS_16_BIT) ?
+            "Wide" : "Narrow",
+            (p->transinfo[target].cur_offset != 0) ?
+            "Sync transfers at" : "Async transfers." );
+      if (p->transinfo[target].cur_offset != 0)
+      {
+        struct aic7xxx_syncrate *sync_rate;
+        int period = p->transinfo[target].cur_period;
+        int rate = (p->transinfo[target].cur_width ==
+                    MSG_EXT_WDTR_BUS_16_BIT) ? 1 : 0;
+
+        sync_rate = aic7xxx_find_syncrate(p, &period, AHC_SYNCRATE_ULTRA2);
+        if (sync_rate != NULL)
+        {
+          size += sprintf(BLS, "  %s MByte/sec, offset %d\n",
+                          sync_rate->rate[rate],
+                          p->transinfo[target].cur_offset );
+        }
+        else
+        {
+          size += sprintf(BLS, "  3.3 MByte/sec, offset %d\n",
+                          p->transinfo[target].cur_offset );
+        }
+      }
+      size += sprintf(BLS, "    Device Negotiation Settings\n");
+      size += sprintf(BLS, "        Period Offset Bus Width\n");
+      size += sprintf(BLS, "User       %03d    %03d        %d\n",
+                      p->transinfo[target].user_period,
+                      p->transinfo[target].user_offset,
+                      p->transinfo[target].user_width);
+      size += sprintf(BLS, "Goal       %03d    %03d        %d\n",
+                      p->transinfo[target].goal_period,
+                      p->transinfo[target].goal_offset,
+                      p->transinfo[target].goal_width);
+      size += sprintf(BLS, "Current    %03d    %03d        %d\n",
+                      p->transinfo[target].cur_period,
+                      p->transinfo[target].cur_offset,
+                      p->transinfo[target].cur_width);
+      size += sprintf(BLS, "    Total transfers %ld (%ld read;%ld written)\n",
           sp->xfers, sp->r_total, sp->w_total);
-      size += sprintf(BLS, "blks(512) rd=%ld; blks(512) wr=%ld\n",
+      size += sprintf(BLS, "      blks(512) rd=%ld; blks(512) wr=%ld\n",
           sp->r_total512, sp->w_total512);
+#ifdef AIC7XXX_PROC_STATS
       size += sprintf(BLS, "%s\n", HDRB);
       size += sprintf(BLS, " Reads:");
       for (i = 0; i < NUMBER(sp->r_bins); i++)
@@ -306,10 +348,10 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length,
       {
         size += sprintf(BLS, "%6ld ", sp->w_bins[i]);
       }
+#endif /* AIC7XXX_PROC_STATS */
       size += sprintf(BLS, "\n\n");
     }
   }
-#endif /* AIC7XXX_PROC_STATS */
 
   if (size >= aic7xxx_buffer_size)
   {
index a0682fd3ee6e7bb82a9efffbfdf262d6db1fadc1..d12d1b6e54a53ab30116bc1f6bb8c75a730915cc 100644 (file)
 
 #define        SCSIRATE                        0x04
 #define                WIDEXFER                0x80
+#define                SXFR_ULTRA2             0x7f
 #define                SXFR                    0x70
 #define                SOFS                    0x0f
 
 #define        SCSIID                          0x05
-#define                OID                     0x0f
+#define        SCSIOFFSET                      0x05
+#define                SOFS_ULTRA2             0x7f
 
 #define        SCSIDATL                        0x06
 
@@ -73,6 +75,7 @@
 #define                SELDO                   0x40
 #define                SELDI                   0x20
 #define                SELINGO                 0x10
+#define                IOERR                   0x08
 #define                SWRAP                   0x08
 #define                SDONE                   0x04
 #define                SPIORDY                 0x02
 #define        SSTAT2                          0x0d
 #define                OVERRUN                 0x80
 #define                SFCNT                   0x1f
+#define                EXP_ACTIVE              0x10
 
 #define        SSTAT3                          0x0e
 #define                SCSICNT                 0xf0
 #define                OFFCNT                  0x0f
 
-#define        SCSITEST                        0x0f
-#define                RQAKCNT                 0x04
-#define                CNTRTEST                0x02
-#define                CMODE                   0x01
+#define        SCSIID_ULTRA2                   0x0f
+#define                OID                     0x0f
 
 #define        SIMODE0                         0x10
 #define                ENSELDO                 0x40
 #define                ENSELDI                 0x20
 #define                ENSELINGO               0x10
+#define                ENIOERR                 0x08
 #define                ENSWRAP                 0x08
 #define                ENSDONE                 0x04
 #define                ENSPIORDY               0x02
 #define                BRDDAT7                 0x80
 #define                BRDDAT6                 0x40
 #define                BRDDAT5                 0x20
+#define                BRDDAT4                 0x10
 #define                BRDSTB                  0x10
 #define                BRDCS                   0x08
+#define                BRDDAT3                 0x08
+#define                BRDDAT2                 0x04
 #define                BRDRW                   0x04
+#define                BRDRW_ULTRA2            0x02
 #define                BRDCTL1                 0x02
+#define                BRDSTB_ULTRA2           0x01
 #define                BRDCTL0                 0x01
 
 #define        SEECTL                          0x1e
 #define                DIAGLEDEN               0x80
 #define                DIAGLEDON               0x40
 #define                AUTOFLUSHDIS            0x20
+#define                ENAB40                  0x08
+#define                ENAB20                  0x04
 #define                SELWIDE                 0x02
+#define                XCVR                    0x01
 
 #define        SRAM_BASE                       0x20
 
-#define        TARG_SCRATCH                    0x20
+#define        TARG_SCSIRATE                   0x20
 
 #define        ULTRA_ENB                       0x30
 
 #define        MSG_OUT                         0x34
 
 #define        DMAPARAMS                       0x35
+#define                PRELOADEN               0x80
 #define                WIDEODD                 0x40
 #define                SCSIEN                  0x20
 #define                SDMAENACK               0x10
 #define                SEND_REJ                0x20
 #define                MSGOUT_PHASEMIS         0x10
 
-#define        LAST_MSG                        0x52
+#define        ARG_2                           0x52
+#define        RETURN_2                        0x52
+
+#define        LAST_MSG                        0x53
+
+#define        PREFETCH_CNT                    0x54
 
 #define        SCSICONF                        0x5a
 #define                TERM_ENB                0x80
 
 #define        STACK                           0x6f
 
+#define        TARG_OFFSET                     0x70
+
 #define        BCTL                            0x84
 #define                ACE                     0x08
 #define                ENABLE                  0x01
 
+#define        DSCOMMAND0                      0x84
+#define                INTSCBRAMSEL            0x08
+#define                RAMPS                   0x04
+#define                USCBSIZE32              0x02
+#define                CIOPARCKEN              0x01
+
 #define        DSCOMMAND                       0x84
 #define                CACHETHEN               0x80
 #define                DPARCKEN                0x40
 #define                BON                     0x0f
 
 #define        BUSSPD                          0x86
-#define                DFTHRSH_100             0xc0
 #define                DFTHRSH                 0xc0
 #define                STBOFF                  0x38
 #define                STBON                   0x07
 
 #define        DSPCISTATUS                     0x86
+#define                DFTHRSH_100             0xc0
 
 #define        HCNTRL                          0x87
 #define                POWRDN                  0x40
 #define                CLRSEQINT               0x01
 
 #define        ERROR                           0x92
+#define                CIOPARERR               0x80
 #define                PCIERRSTAT              0x40
 #define                MPARERR                 0x20
 #define                DPARERR                 0x10
 #define        DFCNTRL                         0x93
 
 #define        DFSTATUS                        0x94
+#define                PRELOAD_AVAIL           0x80
 #define                DWORDEMP                0x20
 #define                MREQPEND                0x10
 #define                HDONE                   0x08
 
 #define        QOUTCNT                         0x9e
 
+#define        SFUNCT                          0x9f
+
 #define        SCB_CONTROL                     0xa0
 #define                MK_MESSAGE              0x80
 #define                DISCENB                 0x40
 #define                ADSEL                   0x1e
 #define                DI_2840                 0x01
 
+#define        CCHADDR                         0xe0
+
+#define        CCHCNT                          0xe8
+
+#define        CCSGRAM                         0xe9
+
+#define        CCSGADDR                        0xea
+
+#define        CCSGCTL                         0xeb
+#define                CCSGDONE                0x80
+#define                CCSGEN                  0x08
+#define                FLAG                    0x02
+#define                CCSGRESET               0x01
+
+#define        CCSCBRAM                        0xec
+
+#define        CCSCBADDR                       0xed
+
+#define        CCSCBCTL                        0xee
+#define                CCSCBDONE               0x80
+#define                ARRDONE                 0x40
+#define                CCARREN                 0x10
+#define                CCSCBEN                 0x08
+#define                CCSCBDIR                0x04
+#define                CCSCBRESET              0x01
+
+#define        CCSCBCNT                        0xef
+
+#define        CCSCBPTR                        0xf1
+
+#define        HNSCB_QOFF                      0xf4
+
+#define        SNSCB_QOFF                      0xf6
+
+#define        SDSCB_QOFF                      0xf8
+
+#define        QOFF_CTLSTA                     0xfa
+#define                SCB_AVAIL               0x40
+#define                SNSCB_ROLLOVER          0x20
+#define                SDSCB_ROLLOVER          0x10
+#define                SCB_QSIZE               0x07
+#define                SCB_QSIZE_256           0x06
+
+#define        DFF_THRSH                       0xfb
+#define                WR_DFTHRSH              0x70
+#define                WR_DFTHRSH_MAX          0x70
+#define                WR_DFTHRSH_90           0x60
+#define                WR_DFTHRSH_85           0x50
+#define                WR_DFTHRSH_75           0x40
+#define                WR_DFTHRSH_63           0x30
+#define                WR_DFTHRSH_50           0x20
+#define                WR_DFTHRSH_25           0x10
+#define                RD_DFTHRSH_MAX          0x07
+#define                RD_DFTHRSH              0x07
+#define                RD_DFTHRSH_90           0x06
+#define                RD_DFTHRSH_85           0x05
+#define                RD_DFTHRSH_75           0x04
+#define                RD_DFTHRSH_63           0x03
+#define                RD_DFTHRSH_50           0x02
+#define                RD_DFTHRSH_25           0x01
+#define                WR_DFTHRSH_MIN          0x00
+#define                RD_DFTHRSH_MIN          0x00
+
+#define        SG_CACHEPTR                     0xfc
+#define                SG_USER_DATA            0xfc
+#define                LAST_SEG                0x02
+#define                LAST_SEG_DONE           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        CMD_GROUP_CODE_SHIFT    0x05
+#define        MAX_OFFSET_ULTRA2       0x7f
 #define        MAX_OFFSET_16BIT        0x08
+#define        BUS_8_BIT       0x00
+#define        QOUTFIFO_OFFSET 0x01
 #define        UNTAGGEDSCB_OFFSET      0x00
+#define        CCSGRAM_MAXSEGS 0x10
 #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
+#define        CCSGADDR_MAX    0x80
 
 
 /* Downloaded Constant Definitions */
-#define        TMODE_NUMCMDS   0x01
-#define        QCNTMASK        0x00
+#define        TMODE_NUMCMDS   0x00
diff --git a/drivers/scsi/aic7xxx_seq.c b/drivers/scsi/aic7xxx_seq.c
new file mode 100644 (file)
index 0000000..9205cc4
--- /dev/null
@@ -0,0 +1,769 @@
+/*
+  * DO NOT EDIT - This file is automatically generated.
+  */
+static unsigned char seqprog[] = {
+       0xff, 0x6a, 0x06, 0x08,
+       0x32, 0x6a, 0x00, 0x00,
+       0x12, 0x6a, 0x00, 0x00,
+       0xff, 0x6a, 0xd6, 0x09,
+       0xff, 0x6a, 0xdc, 0x09,
+       0x00, 0x65, 0x38, 0x59,
+       0xf7, 0x01, 0x02, 0x08,
+       0xff, 0x4e, 0xc8, 0x08,
+       0xbf, 0x60, 0xc0, 0x08,
+       0x60, 0x0b, 0x7c, 0x68,
+       0x40, 0x00, 0x0e, 0x68,
+       0x08, 0x1f, 0x3e, 0x10,
+       0x60, 0x0b, 0x7c, 0x68,
+       0x40, 0x00, 0x0e, 0x68,
+       0x08, 0x1f, 0x3e, 0x10,
+       0xff, 0x3e, 0x3e, 0x60,
+       0x40, 0xfa, 0x10, 0x78,
+       0xff, 0xf6, 0xd4, 0x08,
+       0x01, 0x4e, 0x9c, 0x18,
+       0x40, 0x60, 0xc0, 0x00,
+       0x00, 0x4d, 0x10, 0x70,
+       0x01, 0x4e, 0x9c, 0x18,
+       0xbf, 0x60, 0xc0, 0x08,
+       0x00, 0x6a, 0x72, 0x5c,
+       0xff, 0x4e, 0xc8, 0x18,
+       0x02, 0x6a, 0x88, 0x5b,
+       0xff, 0x52, 0x20, 0x09,
+       0x0d, 0x6a, 0x6a, 0x00,
+       0x00, 0x52, 0xfe, 0x5b,
+       0xff, 0x3e, 0x74, 0x09,
+       0xff, 0x90, 0x7c, 0x08,
+       0xff, 0x3e, 0x20, 0x09,
+       0x00, 0x65, 0x44, 0x58,
+       0x00, 0x65, 0x0e, 0x40,
+       0xf7, 0x1f, 0xca, 0x08,
+       0x08, 0xa1, 0xc8, 0x08,
+       0x00, 0x65, 0xca, 0x00,
+       0xff, 0x65, 0x3e, 0x08,
+       0xf0, 0xa1, 0xc8, 0x08,
+       0x0f, 0x0f, 0x1e, 0x08,
+       0x00, 0x0f, 0x1e, 0x00,
+       0xf0, 0xa1, 0xc8, 0x08,
+       0x0f, 0x05, 0x0a, 0x08,
+       0x00, 0x05, 0x0a, 0x00,
+       0x5a, 0x6a, 0x00, 0x04,
+       0x12, 0x65, 0xc8, 0x00,
+       0x00, 0x01, 0x02, 0x00,
+       0x31, 0x6a, 0xca, 0x00,
+       0x80, 0x37, 0x64, 0x68,
+       0xff, 0x65, 0xca, 0x18,
+       0xff, 0x37, 0xdc, 0x08,
+       0xff, 0x6e, 0xc8, 0x08,
+       0x00, 0x6c, 0x6c, 0x78,
+       0x20, 0x01, 0x02, 0x00,
+       0x4c, 0x37, 0xc8, 0x28,
+       0x08, 0x1f, 0x74, 0x78,
+       0x08, 0x37, 0x6e, 0x00,
+       0x08, 0x64, 0xc8, 0x00,
+       0x70, 0x64, 0xca, 0x18,
+       0xff, 0x6c, 0x0a, 0x08,
+       0x20, 0x64, 0xca, 0x18,
+       0xff, 0x6c, 0x08, 0x0c,
+       0x40, 0x0b, 0x04, 0x69,
+       0x80, 0x0b, 0xf6, 0x78,
+       0xa4, 0x6a, 0x06, 0x00,
+       0x40, 0x6a, 0x16, 0x00,
+       0x10, 0x03, 0xf2, 0x78,
+       0xff, 0x50, 0xc8, 0x08,
+       0x88, 0x6a, 0xcc, 0x00,
+       0x49, 0x6a, 0xee, 0x5b,
+       0x01, 0x6a, 0x26, 0x01,
+       0xff, 0x6a, 0xca, 0x08,
+       0x08, 0x01, 0x02, 0x00,
+       0x02, 0x0b, 0x92, 0x78,
+       0xf7, 0x01, 0x02, 0x08,
+       0xff, 0x06, 0xcc, 0x08,
+       0xff, 0x66, 0x32, 0x09,
+       0x01, 0x65, 0xca, 0x18,
+       0x80, 0x66, 0xa0, 0x78,
+       0xff, 0x66, 0xa2, 0x08,
+       0x10, 0x03, 0x90, 0x68,
+       0xfc, 0x65, 0xc8, 0x18,
+       0x00, 0x65, 0xa8, 0x48,
+       0xff, 0x6a, 0x32, 0x01,
+       0x01, 0x64, 0x18, 0x19,
+       0xff, 0x6a, 0x1a, 0x09,
+       0xff, 0x6a, 0x1c, 0x09,
+       0x84, 0x6a, 0x06, 0x00,
+       0x08, 0x01, 0x02, 0x00,
+       0x02, 0x0b, 0xb2, 0x78,
+       0xff, 0x06, 0xc8, 0x08,
+       0xff, 0x64, 0x32, 0x09,
+       0xff, 0x6a, 0xca, 0x08,
+       0x5b, 0x64, 0xc8, 0x28,
+       0x00, 0x62, 0xc4, 0x18,
+       0xfc, 0x65, 0xca, 0x18,
+       0xff, 0x6a, 0xd4, 0x08,
+       0xfa, 0x65, 0xca, 0x18,
+       0xff, 0x6a, 0xd4, 0x08,
+       0x04, 0x65, 0xca, 0x18,
+       0x0b, 0x65, 0xca, 0x18,
+       0xff, 0x65, 0xc8, 0x08,
+       0x00, 0x8c, 0x18, 0x19,
+       0x02, 0x0b, 0xce, 0x78,
+       0x01, 0x65, 0xd4, 0x60,
+       0xf7, 0x01, 0x02, 0x08,
+       0xff, 0x06, 0x32, 0x09,
+       0xff, 0x65, 0xca, 0x18,
+       0xff, 0x65, 0xce, 0x68,
+       0x0a, 0x93, 0x26, 0x01,
+       0x00, 0x65, 0x64, 0x5c,
+       0x40, 0x51, 0xe6, 0x78,
+       0xe4, 0x6a, 0x06, 0x00,
+       0x08, 0x01, 0x02, 0x00,
+       0x04, 0x6a, 0x18, 0x5b,
+       0x01, 0x50, 0xa0, 0x18,
+       0x00, 0x50, 0xec, 0xe0,
+       0xff, 0x6a, 0xa0, 0x08,
+       0xff, 0x6a, 0x3a, 0x01,
+       0x02, 0x6a, 0x22, 0x01,
+       0x40, 0x51, 0xf2, 0x68,
+       0xff, 0x6a, 0x06, 0x08,
+       0x00, 0x65, 0x0e, 0x40,
+       0x20, 0x6a, 0x16, 0x00,
+       0xf0, 0x19, 0x6e, 0x08,
+       0x08, 0x6a, 0x18, 0x00,
+       0x08, 0x11, 0x22, 0x00,
+       0x08, 0x6a, 0x5a, 0x58,
+       0x08, 0x6a, 0x68, 0x00,
+       0x00, 0x65, 0x18, 0x41,
+       0x12, 0x6a, 0x00, 0x00,
+       0x40, 0x6a, 0x16, 0x00,
+       0xff, 0x3e, 0x20, 0x09,
+       0xff, 0xba, 0x7c, 0x08,
+       0xff, 0xa1, 0x6e, 0x08,
+       0x08, 0x6a, 0x18, 0x00,
+       0x08, 0x11, 0x22, 0x00,
+       0x08, 0x6a, 0x5a, 0x58,
+       0x80, 0x6a, 0x68, 0x00,
+       0x80, 0x36, 0x6c, 0x00,
+       0x00, 0x65, 0xd2, 0x5b,
+       0xff, 0x3d, 0xc8, 0x08,
+       0xbf, 0x64, 0x48, 0x79,
+       0x80, 0x64, 0xf0, 0x71,
+       0xa0, 0x64, 0x0e, 0x72,
+       0xc0, 0x64, 0x08, 0x72,
+       0xe0, 0x64, 0x52, 0x72,
+       0x01, 0x6a, 0x22, 0x01,
+       0x00, 0x65, 0x18, 0x41,
+       0xf7, 0x11, 0x22, 0x08,
+       0x00, 0x65, 0x38, 0x59,
+       0xff, 0x06, 0xd4, 0x08,
+       0xf7, 0x01, 0x02, 0x08,
+       0x09, 0x0c, 0x32, 0x79,
+       0x08, 0x0c, 0x0e, 0x68,
+       0x01, 0x6a, 0x22, 0x01,
+       0xff, 0x6a, 0x26, 0x09,
+       0xff, 0x6a, 0x08, 0x08,
+       0xdf, 0x01, 0x02, 0x08,
+       0x01, 0x6a, 0x7a, 0x00,
+       0x03, 0x36, 0x6c, 0x0c,
+       0x08, 0x6a, 0xcc, 0x00,
+       0xa9, 0x6a, 0xe8, 0x5b,
+       0x00, 0x65, 0x66, 0x41,
+       0xa8, 0x6a, 0x6a, 0x00,
+       0x79, 0x6a, 0x6a, 0x00,
+       0x40, 0x3d, 0x50, 0x69,
+       0x04, 0x35, 0x6a, 0x00,
+       0x00, 0x65, 0x3a, 0x5b,
+       0x80, 0x6a, 0xd4, 0x01,
+       0x10, 0x36, 0x42, 0x69,
+       0x10, 0x36, 0x6c, 0x00,
+       0x07, 0xac, 0x10, 0x31,
+       0x88, 0x6a, 0xcc, 0x00,
+       0xac, 0x6a, 0xe0, 0x5b,
+       0x00, 0x65, 0xda, 0x5b,
+       0xff, 0xa3, 0x70, 0x08,
+       0x39, 0x6a, 0xcc, 0x00,
+       0xa4, 0x6a, 0xe6, 0x5b,
+       0xff, 0x38, 0x74, 0x69,
+       0x80, 0x02, 0x04, 0x00,
+       0xe7, 0x35, 0x6a, 0x08,
+       0x03, 0x69, 0x18, 0x31,
+       0xff, 0x6a, 0x10, 0x00,
+       0xff, 0x6a, 0x12, 0x00,
+       0xff, 0x6a, 0x14, 0x00,
+       0x01, 0x38, 0x7a, 0x61,
+       0x02, 0xfc, 0xf8, 0x01,
+       0xbf, 0x35, 0x6a, 0x08,
+       0xff, 0x69, 0xca, 0x08,
+       0xff, 0x35, 0x26, 0x09,
+       0x04, 0x0b, 0x7e, 0x69,
+       0x04, 0x0b, 0x8a, 0x69,
+       0x10, 0x0c, 0x80, 0x79,
+       0x04, 0x0b, 0x88, 0x69,
+       0xff, 0x6a, 0xca, 0x08,
+       0x00, 0x35, 0x22, 0x5b,
+       0x80, 0x02, 0xd6, 0x69,
+       0xff, 0x65, 0xc8, 0x79,
+       0xff, 0x38, 0x70, 0x18,
+       0xff, 0x38, 0xc8, 0x79,
+       0x80, 0xea, 0xaa, 0x61,
+       0xef, 0x38, 0xc8, 0x18,
+       0x80, 0x6a, 0xc8, 0x00,
+       0x00, 0x65, 0x9c, 0x49,
+       0x33, 0x38, 0xc8, 0x28,
+       0xff, 0x64, 0xd0, 0x09,
+       0x04, 0x39, 0xc0, 0x31,
+       0x09, 0x6a, 0xd6, 0x01,
+       0x80, 0xeb, 0xa2, 0x79,
+       0xf7, 0xeb, 0xd6, 0x09,
+       0x08, 0xeb, 0xa6, 0x69,
+       0x01, 0x6a, 0xd6, 0x01,
+       0x08, 0xe9, 0x10, 0x31,
+       0x88, 0x6a, 0xcc, 0x00,
+       0x39, 0x6a, 0xe6, 0x5b,
+       0x08, 0x6a, 0x18, 0x01,
+       0xff, 0x6a, 0x1a, 0x09,
+       0xff, 0x6a, 0x1c, 0x09,
+       0x0d, 0x93, 0x26, 0x01,
+       0x00, 0x65, 0x64, 0x5c,
+       0x88, 0x6a, 0x54, 0x5c,
+       0x00, 0x65, 0xda, 0x5b,
+       0xff, 0x6a, 0xc8, 0x08,
+       0x08, 0x39, 0x72, 0x18,
+       0x00, 0x3a, 0x74, 0x20,
+       0x10, 0x0c, 0x66, 0x79,
+       0x80, 0x93, 0x26, 0x01,
+       0x00, 0x65, 0xe0, 0x59,
+       0xff, 0x08, 0x52, 0x09,
+       0xff, 0x09, 0x54, 0x09,
+       0xff, 0x0a, 0x56, 0x09,
+       0xff, 0x38, 0x50, 0x09,
+       0x12, 0x01, 0x02, 0x00,
+       0x00, 0x65, 0x18, 0x41,
+       0x00, 0x65, 0xe0, 0x59,
+       0x12, 0x01, 0x02, 0x00,
+       0x7f, 0x02, 0x04, 0x08,
+       0xe1, 0x6a, 0x22, 0x01,
+       0x00, 0x65, 0x18, 0x41,
+       0x04, 0x93, 0xea, 0x69,
+       0xdf, 0x93, 0x26, 0x09,
+       0x20, 0x93, 0xe4, 0x69,
+       0x02, 0x93, 0x26, 0x01,
+       0x01, 0x94, 0xe6, 0x79,
+       0xd7, 0x93, 0x26, 0x09,
+       0x08, 0x93, 0xec, 0x69,
+       0xff, 0x6a, 0xd4, 0x0c,
+       0x00, 0x65, 0x3a, 0x5b,
+       0x02, 0xfc, 0xf8, 0x01,
+       0x05, 0xb4, 0x10, 0x31,
+       0x02, 0x6a, 0x1a, 0x31,
+       0x88, 0x6a, 0xcc, 0x00,
+       0xb4, 0x6a, 0xe4, 0x5b,
+       0xff, 0x6a, 0x1a, 0x09,
+       0xff, 0x6a, 0x1c, 0x09,
+       0x00, 0x65, 0xda, 0x5b,
+       0x3d, 0x6a, 0x22, 0x5b,
+       0xac, 0x6a, 0x22, 0x5b,
+       0x00, 0x65, 0x18, 0x41,
+       0x00, 0x65, 0x3a, 0x5b,
+       0xff, 0x06, 0x44, 0x09,
+       0x00, 0x65, 0x18, 0x41,
+       0xff, 0x34, 0xca, 0x08,
+       0x80, 0x65, 0x32, 0x62,
+       0x0f, 0xa1, 0xca, 0x08,
+       0x07, 0xa1, 0xca, 0x08,
+       0x40, 0xa0, 0xc8, 0x08,
+       0x00, 0x65, 0xca, 0x00,
+       0x80, 0x65, 0xca, 0x00,
+       0x80, 0xa0, 0x22, 0x7a,
+       0xff, 0x65, 0x0c, 0x08,
+       0x00, 0x65, 0x34, 0x42,
+       0x20, 0xa0, 0x3a, 0x7a,
+       0xff, 0x65, 0x0c, 0x08,
+       0x00, 0x65, 0xd2, 0x5b,
+       0xa0, 0x3d, 0x46, 0x62,
+       0x23, 0xa0, 0x0c, 0x08,
+       0x00, 0x65, 0xd2, 0x5b,
+       0xa0, 0x3d, 0x46, 0x62,
+       0x00, 0xb9, 0x3a, 0x42,
+       0xff, 0x65, 0x3a, 0x62,
+       0xa1, 0x6a, 0x22, 0x01,
+       0xff, 0x6a, 0xd4, 0x08,
+       0x10, 0x51, 0x46, 0x72,
+       0x40, 0x6a, 0x18, 0x00,
+       0xff, 0x65, 0x0c, 0x08,
+       0x00, 0x65, 0xd2, 0x5b,
+       0xa0, 0x3d, 0x46, 0x62,
+       0x10, 0x3d, 0x06, 0x00,
+       0x00, 0x65, 0x0e, 0x42,
+       0x40, 0x6a, 0x18, 0x00,
+       0xff, 0x34, 0xa6, 0x08,
+       0x80, 0x34, 0x4e, 0x62,
+       0x7f, 0xa0, 0x40, 0x09,
+       0x08, 0x6a, 0x68, 0x00,
+       0x00, 0x65, 0x18, 0x41,
+       0x64, 0x6a, 0x12, 0x5b,
+       0x80, 0x64, 0xbe, 0x6a,
+       0x04, 0x64, 0xa4, 0x72,
+       0x02, 0x64, 0xaa, 0x72,
+       0x00, 0x6a, 0x6c, 0x72,
+       0x03, 0x64, 0xba, 0x72,
+       0x01, 0x64, 0xa0, 0x72,
+       0x07, 0x64, 0x00, 0x73,
+       0x08, 0x64, 0x68, 0x72,
+       0x11, 0x6a, 0x22, 0x01,
+       0x07, 0x6a, 0x04, 0x5b,
+       0xff, 0x06, 0xd4, 0x08,
+       0x00, 0x65, 0x18, 0x41,
+       0xff, 0xa8, 0x70, 0x6a,
+       0xff, 0xa2, 0x88, 0x7a,
+       0x01, 0x6a, 0x6a, 0x00,
+       0x00, 0xb9, 0xfe, 0x5b,
+       0xff, 0xa2, 0x88, 0x7a,
+       0x71, 0x6a, 0x22, 0x01,
+       0xff, 0x6a, 0xd4, 0x08,
+       0x40, 0x51, 0x88, 0x62,
+       0x0d, 0x6a, 0x6a, 0x00,
+       0x00, 0xb9, 0xfe, 0x5b,
+       0xff, 0x3e, 0x74, 0x09,
+       0xff, 0x90, 0x7c, 0x08,
+       0x00, 0x65, 0x44, 0x58,
+       0x00, 0x65, 0x2a, 0x41,
+       0x20, 0xa0, 0x90, 0x6a,
+       0xff, 0x37, 0xc8, 0x08,
+       0x00, 0x6a, 0xa8, 0x5b,
+       0xff, 0x6a, 0xbe, 0x5b,
+       0xff, 0xf8, 0xc8, 0x08,
+       0xff, 0x4f, 0xc8, 0x08,
+       0x01, 0x6a, 0xa8, 0x5b,
+       0x00, 0xb9, 0xbe, 0x5b,
+       0x01, 0x4f, 0x9e, 0x18,
+       0x02, 0x6a, 0x22, 0x01,
+       0x00, 0x65, 0x6c, 0x5c,
+       0x00, 0x65, 0x2a, 0x41,
+       0x41, 0x6a, 0x22, 0x01,
+       0x00, 0x65, 0x18, 0x41,
+       0x04, 0xa0, 0x40, 0x01,
+       0x00, 0x65, 0x84, 0x5c,
+       0x00, 0x65, 0x2a, 0x41,
+       0x10, 0x36, 0x68, 0x7a,
+       0xff, 0x38, 0x46, 0x09,
+       0xa4, 0x6a, 0xcc, 0x00,
+       0x39, 0x6a, 0xe6, 0x5b,
+       0xac, 0x6a, 0xcc, 0x00,
+       0x14, 0x6a, 0xe6, 0x5b,
+       0xa9, 0x6a, 0xe8, 0x5b,
+       0x00, 0x65, 0x68, 0x42,
+       0xef, 0x36, 0x6c, 0x08,
+       0x00, 0x65, 0x68, 0x42,
+       0x0f, 0x64, 0xc8, 0x08,
+       0x07, 0x64, 0xc8, 0x08,
+       0x00, 0x37, 0x6e, 0x00,
+       0x00, 0x65, 0x78, 0x5b,
+       0xff, 0x51, 0xce, 0x72,
+       0x20, 0x36, 0xde, 0x7a,
+       0x00, 0x90, 0x5c, 0x5b,
+       0x00, 0x65, 0xe0, 0x42,
+       0xff, 0x06, 0xd4, 0x08,
+       0x00, 0x65, 0xd2, 0x5b,
+       0xe0, 0x3d, 0xfa, 0x62,
+       0x20, 0x12, 0xfa, 0x62,
+       0x51, 0x6a, 0x08, 0x5b,
+       0xff, 0x51, 0x20, 0x09,
+       0x20, 0xa0, 0xfa, 0x7a,
+       0x00, 0x90, 0x5c, 0x5b,
+       0x00, 0x65, 0x56, 0x5b,
+       0xff, 0x37, 0xc8, 0x08,
+       0x00, 0xa1, 0xf2, 0x62,
+       0x04, 0xa0, 0xf2, 0x7a,
+       0xfb, 0xa0, 0x40, 0x09,
+       0x80, 0x36, 0x6c, 0x00,
+       0x80, 0xa0, 0x68, 0x7a,
+       0x7f, 0xa0, 0x40, 0x09,
+       0xff, 0x6a, 0x04, 0x5b,
+       0x00, 0x65, 0x68, 0x42,
+       0x04, 0xa0, 0xf8, 0x7a,
+       0x00, 0x65, 0x84, 0x5c,
+       0x00, 0x65, 0xfa, 0x42,
+       0x00, 0x65, 0x6c, 0x5c,
+       0x31, 0x6a, 0x22, 0x01,
+       0x0c, 0x6a, 0x04, 0x5b,
+       0x00, 0x65, 0x68, 0x42,
+       0x61, 0x6a, 0x22, 0x01,
+       0x00, 0x65, 0x68, 0x42,
+       0x10, 0x3d, 0x06, 0x00,
+       0xff, 0x65, 0x68, 0x0c,
+       0xff, 0x06, 0xd4, 0x08,
+       0x01, 0x0c, 0x0a, 0x7b,
+       0x04, 0x0c, 0x0a, 0x6b,
+       0xe0, 0x03, 0x7a, 0x08,
+       0xe0, 0x3d, 0x1e, 0x63,
+       0xff, 0x65, 0xcc, 0x08,
+       0xff, 0x12, 0xda, 0x0c,
+       0xff, 0x06, 0xd4, 0x0c,
+       0xff, 0x65, 0x0c, 0x08,
+       0x02, 0x0b, 0x1a, 0x7b,
+       0xff, 0x6a, 0xd4, 0x0c,
+       0xd1, 0x6a, 0x22, 0x01,
+       0x00, 0x65, 0x18, 0x41,
+       0xff, 0x65, 0x26, 0x09,
+       0x01, 0x0b, 0x32, 0x6b,
+       0x10, 0x0c, 0x24, 0x7b,
+       0x04, 0x0b, 0x2c, 0x6b,
+       0xff, 0x6a, 0xca, 0x08,
+       0x04, 0x93, 0x30, 0x6b,
+       0x01, 0x94, 0x2e, 0x7b,
+       0x10, 0x94, 0x30, 0x6b,
+       0xc7, 0x93, 0x26, 0x09,
+       0xff, 0x99, 0xd4, 0x08,
+       0x08, 0x93, 0x34, 0x6b,
+       0xff, 0x6a, 0xd4, 0x0c,
+       0x80, 0x36, 0x38, 0x6b,
+       0x21, 0x6a, 0x22, 0x05,
+       0xff, 0x65, 0x20, 0x09,
+       0xff, 0x51, 0x46, 0x63,
+       0xff, 0x37, 0xc8, 0x08,
+       0xa1, 0x6a, 0x50, 0x43,
+       0xff, 0x51, 0xc8, 0x08,
+       0xb9, 0x6a, 0x50, 0x43,
+       0xff, 0xba, 0x54, 0x73,
+       0xff, 0xba, 0x20, 0x09,
+       0xff, 0x65, 0xca, 0x18,
+       0x00, 0x6c, 0x4a, 0x63,
+       0xff, 0x90, 0xca, 0x0c,
+       0xff, 0x6a, 0xca, 0x04,
+       0x20, 0x36, 0x72, 0x7b,
+       0x00, 0x90, 0x3e, 0x5b,
+       0xff, 0x65, 0x72, 0x73,
+       0xff, 0xba, 0x66, 0x73,
+       0xff, 0xbb, 0xcc, 0x08,
+       0xff, 0xba, 0x20, 0x09,
+       0xff, 0x66, 0x76, 0x09,
+       0xff, 0x65, 0x20, 0x09,
+       0xff, 0xbb, 0x70, 0x73,
+       0xff, 0xba, 0xcc, 0x08,
+       0xff, 0xbb, 0x20, 0x09,
+       0xff, 0x66, 0x74, 0x09,
+       0xff, 0x65, 0x20, 0x0d,
+       0xff, 0xba, 0x7e, 0x0c,
+       0x00, 0x6a, 0x72, 0x5c,
+       0x0d, 0x6a, 0x6a, 0x00,
+       0x00, 0x51, 0xfe, 0x43,
+       0xff, 0x3f, 0xcc, 0x73,
+       0xff, 0x6a, 0xa2, 0x00,
+       0x00, 0x3f, 0x3e, 0x5b,
+       0xff, 0x65, 0xcc, 0x73,
+       0x20, 0x36, 0x6c, 0x00,
+       0x20, 0xa0, 0x86, 0x6b,
+       0xff, 0xb9, 0xa2, 0x0c,
+       0xff, 0x6a, 0xa2, 0x04,
+       0xff, 0x65, 0xa4, 0x08,
+       0xe0, 0x6a, 0xcc, 0x00,
+       0x45, 0x6a, 0xf2, 0x5b,
+       0x01, 0x6a, 0xd0, 0x01,
+       0x09, 0x6a, 0xd6, 0x01,
+       0x80, 0xeb, 0x92, 0x7b,
+       0x01, 0x6a, 0xd6, 0x01,
+       0x01, 0xe9, 0xa4, 0x34,
+       0x88, 0x6a, 0xcc, 0x00,
+       0x45, 0x6a, 0xf2, 0x5b,
+       0x01, 0x6a, 0x18, 0x01,
+       0xff, 0x6a, 0x1a, 0x09,
+       0xff, 0x6a, 0x1c, 0x09,
+       0x0d, 0x6a, 0x26, 0x01,
+       0x00, 0x65, 0x64, 0x5c,
+       0xff, 0x99, 0xa4, 0x0c,
+       0xff, 0x65, 0xa4, 0x08,
+       0xe0, 0x6a, 0xcc, 0x00,
+       0x45, 0x6a, 0xf2, 0x5b,
+       0x01, 0x6a, 0xd0, 0x01,
+       0x01, 0x6a, 0xdc, 0x05,
+       0x88, 0x6a, 0xcc, 0x00,
+       0x45, 0x6a, 0xf2, 0x5b,
+       0x01, 0x6a, 0x18, 0x01,
+       0xff, 0x6a, 0x1a, 0x09,
+       0xff, 0x6a, 0x1c, 0x09,
+       0x01, 0x6a, 0x26, 0x05,
+       0x01, 0x65, 0xd8, 0x31,
+       0x09, 0xee, 0xdc, 0x01,
+       0x80, 0xee, 0xc2, 0x7b,
+       0xff, 0x6a, 0xdc, 0x0d,
+       0xff, 0x65, 0x32, 0x09,
+       0x0a, 0x93, 0x26, 0x01,
+       0x00, 0x65, 0x64, 0x44,
+       0xff, 0x37, 0xc8, 0x08,
+       0x00, 0x6a, 0x88, 0x5b,
+       0xff, 0x52, 0xa2, 0x0c,
+       0x01, 0x0c, 0xd2, 0x7b,
+       0x04, 0x0c, 0xd2, 0x6b,
+       0xe0, 0x03, 0x7a, 0x08,
+       0xff, 0x3d, 0x06, 0x0c,
+       0xff, 0x8c, 0x10, 0x08,
+       0xff, 0x8d, 0x12, 0x08,
+       0xff, 0x8e, 0x14, 0x0c,
+       0xff, 0x6c, 0xda, 0x08,
+       0xff, 0x6c, 0xda, 0x08,
+       0xff, 0x6c, 0xda, 0x08,
+       0xff, 0x6c, 0xda, 0x08,
+       0xff, 0x6c, 0xda, 0x08,
+       0xff, 0x6c, 0xda, 0x08,
+       0xff, 0x6c, 0xda, 0x0c,
+       0x3d, 0x64, 0xa4, 0x28,
+       0x55, 0x64, 0xc8, 0x28,
+       0x00, 0x6c, 0xda, 0x18,
+       0xff, 0x52, 0xc8, 0x08,
+       0x00, 0x6c, 0xda, 0x20,
+       0xff, 0x6a, 0xc8, 0x08,
+       0x00, 0x6c, 0xda, 0x20,
+       0x00, 0x6c, 0xda, 0x24,
+       0xff, 0x65, 0xc8, 0x08,
+       0xe0, 0x6a, 0xcc, 0x00,
+       0x41, 0x6a, 0xee, 0x5b,
+       0xff, 0x90, 0xe2, 0x09,
+       0x20, 0x6a, 0xd0, 0x01,
+       0x04, 0x35, 0x10, 0x7c,
+       0x1d, 0x6a, 0xdc, 0x01,
+       0xdc, 0xee, 0x0c, 0x64,
+       0x00, 0x65, 0x1c, 0x44,
+       0x01, 0x6a, 0xdc, 0x01,
+       0x20, 0xa0, 0xd8, 0x31,
+       0x09, 0xee, 0xdc, 0x01,
+       0x80, 0xee, 0x16, 0x7c,
+       0x19, 0x6a, 0xdc, 0x01,
+       0xd8, 0xee, 0x1a, 0x64,
+       0xff, 0x6a, 0xdc, 0x09,
+       0x18, 0xee, 0x1e, 0x6c,
+       0xff, 0x6a, 0xd4, 0x0c,
+       0x88, 0x6a, 0xcc, 0x00,
+       0x41, 0x6a, 0xee, 0x5b,
+       0x20, 0x6a, 0x18, 0x01,
+       0xff, 0x6a, 0x1a, 0x09,
+       0xff, 0x6a, 0x1c, 0x09,
+       0xff, 0x35, 0x26, 0x09,
+       0x04, 0x35, 0x48, 0x6c,
+       0xa0, 0x6a, 0xca, 0x00,
+       0x20, 0x65, 0xc8, 0x18,
+       0xff, 0x6c, 0x32, 0x09,
+       0xff, 0x6c, 0x32, 0x09,
+       0xff, 0x6c, 0x32, 0x09,
+       0xff, 0x6c, 0x32, 0x09,
+       0xff, 0x6c, 0x32, 0x09,
+       0xff, 0x6c, 0x32, 0x09,
+       0xff, 0x6c, 0x32, 0x09,
+       0xff, 0x6c, 0x32, 0x09,
+       0x00, 0x65, 0x34, 0x64,
+       0x0a, 0x93, 0x26, 0x01,
+       0x00, 0x65, 0x64, 0x5c,
+       0x04, 0x35, 0x38, 0x7b,
+       0xa0, 0x6a, 0x54, 0x5c,
+       0x00, 0x65, 0x56, 0x5c,
+       0x00, 0x65, 0x56, 0x5c,
+       0x00, 0x65, 0x56, 0x44,
+       0xff, 0x65, 0xcc, 0x08,
+       0xff, 0x99, 0xda, 0x08,
+       0xff, 0x99, 0xda, 0x08,
+       0xff, 0x99, 0xda, 0x08,
+       0xff, 0x99, 0xda, 0x08,
+       0xff, 0x99, 0xda, 0x08,
+       0xff, 0x99, 0xda, 0x08,
+       0xff, 0x99, 0xda, 0x0c,
+       0x08, 0x94, 0x64, 0x7c,
+       0xf7, 0x93, 0x26, 0x09,
+       0x08, 0x93, 0x68, 0x6c,
+       0xff, 0x6a, 0xd4, 0x0c,
+       0xff, 0x40, 0x74, 0x09,
+       0xff, 0x90, 0x80, 0x08,
+       0xff, 0x6a, 0x72, 0x05,
+       0xff, 0x40, 0x80, 0x64,
+       0xff, 0x3f, 0x78, 0x64,
+       0xff, 0x6a, 0xca, 0x04,
+       0xff, 0x3f, 0x20, 0x09,
+       0x01, 0x6a, 0x6a, 0x00,
+       0x00, 0xb9, 0xfe, 0x5b,
+       0x00, 0x90, 0x5c, 0x43,
+       0xff, 0x40, 0x20, 0x09,
+       0xff, 0xba, 0x80, 0x0c,
+       0xff, 0x6a, 0x76, 0x01,
+       0xff, 0x3f, 0x74, 0x09,
+       0xff, 0x90, 0x7e, 0x08,
+       0xff, 0xba, 0x38, 0x73,
+       0xff, 0xba, 0x20, 0x09,
+       0xff, 0x3f, 0x76, 0x09,
+       0xff, 0x3f, 0x20, 0x0d,
+};
+
+static int aic7xxx_patch12_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch12_func(struct aic7xxx_host *p)
+{
+       return ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895);
+}
+
+static int aic7xxx_patch11_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch11_func(struct aic7xxx_host *p)
+{
+       return ((p->features & AHC_WIDE) != 0);
+}
+
+static int aic7xxx_patch10_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch10_func(struct aic7xxx_host *p)
+{
+       return ((p->features & AHC_ULTRA2) == 0);
+}
+
+static int aic7xxx_patch9_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch9_func(struct aic7xxx_host *p)
+{
+       return ((p->features & AHC_ULTRA) != 0);
+}
+
+static int aic7xxx_patch8_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch8_func(struct aic7xxx_host *p)
+{
+       return ((p->features & AHC_ULTRA2) != 0);
+}
+
+static int aic7xxx_patch7_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch7_func(struct aic7xxx_host *p)
+{
+       return ((p->flags & AHC_PAGESCBS) == 0);
+}
+
+static int aic7xxx_patch6_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch6_func(struct aic7xxx_host *p)
+{
+       return ((p->flags & AHC_PAGESCBS) != 0);
+}
+
+static int aic7xxx_patch5_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch5_func(struct aic7xxx_host *p)
+{
+       return ((p->features & AHC_QUEUE_REGS) != 0);
+}
+
+static int aic7xxx_patch4_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch4_func(struct aic7xxx_host *p)
+{
+       return ((p->features & AHC_TWIN) != 0);
+}
+
+static int aic7xxx_patch3_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch3_func(struct aic7xxx_host *p)
+{
+       return ((p->features & AHC_QUEUE_REGS) == 0);
+}
+
+static int aic7xxx_patch2_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch2_func(struct aic7xxx_host *p)
+{
+       return ((p->features & AHC_CMD_CHAN) != 0);
+}
+
+static int aic7xxx_patch1_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch1_func(struct aic7xxx_host *p)
+{
+       return ((p->flags & AHC_TARGETMODE) != 0);
+}
+
+static int aic7xxx_patch0_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch0_func(struct aic7xxx_host *p)
+{
+       return (0);
+}
+
+struct sequencer_patch {
+       int             (*patch_func)(struct aic7xxx_host *);
+       unsigned int    begin      :10,
+                       skip_instr :10,
+                       skip_patch :12;
+} sequencer_patches[] = {
+       { aic7xxx_patch1_func, 1, 1, 2 },
+       { aic7xxx_patch0_func, 2, 1, 1 },
+       { aic7xxx_patch2_func, 3, 2, 1 },
+       { aic7xxx_patch3_func, 7, 1, 1 },
+       { aic7xxx_patch3_func, 8, 1, 1 },
+       { aic7xxx_patch4_func, 11, 4, 1 },
+       { aic7xxx_patch5_func, 16, 3, 2 },
+       { aic7xxx_patch0_func, 19, 4, 1 },
+       { aic7xxx_patch6_func, 23, 1, 1 },
+       { aic7xxx_patch7_func, 26, 1, 1 },
+       { aic7xxx_patch4_func, 34, 4, 1 },
+       { aic7xxx_patch8_func, 38, 3, 2 },
+       { aic7xxx_patch0_func, 41, 3, 1 },
+       { aic7xxx_patch9_func, 47, 7, 1 },
+       { aic7xxx_patch4_func, 55, 3, 1 },
+       { aic7xxx_patch8_func, 58, 2, 1 },
+       { aic7xxx_patch1_func, 63, 60, 1 },
+       { aic7xxx_patch8_func, 164, 1, 2 },
+       { aic7xxx_patch0_func, 165, 1, 1 },
+       { aic7xxx_patch2_func, 169, 1, 1 },
+       { aic7xxx_patch2_func, 172, 1, 2 },
+       { aic7xxx_patch0_func, 173, 2, 1 },
+       { aic7xxx_patch10_func, 175, 1, 1 },
+       { aic7xxx_patch8_func, 182, 1, 2 },
+       { aic7xxx_patch0_func, 183, 3, 1 },
+       { aic7xxx_patch8_func, 187, 1, 2 },
+       { aic7xxx_patch0_func, 188, 1, 1 },
+       { aic7xxx_patch8_func, 189, 7, 2 },
+       { aic7xxx_patch0_func, 196, 1, 1 },
+       { aic7xxx_patch2_func, 201, 13, 2 },
+       { aic7xxx_patch0_func, 214, 8, 1 },
+       { aic7xxx_patch10_func, 222, 1, 1 },
+       { aic7xxx_patch8_func, 227, 1, 1 },
+       { aic7xxx_patch8_func, 228, 1, 1 },
+       { aic7xxx_patch8_func, 233, 1, 1 },
+       { aic7xxx_patch8_func, 235, 2, 1 },
+       { aic7xxx_patch8_func, 240, 8, 1 },
+       { aic7xxx_patch8_func, 249, 1, 1 },
+       { aic7xxx_patch2_func, 250, 2, 2 },
+       { aic7xxx_patch0_func, 252, 4, 1 },
+       { aic7xxx_patch10_func, 256, 2, 2 },
+       { aic7xxx_patch0_func, 258, 1, 1 },
+       { aic7xxx_patch11_func, 265, 1, 2 },
+       { aic7xxx_patch0_func, 266, 1, 1 },
+       { aic7xxx_patch5_func, 328, 1, 2 },
+       { aic7xxx_patch0_func, 329, 1, 1 },
+       { aic7xxx_patch3_func, 332, 1, 1 },
+       { aic7xxx_patch11_func, 351, 1, 2 },
+       { aic7xxx_patch0_func, 352, 1, 1 },
+       { aic7xxx_patch6_func, 356, 1, 1 },
+       { aic7xxx_patch7_func, 364, 3, 2 },
+       { aic7xxx_patch0_func, 367, 1, 1 },
+       { aic7xxx_patch1_func, 396, 3, 1 },
+       { aic7xxx_patch10_func, 410, 1, 1 },
+       { aic7xxx_patch2_func, 453, 7, 2 },
+       { aic7xxx_patch0_func, 460, 8, 1 },
+       { aic7xxx_patch2_func, 469, 4, 2 },
+       { aic7xxx_patch0_func, 473, 6, 1 },
+       { aic7xxx_patch2_func, 479, 4, 2 },
+       { aic7xxx_patch0_func, 483, 3, 1 },
+       { aic7xxx_patch2_func, 512, 17, 4 },
+       { aic7xxx_patch12_func, 520, 4, 2 },
+       { aic7xxx_patch0_func, 524, 2, 1 },
+       { aic7xxx_patch0_func, 529, 33, 1 },
+       { aic7xxx_patch6_func, 566, 2, 1 },
+       { aic7xxx_patch6_func, 569, 9, 1 },
+
+};
diff --git a/drivers/scsi/aic7xxx_seq.h b/drivers/scsi/aic7xxx_seq.h
deleted file mode 100644 (file)
index 02ac060..0000000
+++ /dev/null
@@ -1,524 +0,0 @@
-/*
-  * DO NOT EDIT - This file is automatically generated.
-  */
-static unsigned char seqprog[] = {
-       0xff, 0x6a, 0x03, 0x02,
-       0x32, 0x6a, 0x00, 0x00,
-       0x12, 0x6a, 0x00, 0x00,
-       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,
-       0x60, 0x0b, 0x37, 0x1a,
-       0x40, 0x00, 0x05, 0x1a,
-       0x08, 0x1f, 0x1f, 0x04,
-       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,
-       0xff, 0x65, 0x1f, 0x02,
-       0xf0, 0xa1, 0x64, 0x02,
-       0x0f, 0x05, 0x05, 0x02,
-       0x00, 0x05, 0x05, 0x00,
-       0x5a, 0x6a, 0x00, 0x01,
-       0x12, 0x65, 0x64, 0x00,
-       0x00, 0x01, 0x01, 0x00,
-       0x31, 0x6a, 0x65, 0x00,
-       0x80, 0x37, 0x2d, 0x1a,
-       0xff, 0x65, 0x65, 0x06,
-       0xff, 0x37, 0x6e, 0x02,
-       0xff, 0x6e, 0x64, 0x02,
-       0x00, 0x6c, 0x31, 0x1e,
-       0x20, 0x01, 0x01, 0x00,
-       0x4c, 0x37, 0x64, 0x0a,
-       0x08, 0x1f, 0x35, 0x1e,
-       0x08, 0x37, 0x37, 0x00,
-       0x08, 0x64, 0x64, 0x00,
-       0x20, 0x64, 0x65, 0x06,
-       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, 0x82, 0x10,
-       0xf7, 0x11, 0x11, 0x02,
-       0x00, 0x65, 0x92, 0x16,
-       0xff, 0x06, 0x6a, 0x02,
-       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, 0x3d, 0x00,
-       0x03, 0x36, 0x36, 0x03,
-       0x08, 0x6a, 0x66, 0x00,
-       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, 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, 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, 0x39, 0x39, 0x06,
-       0x00, 0x3a, 0x3a, 0x08,
-       0x88, 0x6a, 0x66, 0x00,
-       0x39, 0x6a, 0xa5, 0x17,
-       0x08, 0x6a, 0x8c, 0x00,
-       0xff, 0x6a, 0x8d, 0x02,
-       0xff, 0x6a, 0x8e, 0x02,
-       0x0d, 0x93, 0x93, 0x00,
-       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, 0x38, 0xa8, 0x02,
-       0x10, 0x36, 0x36, 0x00,
-       0x00, 0x65, 0x82, 0x10,
-       0x7f, 0x02, 0x02, 0x02,
-       0xe1, 0x6a, 0x91, 0x00,
-       0x00, 0x65, 0x82, 0x10,
-       0x00, 0x65, 0x6c, 0x17,
-       0x88, 0x6a, 0x66, 0x00,
-       0xb4, 0x6a, 0xa4, 0x17,
-       0xff, 0x6a, 0x8d, 0x02,
-       0xff, 0x6a, 0x8e, 0x02,
-       0x00, 0x65, 0x9f, 0x17,
-       0x3d, 0x6a, 0x61, 0x17,
-       0x00, 0x65, 0x82, 0x10,
-       0x00, 0x65, 0x6c, 0x17,
-       0xff, 0x06, 0xa2, 0x02,
-       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, 0x65, 0x06, 0x02,
-       0x00, 0x65, 0x9b, 0x17,
-       0xa0, 0x3d, 0xef, 0x18,
-       0x10, 0x3d, 0x03, 0x00,
-       0x00, 0x65, 0xd4, 0x10,
-       0x40, 0x6a, 0x0c, 0x00,
-       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, 0x52, 0x17,
-       0xff, 0x06, 0x6a, 0x02,
-       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, 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,
-       0x00, 0x65, 0xd5, 0x17,
-       0x00, 0x65, 0x8b, 0x10,
-       0x41, 0x6a, 0x91, 0x00,
-       0x00, 0x65, 0x82, 0x10,
-       0x04, 0xa0, 0xa0, 0x00,
-       0x00, 0x65, 0xe1, 0x17,
-       0x00, 0x65, 0x8b, 0x10,
-       0x10, 0x36, 0x00, 0x1f,
-       0xff, 0x38, 0xa3, 0x02,
-       0xa4, 0x6a, 0x66, 0x00,
-       0x39, 0x6a, 0xa5, 0x17,
-       0xac, 0x6a, 0x66, 0x00,
-       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, 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,
-       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,
-       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, 0x52, 0x17,
-       0x00, 0x65, 0x00, 0x11,
-       0x61, 0x6a, 0x91, 0x00,
-       0x00, 0x65, 0x00, 0x11,
-       0x10, 0x3d, 0x03, 0x00,
-       0xff, 0x65, 0x34, 0x03,
-       0xff, 0x06, 0x6a, 0x02,
-       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, 0x82, 0x10,
-       0xff, 0x65, 0x93, 0x02,
-       0x01, 0x0b, 0x69, 0x1b,
-       0x10, 0x0c, 0x62, 0x1f,
-       0x04, 0x0b, 0x66, 0x1b,
-       0xff, 0x6a, 0x65, 0x02,
-       0x04, 0x93, 0x68, 0x1b,
-       0x01, 0x94, 0x67, 0x1f,
-       0x10, 0x94, 0x68, 0x1b,
-       0xc7, 0x93, 0x93, 0x02,
-       0x38, 0x93, 0x6a, 0x1b,
-       0xff, 0x6a, 0x6a, 0x03,
-       0x80, 0x36, 0x6b, 0x1b,
-       0x21, 0x6a, 0x91, 0x01,
-       0xff, 0x65, 0x90, 0x02,
-       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,
-       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, 0x66, 0xbb, 0x02,
-       0xff, 0x65, 0x90, 0x02,
-       0xff, 0xbb, 0x87, 0x1d,
-       0xff, 0xba, 0x66, 0x02,
-       0xff, 0xbb, 0x90, 0x02,
-       0xff, 0x66, 0xba, 0x02,
-       0xff, 0x65, 0x90, 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,
-       0xff, 0x6c, 0x6d, 0x02,
-       0xff, 0x6c, 0x6d, 0x02,
-       0xff, 0x6c, 0x6d, 0x02,
-       0xff, 0x6c, 0x6d, 0x02,
-       0xff, 0x6c, 0x6d, 0x02,
-       0xff, 0x6c, 0x6d, 0x02,
-       0xff, 0x6c, 0x6d, 0x03,
-       0x3d, 0x64, 0x66, 0x0a,
-       0x55, 0x64, 0x64, 0x0a,
-       0x00, 0x6c, 0x88, 0x06,
-       0xff, 0x66, 0x64, 0x02,
-       0x00, 0x6c, 0x89, 0x08,
-       0xff, 0x6a, 0x64, 0x02,
-       0x00, 0x6c, 0x8a, 0x08,
-       0x00, 0x6c, 0x8b, 0x08,
-       0xff, 0x6a, 0x8d, 0x02,
-       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,
-       0xff, 0x6c, 0x99, 0x02,
-       0xff, 0x6c, 0x99, 0x02,
-       0xff, 0x6c, 0x99, 0x02,
-       0xff, 0x6c, 0x99, 0x02,
-       0xff, 0x6c, 0x99, 0x02,
-       0xff, 0x6c, 0x99, 0x02,
-       0x00, 0x65, 0xba, 0x19,
-       0x0a, 0x93, 0x93, 0x00,
-       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,
-       0xff, 0x99, 0x6d, 0x02,
-       0xff, 0x99, 0x6d, 0x02,
-       0xff, 0x99, 0x6d, 0x02,
-       0xff, 0x99, 0x6d, 0x02,
-       0xff, 0x99, 0x6d, 0x03,
-       0x08, 0x94, 0xd1, 0x1f,
-       0xf7, 0x93, 0x93, 0x02,
-       0x08, 0x93, 0xd3, 0x1b,
-       0xff, 0x6a, 0x6a, 0x03,
-       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, 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, 0x3f, 0xba, 0x02,
-       0xff, 0x90, 0x3f, 0x02,
-       0xff, 0xba, 0x6b, 0x1d,
-       0xff, 0xba, 0x90, 0x02,
-       0xff, 0x3f, 0xbb, 0x02,
-       0xff, 0x3f, 0x90, 0x03,
-};
-#define        WIDE                    0x20
-#define        ULTRA                   0x10
-#define        SCB_PAGING              0x8
-#define        TWIN_CHANNEL            0x4
-#define        TARGET_MODE             0x2
-struct sequencer_patch {
-       int     options;
-       int     negative;
-       int     begin;
-       int     end;
-} sequencer_patches[] = {
-       { 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 e909bf0c6a2cbca6d9ecd8a86da08524470689d9..86d9c3e2b8d3cefd5e0ee55eb62cd7433393a96d 100644 (file)
@@ -2,7 +2,7 @@
  * GDT ISA/EISA/PCI Disk Array Controller driver for Linux              *
  *                                                                      *
  * gdth.c                                                               *
- * Copyright (C) 1995-97 ICP vortex Computersysteme GmbH, Achim Leubner *
+ * Copyright (C) 1995-98 ICP vortex Computersysteme GmbH, Achim Leubner *
  *                                                                      *
  * <achim@vortex.de>                                                    *
  *                                                                      *
  * along with this kernel; if not, write to the Free Software           *
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.            *
  *                                                                      *
- * Tested with Linux 1.2.13, ..., 2.0.29                                *
+ * Tested with Linux 1.2.13, ..., 2.1.103                               *
  *                                                                      *
  * $Log: gdth.c,v $
+ * Revision 1.16  1998/09/28 16:08:46  achim
+ * GDT_PCIMPR: DPMEM remapping, if required
+ * mdelay() added
+ *
+ * Revision 1.15  1998/06/03 14:54:06  achim
+ * gdth_delay(), gdth_flush() implemented
+ * Bugfix: gdth_release() changed
+ *
+ * Revision 1.14  1998/05/22 10:01:17  achim
+ * mj: pcibios_strerror() removed
+ * Improved SMP support (if version >= 2.1.95)
+ * gdth_halt(): halt_called flag added (if version < 2.1)
+ *
+ * Revision 1.13  1998/04/16 09:14:57  achim
+ * Reserve drives (for raw service) implemented
+ * New error handling code enabled
+ * Get controller name from board_info() IOCTL
+ * Final round of PCI device driver patches by Martin Mares
+ *
+ * Revision 1.12  1998/03/03 09:32:37  achim
+ * Fibre channel controller support added
+ *
+ * Revision 1.11  1998/01/27 16:19:14  achim
+ * SA_SHIRQ added
+ * add_timer()/del_timer() instead of GDTH_TIMER
+ * scsi_add_timer()/scsi_del_timer() instead of SCSI_TIMER
+ * New error handling included
+ *
+ * Revision 1.10  1997/10/31 12:29:57  achim
+ * Read heads/sectors from host drive
+ *
+ * Revision 1.9  1997/09/04 10:07:25  achim
+ * IO-mapping with virt_to_bus(), readb(), writeb(), ...
+ * register_reboot_notifier() to get a notify on shutdown used
+ *
  * Revision 1.8  1997/04/02 12:14:30  achim
  * Version 1.00 (see gdth.h), tested with kernel 2.0.29
  *
@@ -53,7 +88,7 @@
  * Initial revision
  *
  *
- * $Id: gdth.c,v 1.8 1997/04/02 12:14:30 achim Exp $ 
+ * $Id: gdth.c,v 1.16 1998/09/28 16:08:46 achim Exp $ 
  ************************************************************************/
 
 #ifdef MODULE
@@ -64,7 +99,6 @@
 #include <linux/kernel.h>
 #include <linux/head.h>
 #include <linux/types.h>
-#include <linux/bios32.h>
 #include <linux/pci.h>
 #include <linux/string.h>
 #include <linux/ioport.h>
 #include <linux/proc_fs.h>
 #include <linux/time.h>
 #include <linux/timer.h>
+#if LINUX_VERSION_CODE >= 0x020100
+#include <linux/reboot.h>
+#else
+#include <linux/bios32.h>
+#endif
 
 #include <asm/dma.h>
 #include <asm/system.h>
 #include <asm/io.h>
+#if LINUX_VERSION_CODE >= 0x02015F
+#include <asm/spinlock.h>
+#endif
 
 #if LINUX_VERSION_CODE >= 0x010300
 #include <linux/blk.h>
 
 #include "gdth.h"
 
-#if LINUX_VERSION_CODE >= 0x010346
+/****************************************************************************/
+
+/* LILO params: gdth=<IRQ>
+ *
+ * Where: <IRQ> is any of the valid IRQs for EISA controllers (10,11,12,14)
+ * Sets the IRQ of the GDT3000/3020 EISA controller to this value,
+ * if the IRQ can not automat. detect (controller BIOS disabled)
+ * See gdth_init_eisa() 
+ *
+ * You can use the command line gdth=0 to disable the driver 
+ */
+static unchar irqs[MAXHA] = {0xff};
+static unchar disable_gdth_scan = FALSE;
+
+/* Reserve drives for raw service: Fill the following structure with the
+ * appropriate values: Controller number, Channel, Target ID 
+ */
+static gdth_reserve_str reserve_list[] = {
+    /* { 0, 1, 4 },            Example: Controller 0, Channel B, ID 4 */
+    { 0xff, 0xff, 0xff }       /* end of list */
+};
+
+/****************************************************************************/
+
+#if LINUX_VERSION_CODE >= 0x02015F
+static void gdth_interrupt(int irq,void *dev_id,struct pt_regs *regs);
+static void do_gdth_interrupt(int irq,void *dev_id,struct pt_regs *regs);
+#elif LINUX_VERSION_CODE >= 0x010346
 static void gdth_interrupt(int irq,void *dev_id,struct pt_regs *regs);
 #else
 static void gdth_interrupt(int irq,struct pt_regs *regs);
@@ -116,9 +185,9 @@ static int gdth_fill_cache_cmd(int hanum,Scsi_Cmnd *scp,ushort hdrive);
 static int gdth_search_eisa(ushort eisa_adr);
 static int gdth_search_isa(ulong bios_adr);
 static int gdth_search_pci(ushort device_id,ushort index,gdth_pci_str *pcistr);
-static int gdth_init_eisa(ushort eisa_adr,gdth_ha_str *ha,int firsttime);
-static int gdth_init_isa(ulong bios_adr,gdth_ha_str *ha,int firsttime);
-static int gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha,int firsttime);
+static int gdth_init_eisa(ushort eisa_adr,gdth_ha_str *ha);
+static int gdth_init_isa(ulong bios_adr,gdth_ha_str *ha);
+static int gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha);
 
 static void gdth_enable_int(int hanum);
 static int gdth_get_status(unchar *pIStatus,int irq);
@@ -128,28 +197,25 @@ static void gdth_release_event(int hanum);
 static int gdth_wait(int hanum,int index,ulong time);
 static int gdth_internal_cmd(int hanum,unchar service,ushort opcode,ulong p1,
                              ulong p2,ulong p3);
-static int gdth_search_drives(int hanum,int firsttime);
+static int gdth_search_drives(int hanum);
+
+static void *gdth_mmap(ulong paddr, ulong size);
+static void gdth_munmap(void *addr);
 
 static const char *gdth_ctr_name(int hanum);
+
+static void gdth_flush(int hanum);
+#if LINUX_VERSION_CODE >= 0x020100
+static int gdth_halt(struct notifier_block *nb, ulong event, void *buf);
+#else
+static int halt_called = FALSE;
 void gdth_halt(void);
+#endif
 
 #ifdef DEBUG_GDTH
 static unchar   DebugState = DEBUG_GDTH;
 extern int sys_syslog(int,char*,int);
-#define LOGEN           sys_syslog(7,NULL,0);
-#define WAITSEC(a)      {ulong idx; for(idx=0;idx<a*1000L;++idx) udelay(1000);}
-
-#ifdef SLOWMOTION_GDTH
-#define SLOWM   WAITSEC(2)  
-#undef  INIT_RETRIES
-#undef  INIT_TIMEOUT
-#undef  POLL_TIMEOUT
-#define INIT_RETRIES    15
-#define INIT_TIMEOUT    150
-#define POLL_TIMEOUT    150
-#else
-#define SLOWM
-#endif
+#define LOGEN           sys_syslog(7,NULL,0)
 
 #ifdef __SERIAL__
 #define MAX_SERBUF 160
@@ -213,14 +279,14 @@ static int ser_printk(const char *fmt, ...)
     return i;
 }
 
-#define TRACE(a)    {if (DebugState==1) {ser_printk a; SLOWM}}
-#define TRACE2(a)   {if (DebugState==1 || DebugState==2) {ser_printk a; SLOWM}}
-#define TRACE3(a)   {if (DebugState!=0) {ser_printk a; SLOWM}}
+#define TRACE(a)    {if (DebugState==1) {ser_printk a;}}
+#define TRACE2(a)   {if (DebugState==1 || DebugState==2) {ser_printk a;}}
+#define TRACE3(a)   {if (DebugState!=0) {ser_printk a;}}
 
 #else /* !__SERIAL__ */
-#define TRACE(a)    {if (DebugState==1) {LOGEN;printk a; SLOWM}}
-#define TRACE2(a)   {if (DebugState==1 || DebugState==2) {LOGEN;printk a; SLOWM}}
-#define TRACE3(a)   {if (DebugState!=0) {LOGEN;printk a; SLOWM}}
+#define TRACE(a)    {if (DebugState==1) {LOGEN;printk a;}}
+#define TRACE2(a)   {if (DebugState==1 || DebugState==2) {LOGEN;printk a;}}
+#define TRACE3(a)   {if (DebugState!=0) {LOGEN;printk a;}}
 #endif
 
 #else /* !DEBUG */
@@ -229,15 +295,13 @@ static int ser_printk(const char *fmt, ...)
 #define TRACE3(a)
 #endif
 
-
 #ifdef GDTH_STATISTICS
 static ulong max_rq=0, max_index=0, max_sg=0;
 static ulong act_ints=0, act_ios=0, act_stats=0, act_rq=0;
-#define GDTH_TIMER      31                      /* see linux/timer.h ! */
+static struct timer_list gdth_timer;
 #endif
 
 #define PTR2USHORT(a)   (ushort)(ulong)(a)
-#define JIFFYWAIT(a)    {ulong gdtjf;gdtjf=jiffies+(a);while(gdtjf>jiffies);}
 #define GDTOFFSOF(a,b)  (size_t)&(((a*)0)->b)   
 #define INDEX_OK(i,t)   ((i)<sizeof(t)/sizeof((t)[0]))
 
@@ -246,6 +310,67 @@ static ulong act_ints=0, act_ios=0, act_stats=0, act_rq=0;
 #define CMDDATA(a)      (&((gdth_ext_str *)((a)->hostdata))->cmdext)
 #define DMADATA(a)      (&((gdth_ext_str *)((a)->hostdata))->dmaext)
 
+
+#if LINUX_VERSION_CODE < 0x010300
+static void *gdth_mmap(ulong paddr, ulong size) 
+{
+    if (paddr >= high_memory)
+       return NULL; 
+    else
+       return (void *)paddr;
+}
+static void gdth_munmap(void *addr) 
+{
+}
+inline ulong virt_to_phys(volatile void *addr)
+{
+    return (ulong)addr;
+}
+inline void *phys_to_virt(ulong addr)
+{
+    return (void *)addr;
+}
+#define virt_to_bus            virt_to_phys
+#define bus_to_virt            phys_to_virt
+#define readb(addr)            (*(volatile unchar *)(addr))
+#define readw(addr)            (*(volatile ushort *)(addr))
+#define readl(addr)            (*(volatile ulong *)(addr))
+#define writeb(b,addr)         (*(volatile unchar *)(addr) = (b))
+#define writew(b,addr)         (*(volatile ushort *)(addr) = (b))
+#define writel(b,addr)         (*(volatile ulong *)(addr) = (b))
+#define memset_io(a,b,c)       memset((void *)(a),(b),(c))
+#define memcpy_fromio(a,b,c)   memcpy((a),(void *)(b),(c))
+#define memcpy_toio(a,b,c)     memcpy((void *)(a),(b),(c))
+
+#elif LINUX_VERSION_CODE < 0x020100
+static int remapped = FALSE;
+static void *gdth_mmap(ulong paddr, ulong size) 
+{
+    if ( paddr >= high_memory) {
+       remapped = TRUE;
+       return vremap(paddr, size);
+    } else {
+       return (void *)paddr; 
+    }
+}
+static void gdth_munmap(void *addr) 
+{
+    if (remapped)
+       vfree(addr);
+    remapped = FALSE;
+}
+#else
+static void *gdth_mmap(ulong paddr, ulong size) 
+{ 
+    return ioremap(paddr, size); 
+}
+static void gdth_munmap(void *addr) 
+{
+    return iounmap(addr);
+}
+#endif
+
+
 static unchar   gdth_drq_tab[4] = {5,6,7,7};            /* DRQ table */
 static unchar   gdth_irq_tab[6] = {0,10,11,12,14,0};    /* IRQ table */
 static unchar   gdth_polling;                           /* polling if TRUE */
@@ -253,6 +378,7 @@ static unchar   gdth_from_wait  = FALSE;                /* gdth_wait() */
 static int      wait_index,wait_hanum;                  /* gdth_wait() */
 static int      gdth_ctr_count  = 0;                    /* controller count */
 static int      gdth_ctr_vcount = 0;                    /* virt. ctr. count */
+static int     gdth_ctr_released = 0;                  /* gdth_release() */
 static struct Scsi_Host *gdth_ctr_tab[MAXHA];           /* controller table */
 static struct Scsi_Host *gdth_ctr_vtab[MAXHA*MAXBUS];   /* virt. ctr. table */
 static unchar   gdth_write_through = FALSE;             /* write through */
@@ -289,17 +415,14 @@ static unchar gdth_direction_tab[0x100] = {
     DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN
 };
 
-/* LILO params: gdth=<IRQ>
- *
- * Where: <IRQ> is any of the valid IRQs for EISA controllers (10,11,12,14)
- * Sets the IRQ of the GDT3000/3020 EISA controller to this value,
- * if the IRQ can not automat. detect (controller BIOS disabled)
- * See gdth_init_eisa() 
- *
- * You can use the command line gdth=0 to disable the driver 
- */
-static unchar irqs[MAXHA] = {0xff};
-static unchar disable_gdth_scan = FALSE;
+/* __initfunc, __initdata macros */
+#if LINUX_VERSION_CODE >= 0x020126
+#include <linux/init.h>
+#else
+#define __initfunc(A) A
+#define __initdata
+#define __init
+#endif
 
 /* /proc support */
 #if LINUX_VERSION_CODE >= 0x010300
@@ -312,10 +435,31 @@ struct proc_dir_entry proc_scsi_gdth = {
 #include "gdth_proc.c"
 #endif
 
+#if LINUX_VERSION_CODE >= 0x020100
+/* notifier block to get a notify on system shutdown/halt/reboot */
+static struct notifier_block gdth_notifier = {
+    gdth_halt, NULL, 0
+};
+#endif
+
+static void gdth_delay(int milliseconds)
+{
+    if (milliseconds == 0) {
+        udelay(1);
+    } else {
+#if LINUX_VERSION_CODE >= 0x020168
+        mdelay(milliseconds);
+#else
+        int i;
+        for (i = 0; i < milliseconds; ++i) 
+            udelay(1000);
+#endif
+    }
+}
 
 /* controller search and initialization functions */
 
-static int gdth_search_eisa(ushort eisa_adr)
+__initfunc (static int gdth_search_eisa(ushort eisa_adr))
 {
     ulong id;
     
@@ -333,19 +477,23 @@ static int gdth_search_eisa(ushort eisa_adr)
 }
 
 
-static int gdth_search_isa(ulong bios_adr)
+__initfunc (static int gdth_search_isa(ulong bios_adr))
 {
+    void *addr;
     ulong id;
 
     TRACE(("gdth_search_isa() bios adr. %lx\n",bios_adr));
-    id = *(ulong *)(bios_adr+BIOS_ID_OFFS);
-    if (id == GDT2_ID)                          /* GDT2000 */
-        return 1;
+    if ((addr = gdth_mmap(bios_adr+BIOS_ID_OFFS, sizeof(ulong))) != NULL) {
+       id = readl(addr);
+       gdth_munmap(addr);
+       if (id == GDT2_ID)                          /* GDT2000 */
+           return 1;
+    }
     return 0;
 }
 
 
-static int gdth_search_pci(ushort device_id,ushort index,gdth_pci_str *pcistr)
+__initfunc (static int gdth_search_pci(ushort device_id,ushort index,gdth_pci_str *pcistr))
 {
     int error;
     ulong base0,base1,base2;
@@ -353,14 +501,34 @@ static int gdth_search_pci(ushort device_id,ushort index,gdth_pci_str *pcistr)
     TRACE(("gdth_search_pci() device_id %d, index %d\n",
                  device_id,index));
 
+#if LINUX_VERSION_CODE >= 0x20155
+    if (!pci_present())
+        return 0;
+#else
     if (!pcibios_present())
         return 0;
+#endif
 
     if (pcibios_find_device(PCI_VENDOR_ID_VORTEX,device_id,index,
                              &pcistr->bus,&pcistr->device_fn))
         return 0;
 
     /* GDT PCI controller found, now read resources from config space */
+#if LINUX_VERSION_CODE >= 0x20155
+    {
+       struct pci_dev *pdev = pci_find_slot(pcistr->bus, pcistr->device_fn);
+       base0 = pdev->base_address[0];
+       base1 = pdev->base_address[1];
+       base2 = pdev->base_address[2];
+       if ((error = pcibios_read_config_dword(pcistr->bus,pcistr->device_fn,
+                                              PCI_ROM_ADDRESS,
+                                              (int *) &pcistr->bios))) {
+           printk("GDT-PCI: error %d reading configuration space", error);
+           return -1;
+       }
+       pcistr->irq = pdev->irq;
+    }
+#else
 #if LINUX_VERSION_CODE >= 0x010300
 #define GDTH_BASEP      (int *)
 #else
@@ -380,10 +548,10 @@ static int gdth_search_pci(ushort device_id,ushort index,gdth_pci_str *pcistr)
                                            GDTH_BASEP&pcistr->bios)) ||
         (error = pcibios_read_config_byte(pcistr->bus,pcistr->device_fn,
                                           PCI_INTERRUPT_LINE,&pcistr->irq))) {
-        printk("GDT-PCI: error %s reading configuration space",
-               pcibios_strerror(error));
+        printk("GDT-PCI: error %d reading configuration space", error);
         return -1;
     }
+#endif
 
     pcistr->device_id = device_id;
     if (device_id <= PCI_DEVICE_ID_VORTEX_GDT6000B ||   /* GDT6000 or GDT6000B */
@@ -404,7 +572,7 @@ static int gdth_search_pci(ushort device_id,ushort index,gdth_pci_str *pcistr)
 }
 
 
-static int gdth_init_eisa(ushort eisa_adr,gdth_ha_str *ha,int firsttime)
+__initfunc (static int gdth_init_eisa(ushort eisa_adr,gdth_ha_str *ha))
 {
     ulong retries,id;
     unchar prot_ver,eisacf,i,irq_found;
@@ -418,13 +586,13 @@ static int gdth_init_eisa(ushort eisa_adr,gdth_ha_str *ha,int firsttime)
     
     outb(0xff,eisa_adr+LDOORREG);
     retries = INIT_RETRIES;
-    JIFFYWAIT(2);
+    gdth_delay(20);
     while (inb(eisa_adr+EDOORREG) != 0xff) {
         if (--retries == 0) {
             printk("GDT-EISA: Initialization error (DEINIT failed)\n");
             return 0;
         }
-        udelay(1000);
+        gdth_delay(1);
         TRACE2(("wait for DEINIT: retries=%ld\n",retries));
     }
     prot_ver = inb(eisa_adr+MAILBOXREG);
@@ -433,7 +601,7 @@ static int gdth_init_eisa(ushort eisa_adr,gdth_ha_str *ha,int firsttime)
         printk("GDT-EISA: Illegal protocol version\n");
         return 0;
     }
-    ha->brd = (ulong)eisa_adr;
+    ha->bmic = eisa_adr;
     ha->brd_phys = (ulong)eisa_adr >> 12;
 
     outl(0,eisa_adr+MAILBOXREG);
@@ -448,41 +616,38 @@ static int gdth_init_eisa(ushort eisa_adr,gdth_ha_str *ha,int firsttime)
         outl(1,eisa_adr+MAILBOXREG+8);
         outb(0xfe,eisa_adr+LDOORREG);
         retries = INIT_RETRIES;
-        JIFFYWAIT(2);
+        gdth_delay(20);
         while (inb(eisa_adr+EDOORREG) != 0xfe) {
             if (--retries == 0) {
                 printk("GDT-EISA: Initialization error (get IRQ failed)\n");
                 return 0;
             }
-            udelay(1000);
+            gdth_delay(1);
         }
-        if (firsttime)
-            ha->irq = inb(eisa_adr+MAILBOXREG);
+        ha->irq = inb(eisa_adr+MAILBOXREG);
         outb(0xff,eisa_adr+EDOORREG);
         TRACE2(("GDT3000/3020: IRQ=%d\n",ha->irq));
-        if (firsttime) {
-            /* check the result */
-            if (ha->irq == 0) {
-                TRACE2(("Unknown IRQ, check IRQ table from cmd line !\n"));
-                for (i=0,irq_found=FALSE; i<MAXHA && irqs[i]!=0xff; ++i) {
-                    if (irqs[i]!=0) {
-                        irq_found=TRUE;
-                        break;
-                    }
-                }
-                if (irq_found) {
-                    ha->irq = irqs[i];
-                    irqs[i] = 0;
-                    printk("GDT-EISA: Can not detect controller IRQ,\n");
-                    printk("Use IRQ setting from command line (IRQ = %d)\n",
-                           ha->irq);
-                } else {
-                    printk("GDT-EISA: Initialization error (unknown IRQ), Enable\n");
-                    printk("the controller BIOS or use command line parameters\n");
-                    return 0;
-                }
-            }
-        }
+       /* check the result */
+       if (ha->irq == 0) {
+           TRACE2(("Unknown IRQ, check IRQ table from cmd line !\n"));
+           for (i=0,irq_found=FALSE; i<MAXHA && irqs[i]!=0xff; ++i) {
+               if (irqs[i]!=0) {
+                   irq_found=TRUE;
+                   break;
+               }
+           }
+           if (irq_found) {
+               ha->irq = irqs[i];
+               irqs[i] = 0;
+               printk("GDT-EISA: Can not detect controller IRQ,\n");
+               printk("Use IRQ setting from command line (IRQ = %d)\n",
+                      ha->irq);
+           } else {
+               printk("GDT-EISA: Initialization error (unknown IRQ), Enable\n");
+               printk("the controller BIOS or use command line parameters\n");
+               return 0;
+           }
+       }
     } else {
         eisacf = inb(eisa_adr+EISAREG) & 7;
         if (eisacf > 4)                         /* level triggered */
@@ -495,7 +660,7 @@ static int gdth_init_eisa(ushort eisa_adr,gdth_ha_str *ha,int firsttime)
 }
 
        
-static int gdth_init_isa(ulong bios_adr,gdth_ha_str *ha,int firsttime)
+__initfunc (static int gdth_init_isa(ulong bios_adr,gdth_ha_str *ha))
 {
     register gdt2_dpram_str *dp2_ptr;
     int i;
@@ -504,19 +669,28 @@ static int gdth_init_isa(ulong bios_adr,gdth_ha_str *ha,int firsttime)
 
     TRACE(("gdth_init_isa() bios adr. %lx\n",bios_adr));
 
-    ha->brd = bios_adr;
+    ha->brd = gdth_mmap(bios_adr, sizeof(gdt2_dpram_str));
+    if (ha->brd == NULL) {
+       printk("GDT-ISA: Initialization error (DPMEM remap error)\n");
+       return 0;
+    }
     dp2_ptr = (gdt2_dpram_str *)ha->brd;
-    dp2_ptr->io.memlock = 1;            /* switch off write protection */
+    writeb(1, &dp2_ptr->io.memlock);                   /* switch off write protection */
     /* reset interface area */
-    memset((char *)&dp2_ptr->u,0,sizeof(dp2_ptr->u));
+    memset_io((char *)&dp2_ptr->u,0,sizeof(dp2_ptr->u));
+    if (readl(&dp2_ptr->u) != 0) {
+       printk("GDT-PCI: Initialization error (DPMEM write error)\n");
+       gdth_munmap(ha->brd);
+       return 0;
+    }
 
     /* disable board interrupts, read DRQ and IRQ */
-    dp2_ptr->io.irqdel     = 0xff;
-    dp2_ptr->io.irqen      = 0x00;
-    dp2_ptr->u.ic.S_Status = 0x00;
-    dp2_ptr->u.ic.Cmd_Index= 0x00;
+    writeb(0xff, &dp2_ptr->io.irqdel);
+    writeb(0x00, &dp2_ptr->io.irqen);
+    writeb(0x00, &dp2_ptr->u.ic.S_Status);
+    writeb(0x00, &dp2_ptr->u.ic.Cmd_Index);
 
-    irq_drq = dp2_ptr->io.rq;
+    irq_drq = readb(&dp2_ptr->io.rq);
     for (i=0; i<3; ++i) {
         if ((irq_drq & 1)==0)
             break;
@@ -524,7 +698,7 @@ static int gdth_init_isa(ulong bios_adr,gdth_ha_str *ha,int firsttime)
     }
     ha->drq = gdth_drq_tab[i];
 
-    irq_drq = dp2_ptr->io.rq >> 3;
+    irq_drq = readb(&dp2_ptr->io.rq) >> 3;
     for (i=1; i<5; ++i) {
         if ((irq_drq & 1)==0)
             break;
@@ -533,23 +707,25 @@ static int gdth_init_isa(ulong bios_adr,gdth_ha_str *ha,int firsttime)
     ha->irq = gdth_irq_tab[i];
 
     /* deinitialize services */
-    dp2_ptr->u.ic.S_Info[0] = bios_adr;
-    dp2_ptr->u.ic.S_Cmd_Indx= 0xff;
-    dp2_ptr->io.event = 0;
+    writel(bios_adr, &dp2_ptr->u.ic.S_Info[0]);
+    writeb(0xff, &dp2_ptr->u.ic.S_Cmd_Indx);
+    writeb(0, &dp2_ptr->io.event);
     retries = INIT_RETRIES;
-    JIFFYWAIT(2);
-    while (dp2_ptr->u.ic.S_Status != 0xff) {
+    gdth_delay(20);
+    while (readb(&dp2_ptr->u.ic.S_Status) != 0xff) {
         if (--retries == 0) {
             printk("GDT-ISA: Initialization error (DEINIT failed)\n");
+           gdth_munmap(ha->brd);
             return 0;
         }
-        udelay(1000);
+        gdth_delay(1);
     }
-    prot_ver = (unchar)dp2_ptr->u.ic.S_Info[0];
-    dp2_ptr->u.ic.Status = 0;
-    dp2_ptr->io.irqdel = 0xff;
+    prot_ver = (unchar)readl(&dp2_ptr->u.ic.S_Info[0]);
+    writeb(0, &dp2_ptr->u.ic.Status);
+    writeb(0xff, &dp2_ptr->io.irqdel);
     if (prot_ver != PROTOCOL_VERSION) {
         printk("GDT-ISA: Illegal protocol version\n");
+       gdth_munmap(ha->brd);
         return 0;
     }
 
@@ -559,78 +735,84 @@ static int gdth_init_isa(ulong bios_adr,gdth_ha_str *ha,int firsttime)
     ha->brd_phys = bios_adr >> 4;
 
     /* special request to controller BIOS */
-    dp2_ptr->u.ic.S_Info[0] = 0x00;
-    dp2_ptr->u.ic.S_Info[1] = 0x00;
-    dp2_ptr->u.ic.S_Info[2] = 0x01;
-    dp2_ptr->u.ic.S_Info[3] = 0x00;
-    dp2_ptr->u.ic.S_Cmd_Indx= 0xfe;
-    dp2_ptr->io.event = 0;
+    writel(0x00, &dp2_ptr->u.ic.S_Info[0]);
+    writel(0x00, &dp2_ptr->u.ic.S_Info[1]);
+    writel(0x01, &dp2_ptr->u.ic.S_Info[2]);
+    writel(0x00, &dp2_ptr->u.ic.S_Info[3]);
+    writeb(0xfe, &dp2_ptr->u.ic.S_Cmd_Indx);
+    writeb(0, &dp2_ptr->io.event);
     retries = INIT_RETRIES;
-    JIFFYWAIT(2);
-    while (dp2_ptr->u.ic.S_Status != 0xfe) {
+    gdth_delay(20);
+    while (readb(&dp2_ptr->u.ic.S_Status) != 0xfe) {
         if (--retries == 0) {
             printk("GDT-ISA: Initialization error\n");
+           gdth_munmap(ha->brd);
             return 0;
         }
-        udelay(1000);
+        gdth_delay(1);
     }
-    dp2_ptr->u.ic.Status = 0;
-    dp2_ptr->io.irqdel = 0xff;
+    writeb(0, &dp2_ptr->u.ic.Status);
+    writeb(0xff, &dp2_ptr->io.irqdel);
     return 1;
 }
 
 
-static int gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha,int firsttime)
+__initfunc (static int gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha))
 {
     register gdt6_dpram_str *dp6_ptr;
     register gdt6c_dpram_str *dp6c_ptr;
     register gdt6m_dpram_str *dp6m_ptr;
     ulong retries;
     unchar prot_ver;
-    unchar remapped = FALSE;
+    int i, found = FALSE;
 
     TRACE(("gdth_init_pci()\n"));
 
-    if (firsttime) {
-        ha->brd      = pcistr->dpmem;
-        ha->brd_phys = (pcistr->bus << 8) | (pcistr->device_fn & 0xf8);
-        ha->stype    = (ulong)pcistr->device_id;
-        ha->irq      = pcistr->irq;
-    }
-
+    ha->brd_phys = (pcistr->bus << 8) | (pcistr->device_fn & 0xf8);
+    ha->stype    = (ulong)pcistr->device_id;
+    ha->irq      = pcistr->irq;
+    
     if (ha->stype <= PCI_DEVICE_ID_VORTEX_GDT6000B) {   /* GDT6000 or GDT6000B */
-        TRACE2(("init_pci() dpmem %lx irq %d\n",ha->brd,ha->irq));
+        TRACE2(("init_pci() dpmem %lx irq %d\n",pcistr->dpmem,ha->irq));
+       ha->brd = gdth_mmap(pcistr->dpmem, sizeof(gdt6_dpram_str));
+       if (ha->brd == NULL) {
+           printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
+           return 0;
+       }
         dp6_ptr = (gdt6_dpram_str *)ha->brd;
         /* reset interface area */
-        memset((char *)&dp6_ptr->u,0,sizeof(dp6_ptr->u));
-        if (*(ulong *)&dp6_ptr->u != 0) {
+        memset_io((char *)&dp6_ptr->u,0,sizeof(dp6_ptr->u));
+        if (readl(&dp6_ptr->u) != 0) {
             printk("GDT-PCI: Initialization error (DPMEM write error)\n");
+           gdth_munmap(ha->brd);
             return 0;
         }
         
         /* disable board interrupts, deinit services */
-        dp6_ptr->io.irqdel     = 0xff;
-        dp6_ptr->io.irqen      = 0x00;
-        dp6_ptr->u.ic.S_Status = 0x00;
-        dp6_ptr->u.ic.Cmd_Index= 0x00;
-
-        dp6_ptr->u.ic.S_Info[0] = ha->brd;
-        dp6_ptr->u.ic.S_Cmd_Indx= 0xff;
-        dp6_ptr->io.event = 0;
+        writeb(0xff, &dp6_ptr->io.irqdel);
+        writeb(0x00, &dp6_ptr->io.irqen);;
+        writeb(0x00, &dp6_ptr->u.ic.S_Status);
+        writeb(0x00, &dp6_ptr->u.ic.Cmd_Index);
+
+        writel(pcistr->dpmem, &dp6_ptr->u.ic.S_Info[0]);
+        writeb(0xff, &dp6_ptr->u.ic.S_Cmd_Indx);
+        writeb(0, &dp6_ptr->io.event);
         retries = INIT_RETRIES;
-        JIFFYWAIT(2);
-        while (dp6_ptr->u.ic.S_Status != 0xff) {
+        gdth_delay(20);
+        while (readb(&dp6_ptr->u.ic.S_Status) != 0xff) {
             if (--retries == 0) {
                 printk("GDT-PCI: Initialization error (DEINIT failed)\n");
+               gdth_munmap(ha->brd);
                 return 0;
             }
-            udelay(1000);
+            gdth_delay(1);
         }
-        prot_ver = (unchar)dp6_ptr->u.ic.S_Info[0];
-        dp6_ptr->u.ic.S_Status = 0;
-        dp6_ptr->io.irqdel = 0xff;
+        prot_ver = (unchar)readl(&dp6_ptr->u.ic.S_Info[0]);
+        writeb(0, &dp6_ptr->u.ic.S_Status);
+        writeb(0xff, &dp6_ptr->io.irqdel);
         if (prot_ver != PROTOCOL_VERSION) {
             printk("GDT-PCI: Illegal protocol version\n");
+           gdth_munmap(ha->brd);
             return 0;
         }
 
@@ -638,35 +820,41 @@ static int gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha,int firsttime)
         ha->ic_all_size = sizeof(dp6_ptr->u);
         
         /* special command to controller BIOS */
-        dp6_ptr->u.ic.S_Info[0] = 0x00;
-        dp6_ptr->u.ic.S_Info[1] = 0x00;
-        dp6_ptr->u.ic.S_Info[2] = 0x01;
-        dp6_ptr->u.ic.S_Info[3] = 0x00;
-        dp6_ptr->u.ic.S_Cmd_Indx= 0xfe;
-        dp6_ptr->io.event = 0;
+        writel(0x00, &dp6_ptr->u.ic.S_Info[0]);
+        writel(0x00, &dp6_ptr->u.ic.S_Info[1]);
+        writel(0x01, &dp6_ptr->u.ic.S_Info[2]);
+        writel(0x00, &dp6_ptr->u.ic.S_Info[3]);
+        writeb(0xfe, &dp6_ptr->u.ic.S_Cmd_Indx);
+        writeb(0, &dp6_ptr->io.event);
         retries = INIT_RETRIES;
-        JIFFYWAIT(2);
-        while (dp6_ptr->u.ic.S_Status != 0xfe) {
+        gdth_delay(20);
+        while (readb(&dp6_ptr->u.ic.S_Status) != 0xfe) {
             if (--retries == 0) {
                 printk("GDT-PCI: Initialization error\n");
+               gdth_munmap(ha->brd);
                 return 0;
             }
-            udelay(1000);
+            gdth_delay(1);
         }
-        dp6_ptr->u.ic.S_Status = 0;
-        dp6_ptr->io.irqdel = 0xff;
+        writeb(0, &dp6_ptr->u.ic.S_Status);
+        writeb(0xff, &dp6_ptr->io.irqdel);
 
     } else if (ha->stype <= PCI_DEVICE_ID_VORTEX_GDT6555) { /* GDT6110, GDT6120, .. */
-        if (firsttime) {
-            ha->plx = (gdt6c_plx_regs *)pcistr->io;
-        }
-        TRACE2(("init_pci_new() dpmem %lx io %lx irq %d\n",
-                      ha->brd,(ulong)ha->plx,ha->irq));
+       ha->plx = (gdt6c_plx_regs *)pcistr->io;
+       TRACE2(("init_pci_new() dpmem %lx io %lx irq %d\n",
+               pcistr->dpmem,(ulong)ha->plx,ha->irq));
+       ha->brd = gdth_mmap(pcistr->dpmem, sizeof(gdt6c_dpram_str));
+       if (ha->brd == NULL) {
+           printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
+           gdth_munmap(ha->brd);
+           return 0;
+       }
         dp6c_ptr = (gdt6c_dpram_str *)ha->brd;
         /* reset interface area */
-        memset((char *)&dp6c_ptr->u,0,sizeof(dp6c_ptr->u));
-        if (*(ulong *)&dp6c_ptr->u != 0) {
+        memset_io((char *)&dp6c_ptr->u,0,sizeof(dp6c_ptr->u));
+        if (readl(&dp6c_ptr->u) != 0) {
             printk("GDT-PCI: Initialization error (DPMEM write error)\n");
+           gdth_munmap(ha->brd);
             return 0;
         }
         
@@ -674,27 +862,29 @@ static int gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha,int firsttime)
         outb(0x00,PTR2USHORT(&ha->plx->control1));
         outb(0xff,PTR2USHORT(&ha->plx->edoor_reg));
         
-        dp6c_ptr->u.ic.S_Status = 0x00;
-        dp6c_ptr->u.ic.Cmd_Index= 0x00;
+        writeb(0x00, &dp6c_ptr->u.ic.S_Status);
+        writeb(0x00, &dp6c_ptr->u.ic.Cmd_Index);
 
-        dp6c_ptr->u.ic.S_Info[0] = ha->brd;
-        dp6c_ptr->u.ic.S_Cmd_Indx= 0xff;
+        writel(pcistr->dpmem, &dp6c_ptr->u.ic.S_Info[0]);
+        writeb(0xff, &dp6c_ptr->u.ic.S_Cmd_Indx);
 
         outb(1,PTR2USHORT(&ha->plx->ldoor_reg));
 
         retries = INIT_RETRIES;
-        JIFFYWAIT(2);
-        while (dp6c_ptr->u.ic.S_Status != 0xff) {
+        gdth_delay(20);
+        while (readb(&dp6c_ptr->u.ic.S_Status) != 0xff) {
             if (--retries == 0) {
                 printk("GDT-PCI: Initialization error (DEINIT failed)\n");
+               gdth_munmap(ha->brd);
                 return 0;
             }
-            udelay(1000);
+            gdth_delay(1);
         }
-        prot_ver = (unchar)dp6c_ptr->u.ic.S_Info[0];
-        dp6c_ptr->u.ic.Status = 0;
+        prot_ver = (unchar)readl(&dp6c_ptr->u.ic.S_Info[0]);
+        writeb(0, &dp6c_ptr->u.ic.Status);
         if (prot_ver != PROTOCOL_VERSION) {
             printk("GDT-PCI: Illegal protocol version\n");
+           gdth_munmap(ha->brd);
             return 0;
         }
 
@@ -702,87 +892,92 @@ static int gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha,int firsttime)
         ha->ic_all_size = sizeof(dp6c_ptr->u);
 
         /* special command to controller BIOS */
-        dp6c_ptr->u.ic.S_Info[0] = 0x00;
-        dp6c_ptr->u.ic.S_Info[1] = 0x00;
-        dp6c_ptr->u.ic.S_Info[2] = 0x01;
-        dp6c_ptr->u.ic.S_Info[3] = 0x00;
-        dp6c_ptr->u.ic.S_Cmd_Indx= 0xfe;
+        writel(0x00, &dp6c_ptr->u.ic.S_Info[0]);
+        writel(0x00, &dp6c_ptr->u.ic.S_Info[1]);
+        writel(0x01, &dp6c_ptr->u.ic.S_Info[2]);
+        writel(0x00, &dp6c_ptr->u.ic.S_Info[3]);
+        writeb(0xfe, &dp6c_ptr->u.ic.S_Cmd_Indx);
         
         outb(1,PTR2USHORT(&ha->plx->ldoor_reg));
 
         retries = INIT_RETRIES;
-        JIFFYWAIT(2);
-        while (dp6c_ptr->u.ic.S_Status != 0xfe) {
+        gdth_delay(20);
+        while (readb(&dp6c_ptr->u.ic.S_Status) != 0xfe) {
             if (--retries == 0) {
                 printk("GDT-PCI: Initialization error\n");
+               gdth_munmap(ha->brd);
                 return 0;
             }
-            udelay(1000);
+            gdth_delay(1);
         }
-        dp6c_ptr->u.ic.S_Status = 0;
+        writeb(0, &dp6c_ptr->u.ic.S_Status);
 
     } else {                                            /* MPR */
-        if (ha->brd > 0xfffff) {                        /* NOT below 1MB */
-#if LINUX_VERSION_CODE >= 0x010300
-            /* Linux 1.3.X allow to remap physical pages adresses greater
-               than the highest physical memory address to kernel virtual
-               pages using vremap()/vfree(), Linux 1.2.X doesn't */
-            TRACE2(("init_pci_mpr() dpmem %lx irq %d\n",ha->brd,ha->irq));
-            ha->brd = (ulong)vremap(ha->brd, sizeof(gdt6m_dpram_str));
-            if (ha->brd == 0L) {
-                printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
-                return 0;
-            }
-            TRACE2(("init_pci_mpr() remapped dpmem %lx\n",ha->brd));
-            remapped = TRUE;
-#else
-            printk("GDT-PCI: Initialization error (DPMEM not below 1MB)\n");
-            return 0;
-#endif
-        }
-
+       TRACE2(("init_pci_mpr() dpmem %lx irq %d\n",pcistr->dpmem,ha->irq));
+       ha->brd = gdth_mmap(pcistr->dpmem, sizeof(gdt6m_dpram_str));
+       if (ha->brd == NULL) {
+           printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
+           return 0;
+       }
+
+        /* check and reset interface area */
         dp6m_ptr = (gdt6m_dpram_str *)ha->brd;
-        /* reset interface area */
-        memset((char *)&dp6m_ptr->u,0,sizeof(dp6m_ptr->u));
-        if (*(ulong *)&dp6m_ptr->u != 0) {
-            printk("GDT-PCI: Initialization error (DPMEM write error)\n");
-#if LINUX_VERSION_CODE >= 0x010300
-            if (remapped)
-                vfree((void *)ha->brd);
-#endif
-            return 0;
-        }
+       writel(DPMEM_MAGIC, &dp6m_ptr->u);
+       if (readl(&dp6m_ptr->u) != DPMEM_MAGIC) {
+           printk("GDT-PCI: Cannot access DPMEM at 0x%x (shadowed?)\n", 
+                  (int)ha->brd);
+           found = FALSE;
+           for (i = 0xC8000; i < 0xE8000; i += 0x4000) {
+               pcibios_write_config_dword( pcistr->bus, pcistr->device_fn,
+                                           PCI_BASE_ADDRESS_0, i );
+               gdth_munmap( ha->brd );
+               ha->brd = gdth_mmap(i, sizeof(gdt6m_dpram_str)); 
+               if (ha->brd == NULL) {
+                   printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
+                   return 0;
+               }
+               dp6m_ptr = (gdt6m_dpram_str *)ha->brd;
+               writel(DPMEM_MAGIC, &dp6m_ptr->u);
+               if (readl(&dp6m_ptr->u) == DPMEM_MAGIC) {
+                   printk("GDT-PCI: Use free address at 0x%x\n",
+                          (int)ha->brd);
+                   found = TRUE;
+                   break;
+               }
+           }   
+           if (!found) {
+               printk("GDT-PCI: No free address found!\n");
+               gdth_munmap( ha->brd );
+               return 0;
+           }
+       }
+        memset_io((char *)&dp6m_ptr->u,0,sizeof(dp6m_ptr->u));
         
         /* disable board interrupts, deinit services */
-        dp6m_ptr->i960r.edoor_en_reg |= 4;
-        dp6m_ptr->i960r.edoor_reg = 0xff;
-        dp6m_ptr->u.ic.S_Status   = 0x00;
-        dp6m_ptr->u.ic.Cmd_Index  = 0x00;
-
-        dp6m_ptr->u.ic.S_Info[0]  = ha->brd;
-        dp6m_ptr->u.ic.S_Cmd_Indx = 0xff;
-        dp6m_ptr->i960r.ldoor_reg = 1;
+        writeb(readb(&dp6m_ptr->i960r.edoor_en_reg) | 4,
+              &dp6m_ptr->i960r.edoor_en_reg);
+        writeb(0xff, &dp6m_ptr->i960r.edoor_reg);
+        writeb(0x00, &dp6m_ptr->u.ic.S_Status);
+        writeb(0x00, &dp6m_ptr->u.ic.Cmd_Index);
+
+        writel(pcistr->dpmem, &dp6m_ptr->u.ic.S_Info[0]);
+        writeb(0xff, &dp6m_ptr->u.ic.S_Cmd_Indx);
+        writeb(1, &dp6m_ptr->i960r.ldoor_reg);
         retries = INIT_RETRIES;
-        JIFFYWAIT(2);
-        while (dp6m_ptr->u.ic.S_Status != 0xff) {
+        gdth_delay(20);
+        while (readb(&dp6m_ptr->u.ic.S_Status) != 0xff) {
             if (--retries == 0) {
                 printk("GDT-PCI: Initialization error (DEINIT failed)\n");
-#if LINUX_VERSION_CODE >= 0x010300
-                if (remapped)
-                    vfree((void *)ha->brd);
-#endif
+               gdth_munmap(ha->brd);
                 return 0;
             }
-            udelay(1000);
+            gdth_delay(1);
         }
-        prot_ver = (unchar)dp6m_ptr->u.ic.S_Info[0];
-        dp6m_ptr->u.ic.S_Status = 0;
+        prot_ver = (unchar)readl(&dp6m_ptr->u.ic.S_Info[0]);
+        writeb(0, &dp6m_ptr->u.ic.S_Status);
         if (prot_ver != PROTOCOL_VERSION) {
             printk("GDT-PCI: Illegal protocol version\n");
-#if LINUX_VERSION_CODE >= 0x010300
-            if (remapped)
-                vfree((void *)ha->brd);
-#endif
+           gdth_munmap(ha->brd);
             return 0;
         }
 
@@ -790,26 +985,23 @@ static int gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha,int firsttime)
         ha->ic_all_size = sizeof(dp6m_ptr->u);
         
         /* special command to controller BIOS */
-        dp6m_ptr->u.ic.S_Info[0]  = 0x00;
-        dp6m_ptr->u.ic.S_Info[1]  = 0x00;
-        dp6m_ptr->u.ic.S_Info[2]  = 0x01;
-        dp6m_ptr->u.ic.S_Info[3]  = 0x00;
-        dp6m_ptr->u.ic.S_Cmd_Indx = 0xfe;
-        dp6m_ptr->i960r.ldoor_reg = 1;
+        writel(0x00, &dp6m_ptr->u.ic.S_Info[0]);
+        writel(0x00, &dp6m_ptr->u.ic.S_Info[1]);
+        writel(0x01, &dp6m_ptr->u.ic.S_Info[2]);
+        writel(0x00, &dp6m_ptr->u.ic.S_Info[3]);
+        writeb(0xfe, &dp6m_ptr->u.ic.S_Cmd_Indx);
+        writeb(1, &dp6m_ptr->i960r.ldoor_reg);
         retries = INIT_RETRIES;
-        JIFFYWAIT(2);
-        while (dp6m_ptr->u.ic.S_Status != 0xfe) {
+        gdth_delay(20);
+        while (readb(&dp6m_ptr->u.ic.S_Status) != 0xfe) {
             if (--retries == 0) {
                 printk("GDT-PCI: Initialization error\n");
-#if LINUX_VERSION_CODE >= 0x010300
-                if (remapped)
-                    vfree((void *)ha->brd);
-#endif
+               gdth_munmap(ha->brd);
                 return 0;
             }
-            udelay(1000);
+            gdth_delay(1);
         }
-        dp6m_ptr->u.ic.S_Status = 0;
+        writeb(0, &dp6m_ptr->u.ic.S_Status);
     }
 
     return 1;
@@ -818,11 +1010,10 @@ static int gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha,int firsttime)
 
 /* controller protocol functions */
 
-static void gdth_enable_int(int hanum)
+__initfunc (static void gdth_enable_int(int hanum))
 {
     gdth_ha_str *ha;
     ulong flags;
-    ushort addr;
     gdt2_dpram_str *dp2_ptr;
     gdt6_dpram_str *dp6_ptr;
     gdt6m_dpram_str *dp6m_ptr;
@@ -834,27 +1025,27 @@ static void gdth_enable_int(int hanum)
     cli();
 
     if (ha->type == GDT_EISA) {
-        addr = (ushort)ha->brd;
-        outb(0xff,addr+EDOORREG);
-        outb(0xff,addr+EDENABREG);
-        outb(0x01,addr+EINTENABREG);
+        outb(0xff, ha->bmic + EDOORREG);
+        outb(0xff, ha->bmic + EDENABREG);
+        outb(0x01, ha->bmic + EINTENABREG);
     } else if (ha->type == GDT_ISA) {
         dp2_ptr = (gdt2_dpram_str *)ha->brd;
-        dp2_ptr->io.irqdel = 1;
-        dp2_ptr->u.ic.Cmd_Index = 0;
-        dp2_ptr->io.irqen = 1;
+        writeb(1, &dp2_ptr->io.irqdel);
+        writeb(0, &dp2_ptr->u.ic.Cmd_Index);
+        writeb(1, &dp2_ptr->io.irqen);
     } else if (ha->type == GDT_PCI) {
         dp6_ptr = (gdt6_dpram_str *)ha->brd;
-        dp6_ptr->io.irqdel = 1;
-        dp6_ptr->u.ic.Cmd_Index = 0;
-        dp6_ptr->io.irqen = 1;
+        writeb(1, &dp6_ptr->io.irqdel);
+        writeb(0, &dp6_ptr->u.ic.Cmd_Index);
+        writeb(1, &dp6_ptr->io.irqen);
     } else if (ha->type == GDT_PCINEW) {
-        outb(0xff,PTR2USHORT(&ha->plx->edoor_reg));
-        outb(0x03,PTR2USHORT(&ha->plx->control1));
+        outb(0xff, PTR2USHORT(&ha->plx->edoor_reg));
+        outb(0x03, PTR2USHORT(&ha->plx->control1));
     } else if (ha->type == GDT_PCIMPR) {
         dp6m_ptr = (gdt6m_dpram_str *)ha->brd;
-        dp6m_ptr->i960r.edoor_reg = 0xff;
-        dp6m_ptr->i960r.edoor_en_reg &= ~4;
+        writeb(0xff, &dp6m_ptr->i960r.edoor_reg);
+        writeb(readb(&dp6m_ptr->i960r.edoor_en_reg) & ~4,
+              &dp6m_ptr->i960r.edoor_en_reg);
     }
     restore_flags(flags);
 }
@@ -874,15 +1065,15 @@ static int gdth_get_status(unchar *pIStatus,int irq)
         if (ha->irq != (unchar)irq)             /* check IRQ */
             continue;
         if (ha->type == GDT_EISA)
-            *pIStatus = inb((ushort)ha->brd+EDOORREG);
+            *pIStatus = inb((ushort)ha->bmic + EDOORREG);
         else if (ha->type == GDT_ISA)
-            *pIStatus = ((gdt2_dpram_str *)ha->brd)->u.ic.Cmd_Index;
+            *pIStatus = readb(&((gdt2_dpram_str *)ha->brd)->u.ic.Cmd_Index);
         else if (ha->type == GDT_PCI)
-            *pIStatus = ((gdt6_dpram_str *)ha->brd)->u.ic.Cmd_Index;
+            *pIStatus = readb(&((gdt6_dpram_str *)ha->brd)->u.ic.Cmd_Index);
         else if (ha->type == GDT_PCINEW) 
             *pIStatus = inb(PTR2USHORT(&ha->plx->edoor_reg));
         else if (ha->type == GDT_PCIMPR)
-            *pIStatus = ((gdt6m_dpram_str *)ha->brd)->i960r.edoor_reg;
+            *pIStatus = readb(&((gdt6m_dpram_str *)ha->brd)->i960r.edoor_reg);
    
         if (*pIStatus)                                  
             return i;                           /* board found */
@@ -900,15 +1091,15 @@ static int gdth_test_busy(int hanum)
     
     ha = HADATA(gdth_ctr_tab[hanum]);
     if (ha->type == GDT_EISA)
-        gdtsema0 = (int)inb((ushort)ha->brd+SEMA0REG);
+        gdtsema0 = (int)inb(ha->bmic + SEMA0REG);
     else if (ha->type == GDT_ISA)
-        gdtsema0 = (int)((gdt2_dpram_str *)ha->brd)->u.ic.Sema0;
+        gdtsema0 = (int)readb(&((gdt2_dpram_str *)ha->brd)->u.ic.Sema0);
     else if (ha->type == GDT_PCI)
-        gdtsema0 = (int)((gdt6_dpram_str *)ha->brd)->u.ic.Sema0;
+        gdtsema0 = (int)readb(&((gdt6_dpram_str *)ha->brd)->u.ic.Sema0);
     else if (ha->type == GDT_PCINEW) 
         gdtsema0 = (int)inb(PTR2USHORT(&ha->plx->sema0_reg));
     else if (ha->type == GDT_PCIMPR)
-        gdtsema0 = (int)((gdt6m_dpram_str *)ha->brd)->i960r.sema0_reg;
+        gdtsema0 = (int)readb(&((gdt6m_dpram_str *)ha->brd)->i960r.sema0_reg);
 
     return (gdtsema0 & 1);
 }
@@ -942,15 +1133,15 @@ static void gdth_set_sema0(int hanum)
 
     ha = HADATA(gdth_ctr_tab[hanum]);
     if (ha->type == GDT_EISA)
-        outb(1,(ushort)ha->brd+SEMA0REG);
+        outb(1, ha->bmic + SEMA0REG);
     else if (ha->type == GDT_ISA)
-        ((gdt2_dpram_str *)ha->brd)->u.ic.Sema0 = 1;
+        writeb(1, &((gdt2_dpram_str *)ha->brd)->u.ic.Sema0);
     else if (ha->type == GDT_PCI)
-        ((gdt6_dpram_str *)ha->brd)->u.ic.Sema0 = 1;
+        writeb(1, &((gdt6_dpram_str *)ha->brd)->u.ic.Sema0);
     else if (ha->type == GDT_PCINEW)  
-        outb(1,PTR2USHORT(&ha->plx->sema0_reg));
+        outb(1, PTR2USHORT(&ha->plx->sema0_reg));
     else if (ha->type == GDT_PCIMPR)
-        ((gdt6m_dpram_str *)ha->brd)->i960r.sema0_reg = 1;
+        writeb(1, &((gdt6m_dpram_str *)ha->brd)->i960r.sema0_reg);
     
 }
 
@@ -986,32 +1177,32 @@ static void gdth_copy_command(int hanum)
     /* set offset and service, copy command to DPMEM */
     if (ha->type == GDT_ISA) {
         dp2_ptr = (gdt2_dpram_str *)ha->brd;
-        dp2_ptr->u.ic.comm_queue[cmd_no].offset =
-            dp_offset + DPMEM_COMMAND_OFFSET;
-        dp2_ptr->u.ic.comm_queue[cmd_no].serv_id =
-            (ushort)cmd_ptr->Service;
-        memcpy(&dp2_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count);
+        writew(dp_offset + DPMEM_COMMAND_OFFSET, 
+              &dp2_ptr->u.ic.comm_queue[cmd_no].offset);
+        writew((ushort)cmd_ptr->Service, 
+              &dp2_ptr->u.ic.comm_queue[cmd_no].serv_id);
+       memcpy_toio(&dp2_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count);
     } else if (ha->type == GDT_PCI) {
         dp6_ptr = (gdt6_dpram_str *)ha->brd;
-        dp6_ptr->u.ic.comm_queue[cmd_no].offset =
-            dp_offset + DPMEM_COMMAND_OFFSET;
-        dp6_ptr->u.ic.comm_queue[cmd_no].serv_id =
-            (ushort)cmd_ptr->Service;
-        memcpy(&dp6_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count);
+        writew(dp_offset + DPMEM_COMMAND_OFFSET, 
+              &dp6_ptr->u.ic.comm_queue[cmd_no].offset);
+        writew((ushort)cmd_ptr->Service, 
+              &dp6_ptr->u.ic.comm_queue[cmd_no].serv_id);
+        memcpy_toio(&dp6_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count);
     } else if (ha->type == GDT_PCINEW) {
         dp6c_ptr = (gdt6c_dpram_str *)ha->brd;
-        dp6c_ptr->u.ic.comm_queue[cmd_no].offset =
-            dp_offset + DPMEM_COMMAND_OFFSET;
-        dp6c_ptr->u.ic.comm_queue[cmd_no].serv_id =
-            (ushort)cmd_ptr->Service;
-        memcpy(&dp6c_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count);
+        writew(dp_offset + DPMEM_COMMAND_OFFSET, 
+              &dp6c_ptr->u.ic.comm_queue[cmd_no].offset);
+       writew((ushort)cmd_ptr->Service, 
+              &dp6c_ptr->u.ic.comm_queue[cmd_no].serv_id);
+       memcpy_toio(&dp6c_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count);
     } else if (ha->type == GDT_PCIMPR) {
         dp6m_ptr = (gdt6m_dpram_str *)ha->brd;
-        dp6m_ptr->u.ic.comm_queue[cmd_no].offset =
-            dp_offset + DPMEM_COMMAND_OFFSET;
-        dp6m_ptr->u.ic.comm_queue[cmd_no].serv_id =
-            (ushort)cmd_ptr->Service;
-        memcpy(&dp6m_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count);
+        writew(dp_offset + DPMEM_COMMAND_OFFSET, 
+              &dp6m_ptr->u.ic.comm_queue[cmd_no].offset);
+        writew((ushort)cmd_ptr->Service, 
+              &dp6m_ptr->u.ic.comm_queue[cmd_no].serv_id);
+        memcpy_toio(&dp6m_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count);
     }
 }
 
@@ -1039,17 +1230,17 @@ static void gdth_release_event(int hanum)
         ha->pccb->Service |= 0x80;
 
     if (ha->type == GDT_EISA) {
-        outb(ha->pccb->Service,(ushort)ha->brd+LDOORREG);
+        outb(ha->pccb->Service, ha->bmic + LDOORREG);
         if (ha->pccb->OpCode == GDT_INIT)               /* store DMA buffer */
-            outl((ulong)ha->pccb,(ushort)ha->brd+MAILBOXREG);
+            outl((ulong)ha->pccb, ha->bmic + MAILBOXREG);
     } else if (ha->type == GDT_ISA)
-        ((gdt2_dpram_str *)ha->brd)->io.event = 0;
+        writeb(0, &((gdt2_dpram_str *)ha->brd)->io.event);
     else if (ha->type == GDT_PCI)
-        ((gdt6_dpram_str *)ha->brd)->io.event = 0;
+        writeb(0, &((gdt6_dpram_str *)ha->brd)->io.event);
     else if (ha->type == GDT_PCINEW) 
-        outb(1,PTR2USHORT(&ha->plx->ldoor_reg));
+        outb(1, PTR2USHORT(&ha->plx->ldoor_reg));
     else if (ha->type == GDT_PCIMPR)
-        ((gdt6m_dpram_str *)ha->brd)->i960r.ldoor_reg = 1;
+        writeb(1, &((gdt6m_dpram_str *)ha->brd)->i960r.ldoor_reg);
 }
 
     
@@ -1075,12 +1266,12 @@ static int gdth_wait(int hanum,int index,ulong time)
             answer_found = TRUE;
             break;
         }
-        udelay(1000);
+        gdth_delay(1);
     } while (--time);
     gdth_from_wait = FALSE;
     
     while (gdth_test_busy(hanum))
-        udelay(1);
+        gdth_delay(0);
 
     return (answer_found);
 }
@@ -1115,7 +1306,7 @@ static int gdth_internal_cmd(int hanum,unchar service,ushort opcode,ulong p1,
                 cmd_ptr->u.ioctl.subfunc = p1;
                 cmd_ptr->u.ioctl.channel = p2;
                 cmd_ptr->u.ioctl.param_size = (ushort)p3;
-                cmd_ptr->u.ioctl.p_param = (ulong)ha->pscratch;
+                cmd_ptr->u.ioctl.p_param = virt_to_bus(ha->pscratch);
             } else {
                 cmd_ptr->u.cache.DeviceNo = (ushort)p1;
                 cmd_ptr->u.cache.BlockNo  = p2;
@@ -1131,14 +1322,14 @@ static int gdth_internal_cmd(int hanum,unchar service,ushort opcode,ulong p1,
         ha->cmd_cnt          = 0;
         gdth_copy_command(hanum);
         gdth_release_event(hanum);
-        JIFFYWAIT(2);
+        gdth_delay(20);
         if (!gdth_wait(hanum,index,INIT_TIMEOUT)) {
             printk("GDT: Initialization error (timeout service %d)\n",service);
             return 0;
         }
         if (ha->status != S_BSY || --retries == 0)
             break;
-        udelay(1000);   
+        gdth_delay(1);   
     }   
     
     return (ha->status != S_OK ? 0:1);
@@ -1147,7 +1338,7 @@ static int gdth_internal_cmd(int hanum,unchar service,ushort opcode,ulong p1,
 
 /* search for devices */
 
-static int gdth_search_drives(int hanum,int firsttime)
+__initfunc (static int gdth_search_drives(int hanum))
 {
     register gdth_ha_str *ha;
     ushort cdev_cnt,i;
@@ -1155,8 +1346,9 @@ static int gdth_search_drives(int hanum,int firsttime)
     ulong drv_cyls, drv_hds, drv_secs;
     ulong bus_no;
     gdth_getch_str *chn;
+    gdth_iochan_str *ioc;
     
-    TRACE(("gdth_search_drives() hanum %d flag %d\n",hanum,firsttime));
+    TRACE(("gdth_search_drives() hanum %d\n",hanum));
     ha = HADATA(gdth_ctr_tab[hanum]);
 
     /* initialize controller services, at first: screen service */
@@ -1176,57 +1368,77 @@ static int gdth_search_drives(int hanum,int firsttime)
     TRACE2(("gdth_search_drives(): CACHESERVICE initialized\n"));
     cdev_cnt = (ushort)ha->info;
 
-    if (firsttime) {
-        /* mount all cache devices */
-        if (!gdth_internal_cmd(hanum,CACHESERVICE,GDT_MOUNT,0xffff,1,0)) {
-            printk("GDT: Initialization error cache service (code %d)\n",
-                   ha->status);
-            return 0;
-        }
-        TRACE2(("gdth_search_drives(): mountall CACHESERVICE OK\n"));
+    /* mount all cache devices */
+    gdth_internal_cmd(hanum,CACHESERVICE,GDT_MOUNT,0xffff,1,0);
+    TRACE2(("gdth_search_drives(): mountall CACHESERVICE OK\n"));
 
-        /* initialize cache service after mountall */
-        if (!gdth_internal_cmd(hanum,CACHESERVICE,GDT_INIT,LINUX_OS,0,0)) {
-            printk("GDT: Initialization error cache service (code %d)\n",
-                   ha->status);
-            return 0;
-        }
-        TRACE2(("gdth_search_drives() CACHES. init. after mountall\n"));
-        cdev_cnt = (ushort)ha->info;
-
-        /* detect number of SCSI buses */
-        chn = (gdth_getch_str *)DMADATA(gdth_ctr_tab[hanum]);
-        for (bus_no=0; bus_no<MAXBUS; ++bus_no) {
-            chn->channel_no = bus_no;
-            if (!gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,
-                                   SCSI_CHAN_CNT | L_CTRL_PATTERN,
-                                   IO_CHANNEL | INVALID_CHANNEL,
-                                   sizeof(gdth_getch_str))) {
-                if (bus_no == 0) {
-                    printk("GDT: Error detecting SCSI channel count (0x%x)\n",
-                           ha->status);
-                    return 0;
-                }
-                break;
-            }
-            if (chn->siop_id < MAXID)
-                ha->id[bus_no][chn->siop_id].type = SIOP_DTYP;
-        }       
-        ha->bus_cnt = (unchar)bus_no;
-        TRACE2(("gdth_search_drives() %d SCSI channels\n",ha->bus_cnt));
-
-        /* read cache configuration */
-        if (!gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,CACHE_INFO,
-                               INVALID_CHANNEL,sizeof(gdth_cinfo_str))) {
-            printk("GDT: Initialization error cache service (code %d)\n",
-                   ha->status);
-            return 0;
-        }
-        ha->cpar = ((gdth_cinfo_str *)DMADATA(gdth_ctr_tab[hanum]))->cpar;
-        TRACE2(("gdth_search_drives() cinfo: vs %lx sta %d str %d dw %d b %d\n",
-                ha->cpar.version,ha->cpar.state,ha->cpar.strategy,
-                ha->cpar.write_back,ha->cpar.block_size));
+    /* initialize cache service after mountall */
+    if (!gdth_internal_cmd(hanum,CACHESERVICE,GDT_INIT,LINUX_OS,0,0)) {
+       printk("GDT: Initialization error cache service (code %d)\n",
+              ha->status);
+       return 0;
     }
+    TRACE2(("gdth_search_drives() CACHES. init. after mountall\n"));
+    cdev_cnt = (ushort)ha->info;
+
+    /* detect number of SCSI buses - try new IOCTL */
+    ioc = (gdth_iochan_str *)DMADATA(gdth_ctr_tab[hanum]);
+    ioc->version       = -1UL;
+    ioc->list_entries  = MAXBUS;
+    ioc->first_chan    = 0;
+    ioc->last_chan     = MAXBUS-1;
+    ioc->list_offset   = GDTOFFSOF(gdth_iochan_str, list[0]);
+    if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,GET_IOCHAN_DESC,
+                         INVALID_CHANNEL,sizeof(gdth_iochan_str))) {
+       TRACE2(("GET_IOCHAN_DESC supported!\n"));
+       ha->bus_cnt = ioc->chan_count;
+       for (bus_no = 0; bus_no < ha->bus_cnt; ++bus_no)
+           if (ioc->list[bus_no].proc_id < MAXID)
+               ha->id[bus_no][ioc->list[bus_no].proc_id].type = SIOP_DTYP;
+    } else {
+       /* old method */
+       chn = (gdth_getch_str *)DMADATA(gdth_ctr_tab[hanum]);
+       for (bus_no = 0; bus_no < MAXBUS; ++bus_no) {
+           chn->channel_no = bus_no;
+           if (!gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,
+                                  SCSI_CHAN_CNT | L_CTRL_PATTERN,
+                                  IO_CHANNEL | INVALID_CHANNEL,
+                                  sizeof(gdth_getch_str))) {
+               if (bus_no == 0) {
+                   printk("GDT: Error detecting SCSI channel count (0x%x)\n",
+                          ha->status);
+                   return 0;
+               }
+               break;
+           }
+           if (chn->siop_id < MAXID)
+               ha->id[bus_no][chn->siop_id].type = SIOP_DTYP;
+       }       
+       ha->bus_cnt = (unchar)bus_no;
+    }
+    TRACE2(("gdth_search_drives() %d SCSI channels\n",ha->bus_cnt));
+
+    /* read cache configuration */
+    if (!gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,CACHE_INFO,
+                          INVALID_CHANNEL,sizeof(gdth_cinfo_str))) {
+       printk("GDT: Initialization error cache service (code %d)\n",
+              ha->status);
+       return 0;
+    }
+    ha->cpar = ((gdth_cinfo_str *)DMADATA(gdth_ctr_tab[hanum]))->cpar;
+    TRACE2(("gdth_search_drives() cinfo: vs %lx sta %d str %d dw %d b %d\n",
+           ha->cpar.version,ha->cpar.state,ha->cpar.strategy,
+           ha->cpar.write_back,ha->cpar.block_size));
+
+    /* read board info, fill ctr_name[] */
+    if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,BOARD_INFO,
+                         INVALID_CHANNEL,sizeof(gdth_binfo_str))) {
+       TRACE2(("BOARD_INFO supported!\n"));
+       strcpy(ha->ctr_name, ((gdth_binfo_str *)DMADATA(gdth_ctr_tab[hanum]))->type_string);
+    } else {
+       strcpy(ha->ctr_name, gdth_ctr_name(hanum));
+    }
+    TRACE2(("Controller name: %s\n",ha->ctr_name));
 
     /* initialize raw service */
     if (!gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_INIT,0,0,0)) {
@@ -1241,8 +1453,7 @@ static int gdth_search_drives(int hanum,int firsttime)
     if (gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_SET_FEAT,SCATTER_GATHER,
                           0,0)) {
         TRACE2(("gdth_search_drives(): set features RAWSERVICE OK\n"));
-        if (gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_GET_FEAT,0,0,0))
-        {
+        if (gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_GET_FEAT,0,0,0)) {
             TRACE2(("gdth_search_dr(): get feat RAWSERVICE %ld\n",
                           ha->info));
             ha->raw_feat = (ushort)ha->info;
@@ -1260,9 +1471,20 @@ static int gdth_search_drives(int hanum,int firsttime)
         }
     }
 
-    /* if it is not the first scan, we are ready */
-    if (!firsttime)
-        return 1;
+    /* reserve drives for raw service */
+    for (i = 0; reserve_list[i].hanum != 0xff; ++i) {
+       if (reserve_list[i].hanum < MAXHA && reserve_list[i].hanum == hanum &&
+           reserve_list[i].bus < MAXBUS && reserve_list[i].id < MAXID) {
+           TRACE2(("gdth_search_drives(): reserve ha %d bus %d id %d\n",
+                   reserve_list[i].hanum, reserve_list[i].bus,
+                   reserve_list[i].id));
+           if (!gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_RESERVE,0,
+                                  reserve_list[i].bus, reserve_list[i].id)) {
+               printk("GDT: Error raw service (RESERVE, code %d)\n",
+                      ha->status);
+           }
+       }
+    }
 
     /* scanning for raw devices */
     for (b=0; b<ha->bus_cnt; ++b) {
@@ -1301,27 +1523,33 @@ static int gdth_search_drives(int hanum,int firsttime)
             ha->id[b][t].hostdrive = i;
 
             /* evaluate mapping (sectors per head, heads per cylinder) */
-            ha->id[b][t].size &= ~SECS32;
-            drv_cyls = ha->id[b][t].size /HEADS/SECS;
-            if (drv_cyls <= MAXCYLS) {
-                drv_hds = HEADS;
-                drv_secs= SECS;
-            } else {                            /* too high for 64*32 */
-                drv_cyls = ha->id[b][t].size /MEDHEADS/MEDSECS;
-                if (drv_cyls <= MAXCYLS) {
-                    drv_hds = MEDHEADS;
-                    drv_secs= MEDSECS;
-                } else {                        /* too high for 127*63 */
-                    drv_cyls = ha->id[b][t].size /BIGHEADS/BIGSECS;
-                    drv_hds = BIGHEADS;
-                    drv_secs= BIGSECS;
-                }
-            }
+           ha->id[b][t].size &= ~SECS32;
+           if (ha->info2 == 0) {
+               drv_cyls = ha->id[b][t].size /HEADS/SECS;
+               if (drv_cyls <= MAXCYLS) {
+                   drv_hds = HEADS;
+                   drv_secs= SECS;
+               } else {                            /* too high for 64*32 */
+                   drv_cyls = ha->id[b][t].size /MEDHEADS/MEDSECS;
+                   if (drv_cyls <= MAXCYLS) {
+                       drv_hds = MEDHEADS;
+                       drv_secs= MEDSECS;
+                   } else {                        /* too high for 127*63 */
+                       drv_cyls = ha->id[b][t].size /BIGHEADS/BIGSECS;
+                       drv_hds = BIGHEADS;
+                       drv_secs= BIGSECS;
+                   }
+               }
+            } else {
+               drv_hds = ha->info2 & 0xff;
+               drv_secs = (ha->info2 >> 8) & 0xff;
+               drv_cyls = ha->id[b][t].size /drv_hds/drv_secs;
+           }
             ha->id[b][t].heads = (unchar)drv_hds;
             ha->id[b][t].secs  = (unchar)drv_secs;
             /* round size */
             ha->id[b][t].size  = drv_cyls * drv_hds * drv_secs;
-            TRACE(("gdth_search_dr() cdr. %d size %ld hds %ld scs %ld\n",
+            TRACE2(("gdth_search_dr() cdr. %d size %ld hds %ld scs %ld\n",
                    i,ha->id[b][t].size,drv_hds,drv_secs));
             
             /* get informations about device */
@@ -1355,8 +1583,8 @@ static void gdth_putq(int hanum,Scsi_Cmnd *scp,unchar priority)
 
     ha = HADATA(gdth_ctr_tab[hanum]);
     scp->SCp.this_residual = (int)priority;
-    gdth_update_timeout(scp, scp->timeout * 6);
-#if LINUX_VERSION_CODE >= 0x010400
+    gdth_update_timeout(hanum, scp, scp->timeout_per_command * 6);
+#if LINUX_VERSION_CODE >= 0x020000
     b = scp->channel;
 #else
     b = NUMDATA(nscp->host)->busnum;
@@ -1365,7 +1593,7 @@ static void gdth_putq(int hanum,Scsi_Cmnd *scp,unchar priority)
 #if LINUX_VERSION_CODE >= 0x010300
     if (priority >= DEFAULT_PRI && ha->id[b][t].lock) {
         TRACE2(("gdth_putq(): locked IO -> update_timeout()\n"));
-        scp->SCp.buffers_residual = gdth_update_timeout(scp, 0);
+        scp->SCp.buffers_residual = gdth_update_timeout(hanum, scp, 0);
     }
 #endif
 
@@ -1418,7 +1646,7 @@ static void gdth_next(int hanum)
     for (nscp = pscp = ha->req_first; nscp; nscp = (Scsi_Cmnd *)nscp->SCp.ptr) {
         if (nscp != pscp && nscp != (Scsi_Cmnd *)pscp->SCp.ptr)
             pscp = (Scsi_Cmnd *)pscp->SCp.ptr;
-#if LINUX_VERSION_CODE >= 0x010400
+#if LINUX_VERSION_CODE >= 0x020000
         b = nscp->channel;
 #else
         b = NUMDATA(nscp->host)->busnum;
@@ -1434,7 +1662,7 @@ static void gdth_next(int hanum)
                         return;
                     }
                     while (gdth_test_busy(hanum))
-                        udelay(1000);
+                        gdth_delay(1);
                 }
                 firsttime = FALSE;
             }
@@ -1472,7 +1700,10 @@ static void gdth_next(int hanum)
                         TRACE2(("Prevent r. nonremov. drive->do nothing\n"));
                         nscp->result = DID_OK << 16;
                         restore_flags( flags );
-                        nscp->scsi_done(nscp);
+                        if (!nscp->SCp.have_data_in)
+                            nscp->SCp.have_data_in++;
+                        else
+                            nscp->scsi_done(nscp);
                         save_flags( flags );
                         cli();
                     } else {
@@ -1500,7 +1731,10 @@ static void gdth_next(int hanum)
                        nscp->cmnd[0]);
                     nscp->result = DID_ABORT << 16;
                     restore_flags( flags );
-                    nscp->scsi_done( nscp );
+                    if (!nscp->SCp.have_data_in)
+                        nscp->SCp.have_data_in++;
+                    else
+                        nscp->scsi_done(nscp);
                     save_flags( flags );
                     cli();
                     break;
@@ -1638,7 +1872,10 @@ static int gdth_internal_cache_cmd(int hanum,Scsi_Cmnd *scp,
     }
 
     restore_flags(*flags);
-    scp->scsi_done(scp);
+    if (!scp->SCp.have_data_in)
+        scp->SCp.have_data_in++;
+    else
+        scp->scsi_done(scp);
     save_flags(*flags);
     cli();
     return 1;
@@ -1709,7 +1946,7 @@ static int gdth_fill_cache_cmd(int hanum,Scsi_Cmnd *scp,ushort hdrive)
             cmdp->u.cache.DestAddr= -1UL;
             sl = (struct scatterlist *)scp->request_buffer;
             for (i=0; i<scp->use_sg; ++i,++sl) {
-                cmdp->u.cache.sg_lst[i].sg_ptr = (ulong)sl->address;
+                cmdp->u.cache.sg_lst[i].sg_ptr = virt_to_bus(sl->address);
                 cmdp->u.cache.sg_lst[i].sg_len = (ulong)sl->length;
             }
             cmdp->u.cache.sg_canz = (ulong)i;
@@ -1726,11 +1963,11 @@ static int gdth_fill_cache_cmd(int hanum,Scsi_Cmnd *scp,ushort hdrive)
             if (ha->cache_feat & SCATTER_GATHER) {
                 cmdp->u.cache.DestAddr = -1UL;
                 cmdp->u.cache.sg_canz = 1;
-                cmdp->u.cache.sg_lst[0].sg_ptr = (ulong)scp->request_buffer;
+                cmdp->u.cache.sg_lst[0].sg_ptr = virt_to_bus(scp->request_buffer);
                 cmdp->u.cache.sg_lst[0].sg_len = scp->request_bufflen;
                 cmdp->u.cache.sg_lst[1].sg_len = 0;
             } else {
-                cmdp->u.cache.DestAddr  = (ulong)scp->request_buffer;
+                cmdp->u.cache.DestAddr  = virt_to_bus(scp->request_buffer);
                 cmdp->u.cache.sg_canz= 0;
             }
         }
@@ -1806,7 +2043,7 @@ static int gdth_fill_raw_cmd(int hanum,Scsi_Cmnd *scp,unchar b)
     cmdp->u.raw.link_p     = NULL;
     cmdp->u.raw.sdlen      = scp->request_bufflen;
     cmdp->u.raw.sense_len  = 16;
-    cmdp->u.raw.sense_data = (ulong)scp->sense_buffer;
+    cmdp->u.raw.sense_data = virt_to_bus(scp->sense_buffer);
     cmdp->u.raw.direction  = 
         gdth_direction_tab[scp->cmnd[0]]==DOU ? DATA_OUT : DATA_IN;
     memcpy(cmdp->u.raw.cmd,scp->cmnd,12);
@@ -1815,7 +2052,7 @@ static int gdth_fill_raw_cmd(int hanum,Scsi_Cmnd *scp,unchar b)
         cmdp->u.raw.sdata  = -1UL;
         sl = (struct scatterlist *)scp->request_buffer;
         for (i=0; i<scp->use_sg; ++i,++sl) {
-            cmdp->u.raw.sg_lst[i].sg_ptr = (ulong)sl->address;
+            cmdp->u.raw.sg_lst[i].sg_ptr = virt_to_bus(sl->address);
             cmdp->u.raw.sg_lst[i].sg_len = (ulong)sl->length;
         }
         cmdp->u.raw.sg_ranz = (ulong)i;
@@ -1832,11 +2069,11 @@ static int gdth_fill_raw_cmd(int hanum,Scsi_Cmnd *scp,unchar b)
         if (ha->raw_feat & SCATTER_GATHER) {
             cmdp->u.raw.sdata  = -1UL;
             cmdp->u.raw.sg_ranz= 1;
-            cmdp->u.raw.sg_lst[0].sg_ptr = (ulong)scp->request_buffer;
+            cmdp->u.raw.sg_lst[0].sg_ptr = virt_to_bus(scp->request_buffer);
             cmdp->u.raw.sg_lst[0].sg_len = scp->request_bufflen;
             cmdp->u.raw.sg_lst[1].sg_len = 0;
         } else {
-            cmdp->u.raw.sdata  = (ulong)scp->request_buffer;
+            cmdp->u.raw.sdata  = virt_to_bus(scp->request_buffer);
             cmdp->u.raw.sg_ranz= 0;
         }
     }
@@ -2047,6 +2284,17 @@ static void gdth_clear_events()
 
 /* SCSI interface functions */
 
+#if LINUX_VERSION_CODE >= 0x02015F
+static void do_gdth_interrupt(int irq,void *dev_id,struct pt_regs *regs)
+{
+    ulong flags;
+
+    spin_lock_irqsave(&io_request_lock, flags);
+    gdth_interrupt(irq, dev_id, regs);
+    spin_unlock_irqrestore(&io_request_lock, flags);
+}
+#endif
+
 #if LINUX_VERSION_CODE >= 0x010346
 static void gdth_interrupt(int irq,void *dev_id,struct pt_regs *regs)
 #else
@@ -2091,49 +2339,55 @@ static void gdth_interrupt(int irq,struct pt_regs *regs)
     if (ha->type == GDT_EISA) {
         if (IStatus & 0x80) {                   /* error flag */
             IStatus &= ~0x80;
-            CmdStatus = inw((ushort)ha->brd+MAILBOXREG+8);
+            CmdStatus = inw(ha->bmic + MAILBOXREG+8);
             TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,CmdStatus));
             if (IStatus == ASYNCINDEX) {        /* async. event ? */
-                Service = inw((ushort)ha->brd+MAILBOXREG+10);
-                InfoBytes2 = inl((ushort)ha->brd+MAILBOXREG+4);
+                Service = inw(ha->bmic + MAILBOXREG+10);
+                InfoBytes2 = inl(ha->bmic + MAILBOXREG+4);
             }
         } else                                  /* no error */
             CmdStatus = S_OK;
-        InfoBytes = inl((ushort)ha->brd+MAILBOXREG+12);
-        outb(0xff,(ushort)ha->brd+EDOORREG);    /* acknowledge interrupt */
-        outb(0x00,(ushort)ha->brd+SEMA1REG);    /* reset status semaphore */
+        InfoBytes = inl(ha->bmic + MAILBOXREG+12);
+       if (gdth_polling)                       /* init. -> more info */
+           InfoBytes2 = inl(ha->bmic + MAILBOXREG+4);
+        outb(0xff, ha->bmic + EDOORREG);    /* acknowledge interrupt */
+        outb(0x00, ha->bmic + SEMA1REG);    /* reset status semaphore */
     } else if (ha->type == GDT_ISA) {
         dp2_ptr = (gdt2_dpram_str *)ha->brd;
         if (IStatus & 0x80) {                   /* error flag */
             IStatus &= ~0x80;
-            CmdStatus = dp2_ptr->u.ic.Status;
+            CmdStatus = readw(&dp2_ptr->u.ic.Status);
             TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,CmdStatus));
             if (IStatus == ASYNCINDEX) {        /* async. event ? */
-                Service = dp2_ptr->u.ic.Service;
-                InfoBytes2 = dp2_ptr->u.ic.Info[1];
+                Service = readw(&dp2_ptr->u.ic.Service);
+                InfoBytes2 = readl(&dp2_ptr->u.ic.Info[1]);
             }
         } else                                  /* no error */
             CmdStatus = S_OK;
-        InfoBytes = dp2_ptr->u.ic.Info[0];
-        dp2_ptr->io.irqdel = 0xff;              /* acknowledge interrupt */
-        dp2_ptr->u.ic.Cmd_Index = 0;            /* reset command index */
-        dp2_ptr->io.Sema1  = 0;                 /* reset status semaphore */
+        InfoBytes = readl(&dp2_ptr->u.ic.Info[0]);
+       if (gdth_polling)                       /* init. -> more info */
+           InfoBytes2 = readl(&dp2_ptr->u.ic.Info[1]);
+        writeb(0xff, &dp2_ptr->io.irqdel);              /* acknowledge interrupt */
+        writeb(0, &dp2_ptr->u.ic.Cmd_Index);            /* reset command index */
+        writeb(0, &dp2_ptr->io.Sema1);                 /* reset status semaphore */
     } else if (ha->type == GDT_PCI) {
         dp6_ptr = (gdt6_dpram_str *)ha->brd;
         if (IStatus & 0x80) {                   /* error flag */
             IStatus &= ~0x80;
-            CmdStatus = dp6_ptr->u.ic.Status;
+            CmdStatus = readw(&dp6_ptr->u.ic.Status);
             TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,CmdStatus));
             if (IStatus == ASYNCINDEX) {        /* async. event ? */
-                Service = dp6_ptr->u.ic.Service;
-                InfoBytes2 = dp6_ptr->u.ic.Info[1];
+                Service = readw(&dp6_ptr->u.ic.Service);
+                InfoBytes2 = readl(&dp6_ptr->u.ic.Info[1]);
             }
         } else                                  /* no error */
             CmdStatus = S_OK;
-        InfoBytes = dp6_ptr->u.ic.Info[0];
-        dp6_ptr->io.irqdel = 0xff;              /* acknowledge interrupt */
-        dp6_ptr->u.ic.Cmd_Index = 0;            /* reset command index */
-        dp6_ptr->io.Sema1  = 0;                 /* reset status semaphore */
+        InfoBytes = readl(&dp6_ptr->u.ic.Info[0]);
+       if (gdth_polling)                       /* init. -> more info */
+           InfoBytes2 = readl(&dp6_ptr->u.ic.Info[1]);
+        writeb(0xff, &dp6_ptr->io.irqdel);              /* acknowledge interrupt */
+        writeb(0, &dp6_ptr->u.ic.Cmd_Index);            /* reset command index */
+        writeb(0, &dp6_ptr->io.Sema1);                 /* reset status semaphore */
     } else if (ha->type == GDT_PCINEW) {
         if (IStatus & 0x80) {                   /* error flag */
             IStatus &= ~0x80;
@@ -2147,23 +2401,27 @@ static void gdth_interrupt(int irq,struct pt_regs *regs)
             CmdStatus = S_OK;
 
         InfoBytes = inl(PTR2USHORT(&ha->plx->info[0]));
-        outb(0xff,PTR2USHORT(&ha->plx->edoor_reg)); 
-        outb(0x00,PTR2USHORT(&ha->plx->sema1_reg)); 
+       if (gdth_polling)                       /* init. -> more info */
+           InfoBytes2 = inl(PTR2USHORT(&ha->plx->info[1]));
+        outb(0xff, PTR2USHORT(&ha->plx->edoor_reg)); 
+        outb(0x00, PTR2USHORT(&ha->plx->sema1_reg)); 
     } else if (ha->type == GDT_PCIMPR) {
         dp6m_ptr = (gdt6m_dpram_str *)ha->brd;
         if (IStatus & 0x80) {                   /* error flag */
             IStatus &= ~0x80;
-            CmdStatus = dp6m_ptr->i960r.status;
+            CmdStatus = readw(&dp6m_ptr->i960r.status);
             TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,CmdStatus));
             if (IStatus == ASYNCINDEX) {        /* async. event ? */
-                Service = dp6m_ptr->i960r.service;
-                InfoBytes2 = dp6m_ptr->i960r.info[1];
+                Service = readw(&dp6m_ptr->i960r.service);
+                InfoBytes2 = readl(&dp6m_ptr->i960r.info[1]);
             }
         } else                                  /* no error */
             CmdStatus = S_OK;
-        InfoBytes = dp6m_ptr->i960r.info[0];
-        dp6m_ptr->i960r.edoor_reg = 0xff;
-        dp6m_ptr->i960r.sema1_reg = 0;
+        InfoBytes = readl(&dp6m_ptr->i960r.info[0]);
+       if (gdth_polling)                       /* init. -> more info */
+           InfoBytes2 = readl(&dp6m_ptr->i960r.info[1]);
+        writeb(0xff, &dp6m_ptr->i960r.edoor_reg);
+        writeb(0, &dp6m_ptr->i960r.sema1_reg);
     } else {
         TRACE2(("gdth_interrupt() unknown controller type\n"));
         return;
@@ -2238,7 +2496,7 @@ static int gdth_sync_event(int hanum,int service,unchar index,Scsi_Cmnd *scp)
 
         if (msg->msg_ext && !msg->msg_answer) {
             while (gdth_test_busy(hanum))
-                udelay(1);
+                gdth_delay(0);
             cmdp->Service       = SCREENSERVICE;
             cmdp->RequestBuffer = SCREEN_CMND;
             gdth_get_cmd_index(hanum);
@@ -2275,7 +2533,7 @@ static int gdth_sync_event(int hanum,int service,unchar index,Scsi_Cmnd *scp)
             }
             msg->msg_len = i;
             while (gdth_test_busy(hanum))
-                udelay(1);
+                gdth_delay(0);
             cmdp->Service       = SCREENSERVICE;
             cmdp->RequestBuffer = SCREEN_CMND;
             gdth_get_cmd_index(hanum);
@@ -2302,7 +2560,7 @@ static int gdth_sync_event(int hanum,int service,unchar index,Scsi_Cmnd *scp)
             scp->result = DID_OK << 16;
         } else if (ha->status == S_BSY) {
             TRACE2(("Controller busy -> retry !\n"));
-            gdth_putq(hanum,scp,DEFAULT_PRI);
+            gdth_putq(hanum,scp,scp->SCp.this_residual);
             return 1;
         } else {
             if (service == CACHESERVICE) {
@@ -2318,7 +2576,7 @@ static int gdth_sync_event(int hanum,int service,unchar index,Scsi_Cmnd *scp)
                     dvr.eu.sync.status  = ha->status;
                     dvr.eu.sync.info    = ha->info;
                     dvr.eu.sync.hostdrive =
-#if LINUX_VERSION_CODE >= 0x010400
+#if LINUX_VERSION_CODE >= 0x020000
                         ha->id[scp->channel][scp->target].hostdrive;
 #else
                         ha->id[NUMDATA(scp->host)->busnum][scp->target].hostdrive;
@@ -2329,15 +2587,17 @@ static int gdth_sync_event(int hanum,int service,unchar index,Scsi_Cmnd *scp)
                         gdth_store_event(ES_SYNC, service, &dvr);
                 }
             } else {
-                if (ha->status!=S_RAW_SCSI || ha->status==S_RAW_ILL) {
+                if (ha->status!=S_RAW_SCSI || ha->status==S_RAW_ILL || ha->info>=0x100) {
                     scp->result = DID_BAD_TARGET << 16;
                 } else {
                     scp->result = (DID_OK << 16) | ha->info;
                 }
             }
         }
-        scp->SCp.have_data_in++;
-        scp->scsi_done(scp);
+       if (!scp->SCp.have_data_in)
+           scp->SCp.have_data_in++;
+       else
+           scp->scsi_done(scp);
     }
 
     return 1;
@@ -2456,6 +2716,12 @@ static char *async_cache_tab[] = {
         "GDT HA %u, CPU temperature critical",
 /*55*/  "\003\000\002"
         "GDT HA %u, CPU temperature OK",
+/*56*/  "\005\000\002\006\004"
+        "GDT HA %u, Host drive %lu created",
+/*57*/  "\005\000\002\006\002"
+        "GDT HA %u, Array Drive %u: expand restarted",
+/*58*/  "\005\000\002\006\002"
+        "GDT HA %u, Array Drive %u: expand stopped",
 };
 
 
@@ -2479,7 +2745,7 @@ static int gdth_async_event(int hanum,int service)
     if (service == SCREENSERVICE) {
         if (ha->status == MSG_REQUEST) {
             while (gdth_test_busy(hanum))
-                udelay(1);
+                gdth_delay(0);
             cmdp->Service       = SCREENSERVICE;
             cmdp->RequestBuffer = SCREEN_CMND;
             cmd_index = gdth_get_cmd_index(hanum);
@@ -2546,8 +2812,9 @@ static int gdth_async_event(int hanum,int service)
     return 1;
 }
 
+
 #ifdef GDTH_STATISTICS
-void gdth_timeout(void)
+void gdth_timeout(ulong data)
 {
     ulong flags,i;
     Scsi_Cmnd *nscp;
@@ -2569,13 +2836,14 @@ void gdth_timeout(void)
             act_ints, act_ios, act_stats, act_rq));
     act_ints = act_ios = 0;
 
-    timer_table[GDTH_TIMER].expires = jiffies + 30*HZ;
-    timer_active |= 1<<GDTH_TIMER;
-    sti();
+    gdth_timer.expires = jiffies + 30 * HZ;
+    add_timer(&gdth_timer);
+    restore_flags(flags);
 }
 #endif
 
-int gdth_detect(Scsi_Host_Template *shtp)
+
+__initfunc (int gdth_detect(Scsi_Host_Template *shtp))
 {
     struct Scsi_Host *shp;
     gdth_ha_str *ha;
@@ -2600,7 +2868,7 @@ int gdth_detect(Scsi_Host_Template *shtp)
 #else
     printk("Console\n");
 #endif
-    WAITSEC(3);
+    gdth_delay(3000);
 #endif
 
     TRACE(("gdth_detect()\n"));
@@ -2625,7 +2893,7 @@ int gdth_detect(Scsi_Host_Template *shtp)
         if (gdth_search_isa(isa_bios)) {        /* controller found */
             shp = scsi_register(shtp,sizeof(gdth_ext_str));
             ha = HADATA(shp);
-            if (!gdth_init_isa(isa_bios,ha,TRUE)) {
+            if (!gdth_init_isa(isa_bios,ha)) {
                 scsi_unregister(shp);
                 continue;
             }
@@ -2635,7 +2903,9 @@ int gdth_detect(Scsi_Host_Template *shtp)
 
             save_flags(flags);
             cli();
-#if LINUX_VERSION_CODE >= 0x010346 
+#if LINUX_VERSION_CODE >= 0x02015F 
+            if (request_irq(ha->irq,do_gdth_interrupt,SA_INTERRUPT,"gdth",NULL))
+#elif LINUX_VERSION_CODE >= 0x010346 
             if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth",NULL))
 #else
             if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth")) 
@@ -2682,13 +2952,15 @@ int gdth_detect(Scsi_Host_Template *shtp)
                 for (j=0; j<MAXID; ++j) {
                     ha->id[i][j].type = EMPTY_DTYP;
                     ha->id[i][j].lock = 0;
+                   ha->id[i][j].heads = 0;
                 }
             }
             restore_flags(flags);
 
-            if (!gdth_search_drives(hanum,TRUE)) {
+            if (!gdth_search_drives(hanum)) {
                 printk("GDT-ISA: Error during device scan\n");
                 --gdth_ctr_count;
+               --gdth_ctr_vcount;
                 save_flags(flags);
                 cli();
 #if LINUX_VERSION_CODE >= 0x010346 
@@ -2701,9 +2973,9 @@ int gdth_detect(Scsi_Host_Template *shtp)
                 continue;
             }
 
-#if LINUX_VERSION_CODE >= 0x010400
+#if LINUX_VERSION_CODE >= 0x020000
             shp->max_id      = 8;
-            shp->max_lun     = 8;
+            shp->max_lun     = MAXLUN;
             shp->max_channel = ha->bus_cnt - 1;
 #else
             /* register addit. SCSI channels as virtual controllers */
@@ -2733,7 +3005,7 @@ int gdth_detect(Scsi_Host_Template *shtp)
         if (gdth_search_eisa(eisa_slot)) {      /* controller found */
             shp = scsi_register(shtp,sizeof(gdth_ext_str));
             ha = HADATA(shp);
-            if (!gdth_init_eisa(eisa_slot,ha,TRUE)) {
+            if (!gdth_init_eisa(eisa_slot,ha)) {
                 scsi_unregister(shp);
                 continue;
             }
@@ -2743,7 +3015,9 @@ int gdth_detect(Scsi_Host_Template *shtp)
 
             save_flags(flags);
             cli();
-#if LINUX_VERSION_CODE >= 0x010346 
+#if LINUX_VERSION_CODE >= 0x02015F 
+            if (request_irq(ha->irq,do_gdth_interrupt,SA_INTERRUPT,"gdth",NULL))
+#elif LINUX_VERSION_CODE >= 0x010346 
             if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth",NULL))
 #else
             if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth")) 
@@ -2779,13 +3053,15 @@ int gdth_detect(Scsi_Host_Template *shtp)
                 for (j=0; j<MAXID; ++j) {
                     ha->id[i][j].type = EMPTY_DTYP;
                     ha->id[i][j].lock = 0;
+                   ha->id[i][j].heads = 0;
                 }
             }
             restore_flags(flags);
 
-            if (!gdth_search_drives(hanum,TRUE)) {
+            if (!gdth_search_drives(hanum)) {
                 printk("GDT-EISA: Error during device scan\n");
                 --gdth_ctr_count;
+               --gdth_ctr_vcount;
                 save_flags(flags);
                 cli();
 #if LINUX_VERSION_CODE >= 0x010346 
@@ -2798,9 +3074,9 @@ int gdth_detect(Scsi_Host_Template *shtp)
                 continue;
             }
 
-#if LINUX_VERSION_CODE >= 0x010400
+#if LINUX_VERSION_CODE >= 0x020000
             shp->max_id      = 8;
-            shp->max_lun     = 8;
+            shp->max_lun     = MAXLUN;
             shp->max_channel = ha->bus_cnt - 1;
 #else
             /* register addit. SCSI channels as virtual controllers */
@@ -2829,7 +3105,7 @@ int gdth_detect(Scsi_Host_Template *shtp)
     }
 
     /* scanning for PCI controllers */
-    for (device_id = 0; device_id <= PCI_DEVICE_ID_VORTEX_GDT6x21RP2; ++device_id) {
+    for (device_id = 0; device_id <= PCI_DEVICE_ID_VORTEX_GDTMAXRP; ++device_id) {
         if (device_id > PCI_DEVICE_ID_VORTEX_GDT6555 &&
             device_id < PCI_DEVICE_ID_VORTEX_GDT6x17RP)
             continue;
@@ -2838,7 +3114,7 @@ int gdth_detect(Scsi_Host_Template *shtp)
                 break;                          /* next device_id */
             shp = scsi_register(shtp,sizeof(gdth_ext_str));
             ha = HADATA(shp);
-            if (!gdth_init_pci(&pcistr,ha,TRUE)) {
+            if (!gdth_init_pci(&pcistr,ha)) {
                 scsi_unregister(shp);
                 continue;
             }
@@ -2848,10 +3124,12 @@ int gdth_detect(Scsi_Host_Template *shtp)
 
             save_flags(flags);
             cli();
-#if LINUX_VERSION_CODE >= 0x010346 
-            if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth",NULL))
+#if LINUX_VERSION_CODE >= 0x02015F 
+            if (request_irq(ha->irq,do_gdth_interrupt,SA_INTERRUPT|SA_SHIRQ,"gdth",NULL))
+#elif LINUX_VERSION_CODE >= 0x010346 
+            if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT|SA_SHIRQ,"gdth",NULL))
 #else
-            if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth")) 
+            if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT|SA_SHIRQ,"gdth")) 
 #endif
             {
                 printk("GDT-PCI: Unable to allocate IRQ\n");
@@ -2882,13 +3160,15 @@ int gdth_detect(Scsi_Host_Template *shtp)
                 for (j=0; j<MAXID; ++j) {
                     ha->id[i][j].type = EMPTY_DTYP;
                     ha->id[i][j].lock = 0;
+                   ha->id[i][j].heads = 0;
                 }
             }
             restore_flags(flags);
 
-            if (!gdth_search_drives(hanum,TRUE)) {
+            if (!gdth_search_drives(hanum)) {
                 printk("GDT-PCI: Error during device scan\n");
                 --gdth_ctr_count;
+               --gdth_ctr_vcount;
                 save_flags(flags);
                 cli();
 #if LINUX_VERSION_CODE >= 0x010346 
@@ -2901,9 +3181,9 @@ int gdth_detect(Scsi_Host_Template *shtp)
                 continue;
             }
 
-#if LINUX_VERSION_CODE >= 0x010400
-            shp->max_id      = 8;
-            shp->max_lun     = 8;
+#if LINUX_VERSION_CODE >= 0x020000
+            shp->max_id      = MAXID;
+            shp->max_lun     = MAXLUN;
             shp->max_channel = ha->bus_cnt - 1;
 #else
             /* register addit. SCSI channels as virtual controllers */
@@ -2929,14 +3209,19 @@ int gdth_detect(Scsi_Host_Template *shtp)
     }
 
     TRACE2(("gdth_detect() %d controller detected\n",gdth_ctr_count));
-
+    if (gdth_ctr_count > 0) {
 #ifdef GDTH_STATISTICS
-    TRACE2(("gdth_detect(): Initializing timer !\n"));
-    timer_table[GDTH_TIMER].fn = gdth_timeout;
-    timer_table[GDTH_TIMER].expires = jiffies + HZ;
-    timer_active |= 1<<GDTH_TIMER;
+       TRACE2(("gdth_detect(): Initializing timer !\n"));
+       init_timer(&gdth_timer);
+       gdth_timer.expires = jiffies + HZ;
+       gdth_timer.data = 0L;
+       gdth_timer.function = gdth_timeout;
+       add_timer(&gdth_timer);
 #endif
-
+#if LINUX_VERSION_CODE >= 0x020100
+       register_reboot_notifier(&gdth_notifier);
+#endif
+    }
     gdth_polling = FALSE;
     return gdth_ctr_vcount;
 }
@@ -2948,9 +3233,11 @@ int gdth_release(struct Scsi_Host *shp)
 
     TRACE2(("gdth_release()\n"));
 
-    save_flags(flags);
-    cli();
     if (NUMDATA(shp)->busnum == 0) {
+       gdth_flush(NUMDATA(shp)->hanum);
+
+       save_flags(flags);
+       cli();
         if (shp->irq) {
 #if LINUX_VERSION_CODE >= 0x010346
             free_irq(shp->irq,NULL);
@@ -2961,9 +3248,21 @@ int gdth_release(struct Scsi_Host *shp)
         if (shp->dma_channel != 0xff) {
             free_dma(shp->dma_channel);
         }
+       restore_flags(flags);
+       gdth_ctr_released++;
+       TRACE2(("gdth_release(): HA %d of %d\n", 
+               gdth_ctr_released, gdth_ctr_count));
+
+       if (gdth_ctr_released == gdth_ctr_count) {
+#ifdef GDTH_STATISTICS
+           del_timer(&gdth_timer);
+#endif
+#if LINUX_VERSION_CODE >= 0x020100
+           unregister_reboot_notifier(&gdth_notifier);
+#endif
+       }
     }
 
-    restore_flags(flags);
     scsi_unregister(shp);
     return 0;
 }
@@ -2980,102 +3279,40 @@ static const char *gdth_ctr_name(int hanum)
     if (ha->type == GDT_EISA) {
         switch (ha->stype) {
           case GDT3_ID:
-            return("GDT3000/3020 (EISA)");
+            return("GDT3000/3020");
           case GDT3A_ID:
-            return("GDT3000A/3020A/3050A (EISA)");
+            return("GDT3000A/3020A/3050A");
           case GDT3B_ID:
-            return("GDT3000B/3010A (EISA)");
+            return("GDT3000B/3010A");
         }
     } else if (ha->type == GDT_ISA) {
-        return("GDT2000/2020 (ISA)");
+        return("GDT2000/2020");
     } else if (ha->type == GDT_PCI) {
         switch (ha->stype) {
           case PCI_DEVICE_ID_VORTEX_GDT60x0:
-            return("GDT6000/6020/6050 (PCI)");
+            return("GDT6000/6020/6050");
           case PCI_DEVICE_ID_VORTEX_GDT6000B:
-            return("GDT6000B/6010 (PCI)");
-        }
-    } else if (ha->type == GDT_PCINEW) {
-        switch (ha->stype) {
-          case PCI_DEVICE_ID_VORTEX_GDT6x10:
-            return("GDT6110/6510 (PCI)");
-          case PCI_DEVICE_ID_VORTEX_GDT6x20:
-            return("GDT6120/6520 (PCI)");
-          case PCI_DEVICE_ID_VORTEX_GDT6530:
-            return("GDT6530 (PCI)");
-          case PCI_DEVICE_ID_VORTEX_GDT6550:
-            return("GDT6550 (PCI)");
-          case PCI_DEVICE_ID_VORTEX_GDT6x17:
-            return("GDT6117/6517 (PCI)");
-          case PCI_DEVICE_ID_VORTEX_GDT6x27:
-            return("GDT6127/6527 (PCI)");
-          case PCI_DEVICE_ID_VORTEX_GDT6537:
-            return("GDT6537 (PCI)");
-          case PCI_DEVICE_ID_VORTEX_GDT6557:
-            return("GDT6557/6557-ECC (PCI)");
-          case PCI_DEVICE_ID_VORTEX_GDT6x15:
-            return("GDT6115/6515 (PCI)");
-          case PCI_DEVICE_ID_VORTEX_GDT6x25:
-            return("GDT6125/6525 (PCI)");
-          case PCI_DEVICE_ID_VORTEX_GDT6535:
-            return("GDT6535 (PCI)");
-          case PCI_DEVICE_ID_VORTEX_GDT6555:
-            return("GDT6555/6555-ECC (PCI)");
+            return("GDT6000B/6010");
         }
-    } else if (ha->type == GDT_PCIMPR) {
-        switch (ha->stype) {
-          case PCI_DEVICE_ID_VORTEX_GDT6x17RP:
-            return("GDT6117RP/GDT6517RP (PCI)");
-          case PCI_DEVICE_ID_VORTEX_GDT6x27RP:
-            return("GDT6127RP/GDT6527RP (PCI)");
-          case PCI_DEVICE_ID_VORTEX_GDT6537RP:
-            return("GDT6537RP (PCI)");
-          case PCI_DEVICE_ID_VORTEX_GDT6557RP:
-            return("GDT6557RP (PCI)");
-          case PCI_DEVICE_ID_VORTEX_GDT6x11RP:
-            return("GDT6111RP/GDT6511RP (PCI)");
-          case PCI_DEVICE_ID_VORTEX_GDT6x21RP:
-            return("GDT6121RP/GDT6521RP (PCI)");
-          case PCI_DEVICE_ID_VORTEX_GDT6x17RP1:
-            return("GDT6117RP1/GDT6517RP1 (PCI)");
-          case PCI_DEVICE_ID_VORTEX_GDT6x27RP1:
-            return("GDT6127RP1/GDT6527RP1 (PCI)");
-          case PCI_DEVICE_ID_VORTEX_GDT6537RP1:
-            return("GDT6537RP1 (PCI)");
-          case PCI_DEVICE_ID_VORTEX_GDT6557RP1:
-            return("GDT6557RP1 (PCI)");
-          case PCI_DEVICE_ID_VORTEX_GDT6x11RP1:
-            return("GDT6111RP1/GDT6511RP1 (PCI)");
-          case PCI_DEVICE_ID_VORTEX_GDT6x21RP1:
-            return("GDT6121RP1/GDT6521RP1 (PCI)");
-          case PCI_DEVICE_ID_VORTEX_GDT6x17RP2:
-            return("GDT6117RP2/GDT6517RP2 (PCI)");
-          case PCI_DEVICE_ID_VORTEX_GDT6x27RP2:
-            return("GDT6127RP2/GDT6527RP2 (PCI)");
-          case PCI_DEVICE_ID_VORTEX_GDT6537RP2:
-            return("GDT6537RP2 (PCI)");
-          case PCI_DEVICE_ID_VORTEX_GDT6557RP2:
-            return("GDT6557RP2 (PCI)");
-          case PCI_DEVICE_ID_VORTEX_GDT6x11RP2:
-            return("GDT6111RP2/GDT6511RP2 (PCI)");
-          case PCI_DEVICE_ID_VORTEX_GDT6x21RP2:
-            return("GDT6121RP2/GDT6521RP2 (PCI)");
-        }
-    }
+    } 
+    /* new controllers (GDT_PCINEW, GDT_PCIMPR, ..) use board_info IOCTL! */
+
     return("");
 }
 
 const char *gdth_info(struct Scsi_Host *shp)
 {
     int hanum;
-    
+    gdth_ha_str *ha;
+
     TRACE2(("gdth_info()\n"));
     hanum = NUMDATA(shp)->hanum;
+    ha    = HADATA(gdth_ctr_tab[hanum]);
 
-    return (gdth_ctr_name(hanum));
+    return ((const char *)ha->ctr_name);
 }
 
-
+/* old error handling */
 int gdth_abort(Scsi_Cmnd *scp)
 {
     TRACE2(("gdth_abort() reason %d\n",scp->abort_reason));
@@ -3092,6 +3329,32 @@ int gdth_reset(Scsi_Cmnd *scp)
     return SCSI_RESET_PUNT;
 }
 
+#if LINUX_VERSION_CODE >= 0x02015F
+/* new error handling */
+int gdth_eh_abort(Scsi_Cmnd *scp)
+{
+    TRACE2(("gdth_eh_abort()\n"));
+    return FAILED;
+}
+
+int gdth_eh_device_reset(Scsi_Cmnd *scp)
+{
+    TRACE2(("gdth_eh_device_reset()\n"));
+    return FAILED;
+}
+
+int gdth_eh_bus_reset(Scsi_Cmnd *scp)
+{
+    TRACE2(("gdth_eh_bus_reset()\n"));
+    return FAILED;
+}
+
+int gdth_eh_host_reset(Scsi_Cmnd *scp)
+{
+    TRACE2(("gdth_eh_host_reset()\n"));
+    return FAILED;
+}
+#endif
 
 #if LINUX_VERSION_CODE >= 0x010300
 int gdth_bios_param(Disk *disk,kdev_t dev,int *ip)
@@ -3099,23 +3362,38 @@ int gdth_bios_param(Disk *disk,kdev_t dev,int *ip)
 int gdth_bios_param(Disk *disk,int dev,int *ip)
 #endif
 {
-    TRACE2(("gdth_bios_param()\n"));
+    unchar b, t;
+    int hanum;
+    gdth_ha_str *ha;
+    int drv_hds, drv_secs;
+
+    hanum = NUMDATA(disk->device->host)->hanum;
+    b = disk->device->channel;
+    t = disk->device->id;
+    TRACE2(("gdth_bios_param() ha %d bus %d target %d\n", hanum, b, t));
+    ha = HADATA(gdth_ctr_tab[hanum]);
+
+    if (ha->id[b][t].heads == 0) {
+       /* raw device: evaluate mapping (sectors per head, heads per cylinder) */
+       if (disk->capacity /HEADS/SECS <= MAXCYLS) {
+           drv_hds = HEADS;
+           drv_secs= SECS;
+       } else if (disk->capacity /MEDHEADS/MEDSECS <= MAXCYLS) {
+           drv_hds = MEDHEADS;
+           drv_secs= MEDSECS;
+       } else {
+           drv_hds = BIGHEADS;
+           drv_secs= BIGSECS;
+       }
+       ha->id[b][t].heads = drv_hds;
+       ha->id[b][t].secs = drv_secs;
+       TRACE2(("gdth_bios_param(): raw device -> params evaluated\n"));
+    }
+
+    ip[0] = ha->id[b][t].heads;
+    ip[1] = ha->id[b][t].secs;
+    ip[2] = disk->capacity / ip[0] / ip[1];
 
-    ip[2] = disk->capacity / HEADS / SECS;
-    if (ip[2] <= MAXCYLS) {
-        ip[0] = HEADS;
-        ip[1] = SECS;
-    } else {
-        ip[2] = disk->capacity / MEDHEADS / MEDSECS;
-        if (ip[2] <= MAXCYLS) {
-            ip[0] = MEDHEADS;
-            ip[1] = MEDSECS;
-        } else {
-            ip[2] = disk->capacity / BIGHEADS / BIGSECS;
-            ip[0] = BIGHEADS;
-            ip[1] = BIGSECS;
-        }
-    }
     TRACE2(("gdth_bios_param(): %d heads, %d secs, %d cyls\n",
             ip[0],ip[1],ip[2]));
     return 0;
@@ -3149,7 +3427,7 @@ int gdth_queuecommand(Scsi_Cmnd *scp,void (*done)(Scsi_Cmnd *))
                   scp->cmnd[0],scp->target,scp->lun));
     
     scp->scsi_done = (void *)done;
-    scp->SCp.have_data_in = 0;
+    scp->SCp.have_data_in = 1;
     hanum = NUMDATA(scp->host)->hanum;
 #ifdef GDTH_STATISTICS
     ++act_ios;
@@ -3165,22 +3443,84 @@ int gdth_queuecommand(Scsi_Cmnd *scp,void (*done)(Scsi_Cmnd *))
     return 0;
 }
 
+/* flush routine */
+static void gdth_flush(int hanum)
+{
+    int             i, j;
+    gdth_ha_str     *ha;
+    Scsi_Cmnd       scp;
+    Scsi_Device     sdev;
+    gdth_cmd_str    gdtcmd;
+    char            cmnd[12];
+
+    TRACE2(("gdth_flush() hanum %d\n",hanum));
+    ha = HADATA(gdth_ctr_tab[hanum]);
+    memset(&sdev,0,sizeof(Scsi_Device));
+    memset(&scp, 0,sizeof(Scsi_Cmnd));
+    sdev.host = gdth_ctr_tab[hanum];
+    sdev.id = sdev.host->this_id;
+    scp.cmd_len = 12;
+    scp.host = gdth_ctr_tab[hanum];
+    scp.target = sdev.host->this_id;
+    scp.device = &sdev;
+    scp.use_sg = 0;
+
+    for (i = 0; i < MAXBUS; ++i) {
+       for (j = 0; j < MAXID; ++j) {
+           if (ha->id[i][j].type == CACHE_DTYP) {
+               gdtcmd.BoardNode = LOCALBOARD;
+               gdtcmd.Service = CACHESERVICE;
+               gdtcmd.OpCode = GDT_FLUSH;
+               gdtcmd.u.cache.DeviceNo = ha->id[i][j].hostdrive;
+               gdtcmd.u.cache.BlockNo = 1;
+               gdtcmd.u.cache.sg_canz = 0;
+               TRACE2(("gdth_flush(): flush ha %d drive %d\n",
+                        hanum, ha->id[i][j].hostdrive));
+               {
+                   struct semaphore sem = MUTEX_LOCKED;
+                   scp.request.rq_status = RQ_SCSI_BUSY;
+                   scp.request.sem = &sem;
+                   scp.SCp.this_residual = IOCTL_PRI;
+                   scsi_do_cmd(&scp, cmnd, &gdtcmd,
+                               sizeof(gdth_cmd_str), gdth_scsi_done,
+                               30*HZ, 1);
+                   down(&sem);
+               }
+           }
+       }
+    }
+}
 
 /* shutdown routine */
-void gdth_halt()
+#if LINUX_VERSION_CODE >= 0x020100
+static int gdth_halt(struct notifier_block *nb, ulong event, void *buf)
+#else
+void gdth_halt(void)
+#endif
 {
-    int             hanum, i, j;
-    gdth_ha_str     *ha;
+    int             hanum;
     Scsi_Cmnd       scp;
     Scsi_Device     sdev;
     gdth_cmd_str    gdtcmd;
     char            cmnd[12];
 
+#if LINUX_VERSION_CODE >= 0x020100
+    TRACE2(("gdth_halt() event %d\n",event));
+    if (event != SYS_RESTART && event != SYS_HALT && event != SYS_POWER_OFF)
+       return NOTIFY_DONE;
+#else
     TRACE2(("gdth_halt()\n"));
+    if (halt_called) {
+       TRACE2(("already called\n"));
+       return;
+    }
+    halt_called = TRUE;
+#endif
     printk("GDT: Flushing all host drives .. ");
-
     for (hanum = 0; hanum < gdth_ctr_count; ++hanum) {
-        ha = HADATA(gdth_ctr_tab[hanum]);
+        gdth_flush(hanum);
+
+        /* controller reset */
         memset(&sdev,0,sizeof(Scsi_Device));
         memset(&scp, 0,sizeof(Scsi_Cmnd));
         sdev.host = gdth_ctr_tab[hanum];
@@ -3191,32 +3531,6 @@ void gdth_halt()
         scp.device = &sdev;
         scp.use_sg = 0;
 
-        /* flush */
-        for (i = 0; i < MAXBUS; ++i) {
-            for (j = 0; j < MAXID; ++j) {
-                if (ha->id[i][j].type == CACHE_DTYP) {
-                    gdtcmd.BoardNode = LOCALBOARD;
-                    gdtcmd.Service = CACHESERVICE;
-                    gdtcmd.OpCode = GDT_FLUSH;
-                    gdtcmd.u.cache.DeviceNo = ha->id[i][j].hostdrive;
-                    gdtcmd.u.cache.BlockNo = 1;
-                    gdtcmd.u.cache.sg_canz = 0;
-                    TRACE2(("gdth_halt(): flush ha %d drive %d\n",
-                        hanum, ha->id[i][j].hostdrive));
-                    {
-                        struct semaphore sem = MUTEX_LOCKED;
-                        scp.request.rq_status = RQ_SCSI_BUSY;
-                        scp.request.sem = &sem;
-                        scsi_do_cmd(&scp, cmnd, &gdtcmd,
-                                    sizeof(gdth_cmd_str), gdth_scsi_done,
-                                    30*HZ, 1);
-                        down(&sem);
-                    }
-                }
-            }
-        }
-
-        /* controller reset */
         gdtcmd.BoardNode = LOCALBOARD;
         gdtcmd.Service = CACHESERVICE;
         gdtcmd.OpCode = GDT_RESET;
@@ -3225,6 +3539,7 @@ void gdth_halt()
             struct semaphore sem = MUTEX_LOCKED;
             scp.request.rq_status = RQ_SCSI_BUSY;
             scp.request.sem = &sem;
+            scp.SCp.this_residual = IOCTL_PRI;
             scsi_do_cmd(&scp, cmnd, &gdtcmd,
                 sizeof(gdth_cmd_str), gdth_scsi_done,
                 10*HZ, 1);
@@ -3232,11 +3547,19 @@ void gdth_halt()
         }
     }
     printk("Done.\n");
+
+#ifdef GDTH_STATISTICS
+    del_timer(&gdth_timer);
+#endif
+#if LINUX_VERSION_CODE >= 0x020100
+    unregister_reboot_notifier(&gdth_notifier);
+    return NOTIFY_OK;
+#endif
 }
 
 
 /* called from init/main.c */
-void gdth_setup(char *str,int *ints)
+__initfunc (void gdth_setup(char *str,int *ints))
 {
     static size_t setup_idx = 0;
 
index 3c92be263a478638bcf4ac2393c82395d7fe1e96..104c270a9edbaaa58054e24d640a9fe6b568c33e 100644 (file)
@@ -4,13 +4,13 @@
 /*
  * Header file for the GDT ISA/EISA/PCI Disk Array Controller driver for Linux
  * 
- * gdth.h Copyright (C) 1995-97 ICP vortex Computersysteme GmbH, Achim Leubner
+ * gdth.h Copyright (C) 1995-98 ICP vortex Computersysteme GmbH, Achim Leubner
  * See gdth.c for further informations and 
  * below for supported controller types
  *
  * <achim@vortex.de>
  *
- * $Id: gdth.h,v 1.7 1997/03/20 16:01:59 achim Exp $
+ * $Id: gdth.h,v 1.15 1998/09/28 15:50:10 achim Exp $
  */
 
 #include <linux/version.h>
@@ -29,9 +29,9 @@
 /* defines, macros */
 
 /* driver version */
-#define GDTH_VERSION_STR        "1.00"
+#define GDTH_VERSION_STR        "1.07"
 #define GDTH_VERSION            1
-#define GDTH_SUBVERSION         0
+#define GDTH_SUBVERSION         7
 
 /* protocol version */
 #define PROTOCOL_VERSION        1
 #define PCI_DEVICE_ID_VORTEX_GDT6x21RP2 0x125   /* GDT6121RP2/GDT6521RP2 */
 #endif
 
+#ifndef PCI_DEVICE_ID_VORTEX_GDT6519RD
+/* GDT_MPR, Fibre Channel */
+#define PCI_DEVICE_ID_VORTEX_GDT6519RD  0x210   /* GDT6519RD */
+#define PCI_DEVICE_ID_VORTEX_GDT6529RD  0x211   /* GDT6529RD */
+#endif
+
+#ifndef PCI_DEVICE_ID_VORTEX_GDTMAXRP
+/* GDT_MPR, last device ID */
+#define PCI_DEVICE_ID_VORTEX_GDTMAXRP          0x2ff   
+#endif
+
 /* limits */
 #define GDTH_SCRATCH    4096                    /* 4KB scratch buffer */
 #define GDTH_MAXCMDS    124
 #define GDTH_MAXC_P_L   16                      /* max. cmds per lun */
 #define MAXOFFSETS      128
 #define MAXHA           8
-#define MAXID           8
+#define MAXID           16
 #define MAXLUN          8
-#define MAXBUS          5
+#define MAXBUS          6
 #define MAX_HDRIVES     35                      /* max. host drive count */
 #define MAX_EVENTS      100                     /* event buffer count */
 #define MAXCYLS         1024
 #define SECTOR_SIZE     0x200                   /* always 512 bytes per sector */
 
 /* DPMEM constants */
+#define DPMEM_MAGIC    0xC0FFEE11
 #define IC_HEADER_BYTES 48
 #define IC_QUEUE_BYTES  4
 #define DPMEM_COMMAND_OFFSET    IC_HEADER_BYTES+IC_QUEUE_BYTES*MAXOFFSETS
 
 /* IOCTL command defines */
 #define SCSI_CHAN_CNT   5                       /* subfunctions */
+#define GET_IOCHAN_DESC        0x5e
 #define L_CTRL_PATTERN  0x20000000L
 #define CACHE_INFO      4
 #define CACHE_CONFIG    5
+#define BOARD_INFO     0x28
 #define IO_CHANNEL      0x00020000L             /* channels */
 #define INVALID_CHANNEL 0x0000ffffL     
 
@@ -254,6 +268,21 @@ typedef struct {
     unchar      siop_state;                     /* SCSI processor state */ 
 } gdth_getch_str;
 
+/* get raw channel count IOCTL (NEW!) */
+typedef struct {
+    ulong      version;                        /* version of information (-1UL: newest) */
+    unchar     list_entries;                   /* list entry count */
+    unchar     first_chan;                     /* first channel number */
+    unchar     last_chan;                      /* last channel number */
+    unchar     chan_count;                     /* (R) channel count */
+    ulong      list_offset;                    /* offset of list[0] */
+    struct {
+       unchar  proc_id;                        /* processor id */
+       unchar  proc_defect;                    /* defect ? */
+       unchar  reserved[2];
+    } list[MAXBUS];
+} gdth_iochan_str;
+
 /* cache info/config IOCTL */
 typedef struct {
     ulong       version;                        /* firmware version */
@@ -277,6 +306,35 @@ typedef struct {
     gdth_cstat_str  cstat;
 } gdth_cinfo_str;
 
+/* board info IOCTL */
+typedef struct {
+    ulong      ser_no;                         /* serial no. */
+    unchar     oem_id[2];                      /* OEM ID */
+    ushort     ep_flags;                       /* eprom flags */
+    ulong      proc_id;                        /* processor ID */
+    ulong      memsize;                        /* memory size (bytes) */
+    unchar     mem_banks;                      /* memory banks */
+    unchar     chan_type;                      /* channel type */
+    unchar     chan_count;                     /* channel count */
+    unchar     rdongle_pres;                   /* dongle present? */
+    ulong      epr_fw_ver;                     /* (eprom) firmware version */
+    ulong      upd_fw_ver;                     /* (update) firmware version */
+    ulong      upd_revision;                   /* update revision */
+    char       type_string[16];                /* controller name */
+    char       raid_string[16];                /* RAID firmware name */
+    unchar     update_pres;                    /* update present? */
+    unchar     xor_pres;                       /* XOR engine present? */
+    unchar     prom_type;                      /* ROM type (eprom/flash eprom) */
+    unchar     prom_count;                     /* number of ROM devices */
+    ulong      dup_pres;                       /* duplexing module present? */
+    ulong      chan_pres;                      /* number of expansion channels */
+    ulong      mem_pres;                       /* memory expansion installed? */
+    unchar     ft_bus_system;                  /* fault bus supported? */
+    unchar     subtype_valid;                  /* board_subtype valid? */
+    unchar     board_subtype;                  /* controller subtype/hardware level */
+    unchar     ramparity_pres;                 /* RAM parity check hardware present? */
+} gdth_binfo_str; 
+
 /* scatter/gather element */
 typedef struct {
     ulong       sg_ptr;                         /* address */
@@ -550,9 +608,10 @@ typedef struct {
     unchar              bus_cnt;                /* SCSI bus count */
     unchar              type;                   /* controller class */
     ushort              raw_feat;               /* feat. raw service (s/g,..) */
-    ushort              cache_feat;             /* feat. cache serv. (s/g,..) */
     ulong               stype;                  /* controller subtype */
-    ulong               brd;                    /* BMIC/DPRAM address */
+    ushort              cache_feat;             /* feat. cache serv. (s/g,..) */
+    ushort             bmic;                   /* BMIC address (EISA) */
+    void                       *brd;                   /* DPRAM address */
     ulong               brd_phys;               /* slot number/BIOS address */
     gdt6c_plx_regs      *plx;                   /* PLX regs (new PCI contr.) */
     gdth_cmd_str        *pccb;                  /* address command structure */
@@ -580,6 +639,7 @@ typedef struct {
     unchar              mode;                   /* information from /proc */
     ushort              param_size;
     gdth_cpar_str       cpar;                   /* controller cache par. */
+    char               ctr_name[16];           /* controller name */
 } gdth_ha_str;
 
 /* structure for scsi_register(), SCSI bus != 0 */
@@ -648,12 +708,22 @@ typedef struct {
     } bd;
 } gdth_modep_data;
 
+/* stack frame */
 typedef struct {
     ulong       b[10];                          /* 32 bit compiler ! */
 } gdth_stackframe;
 
 #pragma pack()
 
+
+/* data structure for reserve drives */
+typedef struct {
+    unchar     hanum;                          
+    unchar     bus;
+    unchar     id;
+} gdth_reserve_str;
+
+
 /* function prototyping */
 
 int gdth_detect(Scsi_Host_Template *);
@@ -668,8 +738,38 @@ int gdth_reset(Scsi_Cmnd *);
 #endif
 const char *gdth_info(struct Scsi_Host *);
 
-
-#if LINUX_VERSION_CODE >= 0x010300
+#if LINUX_VERSION_CODE >= 0x02015F
+int gdth_bios_param(Disk *,kdev_t,int *);
+extern struct proc_dir_entry proc_scsi_gdth;
+int gdth_proc_info(char *,char **,off_t,int,int,int);
+int gdth_eh_abort(Scsi_Cmnd *scp);
+int gdth_eh_device_reset(Scsi_Cmnd *scp);
+int gdth_eh_bus_reset(Scsi_Cmnd *scp);
+int gdth_eh_host_reset(Scsi_Cmnd *scp);
+#define GDTH { proc_dir:        &proc_scsi_gdth,                 \
+               proc_info:       gdth_proc_info,                  \
+               name:            "GDT SCSI Disk Array Controller",\
+               detect:          gdth_detect,                     \
+               release:         gdth_release,                    \
+               info:            gdth_info,                       \
+               command:         gdth_command,                    \
+               queuecommand:    gdth_queuecommand,               \
+               eh_abort_handler: gdth_eh_abort,                  \
+               eh_device_reset_handler: gdth_eh_device_reset,    \
+               eh_bus_reset_handler: gdth_eh_bus_reset,          \
+               eh_host_reset_handler: gdth_eh_host_reset,        \
+               abort:           gdth_abort,                      \
+               reset:           gdth_reset,                      \
+               bios_param:      gdth_bios_param,                 \
+               can_queue:       GDTH_MAXCMDS,                    \
+               this_id:         -1,                              \
+               sg_tablesize:    GDTH_MAXSG,                      \
+               cmd_per_lun:     GDTH_MAXC_P_L,                   \
+               present:         0,                               \
+               unchecked_isa_dma: 1,                             \
+               use_clustering:  ENABLE_CLUSTERING,               \
+               use_new_eh_code: 1       /* use new error code */ }    
+#elif LINUX_VERSION_CODE >= 0x010300
 int gdth_bios_param(Disk *,kdev_t,int *);
 extern struct proc_dir_entry proc_scsi_gdth;
 int gdth_proc_info(char *,char **,off_t,int,int,int);
index 269a3c87648d24a86d72b79fce6d498c1f5a9602..1199bfa4906b9bf76f07e4b734f6ed0df99f51dc 100644 (file)
@@ -1,5 +1,5 @@
 /* gdth_proc.c 
- * $Id: gdth_proc.c,v 1.4 1997/02/25 13:33:47 achim Exp $
+ * $Id: gdth_proc.c,v 1.10 1998/06/03 14:53:49 achim Exp $
  */
 
 #include "gdth_ioctl.h"
@@ -10,7 +10,7 @@ int gdth_proc_info(char *buffer,char **start,off_t offset,int length,
     int hanum,busnum,i;
 
     TRACE2(("gdth_proc_info() length %d ha %d offs %d inout %d\n",
-            length,hostno,offset,inout));
+            length,hostno,(int)offset,inout));
 
     for (i=0; i<gdth_ctr_vcount; ++i) {
         if (gdth_ctr_vtab[i]->host_no == hostno)
@@ -113,6 +113,7 @@ static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Cmnd scp)
                         struct semaphore sem = MUTEX_LOCKED;
                         scp.request.rq_status = RQ_SCSI_BUSY;
                         scp.request.sem = &sem;
+                        scp.SCp.this_residual = IOCTL_PRI;
                         scsi_do_cmd(&scp, cmnd, &gdtcmd,
                                     sizeof(gdth_cmd_str), gdth_scsi_done,
                                     30*HZ, 1);
@@ -170,7 +171,7 @@ static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Cmnd scp)
         gdtcmd.BoardNode = LOCALBOARD;
         gdtcmd.Service = CACHESERVICE;
         gdtcmd.OpCode = GDT_IOCTL;
-        gdtcmd.u.ioctl.p_param = (ulong)pcpar;
+        gdtcmd.u.ioctl.p_param = virt_to_bus(pcpar);
         gdtcmd.u.ioctl.param_size = sizeof(gdth_cpar_str);
         gdtcmd.u.ioctl.subfunc = CACHE_CONFIG;
         gdtcmd.u.ioctl.channel = INVALID_CHANNEL;
@@ -179,6 +180,7 @@ static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Cmnd scp)
             struct semaphore sem = MUTEX_LOCKED;
             scp.request.rq_status = RQ_SCSI_BUSY;
             scp.request.sem = &sem;
+            scp.SCp.this_residual = IOCTL_PRI;
             scsi_do_cmd(&scp, cmnd, &gdtcmd, sizeof(gdth_cmd_str),
                         gdth_scsi_done, 30*HZ, 1);
             down(&sem);
@@ -257,7 +259,7 @@ static int gdth_set_bin_info(char *buffer,int length,int hanum,Scsi_Cmnd scp)
         piord->size = sizeof(gdth_iord_str) + add_size;
         if (add_size > 0) {
             memcpy(piord->iu.general.data, piowr->iu.general.data, add_size);
-            *ppadd = (ulong)piord->iu.general.data;
+            *ppadd = virt_to_bus(piord->iu.general.data);
         }
         /* do IOCTL */
         {
@@ -291,7 +293,7 @@ static int gdth_set_bin_info(char *buffer,int length,int hanum,Scsi_Cmnd scp)
         piord->size = sizeof(gdth_iord_str);
         piord->status = S_OK;
         if (ha->type == GDT_ISA || ha->type == GDT_EISA) {
-            piord->iu.ctrtype.type = (unchar)((ha->stype>>20) - 10);
+            piord->iu.ctrtype.type = (unchar)((ha->stype>>20) - 0x10);
         } else if (ha->type != GDT_PCIMPR) {
             piord->iu.ctrtype.type = (unchar)((ha->stype<<8) + 6);
         } else {
@@ -433,14 +435,14 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,
 
     /* look for buffer ID in length */
     if (id > 4) {
-#if LINUX_VERSION_CODE >= 0x010400
+#if LINUX_VERSION_CODE >= 0x020000
         size = sprintf(buffer+len,
                        "%s SCSI Disk Array Controller\n",
-                       gdth_ctr_name(hanum));
+                       ha->ctr_name);
 #else
         size = sprintf(buffer+len,
                        "%s SCSI Disk Array Controller (SCSI Bus %d)\n",
-                       gdth_ctr_name(hanum),busnum);
+                       ha->ctr_name,busnum);
 #endif
         len += size;  pos = begin + len;
         size = sprintf(buffer+len,
@@ -479,7 +481,7 @@ stop_output:
     if (len > length)
         len = length;
     TRACE2(("get_info() len %d pos %d begin %d offset %d length %d size %d\n",
-            len,pos,begin,offset,length,size));
+            len,(int)pos,(int)begin,(int)offset,length,size));
     return(len);
 }
 
@@ -542,16 +544,19 @@ static void gdth_wait_completion(int hanum, int busnum, int id)
 
     for (i = 0; i < GDTH_MAXCMDS; ++i) {
         scp = gdth_cmd_tab[i][hanum].cmnd;
+#if LINUX_VERSION_CODE >= 0x020000
         if (!SPECIAL_SCP(scp) && scp->target == (unchar)id &&
-#if LINUX_VERSION_CODE >= 0x010400
             scp->channel == (unchar)busnum)
 #else
+        if (!SPECIAL_SCP(scp) && scp->target == (unchar)id &&
             NUMDATA(scp->host)->busnum == (unchar)busnum)
 #endif
         {
+           scp->SCp.have_data_in = 0;
             restore_flags(flags);
             while (!scp->SCp.have_data_in)
                 barrier();
+           scp->scsi_done(scp);
             save_flags(flags);
             cli();
         }
@@ -570,15 +575,16 @@ static void gdth_stop_timeout(int hanum, int busnum, int id)
     ha = HADATA(gdth_ctr_tab[hanum]);
 
     for (scp = ha->req_first; scp; scp = (Scsi_Cmnd *)scp->SCp.ptr) {
+#if LINUX_VERSION_CODE >= 0x020000
         if (scp->target == (unchar)id &&
-#if LINUX_VERSION_CODE >= 0x010400
             scp->channel == (unchar)busnum)
 #else
+        if (scp->target == (unchar)id &&
             NUMDATA(scp->host)->busnum == (unchar)busnum)
 #endif
         {
             TRACE2(("gdth_stop_timeout(): update_timeout()\n"));
-            scp->SCp.buffers_residual = gdth_update_timeout(scp, 0);
+            scp->SCp.buffers_residual = gdth_update_timeout(hanum, scp, 0);
         }
     }
     restore_flags(flags);
@@ -595,30 +601,44 @@ static void gdth_start_timeout(int hanum, int busnum, int id)
     ha = HADATA(gdth_ctr_tab[hanum]);
 
     for (scp = ha->req_first; scp; scp = (Scsi_Cmnd *)scp->SCp.ptr) {
+#if LINUX_VERSION_CODE >= 0x020000
         if (scp->target == (unchar)id &&
-#if LINUX_VERSION_CODE >= 0x010400
             scp->channel == (unchar)busnum)
 #else
+        if (scp->target == (unchar)id &&
             NUMDATA(scp->host)->busnum == (unchar)busnum)
 #endif
         {
             TRACE2(("gdth_start_timeout(): update_timeout()\n"));
-            gdth_update_timeout(scp, scp->SCp.buffers_residual);
+            gdth_update_timeout(hanum, scp, scp->SCp.buffers_residual);
         }
     }
     restore_flags(flags);
 }
 
-static int gdth_update_timeout(Scsi_Cmnd *scp, int timeout)
+static int gdth_update_timeout(int hanum, Scsi_Cmnd *scp, int timeout)
 {
     ulong flags;
     int oldto;
 
     save_flags(flags);
     cli();
-
-    oldto = scp->timeout;
-    scp->timeout = timeout;
+    oldto = scp->timeout_per_command;
+    scp->timeout_per_command = timeout;
+
+#if LINUX_VERSION_CODE >= 0x02014B
+    if (timeout == 0) {
+       del_timer(&scp->eh_timeout);
+       scp->eh_timeout.data = (unsigned long) NULL;
+       scp->eh_timeout.expires = 0;
+    } else {
+       if (scp->eh_timeout.data != (unsigned long) NULL) 
+           del_timer(&scp->eh_timeout);
+       scp->eh_timeout.data = (unsigned long) scp;
+       scp->eh_timeout.expires = jiffies + timeout;
+       add_timer(&scp->eh_timeout);
+    }
+#else
     if (timeout > 0) {
         if (timer_table[SCSI_TIMER].expires == 0) {
             timer_table[SCSI_TIMER].expires = jiffies + timeout;
@@ -628,6 +648,7 @@ static int gdth_update_timeout(Scsi_Cmnd *scp, int timeout)
                 timer_table[SCSI_TIMER].expires = jiffies + timeout;
         }
     }
+#endif
 
     restore_flags(flags);
     return oldto;
index a3d5dcd71ca59c5a9ffa4a2e1e0d0c8a352e448d..99b990c3f9ab112cb1d5097f32f4e792e9abe283 100644 (file)
@@ -2,7 +2,7 @@
 #define _GDTH_PROC_H
 
 /* gdth_proc.h 
- * $Id: gdth_proc.h,v 1.2 1997/02/21 08:08:51 achim Exp $
+ * $Id: gdth_proc.h,v 1.4 1998/06/10 12:20:34 achim Exp $
  */
 
 static int gdth_set_info(char *buffer,int length,int vh,int hanum,int busnum);
@@ -16,7 +16,7 @@ static void gdth_ioctl_free(int hanum, int id);
 static void gdth_wait_completion(int hanum, int busnum, int id);
 static void gdth_stop_timeout(int hanum, int busnum, int id);
 static void gdth_start_timeout(int hanum, int busnum, int id);
-static int gdth_update_timeout(Scsi_Cmnd *scp, int timeout);
+static int gdth_update_timeout(int hanum, Scsi_Cmnd *scp, int timeout);
 
 void gdth_scsi_done(Scsi_Cmnd *scp);
 
index 65c28f9b2e1849d0f98d5af522ecff62ed503521..76fce310f378d653105aa656c7a771071fe80820 100644 (file)
 #include "AM53C974.h"
 #endif
 
+#ifdef CONFIG_SCSI_MEGARAID
+#include "megaraid.h"
+#endif
+
 #ifdef CONFIG_SCSI_PPA
 #include "ppa.h"
 #endif
@@ -312,6 +316,9 @@ static Scsi_Host_Template builtin_scsi_hosts[] =
 #ifdef CONFIG_SCSI_AM53C974
     AM53C974,
 #endif
+#ifdef CONFIG_SCSI_MEGARAID
+    MEGARAID,
+#endif
 #ifdef CONFIG_SCSI_PPA
     PPA,
 #endif
diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c
new file mode 100644 (file)
index 0000000..57eadf4
--- /dev/null
@@ -0,0 +1,1342 @@
+/*===================================================================
+ *
+ *                    Linux MegaRAID device driver
+ * 
+ * Copyright 1998 American Megatrends Inc.
+ *
+ * Version : 0.92
+ * 
+ * Description: Linux device driver for AMI MegaRAID controller
+ *
+ * History:
+ *
+ * Version 0.90:
+ *     Works and has been tested with the MegaRAID 428 controller, and
+ *     the MegaRAID 438 controller.  Probably works with the 466 also,
+ *     but not tested.
+ *
+ * Version 0.91:
+ *     Aligned mailbox area on 16-byte boundry.
+ *     Added schedule() at the end to properly clean up.
+ *     Made improvements for conformity to linux driver standards.
+ *
+ * Version 0.92:
+ *     Added support for 2.1 kernels.
+ *         Reads from pci_dev struct, so it's not dependent on pcibios.
+ *         Added some missing virt_to_bus() translations.
+ *     Added support for SMP.
+ *         Changed global cli()'s to spinlocks for 2.1, and simulated
+ *          spinlocks for 2.0.
+ *     Removed setting of SA_INTERRUPT flag when requesting Irq.
+ *
+ * Version 0.92ac:
+ *     Small changes to the comments/formatting. Plus a couple of
+ *     added notes. Returned to the authors. No actual code changes
+ *     save printk levels.
+ *     8 Oct 98        Alan Cox <alan.cox@linux.org>
+ *
+ * BUGS:
+ *     Tested with 2.1.90, but unfortunately there is a bug in pci.c which
+ *     fails to detect our controller.  Does work with 2.1.118--don't know
+ *     which kernel in between it was fixed in.
+ *     With SMP enabled under 2.1.118 with more than one processor, gets an
+ *     error message "scsi_end_request: buffer-list destroyed" under heavy
+ *     IO, but doesn't seem to affect operation, or data integrity.  The
+ *     message doesn't occur without SMP enabled, or with one proccessor with
+ *     SMP enabled, or under any combination under 2.0 kernels.
+ *
+ *===================================================================*/
+#define QISR 1
+
+#define CRLFSTR "\n"
+
+#define MULTIQ 1
+
+#include <linux/config.h>
+#include <linux/version.h>
+
+#ifdef MODULE
+#include <linux/module.h>
+
+#if LINUX_VERSION_CODE >= 0x20100
+char kernel_version[] = UTS_RELEASE;
+
+/* originally ported by Dell Corporation; updated, released, and maintained by
+   American Megatrends */
+MODULE_AUTHOR("American Megatrends Inc."); 
+MODULE_DESCRIPTION("AMI MegaRAID driver");    
+#endif
+#endif
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/ioport.h>
+#include <linux/fcntl.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/proc_fs.h>
+#include <linux/blk.h>
+#include <linux/wait.h>
+#include <linux/tqueue.h>
+#include <linux/interrupt.h>
+
+#include <linux/sched.h>
+#include <linux/stat.h>
+#include <linux/malloc.h>      /* for kmalloc() */
+#include <linux/config.h>      /* for CONFIG_PCI */
+#if LINUX_VERSION_CODE < 0x20100
+#include <linux/bios32.h>
+#else
+#include <asm/spinlock.h>
+#endif
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "sd.h"
+#include "scsi.h"
+#include "hosts.h"
+
+#include "megaraid.h"
+
+/*================================================================
+ *
+ *                          #Defines
+ *
+ *================================================================*/
+
+#if LINUX_VERSION_CODE < 0x020100
+#define ioremap vremap
+#define iounmap vfree
+
+/* simulate spin locks */
+typedef struct {volatile char lock;} spinlock_t;
+#define spin_lock_init(x) { (x)->lock = 0;}
+#define spin_lock_irqsave(x,flags) { while ((x)->lock) barrier();\
+                                        (x)->lock=1; save_flags(flags);\
+                                        cli();}
+#define spin_unlock_irqrestore(x,flags) { (x)->lock=0; restore_flags(flags);}
+
+#endif
+
+#if LINUX_VERSION_CODE >= 0x020100
+#define queue_task_irq(a,b)     queue_task(a,b)
+#define queue_task_irq_off(a,b) queue_task(a,b)
+#endif
+
+#define MAX_SERBUF 160
+#define COM_BASE 0x2f8
+
+#define ENQUEUE(obj,type,list,next) \
+{ type **node; long cpuflag; \
+  spin_lock_irqsave(&mega_lock,cpuflag);\
+  for(node=&(list); *node; node=(type **)&(*node)->##next); \
+  (*node) = obj; \
+  (*node)->##next = NULL; \
+  spin_unlock_irqrestore(&mega_lock,cpuflag);\
+};
+
+#define DEQUEUE(obj,type,list,next) \
+{ long cpuflag; \
+  spin_lock_irqsave(&mega_lock,cpuflag);\
+  if ((obj=list) != NULL) {\
+    list = (type *)(list)->##next; \
+  } \
+  spin_unlock_irqrestore(&mega_lock,cpuflag);\
+};
+
+u_long RDINDOOR(mega_host_config *megaCfg)
+{
+  return readl(megaCfg->base + 0x20);
+}
+
+void WRINDOOR(mega_host_config *megaCfg, u_long value)
+{
+  writel(value,megaCfg->base+0x20);
+}
+
+u_long RDOUTDOOR(mega_host_config *megaCfg)
+{
+  return readl(megaCfg->base+0x2C);
+}
+
+void WROUTDOOR(mega_host_config *megaCfg, u_long value)
+{
+  writel(value,megaCfg->base+0x2C);
+}
+
+/*================================================================
+ *
+ *                    Function prototypes
+ *
+ *================================================================*/
+static int  MegaIssueCmd(mega_host_config *megaCfg,
+                        u_char *mboxData,
+                        mega_scb *scb,
+                        int intr);
+static int  build_sglist(mega_host_config *megaCfg, mega_scb *scb, 
+                        u_long *buffer, u_long *length);
+
+static void mega_runque(void *);
+static void mega_rundoneq(void);
+static void mega_cmd_done(mega_host_config *,mega_scb *, int);
+
+/* set SERDEBUG to 1 to enable serial debugging */
+#define SERDEBUG 0
+#if SERDEBUG
+static void ser_init(void);
+static void ser_puts(char *str);
+static void ser_putc(char c);
+static int  ser_printk(const char *fmt, ...);
+#endif
+
+/*================================================================
+ *
+ *                    Global variables
+ *
+ *================================================================*/
+static int               numCtlrs = 0;
+static mega_host_config *megaCtlrs[4] = { 0 };
+
+/* Change this to 0 if you want to see the raw drives */
+static int use_raid   = 1;
+
+/* Queue of pending/completed SCBs */
+static mega_scb  *qPending   = NULL;
+static Scsi_Cmnd *qCompleted = NULL;
+
+volatile static spinlock_t mega_lock;
+static struct tq_struct runq = {0,0,mega_runque,NULL};
+
+struct proc_dir_entry proc_scsi_megaraid = {
+  PROC_SCSI_MEGARAID, 8, "megaraid",
+  S_IFDIR | S_IRUGO | S_IXUGO, 2
+};
+
+#if SERDEBUG
+static char strbuf[MAX_SERBUF+1];
+
+static void ser_init()
+{
+    unsigned port=COM_BASE;
+
+    outb(0x80,port+3);
+    outb(0,port+1);
+    /* 9600 Baud, if 19200: outb(6,port) */
+    outb(12, port);
+    outb(3,port+3);
+    outb(0,port+1);
+}
+
+static void ser_puts(char *str)
+{
+    char *ptr;
+
+    ser_init();
+    for (ptr=str;*ptr;++ptr)
+        ser_putc(*ptr);
+}
+
+static void ser_putc(char c)
+{
+    unsigned port=COM_BASE;
+
+    while ((inb(port+5) & 0x20)==0);
+    outb(c,port);
+    if (c==0x0a)
+    {
+        while ((inb(port+5) & 0x20)==0);
+        outb(0x0d,port);
+    }
+}
+
+static int ser_printk(const char *fmt, ...)
+{
+    va_list args;
+    int i;
+    long flags;
+
+    spin_lock_irqsave(mega_lock,flags);
+    va_start(args,fmt);
+    i = vsprintf(strbuf,fmt,args);
+    ser_puts(strbuf);
+    va_end(args);
+    spin_unlock_irqrestore(&mega_lock,flags);
+
+    return i;
+}
+
+#define TRACE(a)    { ser_printk a;}
+
+#else
+#define TRACE(A)
+#endif
+
+void callDone(Scsi_Cmnd *SCpnt)
+{
+  if (SCpnt->result) {
+    TRACE(("*** %.08lx %.02x <%d.%d.%d> = %x\n", SCpnt->serial_number, 
+          SCpnt->cmnd[0], SCpnt->channel, SCpnt->target, SCpnt->lun, 
+          SCpnt->result));
+  }
+  SCpnt->scsi_done(SCpnt);
+}
+
+/*-------------------------------------------------------------------------
+ *
+ *                      Local functions
+ *
+ *-------------------------------------------------------------------------*/
+
+/*================================================
+ * Initialize SCB structures
+ *================================================*/
+static void initSCB(mega_host_config *megaCfg)
+{
+  int idx;
+
+  for(idx=0; idx<megaCfg->max_cmds; idx++) {
+    megaCfg->scbList[idx].idx    = -1;
+    megaCfg->scbList[idx].flag   = 0;
+    megaCfg->scbList[idx].sgList = NULL;
+    megaCfg->scbList[idx].SCpnt  = NULL;
+  }
+}
+
+/*===========================
+ * Allocate a SCB structure
+ *===========================*/
+static mega_scb *allocateSCB(mega_host_config *megaCfg,Scsi_Cmnd *SCpnt)
+{
+  int        idx;
+  long       flags;
+
+  spin_lock_irqsave(&mega_lock,flags);
+  for(idx=0; idx<megaCfg->max_cmds; idx++) {
+    if (megaCfg->scbList[idx].idx < 0) {
+
+      /* Set Index and SCB pointer */ 
+      megaCfg->scbList[idx].flag  = 0;
+      megaCfg->scbList[idx].idx   = idx;
+      megaCfg->scbList[idx].SCpnt = SCpnt;
+      megaCfg->scbList[idx].next  = NULL;
+      spin_unlock_irqrestore(&mega_lock,flags);
+
+      if (megaCfg->scbList[idx].sgList == NULL) {
+       megaCfg->scbList[idx].sgList =
+                  kmalloc(sizeof(mega_sglist)*MAX_SGLIST,GFP_ATOMIC|GFP_DMA);
+      }
+
+      return &megaCfg->scbList[idx];
+    }
+  }
+  spin_unlock_irqrestore(&mega_lock,flags);
+
+  printk(KERN_WARNING "Megaraid: Could not allocate free SCB!!!\n");
+  
+  return NULL;
+}
+
+/*=======================
+ * Free a SCB structure
+ *=======================*/
+static void freeSCB(mega_scb *scb)
+{
+  long flags;
+
+  spin_lock_irqsave(&mega_lock,flags);
+  scb->flag  = 0;
+  scb->idx   = -1;
+  scb->next  = NULL;
+  scb->SCpnt = NULL;
+  spin_unlock_irqrestore(&mega_lock,flags);
+}
+
+/* Run through the list of completed requests */
+static void mega_rundoneq()
+{
+  mega_host_config *megaCfg;
+  Scsi_Cmnd        *SCpnt;
+  long              islogical;
+
+  while(1) {
+    DEQUEUE(SCpnt, Scsi_Cmnd, qCompleted, host_scribble);
+    if (SCpnt == NULL) return;
+
+    megaCfg = (mega_host_config *)SCpnt->host->hostdata;
+
+    /* Check if we're allowing access to RAID drives or physical
+     *  if use_raid == 1 and this wasn't a disk on the max channel or
+     *  if use_raid == 0 and this was a disk on the max channel
+     *  then fail.
+     */
+    islogical = (SCpnt->channel == megaCfg->host->max_channel) ? 1 : 0;
+    if (SCpnt->cmnd[0] == INQUIRY &&
+       ((((u_char*)SCpnt->request_buffer)[0] & 0x1F) == TYPE_DISK) &&
+       (islogical != use_raid)) {
+       SCpnt->result = 0xF0;
+    }
+
+    /* Convert result to error */
+    switch(SCpnt->result) {
+    case 0x00: case 0x02:
+      SCpnt->result |= (DID_OK << 16);
+      break;
+    case 0x8:
+      SCpnt->result |= (DID_BUS_BUSY << 16);
+      break;
+    default:
+      SCpnt->result |= (DID_BAD_TARGET << 16);
+      break;
+    }
+
+    /* Callback */
+    callDone(SCpnt);
+  }
+}
+
+/* Add command to the list of completed requests */
+static void mega_cmd_done(mega_host_config *megaCfg,mega_scb *pScb, int status)
+{
+  pScb->SCpnt->result = status;
+  ENQUEUE(pScb->SCpnt, Scsi_Cmnd, qCompleted, host_scribble);
+  freeSCB(pScb);
+}
+
+/*----------------------------------------------------
+ * Process pending queue list
+ *
+ * Run as a scheduled task 
+ *----------------------------------------------------*/
+static void mega_runque(void *dummy)
+{
+  mega_host_config *megaCfg;
+  mega_scb         *pScb;
+  long              flags;
+
+  /* Take care of any completed requests */
+  mega_rundoneq();
+
+  DEQUEUE(pScb,mega_scb,qPending,next);
+
+  if (pScb) {
+    megaCfg = (mega_host_config *)pScb->SCpnt->host->hostdata;
+
+    if (megaCfg->mbox->busy || megaCfg->flag & (IN_ISR|PENDING)) {
+      printk(KERN_DEBUG "PENDING = %x, IN_ISR = %x, mbox.busy = %x\n",(u_int)(megaCfg->flag
+            & PENDING), (u_int)(megaCfg->flag & IN_ISR), megaCfg->mbox->busy);
+      TRACE(("%.08lx %.02x <%d.%d.%d> intr%d busy%d isr%d pending%d\n",
+            pScb->SCpnt->serial_number,
+            pScb->SCpnt->cmnd[0],
+            pScb->SCpnt->channel,
+            pScb->SCpnt->target,
+            pScb->SCpnt->lun,
+            intr_count,
+            megaCfg->mbox->busy,
+            (megaCfg->flag & IN_ISR)  ? 1 : 0,
+            (megaCfg->flag & PENDING) ? 1 : 0));
+    }
+
+    if (MegaIssueCmd(megaCfg, pScb->mboxData, pScb, 1)) {
+      printk(KERN_DEBUG "MegaIssueCmd returned BUSY.  Rescheduling command.\n");
+      /* We're BUSY... come back later */
+      spin_lock_irqsave(&mega_lock,flags);
+      pScb->next = qPending;
+      qPending   = pScb;
+      spin_unlock_irqrestore(&mega_lock,flags);
+
+      if (!(megaCfg->flag & PENDING)) { /* If PENDING, irq will schedule task */
+          queue_task(&runq, &tq_scheduler);
+      }
+    }
+  }
+}
+
+/*-------------------------------------------------------------------
+ *
+ *                 Build a SCB from a Scsi_Cmnd
+ *
+ * Returns a SCB pointer, or NULL
+ * If NULL is returned, the scsi_done function MUST have been called
+ *
+ *-------------------------------------------------------------------*/
+static mega_scb *mega_build_cmd(mega_host_config *megaCfg, Scsi_Cmnd *SCpnt)
+{
+  mega_scb      *pScb;
+  mega_mailbox  *mbox;
+  mega_passthru *pthru;
+  long           seg;
+
+  /* We don't support multi-luns */
+  if (SCpnt->lun != 0) {
+    SCpnt->result = (DID_BAD_TARGET << 16);
+    callDone(SCpnt);
+    return NULL;
+  }
+
+  /*-----------------------------------------------------
+   *
+   *               Logical drive commands
+   *
+   *-----------------------------------------------------*/
+  if (SCpnt->channel == megaCfg->host->max_channel) {
+    switch(SCpnt->cmnd[0]) {
+    case TEST_UNIT_READY:
+      memset(SCpnt->request_buffer, 0, SCpnt->request_bufflen);
+      SCpnt->result = (DID_OK << 16);
+      callDone(SCpnt);
+      return NULL;
+
+    case MODE_SENSE:
+      memset(SCpnt->request_buffer, 0, SCpnt->cmnd[4]);
+      SCpnt->result = (DID_OK << 16);
+      callDone(SCpnt);
+      return NULL;
+
+    case READ_CAPACITY:
+    case INQUIRY:
+      /* Allocate a SCB and initialize passthru */
+      if ((pScb = allocateSCB(megaCfg,SCpnt)) == NULL) {
+       SCpnt->result = (DID_ERROR << 16);
+       callDone(SCpnt);
+       return NULL;
+      }
+      pthru = &pScb->pthru;
+      mbox  = (mega_mailbox *)&pScb->mboxData;
+
+      memset(mbox,  0, sizeof(pScb->mboxData));
+      memset(pthru, 0, sizeof(mega_passthru));
+      pthru->timeout      = 0;
+      pthru->ars          = 0;
+      pthru->islogical    = 1;
+      pthru->logdrv       = SCpnt->target;
+      pthru->cdblen       = SCpnt->cmd_len;
+      pthru->dataxferaddr = virt_to_bus(SCpnt->request_buffer);
+      pthru->dataxferlen  = SCpnt->request_bufflen;
+      memcpy(pthru->cdb, SCpnt->cmnd, SCpnt->cmd_len);
+
+      /* Initialize mailbox area */
+      mbox->cmd      = MEGA_MBOXCMD_PASSTHRU;
+      mbox->xferaddr = virt_to_bus(pthru);
+
+      return pScb;
+
+    case READ_6:
+    case WRITE_6:
+    case READ_10:
+    case WRITE_10:
+      /* Allocate a SCB and initialize mailbox */
+      if ((pScb = allocateSCB(megaCfg,SCpnt)) == NULL) {
+       SCpnt->result = (DID_ERROR << 16);
+       callDone(SCpnt);
+       return NULL;
+      }
+      mbox = (mega_mailbox *)&pScb->mboxData;
+
+      memset(mbox, 0, sizeof(pScb->mboxData));
+      mbox->logdrv = SCpnt->target;
+      mbox->cmd    = (*SCpnt->cmnd == READ_6 || *SCpnt->cmnd == READ_10) ?
+       MEGA_MBOXCMD_LREAD : MEGA_MBOXCMD_LWRITE;
+      
+      /* 6-byte */
+      if (*SCpnt->cmnd == READ_6 || *SCpnt->cmnd == WRITE_6) {
+       mbox->numsectors = 
+         (u_long)SCpnt->cmnd[4];
+       mbox->lba = 
+         ((u_long)SCpnt->cmnd[1] << 16) |
+         ((u_long)SCpnt->cmnd[2] << 8) |
+         (u_long)SCpnt->cmnd[3];
+       mbox->lba &= 0x1FFFFF;
+      }
+      
+      /* 10-byte */
+      if (*SCpnt->cmnd == READ_10 || *SCpnt->cmnd == WRITE_10) {
+       mbox->numsectors = 
+         (u_long)SCpnt->cmnd[8] |
+         ((u_long)SCpnt->cmnd[7] << 8);
+       mbox->lba =
+         ((u_long)SCpnt->cmnd[2] << 24) |
+         ((u_long)SCpnt->cmnd[3] << 16) |
+         ((u_long)SCpnt->cmnd[4] << 8) |
+         (u_long)SCpnt->cmnd[5];
+      }
+      
+      /* Calculate Scatter-Gather info */
+      mbox->numsgelements = build_sglist(megaCfg, pScb, 
+                                        (u_long*)&mbox->xferaddr,
+                                        (u_long*)&seg);
+
+      return pScb;
+      
+    default:
+      SCpnt->result = (DID_BAD_TARGET << 16);
+      callDone(SCpnt);
+      return NULL;
+    }
+  }
+  /*-----------------------------------------------------
+   *
+   *               Passthru drive commands
+   *
+   *-----------------------------------------------------*/
+  else {
+    /* Allocate a SCB and initialize passthru */
+    if ((pScb = allocateSCB(megaCfg,SCpnt)) == NULL) {
+      SCpnt->result = (DID_ERROR << 16);
+      callDone(SCpnt);
+      return NULL;
+    }
+    pthru = &pScb->pthru;
+    mbox  = (mega_mailbox *)pScb->mboxData;
+    
+    memset(mbox,  0, sizeof(pScb->mboxData));
+    memset(pthru, 0, sizeof(mega_passthru));
+    pthru->timeout   = 0;
+    pthru->ars       = 0;
+    pthru->islogical = 0;
+    pthru->channel   = SCpnt->channel;
+    pthru->target    = SCpnt->target;
+    pthru->cdblen    = SCpnt->cmd_len;
+    memcpy(pthru->cdb, SCpnt->cmnd, SCpnt->cmd_len);
+   
+    pthru->numsgelements = build_sglist(megaCfg, pScb,
+                                       (u_long *)&pthru->dataxferaddr,
+                                       (u_long *)&pthru->dataxferlen);
+    
+    /* Initialize mailbox */
+    mbox->cmd      = MEGA_MBOXCMD_PASSTHRU;
+    mbox->xferaddr = virt_to_bus(pthru);
+
+    return pScb;
+  }
+  return NULL;
+}
+
+/*--------------------------------------------------------------------
+ * Interrupt service routine
+ *--------------------------------------------------------------------*/
+static void megaraid_isr(int irq, void *devp, struct pt_regs *regs)
+{
+  mega_host_config *megaCfg;
+  u_char            byte, idx, sIdx;
+  u_long            dword;
+  mega_mailbox     *mbox;
+  mega_scb         *pScb;
+  long              flags;
+  int               qCnt, qStatus;
+
+  megaCfg = (mega_host_config *)devp;
+  mbox    = (mega_mailbox *)megaCfg->mbox;
+
+  if (megaCfg->host->irq == irq) {
+    spin_lock_irqsave(&mega_lock,flags);
+
+    if (megaCfg->flag & IN_ISR) {
+      TRACE(("ISR called reentrantly!!\n"));
+    }
+
+    megaCfg->flag |= IN_ISR;
+
+    /* Check if a valid interrupt is pending */
+    if (megaCfg->flag & BOARD_QUARTZ) {
+        dword = RDOUTDOOR(megaCfg);
+        if (dword != 0x10001234) {
+            /* Spurious interrupt */
+            megaCfg->flag &= ~IN_ISR;
+            spin_unlock_irqrestore(&mega_lock,flags);
+            return;
+        }
+        WROUTDOOR(megaCfg,dword);
+    } else {
+        byte = READ_PORT(megaCfg->host->io_port, INTR_PORT);
+        if ((byte & VALID_INTR_BYTE) == 0) {
+          /* Spurious interrupt */
+          megaCfg->flag &= ~IN_ISR;
+          spin_unlock_irqrestore(&mega_lock,flags);
+          return;
+        }
+        WRITE_PORT(megaCfg->host->io_port, INTR_PORT, byte);
+    }
+    
+    qCnt    = mbox->numstatus;
+    qStatus = mbox->status;
+
+    if (qCnt > 1) {TRACE(("ISR: Received %d status\n", qCnt))
+        printk(KERN_DEBUG "Got numstatus = %d\n",qCnt);
+    }
+    
+    for(idx=0; idx<qCnt; idx++) {
+      sIdx = mbox->completed[idx];
+      if (sIdx > 0) {
+       pScb = &megaCfg->scbList[sIdx-1];
+        spin_unlock_irqrestore(&mega_lock,flags); /* locks within cmd_done */
+       mega_cmd_done(megaCfg,&megaCfg->scbList[sIdx-1], qStatus);
+        spin_lock_irqsave(&mega_lock,flags);
+      }
+    }
+    if (megaCfg->flag & BOARD_QUARTZ) {
+        WRINDOOR(megaCfg,virt_to_bus(megaCfg->mbox)|0x2);
+        while (RDINDOOR(megaCfg) & 0x02);
+    } else {
+        CLEAR_INTR(megaCfg->host->io_port);
+    }
+
+    megaCfg->flag &= ~IN_ISR;
+    megaCfg->flag &= ~PENDING;
+
+    /* Queue as a delayed ISR routine */
+    queue_task_irq_off(&runq, &tq_immediate);
+    mark_bh(IMMEDIATE_BH);
+    spin_unlock_irqrestore(&mega_lock,flags);
+
+  }
+}
+
+/*==================================================*/
+/* Wait until the controller's mailbox is available */
+/*==================================================*/
+static int busyWaitMbox(mega_host_config *megaCfg)
+{
+  mega_mailbox *mbox = (mega_mailbox *)megaCfg->mbox;
+  long          counter;
+
+  for(counter=0; counter<0xFFFFFF; counter++) {
+    if (!mbox->busy) return 0;
+  }
+  return -1;
+}
+
+/*=====================================================
+ * Post a command to the card
+ *
+ * Arguments:
+ *   mega_host_config *megaCfg - Controller structure
+ *   u_char *mboxData - Mailbox area, 16 bytes
+ *   mega_scb *pScb   - SCB posting (or NULL if N/A)
+ *   int intr         - if 1, interrupt, 0 is blocking
+ *=====================================================*/
+static int MegaIssueCmd(mega_host_config *megaCfg,
+                       u_char *mboxData,
+                       mega_scb *pScb,
+                       int intr)
+{
+  mega_mailbox *mbox = (mega_mailbox *)megaCfg->mbox;
+  long          flags;
+  u_char        byte;
+  u_long        cmdDone;
+
+  mboxData[0x1] = (pScb ? pScb->idx+1 : 0x00);  /* Set cmdid */
+  mboxData[0xF] = 1;                            /* Set busy */
+
+  /* one bad report of problem when issuing a command while pending.
+   * Wasn't able to duplicate, but it doesn't really affect performance
+   * anyway, so don't allow command while PENDING
+   */
+  if (megaCfg->flag & PENDING) {
+    return -1;
+  }
+
+  /* Wait until mailbox is free */
+  if (busyWaitMbox(megaCfg)) {
+    if (pScb) {
+      TRACE(("Mailbox busy %.08lx <%d.%d.%d>\n", pScb->SCpnt->serial_number,
+            pScb->SCpnt->channel, pScb->SCpnt->target, pScb->SCpnt->lun));
+    }
+    return -1;
+  }
+
+  /* Copy mailbox data into host structure */
+  spin_lock_irqsave(&mega_lock,flags);
+  memset(mbox, 0, sizeof(mega_mailbox));
+  memcpy(mbox, mboxData, 16);
+  spin_unlock_irqrestore(&mega_lock,flags);
+
+  /* Kick IO */
+  megaCfg->flag |= PENDING;
+  if (intr) {
+    /* Issue interrupt (non-blocking) command */
+    if (megaCfg->flag & BOARD_QUARTZ) {
+        mbox->mraid_poll = 0; 
+        mbox->mraid_ack = 0; 
+        WRINDOOR(megaCfg, virt_to_bus(megaCfg->mbox) | 0x1);
+    } else {
+        ENABLE_INTR(megaCfg->host->io_port);
+        ISSUE_COMMAND(megaCfg->host->io_port);
+    }
+  }
+  else {      /* Issue non-ISR (blocking) command */
+
+    if (megaCfg->flag & BOARD_QUARTZ) {
+
+      mbox->mraid_poll = 0; 
+      mbox->mraid_ack = 0; 
+      WRINDOOR(megaCfg, virt_to_bus(megaCfg->mbox) | 0x1);
+
+      while((cmdDone=RDOUTDOOR(megaCfg)) != 0x10001234);
+      WROUTDOOR(megaCfg, cmdDone);
+
+      if (pScb) {
+       mega_cmd_done(megaCfg,pScb, mbox->status);
+       mega_rundoneq();
+      }
+
+      WRINDOOR(megaCfg,virt_to_bus(megaCfg->mbox) | 0x2);
+      while(RDINDOOR(megaCfg) & 0x2);
+
+      megaCfg->flag &= ~PENDING;
+    }
+    else {
+      DISABLE_INTR(megaCfg->host->io_port);
+      ISSUE_COMMAND(megaCfg->host->io_port);
+      
+      while(!((byte=READ_PORT(megaCfg->host->io_port,INTR_PORT))&INTR_VALID));
+      WRITE_PORT(megaCfg->host->io_port, INTR_PORT, byte);
+      
+      ENABLE_INTR(megaCfg->host->io_port);
+      CLEAR_INTR(megaCfg->host->io_port);
+      
+      if (pScb) {
+       mega_cmd_done(megaCfg,pScb, mbox->status);
+       mega_rundoneq();
+      }
+      megaCfg->flag &= ~PENDING;
+    }
+  }
+
+  return 0;
+}
+
+/*-------------------------------------------------------------------
+ * Copies data to SGLIST
+ *-------------------------------------------------------------------*/
+static int build_sglist(mega_host_config *megaCfg, mega_scb *scb, 
+                       u_long *buffer, u_long *length)
+{
+  struct scatterlist *sgList;
+  int idx;
+
+  /* Scatter-gather not used */
+  if (scb->SCpnt->use_sg == 0) {
+    *buffer = virt_to_bus(scb->SCpnt->request_buffer);
+    *length = (u_long)scb->SCpnt->request_bufflen;
+    return 0;
+  }
+
+  sgList = (struct scatterlist *)scb->SCpnt->buffer;
+  if (scb->SCpnt->use_sg == 1) {
+    *buffer = virt_to_bus(sgList[0].address);
+    *length = (u_long)sgList[0].length;
+    return 0;
+  }
+
+  /* Copy Scatter-Gather list info into controller structure */
+  for(idx=0; idx<scb->SCpnt->use_sg; idx++) {
+    scb->sgList[idx].address = virt_to_bus(sgList[idx].address);
+    scb->sgList[idx].length  = (u_long)sgList[idx].length;
+  }
+  
+  /* Reset pointer and length fields */
+  *buffer = virt_to_bus(scb->sgList);
+  *length = 0;
+
+  /* Return count of SG requests */
+  return scb->SCpnt->use_sg;
+}
+    
+/*--------------------------------------------------------------------
+ * Initializes the adress of the controller's mailbox register
+ *  The mailbox register is used to issue commands to the card.
+ *  Format of the mailbox area:
+ *   00 01 command
+ *   01 01 command id
+ *   02 02 # of sectors
+ *   04 04 logical bus address
+ *   08 04 physical buffer address
+ *   0C 01 logical drive #
+ *   0D 01 length of scatter/gather list
+ *   0E 01 reserved
+ *   0F 01 mailbox busy
+ *   10 01 numstatus byte
+ *   11 01 status byte
+ *--------------------------------------------------------------------*/
+static int mega_register_mailbox(mega_host_config *megaCfg, u_long paddr)
+{
+  /* align on 16-byte boundry */
+  megaCfg->mbox = &megaCfg->mailbox;
+  megaCfg->mbox = (mega_mailbox *) ((((ulong)megaCfg->mbox) + 16)&0xfffffff0);
+  paddr = (paddr+16)&0xfffffff0;
+
+  /* Register mailbox area with the firmware */
+  if (megaCfg->flag & BOARD_QUARTZ) {
+  }
+  else {
+    WRITE_PORT(megaCfg->host->io_port, MBOX_PORT0, paddr         & 0xFF);
+    WRITE_PORT(megaCfg->host->io_port, MBOX_PORT1, (paddr >>  8) & 0xFF);
+    WRITE_PORT(megaCfg->host->io_port, MBOX_PORT2, (paddr >> 16) & 0xFF);
+    WRITE_PORT(megaCfg->host->io_port, MBOX_PORT3, (paddr >> 24) & 0xFF);
+    WRITE_PORT(megaCfg->host->io_port, ENABLE_MBOX_REGION, ENABLE_MBOX_BYTE);
+    
+    CLEAR_INTR(megaCfg->host->io_port);
+    ENABLE_INTR(megaCfg->host->io_port);
+  }
+  return 0;
+}
+
+/*-------------------------------------------------------------------
+ * Issue an adapter info query to the controller
+ *-------------------------------------------------------------------*/
+static int mega_i_query_adapter(mega_host_config *megaCfg)
+{
+  mega_RAIDINQ *adapterInfo;
+  mega_mailbox *mbox;
+  u_char        mboxData[16];
+  u_long        paddr;
+
+  spin_lock_init(&mega_lock);
+  /* Initialize adapter inquiry */
+  paddr = virt_to_bus(megaCfg->mega_buffer);
+  mbox  = (mega_mailbox *)mboxData;
+
+  memset((void *)megaCfg->mega_buffer, 0, sizeof(megaCfg->mega_buffer));
+  memset(mbox, 0, 16);
+
+  /* Initialize mailbox registers */
+  mbox->cmd      = MEGA_MBOXCMD_ADAPTERINQ;
+  mbox->xferaddr = paddr;
+
+  /* Issue a blocking command to the card */
+  MegaIssueCmd(megaCfg, mboxData, NULL, 0);
+  
+  /* Initialize host/local structures with Adapter info */
+  adapterInfo = (mega_RAIDINQ *)megaCfg->mega_buffer;
+  megaCfg->host->max_channel = adapterInfo->AdpInfo.ChanPresent;
+  megaCfg->host->max_id      = adapterInfo->AdpInfo.MaxTargPerChan;
+  megaCfg->numldrv           = adapterInfo->LogdrvInfo.NumLDrv;
+
+#if 0
+  printk(KERN_DEBUG "---- Logical drive info ----\n");
+  for(i=0; i<megaCfg->numldrv; i++) {
+    printk(KERN_DEBUG "%d: size: %ld prop: %x state: %x\n",i,
+          adapterInfo->LogdrvInfo.LDrvSize[i],
+          adapterInfo->LogdrvInfo.LDrvProp[i],
+          adapterInfo->LogdrvInfo.LDrvState[i]);
+  }
+  printk(KERN_DEBUG "---- Physical drive info ----\n");
+  for(i=0; i<MAX_PHYSICAL_DRIVES; i++) {
+    if (i && !(i % 8)) printk("\n");
+    printk("%d: %x   ", i, adapterInfo->PhysdrvInfo.PDrvState[i]);
+  }
+  printk("\n");
+#endif
+
+  megaCfg->max_cmds = adapterInfo->AdpInfo.MaxConcCmds;
+
+#ifdef HP            /* use HP firmware and bios version encoding */
+      sprintf(megaCfg->fwVer,"%c%d%d.%d%d",
+          adapterInfo->AdpInfo.FwVer[2],
+          adapterInfo->AdpInfo.FwVer[1] >> 8,
+          adapterInfo->AdpInfo.FwVer[1] & 0x0f,
+          adapterInfo->AdpInfo.FwVer[2] >> 8,
+          adapterInfo->AdpInfo.FwVer[2] & 0x0f);
+      sprintf(megaCfg->biosVer,"%c%d%d.%d%d",
+          adapterInfo->AdpInfo.BiosVer[2],
+          adapterInfo->AdpInfo.BiosVer[1] >> 8,
+          adapterInfo->AdpInfo.BiosVer[1] & 0x0f,
+          adapterInfo->AdpInfo.BiosVer[2] >> 8,
+          adapterInfo->AdpInfo.BiosVer[2] & 0x0f);
+#else
+      memcpy(megaCfg->fwVer, adapterInfo->AdpInfo.FwVer, 4);
+      megaCfg->fwVer[4] = 0;
+
+      memcpy(megaCfg->biosVer, adapterInfo->AdpInfo.BiosVer, 4);
+      megaCfg->biosVer[4] = 0;
+#endif
+
+  printk(KERN_INFO "megaraid: [%s:%s] detected %d logical drives" CRLFSTR,
+        megaCfg->fwVer,
+        megaCfg->biosVer,
+        megaCfg->numldrv);
+  return 0;
+}
+
+/*-------------------------------------------------------------------------
+ *
+ *                      Driver interface functions
+ *
+ *-------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------
+ * Returns data to be displayed in /proc/scsi/megaraid/X
+ *----------------------------------------------------------*/
+int megaraid_proc_info(char *buffer, char **start, off_t offset,
+                      int length, int inode, int inout)
+{
+  *start = buffer;
+  return 0;
+}
+
+int findCard(Scsi_Host_Template *pHostTmpl, 
+            u_short pciVendor, u_short pciDev,
+            long flag)
+{
+  mega_host_config *megaCfg;
+  struct Scsi_Host *host;
+  u_char            pciBus, pciDevFun, megaIrq;
+  u_long            megaBase;
+  u_short           pciIdx = 0;
+
+#if LINUX_VERSION_CODE < 0x20100
+  while(!pcibios_find_device(pciVendor, pciDev, pciIdx,&pciBus,&pciDevFun)) {
+#else
+  struct pci_dev   *pdev=pci_devices;
+
+  while((pdev = pci_find_device(pciVendor, pciDev, pdev))) {
+    pciBus = pdev->bus->number;
+    pciDevFun = pdev->devfn;
+#endif
+    printk(KERN_INFO "megaraid: found 0x%4.04x:0x%4.04x:idx %d:bus %d:slot %d:fun %d\n",
+          pciVendor, 
+          pciDev, 
+          pciIdx, pciBus, 
+          PCI_SLOT(pciDevFun), 
+          PCI_FUNC(pciDevFun));
+    
+    /* Read the base port and IRQ from PCI */
+#if LINUX_VERSION_CODE < 0x20100
+    pcibios_read_config_dword(pciBus, pciDevFun,
+                            PCI_BASE_ADDRESS_0,
+                            (u_int *)&megaBase);
+    pcibios_read_config_byte(pciBus, pciDevFun,                               
+                            PCI_INTERRUPT_LINE,
+                            &megaIrq);
+#else
+    megaBase = pdev->base_address[0];
+    megaIrq = pdev->irq;
+#endif
+    pciIdx++;
+
+    if (flag & BOARD_QUARTZ) {
+      megaBase &= PCI_BASE_ADDRESS_MEM_MASK;
+      megaBase = (long) ioremap(megaBase,128);
+    }
+    else {
+      megaBase &= PCI_BASE_ADDRESS_IO_MASK;
+      megaBase += 0x10;
+    }
+
+    /* Initialize SCSI Host structure */
+    host    = scsi_register(pHostTmpl, sizeof(mega_host_config));
+    megaCfg = (mega_host_config *)host->hostdata;
+    memset(megaCfg, 0, sizeof(mega_host_config));
+
+    printk(KERN_INFO " scsi%d: Found a MegaRAID controller at 0x%x, IRQ: %d" CRLFSTR, 
+          host->host_no, (u_int)megaBase, megaIrq);
+    
+    /* Copy resource info into structure */
+    megaCfg->flag            = flag;
+    megaCfg->host            = host;
+    megaCfg->base            = megaBase;
+    megaCfg->host->irq       = megaIrq;
+    megaCfg->host->io_port   = megaBase;
+    megaCfg->host->n_io_port = 16;
+    megaCfg->host->unique_id = (pciBus << 8) | pciDevFun;
+    megaCtlrs[numCtlrs++]    = megaCfg;
+
+    if (flag != BOARD_QUARTZ) {
+      /* Request our IO Range */
+      if (check_region(megaBase, 16)) {
+       printk(KERN_WARNING "megaraid: Couldn't register I/O range!" CRLFSTR);
+       scsi_unregister(host);
+       continue;
+      }
+      request_region(megaBase, 16, "megaraid");
+    }
+
+    /* Request our IRQ */
+    if (request_irq(megaIrq, megaraid_isr, SA_SHIRQ, 
+                   "megaraid", megaCfg)) {
+      printk(KERN_WARNING "megaraid: Couldn't register IRQ %d!" CRLFSTR,
+            megaIrq);
+      scsi_unregister(host);
+      continue;
+    }
+
+    mega_register_mailbox(megaCfg, virt_to_bus((void*)&megaCfg->mailbox));
+    mega_i_query_adapter(megaCfg);
+
+    /* Initialize SCBs */
+    initSCB(megaCfg);
+
+  }
+  return pciIdx;
+}
+
+/*---------------------------------------------------------
+ * Detects if a megaraid controller exists in this system
+ *---------------------------------------------------------*/
+int megaraid_detect(Scsi_Host_Template *pHostTmpl)
+{
+  int count = 0;
+
+  pHostTmpl->proc_dir = &proc_scsi_megaraid;
+
+#if LINUX_VERSION_CODE < 0x20100
+  if (!pcibios_present()) 
+    {
+      printk(KERN_WARNING "megaraid: PCI bios not present." CRLFSTR);
+      return 0;
+    }
+#endif
+
+  count += findCard(pHostTmpl, 0x101E, 0x9010, 0);
+  count += findCard(pHostTmpl, 0x101E, 0x9060, 0);
+  count += findCard(pHostTmpl, 0x8086, 0x1960, BOARD_QUARTZ);
+
+  return count;
+}
+
+/*---------------------------------------------------------------------
+ * Release the controller's resources
+ *---------------------------------------------------------------------*/
+int megaraid_release(struct Scsi_Host *pSHost)
+{
+  mega_host_config *megaCfg;
+  mega_mailbox         *mbox;
+  u_char                mboxData[16];
+
+  megaCfg = (mega_host_config*)pSHost->hostdata;
+  mbox    = (mega_mailbox *)mboxData;
+
+  /* Flush cache to disk */
+  memset(mbox, 0, 16);
+  mboxData[0] = 0xA;
+
+  /* Issue a blocking (interrupts disabled) command to the card */
+  MegaIssueCmd(megaCfg, mboxData, NULL, 0);
+
+  schedule();
+
+  /* Free our resources */
+  if (megaCfg->flag & BOARD_QUARTZ) {
+      iounmap((void *)megaCfg->base);
+  } else {
+      release_region(megaCfg->host->io_port, 16);
+  }
+  free_irq(megaCfg->host->irq, megaCfg); /* Must be freed first, otherwise
+                                            extra interrupt is generated */
+  scsi_unregister(pSHost);
+
+  return 0;
+}
+
+/*----------------------------------------------
+ * Get information about the card/driver 
+ *----------------------------------------------*/
+const char *megaraid_info(struct Scsi_Host *pSHost)
+{
+  static char           buffer[512];
+  mega_host_config  *megaCfg;
+  mega_RAIDINQ          *adapterInfo;
+
+  megaCfg     = (mega_host_config *)pSHost->hostdata;
+  adapterInfo = (mega_RAIDINQ *)megaCfg->mega_buffer;
+
+  sprintf(buffer, "AMI MegaRAID %s %d commands %d targs %d chans",
+         megaCfg->fwVer,
+         adapterInfo->AdpInfo.MaxConcCmds,
+         megaCfg->host->max_id,
+         megaCfg->host->max_channel);
+  return buffer;
+}
+
+/*-----------------------------------------------------------------
+ * Perform a SCSI command
+ * Mailbox area:
+ *   00 01 command
+ *   01 01 command id
+ *   02 02 # of sectors
+ *   04 04 logical bus address
+ *   08 04 physical buffer address
+ *   0C 01 logical drive #
+ *   0D 01 length of scatter/gather list
+ *   0E 01 reserved
+ *   0F 01 mailbox busy
+ *   10 01 numstatus byte
+ *   11 01 status byte 
+ *-----------------------------------------------------------------*/
+int megaraid_queue(Scsi_Cmnd *SCpnt, void (*pktComp)(Scsi_Cmnd *))
+{
+  mega_host_config *megaCfg;
+  mega_scb         *pScb;
+
+  megaCfg = (mega_host_config *)SCpnt->host->hostdata;
+
+  if (!(megaCfg->flag & (1L << SCpnt->channel))) {
+    printk(KERN_INFO "scsi%d: scanning channel %c for devices.\n",
+          megaCfg->host->host_no,
+          SCpnt->channel + 'A');
+    megaCfg->flag |= (1L << SCpnt->channel);
+  }
+
+  SCpnt->scsi_done = pktComp;
+
+  /* Allocate and build a SCB request */
+  if ((pScb = mega_build_cmd(megaCfg, SCpnt)) != NULL) {
+    /* Add SCB to the head of the pending queue */
+    ENQUEUE(pScb, mega_scb, qPending, next);
+
+    /* Issue the command to the card */
+      mega_runque(NULL);
+  }
+
+  return 0;
+}
+
+/*----------------------------------------------------------------------
+ * Issue a blocking command to the controller
+ *
+ * Note - this isnt 2.0.x SMP safe
+ *----------------------------------------------------------------------*/
+volatile static int internal_done_flag    = 0;
+volatile static int internal_done_errcode = 0;
+
+static void internal_done(Scsi_Cmnd *SCpnt)
+{
+  internal_done_errcode = SCpnt->result;
+  internal_done_flag++;
+}
+
+/*
+ *     This seems dangerous in an SMP environment because 
+ *     while spinning on internal_done_flag in 2.0.x SMP
+ *     no IRQ's will be taken, including those that might
+ *     be needed to clear this.
+ *
+ *     I think this should be using a wait queue ?
+ *                             -- AC
+ */
+int megaraid_command(Scsi_Cmnd *SCpnt)
+{
+  internal_done_flag = 0;
+
+  /* Queue command, and wait until it has completed */
+  megaraid_queue(SCpnt, internal_done);
+
+  while(!internal_done_flag)
+    barrier();
+
+  return internal_done_errcode;
+}
+
+/*---------------------------------------------------------------------
+ * Abort a previous SCSI request
+ *---------------------------------------------------------------------*/
+int megaraid_abort(Scsi_Cmnd *SCpnt)
+{
+  mega_host_config *megaCfg;
+  int       idx;
+  long      flags;
+
+  spin_lock_irqsave(&mega_lock,flags);
+
+  megaCfg = (mega_host_config *)SCpnt->host->hostdata;
+
+  TRACE(("ABORT!!! %.08lx %.02x <%d.%d.%d>\n",
+        SCpnt->serial_number, SCpnt->cmnd[0], SCpnt->channel, SCpnt->target, 
+        SCpnt->lun));
+  /*
+   * Walk list of SCBs for any that are still outstanding
+   */
+  for(idx=0; idx<megaCfg->max_cmds; idx++) {
+    if (megaCfg->scbList[idx].idx >= 0) {
+      if (megaCfg->scbList[idx].SCpnt == SCpnt) {
+       freeSCB(&megaCfg->scbList[idx]);
+
+       SCpnt->result = (DID_RESET << 16) | (SUGGEST_RETRY<<24);
+       callDone(SCpnt);
+      }
+    }
+  }
+  spin_unlock_irqrestore(&mega_lock,flags);
+  return SCSI_ABORT_SNOOZE;
+}
+
+/*---------------------------------------------------------------------
+ * Reset a previous SCSI request
+ *---------------------------------------------------------------------*/
+int megaraid_reset(Scsi_Cmnd *SCpnt, unsigned int rstflags)
+{
+  mega_host_config *megaCfg;
+  int       idx;
+  long      flags;
+
+  spin_lock_irqsave(&mega_lock,flags);
+
+  megaCfg = (mega_host_config *)SCpnt->host->hostdata;
+
+  TRACE(("RESET: %.08lx %.02x <%d.%d.%d>\n",
+        SCpnt->serial_number, SCpnt->cmnd[0], SCpnt->channel, SCpnt->target, 
+        SCpnt->lun));
+
+  /*
+   * Walk list of SCBs for any that are still outstanding
+   */
+  for(idx=0; idx<megaCfg->max_cmds; idx++) {
+    if (megaCfg->scbList[idx].idx >= 0) {
+      SCpnt = megaCfg->scbList[idx].SCpnt;
+      freeSCB(&megaCfg->scbList[idx]);
+      SCpnt->result = (DID_RESET << 16) | (SUGGEST_RETRY<<24);
+      callDone(SCpnt);
+    }
+  }
+  spin_unlock_irqrestore(&mega_lock,flags);
+  return SCSI_RESET_PUNT;
+} 
+
+/*-------------------------------------------------------------
+ * Return the disk geometry for a particular disk
+ * Input:
+ *   Disk *disk - Disk geometry
+ *   kdev_t dev - Device node
+ *   int *geom  - Returns geometry fields
+ *     geom[0] = heads
+ *     geom[1] = sectors
+ *     geom[2] = cylinders
+ *-------------------------------------------------------------*/
+int megaraid_biosparam(Disk *disk, kdev_t dev, int *geom)
+{
+  int                   heads, sectors, cylinders;
+  mega_host_config *megaCfg;
+
+  /* Get pointer to host config structure */
+  megaCfg = (mega_host_config *)disk->device->host->hostdata;
+
+  /* Default heads (64) & sectors (32) */
+  heads     = 64;
+  sectors   = 32;
+  cylinders = disk->capacity / (heads * sectors);
+
+  /* Handle extended translation size for logical drives > 1Gb */
+  if (disk->capacity >= 0x200000) {
+    heads     = 255;
+    sectors   = 63;
+    cylinders = disk->capacity / (heads * sectors);
+  }
+
+  /* return result */
+  geom[0] = heads;
+  geom[1] = sectors;
+  geom[2] = cylinders;
+
+  return 0;
+}
+
+#ifdef MODULE
+Scsi_Host_Template driver_template = MEGARAID;
+
+#include "scsi_module.c"
+#endif
diff --git a/drivers/scsi/megaraid.h b/drivers/scsi/megaraid.h
new file mode 100644 (file)
index 0000000..5442407
--- /dev/null
@@ -0,0 +1,282 @@
+#ifndef __MEGARAID_H__
+#define __MEGARAID_H__
+
+#define IN_ISR                  0x80000000L
+#define NO_INTR                 0x40000000L
+#define IN_TIMEOUT              0x20000000L
+#define PENDING                 0x10000000L
+#define BOARD_QUARTZ            0x08000000L
+
+#define SCB_ACTIVE 0x1
+#define SCB_WAITQ  0x2
+#define SCB_ISSUED 0x4
+
+#define SCB_FREE                -1
+#define SCB_RESET               -2
+#define SCB_ABORT               -3
+#define SCB_LOCKED              -4
+
+#define MEGA_CMD_TIMEOUT        10
+
+#define MAX_SGLIST              20
+#define MAX_COMMANDS            254
+
+#define MAX_LOGICAL_DRIVES      8
+#define MAX_CHANNEL             5
+#define MAX_TARGET              15
+#define MAX_PHYSICAL_DRIVES     MAX_CHANNEL*MAX_TARGET
+
+#define INQUIRY_DATA_SIZE       0x24
+#define MAX_CDB_LEN             0x0A
+#define MAX_REQ_SENSE_LEN       0x20
+
+#define INTR_VALID              0x40
+
+/* Mailbox commands */
+#define MEGA_MBOXCMD_LREAD      0x01
+#define MEGA_MBOXCMD_LWRITE     0x02
+#define MEGA_MBOXCMD_PASSTHRU   0x03
+#define MEGA_MBOXCMD_ADAPTERINQ 0x05
+
+/* Offsets into Mailbox */
+#define COMMAND_PORT       0x00
+#define COMMAND_ID_PORT    0x01
+#define SG_LIST_PORT0      0x08
+#define SG_LIST_PORT1      0x09
+#define SG_LIST_PORT2      0x0a
+#define SG_LIST_PORT3      0x0b
+#define SG_ELEMENT_PORT    0x0d
+#define NO_FIRED_PORT      0x0f
+
+/* I/O Port offsets */
+#define I_CMD_PORT         0x00
+#define I_ACK_PORT         0x00
+#define I_TOGGLE_PORT      0x01
+#define INTR_PORT          0x0a
+
+#define MAILBOX_SIZE       70
+#define MBOX_BUSY_PORT     0x00
+#define MBOX_PORT0         0x04
+#define MBOX_PORT1         0x05
+#define MBOX_PORT2         0x06
+#define MBOX_PORT3         0x07
+#define ENABLE_MBOX_REGION 0x0B
+
+/* I/O Port Values */
+#define ISSUE_BYTE         0x10
+#define ACK_BYTE           0x08
+#define ENABLE_INTR_BYTE   0xc0
+#define DISABLE_INTR_BYTE  0x00
+#define VALID_INTR_BYTE    0x40
+#define MBOX_BUSY_BYTE     0x10
+#define ENABLE_MBOX_BYTE   0x00
+
+/* Setup some port macros here */
+#define WRITE_MAILBOX(base,offset,value)   *(base+offset)=value
+#define READ_MAILBOX(base,offset)          *(base+offset)
+
+#define WRITE_PORT(base,offset,value)      outb_p(value,base+offset)
+#define READ_PORT(base,offset)             inb_p(base+offset)
+
+#define ISSUE_COMMAND(base)   WRITE_PORT(base,I_CMD_PORT,ISSUE_BYTE)
+#define CLEAR_INTR(base)      WRITE_PORT(base,I_ACK_PORT,ACK_BYTE)
+#define ENABLE_INTR(base)     WRITE_PORT(base,I_TOGGLE_PORT,ENABLE_INTR_BYTE)
+#define DISABLE_INTR(base)    WRITE_PORT(base,I_TOGGLE_PORT,DISABLE_INTR_BYTE)
+
+/* Define AMI's PCI codes */
+#undef PCI_VENDOR_ID_AMI
+#undef PCI_DEVICE_ID_AMI_MEGARAID
+
+#ifndef PCI_VENDOR_ID_AMI
+#define PCI_VENDOR_ID_AMI          0x101E
+#define PCI_DEVICE_ID_AMI_MEGARAID 0x9010
+#endif
+
+#define PCI_CONF_BASE_ADDR_OFFSET  0x10
+#define PCI_CONF_IRQ_OFFSET        0x3c
+
+#if LINUX_VERSION_CODE < 0x20100
+#define MEGARAID \
+  { NULL,                               /* Next                      */\
+    NULL,                               /* Usage Count Pointer       */\
+    NULL,                               /* /proc Directory Entry     */\
+    megaraid_proc_info,                 /* /proc Info Function       */\
+    "MegaRAID",                         /* Driver Name               */\
+    megaraid_detect,                    /* Detect Host Adapter       */\
+    megaraid_release,                   /* Release Host Adapter      */\
+    megaraid_info,                      /* Driver Info Function      */\
+    megaraid_command,                   /* Command Function          */\
+    megaraid_queue,                     /* Queue Command Function    */\
+    megaraid_abort,                     /* Abort Command Function    */\
+    megaraid_reset,                     /* Reset Command Function    */\
+    NULL,                               /* Slave Attach Function     */\
+    megaraid_biosparam,                 /* Disk BIOS Parameters      */\
+    1,                                  /* # of cmds that can be\
+                                           outstanding at any time */\
+    7,                                  /* HBA Target ID             */\
+    MAX_SGLIST,                         /* Scatter/Gather Table Size */\
+    1,                                  /* SCSI Commands per LUN     */\
+    0,                                  /* Present                   */\
+    0,                                  /* Default Unchecked ISA DMA */\
+    ENABLE_CLUSTERING }                 /* Enable Clustering         */
+#else
+#define MEGARAID \
+  {\
+    name:            "MegaRAID",               /* Driver Name               */\
+    proc_info:        megaraid_proc_info,      /* /proc driver info         */\
+    detect:           megaraid_detect,         /* Detect Host Adapter       */\
+    release:          megaraid_release,        /* Release Host Adapter      */\
+    info:             megaraid_info,           /* Driver Info Function      */\
+    command:          megaraid_command,        /* Command Function          */\
+    queuecommand:     megaraid_queue,          /* Queue Command Function    */\
+    abort:            megaraid_abort,          /* Abort Command Function    */\
+    reset:            megaraid_reset,          /* Reset Command Function    */\
+    bios_param:       megaraid_biosparam,      /* Disk BIOS Parameters      */\
+    can_queue:        255,                     /* Can Queue                 */\
+    this_id:          7,                       /* HBA Target ID             */\
+    sg_tablesize:     MAX_SGLIST,              /* Scatter/Gather Table Size */\
+    cmd_per_lun:      1,                       /* SCSI Commands per LUN     */\
+    present:          0,                       /* Present                   */\
+    unchecked_isa_dma:0,                       /* Default Unchecked ISA DMA */\
+    use_clustering:   ENABLE_CLUSTERING       /* Enable Clustering         */\
+  }
+#endif
+
+/* Structures */
+typedef struct _mega_ADP_INFO
+{
+  u_char    MaxConcCmds;
+  u_char    RbldRate;
+  u_char    MaxTargPerChan;
+  u_char    ChanPresent;
+  u_char    FwVer[4];
+  u_short   AgeOfFlash;
+  u_char    ChipSet;
+  u_char    DRAMSize;
+  u_char    CacheFlushInterval;
+  u_char    BiosVer[4];
+  u_char    resvd[7];
+} mega_ADP_INFO;
+
+typedef struct _mega_LDRV_INFO
+{
+  u_char   NumLDrv;
+  u_char   resvd[3];
+  u_long   LDrvSize[MAX_LOGICAL_DRIVES];
+  u_char   LDrvProp[MAX_LOGICAL_DRIVES];
+  u_char   LDrvState[MAX_LOGICAL_DRIVES];
+} mega_LDRV_INFO;
+
+typedef struct _mega_PDRV_INFO
+{
+  u_char   PDrvState[MAX_PHYSICAL_DRIVES];
+  u_char   resvd;
+} mega_PDRV_INFO;
+
+// RAID inquiry: Mailbox command 0x5
+typedef struct _mega_RAIDINQ
+{
+  mega_ADP_INFO    AdpInfo;
+  mega_LDRV_INFO   LogdrvInfo;
+  mega_PDRV_INFO   PhysdrvInfo;
+} mega_RAIDINQ;
+
+// Passthrough command: Mailbox command 0x3
+typedef struct mega_passthru
+{
+  u_char            timeout:3;              /* 0=6sec/1=60sec/2=10min/3=3hrs */
+  u_char            ars:1;
+  u_char            reserved:3;
+  u_char            islogical:1;
+  u_char            logdrv;                 /* if islogical == 1 */
+  u_char            channel;                /* if islogical == 0 */
+  u_char            target;                 /* if islogical == 0 */
+  u_char            queuetag;               /* unused */
+  u_char            queueaction;            /* unused */
+  u_char            cdb[MAX_CDB_LEN];
+  u_char            cdblen;
+  u_char            reqsenselen;
+  u_char            reqsensearea[MAX_REQ_SENSE_LEN];
+  u_char            numsgelements;
+  u_char            scsistatus;
+  u_long            dataxferaddr;
+  u_long            dataxferlen;
+} mega_passthru;
+
+typedef struct _mega_mailbox
+{
+  /* 0x0 */ u_char    cmd;
+  /* 0x1 */ u_char    cmdid;
+  /* 0x2 */ u_short   numsectors;
+  /* 0x4 */ u_long    lba;
+  /* 0x8 */ u_long    xferaddr;
+  /* 0xC */ u_char    logdrv;
+  /* 0xD */ u_char    numsgelements;
+  /* 0xE */ u_char    resvd;
+  /* 0xF */ u_char    busy;
+  /* 0x10*/ u_char    numstatus;
+  /* 0x11*/ u_char    status;
+  /* 0x12*/ u_char    completed[46];
+            u_char    mraid_poll;
+            u_char    mraid_ack;
+            u_char    pad[16];
+} mega_mailbox;
+
+typedef struct _mega_sglist
+{
+  u_long     address;
+  u_long     length;
+} mega_sglist;
+
+/* Queued command data */
+typedef struct _mega_scb mega_scb;
+
+struct _mega_scb
+{
+  int             idx;
+  u_long          flag;
+  Scsi_Cmnd      *SCpnt;
+  u_char          mboxData[16];
+  mega_passthru   pthru;
+  mega_sglist    *sgList;
+  mega_scb       *next;
+};
+
+/* Per-controller data */
+typedef struct _mega_host_config
+{
+  u_char               numldrv;
+  u_long               flag;
+  u_long               base;
+
+  struct tq_struct     megaTq;
+
+  /* Host adapter parameters */
+  u_char               fwVer[7];
+  u_char               biosVer[7];
+
+  struct Scsi_Host     *host;
+
+  /* The following must be DMA-able!! */
+  volatile mega_mailbox *mbox;
+  volatile mega_mailbox mailbox;
+  volatile u_char       mega_buffer[2*1024L];
+
+  u_char                max_cmds;
+  mega_scb              scbList[MAX_COMMANDS];
+} mega_host_config;
+
+extern struct proc_dir_entry proc_scsi_megaraid;
+
+const char *megaraid_info( struct Scsi_Host * );
+int        megaraid_detect( Scsi_Host_Template * );
+int        megaraid_release(struct Scsi_Host *);
+int        megaraid_command( Scsi_Cmnd * );
+int        megaraid_abort( Scsi_Cmnd * );
+int        megaraid_reset( Scsi_Cmnd *, unsigned int); 
+int        megaraid_queue( Scsi_Cmnd *, void (*done)(Scsi_Cmnd *) );
+int        megaraid_biosparam( Disk *, kdev_t, int * );
+int        megaraid_proc_info( char *buffer, char **start, off_t offset,
+                              int length, int hostno, int inout );
+
+#endif
index b1bc3607904bd99befe4226407f4ba54ee59935f..b160c29e591e38f9491037db7bf98aa84e30d9b2 100644 (file)
-#
-# Sound driver configuration
-#
-#--------
-# There is another config script which is compatible with rest of
-# the kernel. It can be activated by running 'make mkscript' in this
-# directory. Please note that this is an _experimental_ feature which
-# doesn't work with all cards (PSS, SM Wave, AudioTrix Pro, Maui).
-#--------
-#
-$MAKE -C drivers/sound config || exit 1
+bool 'ProAudioSpectrum 16 support' CONFIG_PAS
+bool 'Sound Blaster (SB, SBPro, SB16, clones) support' CONFIG_SB
+bool 'Generic OPL2/OPL3 FM synthesizer support' CONFIG_ADLIB
+bool 'Gravis Ultrasound support' CONFIG_GUS
+bool 'MPU-401 support (NOT for SB16)' CONFIG_MPU401
+bool '6850 UART Midi support' CONFIG_UART6850
+bool 'PSS (ECHO-ADI2111) support' CONFIG_PSS
+bool '16 bit sampling option of GUS (_NOT_ GUS MAX)' CONFIG_GUS16
+bool 'GUS MAX support' CONFIG_GUSMAX
+bool 'Microsoft Sound System support' CONFIG_MSS
+bool 'Ensoniq SoundScape support' CONFIG_SSCAPE
+bool 'MediaTrix AudioTrix Pro support' CONFIG_TRIX
+bool 'Support for MAD16 and/or Mozart based cards' CONFIG_MAD16
+bool 'Support for Crystal CS4232 based (PnP) cards' CONFIG_CS4232
+bool 'Support for Turtle Beach Wave Front (Maui, Tropez) synthesizers' CONFIG_MAUI
+bool '/dev/dsp and /dev/audio support' CONFIG_AUDIO
+bool 'MIDI interface support' CONFIG_MIDI
+bool 'FM synthesizer (YM3812/OPL-3) support' CONFIG_YM3812
+
+if [ "$CONFIG_SB" = "y" ]; then
+hex 'I/O base for SB Check from manual of the card' SBC_BASE 220
+fi
+
+if [ "$CONFIG_SB" = "y" ]; then
+int 'Sound Blaster IRQ Check from manual of the card' SBC_IRQ 7
+fi
+
+if [ "$CONFIG_SB" = "y" ]; then
+int 'Sound Blaster DMA 0, 1 or 3' SBC_DMA 1
+fi
+
+if [ "$CONFIG_SB" = "y" ]; then
+int 'Sound Blaster 16 bit DMA (_REQUIRED_for SB16, Jazz16, SMW) 5, 6 or 7 (use 1 for 8 bit cards)' SB_DMA2 5
+fi
+
+if [ "$CONFIG_SB" = "y" ]; then
+hex 'MPU401 I/O base of SB16, Jazz16 and ES1688 Check from manual of the card' SB_MPU_BASE 0
+fi
+
+if [ "$CONFIG_SB" = "y" ]; then
+int 'SB MPU401 IRQ (Jazz16, SM Wave and ES1688) Use -1 with SB16' SB_MPU_IRQ -1
+fi
+
+if [ "$CONFIG_PAS" = "y" ]; then
+int 'PAS16 IRQ 3, 4, 5, 7, 9, 10, 11, 12, 14 or 15' PAS_IRQ 10
+fi
+
+if [ "$CONFIG_PAS" = "y" ]; then
+int 'PAS16 DMA 0, 1, 3, 5, 6 or 7' PAS_DMA 3
+fi
+
+if [ "$CONFIG_GUS" = "y" ]; then
+hex 'I/O base for GUS 210, 220, 230, 240, 250 or 260' GUS_BASE 220
+fi
+
+if [ "$CONFIG_GUS" = "y" ]; then
+int 'GUS IRQ 3, 5, 7, 9, 11, 12 or 15' GUS_IRQ 15
+fi
+
+if [ "$CONFIG_GUS" = "y" ]; then
+int 'GUS DMA 1, 3, 5, 6 or 7' GUS_DMA 6
+fi
+
+if [ "$CONFIG_GUS" = "y" ]; then
+int 'Second DMA channel for GUS 1, 3, 5, 6 or 7' GUS_DMA2 -1
+fi
+
+if [ "$CONFIG_GUS16" = "y" ]; then
+hex 'I/O base for the 16 bit daughtercard of GUS 530, 604, E80 or F40' GUS16_BASE 530
+fi
+
+if [ "$CONFIG_GUS16" = "y" ]; then
+int 'GUS 16 bit daughtercard IRQ 3, 4, 5, 7, or 9' GUS16_IRQ 7
+fi
+
+if [ "$CONFIG_GUS16" = "y" ]; then
+int 'GUS DMA 0, 1 or 3' GUS16_DMA 3
+fi
+
+if [ "$CONFIG_MPU401" = "y" ]; then
+hex 'I/O base for MPU401 Check from manual of the card' MPU_BASE 330
+fi
+
+if [ "$CONFIG_MPU401" = "y" ]; then
+int 'MPU401 IRQ Check from manual of the card' MPU_IRQ 9
+fi
+
+if [ "$CONFIG_MAUI" = "y" ]; then
+hex 'I/O base for Maui 210, 230, 260, 290, 300, 320, 338 or 330' MAUI_BASE 330
+fi
+
+if [ "$CONFIG_MAUI" = "y" ]; then
+int 'Maui IRQ 5, 9, 12 or 15' MAUI_IRQ 9
+fi
+
+if [ "$CONFIG_UART6850" = "y" ]; then
+hex 'I/O base for UART 6850 MIDI port (Unknown)' U6850_BASE 0
+fi
+
+if [ "$CONFIG_UART6850" = "y" ]; then
+int 'UART6850 IRQ (Unknown)' U6850_IRQ -1
+fi
+
+if [ "$CONFIG_PSS" = "y" ]; then
+hex 'PSS I/O base 220 or 240' PSS_BASE 220
+fi
+
+if [ "$CONFIG_PSS" = "y" ]; then
+hex 'PSS audio I/O base 530, 604, E80 or F40' PSS_MSS_BASE 530
+fi
+
+if [ "$CONFIG_PSS" = "y" ]; then
+int 'PSS audio IRQ 7, 9, 10 or 11' PSS_MSS_IRQ 11
+fi
+
+if [ "$CONFIG_PSS" = "y" ]; then
+int 'PSS audio DMA 0, 1 or 3' PSS_MSS_DMA 3
+fi
+
+if [ "$CONFIG_PSS" = "y" ]; then
+hex 'PSS MIDI I/O base ' PSS_MPU_BASE 330
+fi
+
+if [ "$CONFIG_PSS" = "y" ]; then
+int 'PSS MIDI IRQ 3, 4, 5, 7 or 9' PSS_MPU_IRQ 9
+fi
+
+if [ "$CONFIG_MSS" = "y" ]; then
+hex 'MSS/WSS I/O base 530, 604, E80 or F40' MSS_BASE 530
+fi
 
+if [ "$CONFIG_MSS" = "y" ]; then
+int 'MSS/WSS IRQ 7, 9, 10 or 11' MSS_IRQ 11
+fi
+
+if [ "$CONFIG_MSS" = "y" ]; then
+int 'MSS/WSS DMA 0, 1 or 3' MSS_DMA 3
+fi
+
+if [ "$CONFIG_SSCAPE" = "y" ]; then
+hex 'SoundScape MIDI I/O base 320, 330, 340 or 350' SSCAPE_BASE 330
+fi
+
+if [ "$CONFIG_SSCAPE" = "y" ]; then
+int 'SoundScape MIDI IRQ ' SSCAPE_IRQ 9
+fi
+
+if [ "$CONFIG_SSCAPE" = "y" ]; then
+int 'SoundScape initialization DMA 0, 1 or 3' SSCAPE_DMA 3
+fi
+
+if [ "$CONFIG_SSCAPE" = "y" ]; then
+hex 'SoundScape audio I/O base 534, 608, E84 or F44' SSCAPE_MSS_BASE 534
+fi
+
+if [ "$CONFIG_SSCAPE" = "y" ]; then
+int 'SoundScape audio IRQ 7, 9, 10 or 11' SSCAPE_MSS_IRQ 11
+fi
+
+if [ "$CONFIG_TRIX" = "y" ]; then
+hex 'AudioTrix audio I/O base 530, 604, E80 or F40' TRIX_BASE 530
+fi
+
+if [ "$CONFIG_TRIX" = "y" ]; then
+int 'AudioTrix audio IRQ 7, 9, 10 or 11' TRIX_IRQ 11
+fi
+
+if [ "$CONFIG_TRIX" = "y" ]; then
+int 'AudioTrix audio DMA 0, 1 or 3' TRIX_DMA 0
+fi
+
+if [ "$CONFIG_TRIX" = "y" ]; then
+int 'AudioTrix second (duplex) DMA 0, 1 or 3' TRIX_DMA2 3
+fi
+
+if [ "$CONFIG_TRIX" = "y" ]; then
+hex 'AudioTrix MIDI I/O base 330, 370, 3B0 or 3F0' TRIX_MPU_BASE 330
+fi
+
+if [ "$CONFIG_TRIX" = "y" ]; then
+int 'AudioTrix MIDI IRQ 3, 4, 5, 7 or 9' TRIX_MPU_IRQ 9
+fi
+
+if [ "$CONFIG_TRIX" = "y" ]; then
+hex 'AudioTrix SB I/O base 220, 210, 230, 240, 250, 260 or 270' TRIX_SB_BASE 220
+fi
+
+if [ "$CONFIG_TRIX" = "y" ]; then
+int 'AudioTrix SB IRQ 3, 4, 5 or 7' TRIX_SB_IRQ 7
+fi
+
+if [ "$CONFIG_TRIX" = "y" ]; then
+int 'AudioTrix SB DMA 1 or 3' TRIX_SB_DMA 1
+fi
+
+if [ "$CONFIG_CS4232" = "y" ]; then
+hex 'CS4232 audio I/O base 530, 604, E80 or F40' CS4232_BASE 530
+fi
+
+if [ "$CONFIG_CS4232" = "y" ]; then
+int 'CS4232 audio IRQ 5, 7, 9, 11, 12 or 15' CS4232_IRQ 11
+fi
+
+if [ "$CONFIG_CS4232" = "y" ]; then
+int 'CS4232 audio DMA 0, 1 or 3' CS4232_DMA 0
+fi
+
+if [ "$CONFIG_CS4232" = "y" ]; then
+int 'CS4232 second (duplex) DMA 0, 1 or 3' CS4232_DMA2 3
+fi
+
+if [ "$CONFIG_CS4232" = "y" ]; then
+hex 'CS4232 MIDI I/O base 330, 370, 3B0 or 3F0' CS4232_MPU_BASE 330
+fi
+
+if [ "$CONFIG_CS4232" = "y" ]; then
+int 'CS4232 MIDI IRQ 5, 7, 9, 11, 12 or 15' CS4232_MPU_IRQ 9
+fi
+
+if [ "$CONFIG_MAD16" = "y" ]; then
+hex 'MAD16 audio I/O base 530, 604, E80 or F40' MAD16_BASE 530
+fi
+
+if [ "$CONFIG_MAD16" = "y" ]; then
+int 'MAD16 audio IRQ 7, 9, 10 or 11' MAD16_IRQ 11
+fi
+
+if [ "$CONFIG_MAD16" = "y" ]; then
+int 'MAD16 audio DMA 0, 1 or 3' MAD16_DMA 3
+fi
+
+if [ "$CONFIG_MAD16" = "y" ]; then
+int 'MAD16 second (duplex) DMA 0, 1 or 3' MAD16_DMA2 0
+fi
+
+if [ "$CONFIG_MAD16" = "y" ]; then
+hex 'MAD16 MIDI I/O base 300, 310, 320 or 330 (0 disables)' MAD16_MPU_BASE 330
+fi
+
+if [ "$CONFIG_MAD16" = "y" ]; then
+int 'MAD16 MIDI IRQ 5, 7, 9 or 10' MAD16_MPU_IRQ 9
+fi
+
+if [ "$CONFIG_AUDIO" = "y" ]; then
+int 'Audio DMA buffer size 4096, 16384, 32768 or 65536' DSP_BUFFSIZE 65536
+fi
+#
+$MAKE -C drivers/sound kernelconfig || exit 1
 bool 'Additional low level drivers' CONFIG_LOWLEVEL_SOUND
 
 if [ "$CONFIG_LOWLEVEL_SOUND" = "y" ]; then
index 24d3d32336d5711e58d62090124b9c781fed069e..ec683c102d96c0762c898d36e945639640ecbc07 100644 (file)
@@ -1196,7 +1196,7 @@ probe_sbmpu (struct address_info *hw_config)
     case MDL_SB16:
       if (hw_config->io_base != 0x300 && hw_config->io_base != 0x330)
        {
-         printk ("SB16: Invalid MIDI port %x\n", hw_config->irq);
+         printk ("SB16: Invalid MIDI port %x\n", hw_config->io_base);
          return 0;
        }
       hw_config->name = "Sound Blaster 16";
index 337236a304931073ffad9291ab46623dfe2e1235..1072f4be09a5f9c204578eff99c97f6e986182b8 100644 (file)
@@ -203,8 +203,11 @@ int block_read(struct inode * inode, struct file * filp,
                        blocks = rblocks;
                
        }
-       if (block + blocks > size)
+       if (block + blocks > size) {
                blocks = size - block;
+               if (blocks == 0)
+                       return 0;
+       }
 
        /* We do this in a two stage process.  We first try to request
           as many blocks as we can, then we wait for the first one to
index 771d98a8fe90f61b512d72d97bef530355872678..668220e5c4905987450373acd0098f02d0b7f7e3 100644 (file)
@@ -219,7 +219,7 @@ int mem_mmap(struct inode * inode, struct file * file,
        pgd_t *src_dir, *dest_dir;
        pmd_t *src_middle, *dest_middle;
        pte_t *src_table, *dest_table;
-       unsigned long stmp, dtmp;
+       unsigned long stmp, dtmp, mapnr;
        struct vm_area_struct *src_vma = NULL;
 
        /* Get the source's task information */
@@ -299,7 +299,9 @@ int mem_mmap(struct inode * inode, struct file * file,
 
                set_pte(src_table, pte_mkdirty(*src_table));
                set_pte(dest_table, *src_table);
-               mem_map[MAP_NR(pte_page(*src_table))].count++;
+                mapnr = MAP_NR(pte_page(*src_table));
+               if (mapnr < MAP_NR(high_memory))
+                        mem_map[mapnr].count++;
 
                stmp += PAGE_SIZE;
                dtmp += PAGE_SIZE;
index 34c4b5e64313da05d7e7a901743f712aa8bd947b..5620b5c40a2221681c71060ca9d4d3da3b9fc26e 100644 (file)
@@ -757,9 +757,9 @@ struct cyclades_port {
 /* Custom Registers */
 
 #define        CyPLX_VER       (0x3400)
-#define        PLX_9050        0x11
-#define        PLX_9060        0x12
-#define        PLX_9080        0x13
+#define        PLX_9050        0x0b
+#define        PLX_9060        0x0c
+#define        PLX_9080        0x0d
 
 /***************************************************************************/
 
index d5533077a0357ee738113c03a9be92978934d1b4..aa04dd9017ec15d5762c794741ee0dc7d8e06749 100644 (file)
 #define PCI_DEVICE_ID_ADAPTEC_7884     0x8478
 #define PCI_DEVICE_ID_ADAPTEC_1030     0x8b78
 
+#define PCI_VENDOR_ID_ADAPTEC2         0x9005
+#define PCI_DEVICE_ID_ADAPTEC2_2940U2  0x0010
+#define PCI_DEVICE_ID_ADAPTEC2_7890    0x001f
+#define PCI_DEVICE_ID_ADAPTEC2_3940U2  0x0050
+#define PCI_DEVICE_ID_ADAPTEC2_7896    0x005f
+
 #define PCI_VENDOR_ID_ATRONICS         0x907f
 #define PCI_DEVICE_ID_ATRONICS_2015    0x2015
 
index fc1a4b8f5a9ba248e20f61cdb4db8c6e042fd654..bbb74dd2e009c0660ad5b356a76f9b4b2dc0cd01 100644 (file)
@@ -141,6 +141,7 @@ enum scsi_directory_inos {
        PROC_SCSI_AM53C974,
        PROC_SCSI_SSC,
        PROC_SCSI_NCR53C406A,
+       PROC_SCSI_MEGARAID,
        PROC_SCSI_PPA,
        PROC_SCSI_ESP,
        PROC_SCSI_A3000,
index 49ea2a3922155372c929f0190b0c0c09222fdcd2..998465d7d0296db080b8226da15c64de34638624 100644 (file)
@@ -197,6 +197,9 @@ asmlinkage int sys_reboot(int magic, int magic_too, int flag)
        else if (!flag)
                C_A_D = 0;
        else if (flag == 0xCDEF0123) {
+#ifdef CONFIG_SCSI_GDTH
+               gdth_halt();
+#endif
                printk(KERN_EMERG "System halted\n");
                sys_kill(-1, SIGKILL);
 #if defined(CONFIG_APM) && defined(CONFIG_APM_POWER_OFF)
index 0210b29d8910e21927d58a79f58c992ec6477d1b..ab57b0591a45ab137d8e2eaffb23b6bca2ef11f4 100644 (file)
@@ -2053,11 +2053,12 @@ static void tcp_close(struct sock *sk, unsigned long timeout)
                        tcp_reset_msl_timer(sk, TIME_CLOSE, TCP_FIN_TIMEOUT);
        }
 
-       sk->dead = 1;
        release_sock(sk);
 
        if(sk->state == TCP_CLOSE)
                tcp_v4_unhash(sk);
+
+       sk->dead = 1;
 }