]> git.hungrycats.org Git - linux/commitdiff
v2.4.6.2 -> v2.4.6.3
authorLinus Torvalds <torvalds@athlon.transmeta.com>
Tue, 5 Feb 2002 03:10:34 +0000 (19:10 -0800)
committerLinus Torvalds <torvalds@athlon.transmeta.com>
Tue, 5 Feb 2002 03:10:34 +0000 (19:10 -0800)
  - merge with Alan (SCSI subsystem)
  - Jeff Garzik: make serial driver PCI hotplug-aware

48 files changed:
Makefile
arch/i386/boot/video.S
arch/i386/kernel/setup.c
drivers/char/serial.c
drivers/scsi/BusLogic.c
drivers/scsi/BusLogic.h
drivers/scsi/ChangeLog.ncr53c8xx
drivers/scsi/ChangeLog.sym53c8xx
drivers/scsi/Config.in
drivers/scsi/FlashPoint.c
drivers/scsi/README.aic7xxx [new file with mode: 0644]
drivers/scsi/README.ncr53c8xx
drivers/scsi/aic7xxx/aic7xxx_linux_pci.c
drivers/scsi/aic7xxx_old.c
drivers/scsi/aic7xxx_old/README.aic7xxx
drivers/scsi/aic7xxx_old/aic7xxx.reg
drivers/scsi/aic7xxx_old/aic7xxx.seq
drivers/scsi/aic7xxx_old/aic7xxx_proc.c
drivers/scsi/aic7xxx_old/aic7xxx_reg.h
drivers/scsi/aic7xxx_old/aic7xxx_seq.c
drivers/scsi/dec_esp.c
drivers/scsi/hosts.c
drivers/scsi/hosts.h
drivers/scsi/ncr53c8xx.c
drivers/scsi/qlogicisp.c
drivers/scsi/qlogicpti.c
drivers/scsi/scsi.c
drivers/scsi/scsi.h
drivers/scsi/scsi_error.c
drivers/scsi/scsi_ioctl.c
drivers/scsi/scsi_lib.c
drivers/scsi/scsi_merge.c
drivers/scsi/scsi_obsolete.c
drivers/scsi/scsi_scan.c
drivers/scsi/sd.c
drivers/scsi/sr.c
drivers/scsi/sr_ioctl.c
drivers/scsi/sr_vendor.c
drivers/scsi/st.c
drivers/scsi/sym53c8xx.c
drivers/scsi/sym53c8xx_comm.h
drivers/scsi/sym53c8xx_defs.h
drivers/video/fbcon.c
fs/dcache.c
fs/inode.c
include/linux/serialP.h
init/main.c
mm/vmscan.c

index c28985e62dd5907b05444f1207a41f40d2a17321..6df0bb486ad82ad2de38e3271afef3689ed002bf 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
 SUBLEVEL = 7
-EXTRAVERSION =-pre2
+EXTRAVERSION =-pre3
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
index 745f47275179584addffb78016aaf60853e5f547..1a49d97c91107476fc3643415af781687d940b7b 100644 (file)
@@ -496,7 +496,7 @@ setspc:     xorb    %bh, %bh                        # Set special mode
        jnc     setbad
        
        addw    %bx, %bx
-       .word   0xa7ff, spec_inits              # JMP [BX+spec_inits]
+       jmp     *spec_inits(%bx)
 
 setmenu:
        orb     %al, %al                        # 80x25 is an exception
@@ -1008,7 +1008,7 @@ vesa_modes:
 vesa1:
 # gas version 2.9.1, using BFD version 2.9.1.0.23 buggers the next inst.
 # XXX: lodsw   %gs:(%si), %ax                  # Get next mode in the list
-       .byte   0x65, 0xAD                      # %gs seg prefix + lodsw
+       gs; lodsw
        cmpw    $0xffff, %ax                    # End of the table?
        jz      vesar
        
index 9d349da28d322c7757b2cb94da951d36f76718f8..134f9d004cd0988a6a715c24231d8a810aada45d 100644 (file)
@@ -1123,7 +1123,6 @@ __asm__(".align 4\nvide: ret");
 static int __init init_amd(struct cpuinfo_x86 *c)
 {
        u32 l, h;
-       unsigned long flags;
        int mbytes = max_mapnr >> (20-PAGE_SHIFT);
        int r;
 
@@ -1187,14 +1186,13 @@ static int __init init_amd(struct cpuinfo_x86 *c)
                                        mbytes=508;
                                        
                                rdmsr(0xC0000082, l, h);
-                               if((l&0x0000FFFF)==0)
-                               {               
+                               if ((l&0x0000FFFF)==0) {
+                                       unsigned long flags;
                                        l=(1<<0)|((mbytes/4)<<1);
-                                       save_flags(flags);
-                                       __cli();
+                                       local_irq_save(flags);
                                        __asm__ __volatile__ ("wbinvd": : :"memory");
                                        wrmsr(0xC0000082, l, h);
-                                       restore_flags(flags);
+                                       local_irq_restore(flags);
                                        printk(KERN_INFO "Enabling old style K6 write allocation for %d Mb\n",
                                                mbytes);
                                        
@@ -1209,14 +1207,13 @@ static int __init init_amd(struct cpuinfo_x86 *c)
                                        mbytes=4092;
 
                                rdmsr(0xC0000082, l, h);
-                               if((l&0xFFFF0000)==0)
-                               {
+                               if ((l&0xFFFF0000)==0) {
+                                       unsigned long flags;
                                        l=((mbytes>>2)<<22)|(1<<16);
-                                       save_flags(flags);
-                                       __cli();
+                                       local_irq_save(flags);
                                        __asm__ __volatile__ ("wbinvd": : :"memory");
                                        wrmsr(0xC0000082, l, h);
-                                       restore_flags(flags);
+                                       local_irq_restore(flags);
                                        printk(KERN_INFO "Enabling new style K6 write allocation for %d Mb\n",
                                                mbytes);
                                }
@@ -1243,12 +1240,13 @@ static int __init init_amd(struct cpuinfo_x86 *c)
 /*
  * Read Cyrix DEVID registers (DIR) to get more detailed info. about the CPU
  */
-static inline void do_cyrix_devid(unsigned char *dir0, unsigned char *dir1)
+static void do_cyrix_devid(unsigned char *dir0, unsigned char *dir1)
 {
        unsigned char ccr2, ccr3;
+       unsigned long flags;
 
        /* we test for DEVID by checking whether CCR3 is writable */
-       cli();
+       local_irq_save(flags);
        ccr3 = getCx86(CX86_CCR3);
        setCx86(CX86_CCR3, ccr3 ^ 0x80);
        getCx86(0xc0);   /* dummy to change bus */
@@ -1272,7 +1270,7 @@ static inline void do_cyrix_devid(unsigned char *dir0, unsigned char *dir1)
                *dir0 = getCx86(CX86_DIR0);
                *dir1 = getCx86(CX86_DIR1);
        }
-       sti();
+       local_irq_restore(flags);
 }
 
 /*
@@ -1316,15 +1314,16 @@ static void __init check_cx686_slop(struct cpuinfo_x86 *c)
 {
        if (Cx86_dir0_msb == 3) {
                unsigned char ccr3, ccr5;
+               unsigned long flags;
 
-               cli();
+               local_irq_save(flags);
                ccr3 = getCx86(CX86_CCR3);
                setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* enable MAPEN  */
                ccr5 = getCx86(CX86_CCR5);
                if (ccr5 & 2)
                        setCx86(CX86_CCR5, ccr5 & 0xfd);  /* reset SLOP */
                setCx86(CX86_CCR3, ccr3);                 /* disable MAPEN */
-               sti();
+               local_irq_restore(flags);
 
                if (ccr5 & 2) { /* possible wrong calibration done */
                        printk(KERN_INFO "Recalibrating delay loop with SLOP bit reset\n");
@@ -2100,15 +2099,16 @@ static int __init id_and_try_enable_cpuid(struct cpuinfo_x86 *c)
                if (dir0 == 5 || dir0 == 3)
                {
                        unsigned char ccr3, ccr4;
+                       unsigned long flags;
 
                        printk(KERN_INFO "Enabling CPUID on Cyrix processor.\n");
-                       cli();
+                       local_irq_save(flags);
                        ccr3 = getCx86(CX86_CCR3);
                        setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* enable MAPEN  */
                        ccr4 = getCx86(CX86_CCR4);
                        setCx86(CX86_CCR4, ccr4 | 0x80);          /* enable cpuid  */
                        setCx86(CX86_CCR3, ccr3);                 /* disable MAPEN */
-                       sti();
+                       local_irq_restore(flags);
                }
        } else
 
index d45a3b29c259e3c98aa442bfd97ec9d309f55af0..646cfb103bf8fc05ebd14431b049c3ed4d9321ba 100644 (file)
@@ -59,8 +59,8 @@
  *
  */
 
-static char *serial_version = "5.05a";
-static char *serial_revdate = "2001-03-20";
+static char *serial_version = "5.05b";
+static char *serial_revdate = "2001-05-03";
 
 /*
  * Serial driver configuration section.  Here are the various options:
@@ -3917,14 +3917,14 @@ static void __devinit start_pci_pnp_board(struct pci_dev *dev,
 
        if (PREPARE_FUNC(dev) && (PREPARE_FUNC(dev))(dev) < 0) {
               printk("serial: PNP device '");
-              printk_pnp_dev_id(board->vendor, board->device);
+              printk_pnp_dev_id(dev->vendor, dev->device);
               printk("' prepare failed\n");
               return;
        }
 
        if (ACTIVATE_FUNC(dev) && (ACTIVATE_FUNC(dev))(dev) < 0) {
               printk("serial: PNP device '");
-              printk_pnp_dev_id(board->vendor, board->device);
+              printk_pnp_dev_id(dev->vendor, dev->device);
               printk("' activate failed\n");
               return;
        }
@@ -4112,7 +4112,7 @@ pci_inteli960ni_fn(struct pci_dev *dev,
 {
        unsigned long oldval;
        
-       if (!(board->subdevice & 0x1000))
+       if (!(pci_get_subdevice(dev) & 0x1000))
                return(-1);
 
        if (!enable) /* is there something to deinit? */
@@ -4178,7 +4178,7 @@ pci_timedia_fn(struct pci_dev *dev, struct pci_board *board, int enable)
        for (i=0; timedia_data[i].num; i++) {
                ids = timedia_data[i].ids;
                for (j=0; ids[j]; j++) {
-                       if (pci_get_subvendor(dev) == ids[j]) {
+                       if (pci_get_subdevice(dev) == ids[j]) {
                                board->num_ports = timedia_data[i].num;
                                return 0;
                        }
@@ -4187,530 +4187,661 @@ pci_timedia_fn(struct pci_dev *dev, struct pci_board *board, int enable)
        return 0;
 }
 
+static int
+#ifndef MODULE
+__devinit
+#endif
+pci_xircom_fn(struct pci_dev *dev, struct pci_board *board, int enable)
+{
+       __set_current_state(TASK_UNINTERRUPTIBLE);
+       schedule_timeout(HZ/10);
+       return 0;
+}
 
 /*
  * This is the configuration table for all of the PCI serial boards
- * which we support.
+ * which we support.  It is directly indexed by the pci_board_num_t enum
+ * value, which is encoded in the pci_device_id PCI probe table's
+ * driver_data member.
  */
+enum pci_board_num_t {
+       pbn_b0_1_115200,
+       pbn_default = 0,
+
+       pbn_b0_2_115200,
+       pbn_b0_4_115200,
+
+       pbn_b0_1_921600,
+       pbn_b0_2_921600,
+       pbn_b0_4_921600,
+
+       pbn_b0_bt_1_115200,
+       pbn_b0_bt_2_115200,
+       pbn_b0_bt_1_460800,
+       pbn_b0_bt_2_460800,
+
+       pbn_b1_1_115200,
+       pbn_b1_2_115200,
+       pbn_b1_4_115200,
+       pbn_b1_8_115200,
+
+       pbn_b1_2_921600,
+       pbn_b1_4_921600,
+       pbn_b1_8_921600,
+
+       pbn_b1_2_1382400,
+       pbn_b1_4_1382400,
+       pbn_b1_8_1382400,
+
+       pbn_b2_8_115200,
+       pbn_b2_4_460800,
+       pbn_b2_8_460800,
+       pbn_b2_16_460800,
+       pbn_b2_4_921600,
+       pbn_b2_8_921600,
+
+       pbn_b2_bt_1_115200,
+       pbn_b2_bt_2_115200,
+       pbn_b2_bt_4_115200,
+       pbn_b2_bt_2_921600,
+
+       pbn_panacom,
+       pbn_panacom2,
+       pbn_panacom4,
+       pbn_plx_romulus,
+       pbn_oxsemi,
+       pbn_timedia,
+       pbn_intel_i960,
+       pbn_sgi_ioc3,
+#ifdef CONFIG_DDB5074
+       pbn_nec_nile4,
+#endif
+#if 0
+       pbn_dci_pccom8,
+#endif
+       pbn_xircom_combo,
+
+       pbn_siig10x_0,
+       pbn_siig10x_1,
+       pbn_siig10x_2,
+       pbn_siig10x_4,
+       pbn_siig20x_0,
+       pbn_siig20x_2,
+       pbn_siig20x_4,
+       
+       pbn_computone_4,
+       pbn_computone_6,
+       pbn_computone_8,
+};
+
 static struct pci_board pci_boards[] __devinitdata = {
        /*
-        * Vendor ID,   Device ID,
-        * Subvendor ID,        Subdevice ID,
         * PCI Flags, Number of Ports, Base (Maximum) Baud Rate,
         * Offset to get to next UART's registers,
         * Register shift to use for memory-mapped I/O,
         * Initialization function, first UART offset
         */
+
+       /* Generic serial board, pbn_b0_1_115200, pbn_default */
+       { SPCI_FL_BASE0, 1, 115200 },           /* pbn_b0_1_115200,
+                                                  pbn_default */
+
+       { SPCI_FL_BASE0, 2, 115200 },           /* pbn_b0_2_115200 */
+       { SPCI_FL_BASE0, 4, 115200 },           /* pbn_b0_4_115200 */
+
+       { SPCI_FL_BASE0, 1, 921600 },           /* pbn_b0_1_921600 */
+       { SPCI_FL_BASE0, 2, 921600 },           /* pbn_b0_2_921600 */
+       { SPCI_FL_BASE0, 4, 921600 },           /* pbn_b0_4_921600 */
+
+       { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 }, /* pbn_b0_bt_1_115200 */
+       { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 }, /* pbn_b0_bt_2_115200 */
+       { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 460800 }, /* pbn_b0_bt_1_460800 */
+       { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 460800 }, /* pbn_b0_bt_2_460800 */
+
+       { SPCI_FL_BASE1, 1, 115200 },           /* pbn_b1_1_115200 */
+       { SPCI_FL_BASE1, 2, 115200 },           /* pbn_b1_2_115200 */
+       { SPCI_FL_BASE1, 4, 115200 },           /* pbn_b1_4_115200 */
+       { SPCI_FL_BASE1, 8, 115200 },           /* pbn_b1_8_115200 */
+
+       { SPCI_FL_BASE1, 2, 921600 },           /* pbn_b1_2_921600 */
+       { SPCI_FL_BASE1, 4, 921600 },           /* pbn_b1_4_921600 */
+       { SPCI_FL_BASE1, 8, 921600 },           /* pbn_b1_8_921600 */
+
+       { SPCI_FL_BASE1, 2, 1382400 },          /* pbn_b1_2_1382400 */
+       { SPCI_FL_BASE1, 4, 1382400 },          /* pbn_b1_4_1382400 */
+       { SPCI_FL_BASE1, 8, 1382400 },          /* pbn_b1_8_1382400 */
+
+       { SPCI_FL_BASE2, 8, 115200 },           /* pbn_b2_8_115200 */
+       { SPCI_FL_BASE2, 4, 460800 },           /* pbn_b2_4_460800 */
+       { SPCI_FL_BASE2, 8, 460800 },           /* pbn_b2_8_460800 */
+       { SPCI_FL_BASE2, 16, 460800 },          /* pbn_b2_16_460800 */
+       { SPCI_FL_BASE2, 4, 921600 },           /* pbn_b2_4_921600 */
+       { SPCI_FL_BASE2, 8, 921600 },           /* pbn_b2_8_921600 */
+
+       { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 1, 115200 }, /* pbn_b2_bt_1_115200 */
+       { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 115200 }, /* pbn_b2_bt_2_115200 */
+       { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 115200 }, /* pbn_b2_bt_4_115200 */
+       { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600 }, /* pbn_b2_bt_2_921600 */
+
+       { SPCI_FL_BASE2, 2, 921600, /* IOMEM */            /* pbn_panacom */
+               0x400, 7, pci_plx9050_fn },
+       { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600,   /* pbn_panacom2 */
+               0x400, 7, pci_plx9050_fn },
+       { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 921600,   /* pbn_panacom4 */
+               0x400, 7, pci_plx9050_fn },
+       { SPCI_FL_BASE2, 4, 921600,                        /* pbn_plx_romulus */
+               0x20, 2, pci_plx9050_fn, 0x03 },
+               /* This board uses the size of PCI Base region 0 to
+                * signal now many ports are available */
+       { SPCI_FL_BASE0 | SPCI_FL_REGION_SZ_CAP, 32, 115200 }, /* pbn_oxsemi */
+       { SPCI_FL_BASE_TABLE, 1, 921600,                   /* pbn_timedia */
+               0, 0, pci_timedia_fn },
+       /* EKF addition for i960 Boards form EKF with serial port */
+       { SPCI_FL_BASE0, 32, 921600, /* max 256 ports */   /* pbn_intel_i960 */
+               8<<2, 2, pci_inteli960ni_fn, 0x10000},
+       { SPCI_FL_BASE0 | SPCI_FL_IRQRESOURCE,             /* pbn_sgi_ioc3 */
+               1, 458333, 0, 0, 0, 0x20178 },
+#ifdef CONFIG_DDB5074
+       /*
+        * NEC Vrc-5074 (Nile 4) builtin UART.
+        * Conditionally compiled in since this is a motherboard device.
+        */
+       { SPCI_FL_BASE0, 1, 520833,                        /* pbn_nec_nile4 */
+               64, 3, NULL, 0x300 },
+#endif
+#if 0  /* PCI_DEVICE_ID_DCI_PCCOM8 ? */                   /* pbn_dci_pccom8 */
+       { SPCI_FL_BASE3, 8, 115200, 8 },
+#endif
+       { SPCI_FL_BASE0, 1, 115200,                       /* pbn_xircom_combo */
+               0, 0, pci_xircom_fn },
+
+       { SPCI_FL_BASE2, 1, 460800,                        /* pbn_siig10x_0 */
+               0, 0, pci_siig10x_fn },
+       { SPCI_FL_BASE2, 1, 921600,                        /* pbn_siig10x_1 */
+               0, 0, pci_siig10x_fn },
+       { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600,   /* pbn_siig10x_2 */
+               0, 0, pci_siig10x_fn },
+       { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 921600,   /* pbn_siig10x_4 */
+               0, 0, pci_siig10x_fn },
+       { SPCI_FL_BASE0, 1, 921600,                        /* pbn_siix20x_0 */
+               0, 0, pci_siig20x_fn },
+       { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600,   /* pbn_siix20x_2 */
+               0, 0, pci_siig20x_fn },
+       { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 4, 921600,   /* pbn_siix20x_4 */
+               0, 0, pci_siig20x_fn },
+
+       { SPCI_FL_BASE0, 4, 921600, /* IOMEM */            /* pbn_computone_4 */
+               0x40, 2, NULL, 0x200 },
+       { SPCI_FL_BASE0, 6, 921600, /* IOMEM */            /* pbn_computone_6 */
+               0x40, 2, NULL, 0x200 },
+       { SPCI_FL_BASE0, 8, 921600, /* IOMEM */            /* pbn_computone_8 */
+               0x40, 2, NULL, 0x200 },
+};
+
+/*
+ * Given a complete unknown PCI device, try to use some heuristics to
+ * guess what the configuration might be, based on the pitiful PCI
+ * serial specs.  Returns 0 on success, 1 on failure.
+ */
+static int __devinit serial_pci_guess_board(struct pci_dev *dev,
+                                          struct pci_board *board)
+{
+       int     num_iomem = 0, num_port = 0, first_port = -1;
+       int     i;
+       
+       /*
+        * If it is not a communications device or the programming
+        * interface is greater than 6, give up.
+        *
+        * (Should we try to make guesses for multiport serial devices
+        * later?) 
+        */
+       if ((((dev->class >> 8) != PCI_CLASS_COMMUNICATION_SERIAL) &&
+           ((dev->class >> 8) != PCI_CLASS_COMMUNICATION_MODEM)) ||
+           (dev->class & 0xff) > 6)
+               return 1;
+
+       for (i=0; i < 6; i++) {
+               if (IS_PCI_REGION_IOPORT(dev, i)) {
+                       num_port++;
+                       if (first_port == -1)
+                               first_port = i;
+               }
+               if (IS_PCI_REGION_IOMEM(dev, i))
+                       num_iomem++;
+       }
+
+       /*
+        * If there is 1 or 0 iomem regions, and exactly one port, use
+        * it.
+        */
+       if (num_iomem <= 1 && num_port == 1) {
+               board->flags = first_port;
+               return 0;
+       }
+       return 1;
+}
+
+static int __devinit serial_init_one(struct pci_dev *dev,
+                                    const struct pci_device_id *ent)
+{
+       struct pci_board *board, tmp;
+       int rc;
+
+       board = &pci_boards[ent->driver_data];
+
+       rc = pci_enable_device(dev);
+       if (rc) return rc;
+
+       if (ent->driver_data == pbn_default &&
+           serial_pci_guess_board(dev, board))
+               return -ENODEV;
+       else if (serial_pci_guess_board(dev, &tmp) == 0) {
+               printk(KERN_INFO "Redundant entry in serial pci_table.  "
+                      "Please send the output of\n"
+                      "lspci -vv, this message (%d,%d,%d,%d)\n"
+                      "and the manufacturer and name of "
+                      "serial board or modem board\n"
+                      "to serial-pci-info@lists.sourceforge.net.\n",
+                      dev->vendor, dev->device,
+                      pci_get_subvendor(dev), pci_get_subdevice(dev));
+       }
+                      
+       start_pci_pnp_board(dev, board);
+
+       return 0;
+}
+
+static void __devexit serial_remove_one(struct pci_dev *dev)
+{
+       int     i;
+
+       /*
+        * Iterate through all of the ports finding those that belong
+        * to this PCI device.
+        */
+       for(i = 0; i < NR_PORTS; i++) {
+               if (rs_table[i].dev != dev)
+                       continue;
+               unregister_serial(i);
+               rs_table[i].dev = 0;
+       }
+       /*
+        * Now execute any board-specific shutdown procedure
+        */
+       for (i=0; i < NR_PCI_BOARDS; i++) {
+               struct pci_board_inst *brd = &serial_pci_board[i];
+
+               if (serial_pci_board[i].dev != dev)
+                       continue;
+               if (brd->board.init_fn)
+                       (brd->board.init_fn)(brd->dev, &brd->board, 0);
+               if (DEACTIVATE_FUNC(brd->dev))
+                       (DEACTIVATE_FUNC(brd->dev))(brd->dev);
+               serial_pci_board[i].dev = 0;
+       }
+}
+
+
+static struct pci_device_id serial_pci_tbl[] __devinitdata = {
        {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
                PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232,
-               SPCI_FL_BASE1, 8, 1382400 },
+               PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232, 0, 0,
+               pbn_b1_8_1382400 },
        {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
                PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232,
-               SPCI_FL_BASE1, 4, 1382400 },
+               PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232, 0, 0,
+               pbn_b1_4_1382400 },
        {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
                PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232,
-               SPCI_FL_BASE1, 2, 1382400 },
+               PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232, 0, 0,
+               pbn_b1_2_1382400 },
        {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
                PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232,
-               SPCI_FL_BASE1, 8, 1382400 },
+               PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232, 0, 0,
+               pbn_b1_8_1382400 },
        {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
                PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232,
-               SPCI_FL_BASE1, 4, 1382400 },
+               PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232, 0, 0,
+               pbn_b1_4_1382400 },
        {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
                PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232,
-               SPCI_FL_BASE1, 2, 1382400 },
+               PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232, 0, 0,
+               pbn_b1_2_1382400 },
        {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
                PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485,
-               SPCI_FL_BASE1, 8, 921600 },
+               PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485, 0, 0,
+               pbn_b1_8_921600 },
        {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
                PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_4_4,
-               SPCI_FL_BASE1, 8, 921600 },
+               PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_4_4, 0, 0,
+               pbn_b1_8_921600 },
        {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
                PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485,
-               SPCI_FL_BASE1, 4, 921600 },
+               PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485, 0, 0,
+               pbn_b1_4_921600 },
        {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
                PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485_2_2,
-               SPCI_FL_BASE1, 4, 921600 },
+               PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485_2_2, 0, 0,
+               pbn_b1_4_921600 },
        {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
                PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_485,
-               SPCI_FL_BASE1, 2, 921600 },
+               PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_485, 0, 0,
+               pbn_b1_2_921600 },
        {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
                PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_2_6,
-               SPCI_FL_BASE1, 8, 921600 },
+               PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_2_6, 0, 0,
+               pbn_b1_8_921600 },
        {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
                PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_BH081101V1,
-               SPCI_FL_BASE1, 8, 921600 },
+               PCI_SUBDEVICE_ID_CONNECT_TECH_BH081101V1, 0, 0,
+               pbn_b1_8_921600 },
        {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
                PCI_SUBVENDOR_ID_CONNECT_TECH,
-               PCI_SUBDEVICE_ID_CONNECT_TECH_BH041101V1,
-               SPCI_FL_BASE1, 4, 921600 },
+               PCI_SUBDEVICE_ID_CONNECT_TECH_BH041101V1, 0, 0,
+               pbn_b1_4_921600 },
+
        {       PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_U530,
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 1, 115200 },
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+               pbn_b2_bt_1_115200 },
        {       PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM2,
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 115200 },
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+               pbn_b2_bt_2_115200 },
        {       PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM422,
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 115200 },
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+               pbn_b2_bt_4_115200 },
        {       PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM232,
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 115200 },
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+               pbn_b2_bt_2_115200 },
        {       PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM4,
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 115200 },
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+               pbn_b2_bt_4_115200 },
        {       PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM8,
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE2, 8, 115200 },
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+               pbn_b2_8_115200 },
+
        {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_GTEK_SERIAL2,
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 115200 },
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b2_bt_2_115200 },
        {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM200,
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600 },
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b2_bt_2_921600 },
        /* VScom SPCOM800, from sl@s.pl */
        {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM800, 
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE2, 8, 921600 },
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+               pbn_b2_8_921600 },
        {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_1077,
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE2, 4, 921600 },
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+               pbn_b2_4_921600 },
        {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
                PCI_SUBVENDOR_ID_KEYSPAN,
-               PCI_SUBDEVICE_ID_KEYSPAN_SX2,
-               SPCI_FL_BASE2, 2, 921600, /* IOMEM */
-               0x400, 7, pci_plx9050_fn },
+               PCI_SUBDEVICE_ID_KEYSPAN_SX2, 0, 0,
+               pbn_panacom },
        {       PCI_VENDOR_ID_PANACOM, PCI_DEVICE_ID_PANACOM_QUADMODEM,
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 921600,
-               0x400, 7, pci_plx9050_fn },
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_panacom4 },
        {       PCI_VENDOR_ID_PANACOM, PCI_DEVICE_ID_PANACOM_DUALMODEM,
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600,
-               0x400, 7, pci_plx9050_fn },
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_panacom2 },
        {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
                PCI_SUBVENDOR_ID_CHASE_PCIFAST,
-               PCI_SUBDEVICE_ID_CHASE_PCIFAST4,
-               SPCI_FL_BASE2, 4, 460800 },
+               PCI_SUBDEVICE_ID_CHASE_PCIFAST4, 0, 0, 
+               pbn_b2_4_460800 },
        {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
                PCI_SUBVENDOR_ID_CHASE_PCIFAST,
-               PCI_SUBDEVICE_ID_CHASE_PCIFAST8,
-               SPCI_FL_BASE2, 8, 460800 },
+               PCI_SUBDEVICE_ID_CHASE_PCIFAST8, 0, 0, 
+               pbn_b2_8_460800 },
        {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
                PCI_SUBVENDOR_ID_CHASE_PCIFAST,
-               PCI_SUBDEVICE_ID_CHASE_PCIFAST16,
-               SPCI_FL_BASE2, 16, 460800 },
+               PCI_SUBDEVICE_ID_CHASE_PCIFAST16, 0, 0, 
+               pbn_b2_16_460800 },
        {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
                PCI_SUBVENDOR_ID_CHASE_PCIFAST,
-               PCI_SUBDEVICE_ID_CHASE_PCIFAST16FMC,
-               SPCI_FL_BASE2, 16, 460800 },
+               PCI_SUBDEVICE_ID_CHASE_PCIFAST16FMC, 0, 0, 
+               pbn_b2_16_460800 },
        {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
                PCI_SUBVENDOR_ID_CHASE_PCIRAS,
-               PCI_SUBDEVICE_ID_CHASE_PCIRAS4,
-               SPCI_FL_BASE2, 4, 460800 },
+               PCI_SUBDEVICE_ID_CHASE_PCIRAS4, 0, 0, 
+               pbn_b2_4_460800 },
        {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
                PCI_SUBVENDOR_ID_CHASE_PCIRAS,
-               PCI_SUBDEVICE_ID_CHASE_PCIRAS8,
-               SPCI_FL_BASE2, 8, 460800 },
+               PCI_SUBDEVICE_ID_CHASE_PCIRAS8, 0, 0, 
+               pbn_b2_8_460800 },
        /* Megawolf Romulus PCI Serial Card, from Mike Hudson */
        /* (Exoray@isys.ca) */
        {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_ROMULUS,
-               0x10b5, 0x106a,
-               SPCI_FL_BASE2, 4, 921600,
-               0x20, 2, pci_plx9050_fn, 0x03 },
+               0x10b5, 0x106a, 0, 0,
+               pbn_plx_romulus },
        {       PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSC100,
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE1, 4, 115200 },
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+               pbn_b1_4_115200 },
        {       PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSC100,
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE1, 2, 115200 },
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+               pbn_b1_2_115200 },
        {       PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESC100D,
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE1, 8, 115200 },
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+               pbn_b1_8_115200 },
        {       PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESC100M,
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE1, 8, 115200 },
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+               pbn_b1_8_115200 },
        {       PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_OXSEMI_16PCI954,
-               PCI_VENDOR_ID_SPECIALIX, PCI_SUBDEVICE_ID_SPECIALIX_SPEED4,
-               SPCI_FL_BASE0 , 4, 921600 },
+               PCI_VENDOR_ID_SPECIALIX, PCI_SUBDEVICE_ID_SPECIALIX_SPEED4, 0, 0, 
+               pbn_b0_4_921600 },
        {       PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954,
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE0 , 4, 115200 },
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+               pbn_b0_4_115200 },
        {       PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI952,
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE0 , 2, 115200 },
-               /* This board uses the size of PCI Base region 0 to
-                * signal now many ports are available */
-       {       PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI95N,
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE0 | SPCI_FL_REGION_SZ_CAP, 32, 115200 },
-       {       PCI_VENDOR_ID_TIMEDIA, PCI_DEVICE_ID_TIMEDIA_1889,
-               PCI_VENDOR_ID_TIMEDIA, PCI_ANY_ID,
-               SPCI_FL_BASE_TABLE, 1, 921600,
-               0, 0, pci_timedia_fn },
-       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DSERIAL,
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 },
-       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATRO_A,
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 },
-       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATRO_B,
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 },
-       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PORT_PLUS,
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 460800 },
-       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUAD_A,
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 460800 },
-       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUAD_B,
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 460800 },
-       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_SSERIAL,
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 },
-       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PORT_650,
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 460800 },
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+               pbn_b0_2_115200 },
+
+       /* Digitan DS560-558, from jimd@esoft.com */
+       {       PCI_VENDOR_ID_ATT, PCI_DEVICE_ID_ATT_VENUS_MODEM,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+               pbn_b1_1_115200 },
+
+       /* 3Com US Robotics 56k Voice Internal PCI model 5610 */
+       {       PCI_VENDOR_ID_USR, 0x1008,
+               PCI_ANY_ID, PCI_ANY_ID, },
+
+       /* Titan Electronic cards */
+       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+               pbn_b0_1_921600 },
+       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+               pbn_b0_2_921600 },
+       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+               pbn_b0_4_921600 },
+       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800B,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+               pbn_b0_4_921600 },
+
        {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_550,
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE2, 1, 460800,
-               0, 0, pci_siig10x_fn },
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_siig10x_0 },
        {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_650,
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE2, 1, 460800,
-               0, 0, pci_siig10x_fn },
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_siig10x_0 },
        {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_850,
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE2, 1, 460800,
-               0, 0, pci_siig10x_fn },
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_siig10x_0 },
        {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_550,
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE2, 1, 921600,
-               0, 0, pci_siig10x_fn },
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_siig10x_1 },
        {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_650,
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE2, 1, 921600,
-               0, 0, pci_siig10x_fn },
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_siig10x_1 },
        {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_850,
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE2, 1, 921600,
-               0, 0, pci_siig10x_fn },
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_siig10x_1 },
        {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_550,
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600,
-               0, 0, pci_siig10x_fn },
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_siig10x_2 },
        {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_650,
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600,
-               0, 0, pci_siig10x_fn },
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_siig10x_2 },
        {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_850,
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600,
-               0, 0, pci_siig10x_fn },
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_siig10x_2 },
        {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_550,
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600,
-               0, 0, pci_siig10x_fn },
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_siig10x_2 },
        {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_650,
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600,
-               0, 0, pci_siig10x_fn },
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_siig10x_2 },
        {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_850,
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600,
-               0, 0, pci_siig10x_fn },
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_siig10x_2 },
        {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_550,
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 921600,
-               0, 0, pci_siig10x_fn },
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_siig10x_4 },
        {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_650,
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 921600,
-               0, 0, pci_siig10x_fn },
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_siig10x_4 },
        {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_850,
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 921600,
-               0, 0, pci_siig10x_fn },
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_siig10x_4 },
        {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_550,
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE0, 1, 921600,
-               0, 0, pci_siig20x_fn },
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_siig20x_0 },
        {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_650,
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE0, 1, 921600,
-               0, 0, pci_siig20x_fn },
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_siig20x_0 },
        {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_850,
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE0, 1, 921600,
-               0, 0, pci_siig20x_fn },
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_siig20x_0 },
        {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_550,
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE0, 1, 921600,
-               0, 0, pci_siig20x_fn },
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_siig20x_0 },
        {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_650,
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE0, 1, 921600,
-               0, 0, pci_siig20x_fn },
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_siig20x_0 },
        {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_850,
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE0, 1, 921600,
-               0, 0, pci_siig20x_fn },
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_siig20x_0 },
        {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_550,
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE0, 1, 921600,
-               0, 0, pci_siig20x_fn },
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_siig20x_0 },
        {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_650,
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE0, 1, 921600,
-               0, 0, pci_siig20x_fn },
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_siig20x_0 },
        {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_850,
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE0, 1, 921600,
-               0, 0, pci_siig20x_fn },
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_siig20x_0 },
        {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_550,
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600,
-               0, 0, pci_siig20x_fn },
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_siig20x_2 },
        {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_650,
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600,
-               0, 0, pci_siig20x_fn },
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_siig20x_2 },
        {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_850,
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600,
-               0, 0, pci_siig20x_fn },
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_siig20x_2 },
        {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_550,
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600,
-               0, 0, pci_siig20x_fn },
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_siig20x_2 },
        {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_650,
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600,
-               0, 0, pci_siig20x_fn },
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_siig20x_2 },
        {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_850,
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600,
-               0, 0, pci_siig20x_fn },
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_siig20x_2 },
        {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_550,
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 4, 921600,
-               0, 0, pci_siig20x_fn },
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_siig20x_4 },
        {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_650,
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 4, 921600,
-               0, 0, pci_siig20x_fn },
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_siig20x_4 },
        {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_850,
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 4, 921600,
-               0, 0, pci_siig20x_fn },
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_siig20x_4 },
+
        /* Computone devices submitted by Doug McNash dmcnash@computone.com */
        {       PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG,
                PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG4,
-               SPCI_FL_BASE0, 4, 921600, /* IOMEM */
-               0x40, 2, NULL, 0x200 },
+               0, 0, pbn_computone_4 },
        {       PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG,
                PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG8,
-               SPCI_FL_BASE0, 8, 921600, /* IOMEM */
-               0x40, 2, NULL, 0x200 },
+               0, 0, pbn_computone_8 },
        {       PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG,
                PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG6,
-               SPCI_FL_BASE0, 6, 921600, /* IOMEM */
-               0x40, 2, NULL, 0x200 },
-       /* Digitan DS560-558, from jimd@esoft.com */
-       {       PCI_VENDOR_ID_ATT, PCI_DEVICE_ID_ATT_VENUS_MODEM,
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE1, 1, 115200 },
-       /* 3Com US Robotics 56k Voice Internal PCI model 5610 */
-       {       PCI_VENDOR_ID_USR, 0x1008,
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE0, 1, 115200 },
-       /* Titan Electronic cards */
-       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100,
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE0, 1, 921600 },
-       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200,
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE0, 2, 921600 },
-       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400,
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE0, 4, 921600 },
-       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800B,
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE0, 4, 921600 },
-       /* EKF addition for i960 Boards form EKF with serial port */
-       {       PCI_VENDOR_ID_INTEL, 0x1960,
-               0xE4BF, PCI_ANY_ID,
-               SPCI_FL_BASE0, 32, 921600, /* max 256 ports */
-               8<<2, 2, pci_inteli960ni_fn, 0x10000},
+               0, 0, pbn_computone_6 },
+
+       {       PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI95N,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_oxsemi },
+       {       PCI_VENDOR_ID_TIMEDIA, PCI_DEVICE_ID_TIMEDIA_1889,
+               PCI_VENDOR_ID_TIMEDIA, PCI_ANY_ID, 0, 0, pbn_timedia },
+
+       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DSERIAL,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_2_115200 },
+       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATRO_A,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_2_115200 },
+       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATRO_B,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_2_115200 },
+       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PORT_PLUS,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_2_460800 },
+       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUAD_A,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_2_460800 },
+       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUAD_B,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_2_460800 },
+       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_SSERIAL,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_1_115200 },
+       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PORT_650,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_1_460800 },
+
        /* RAStel 2 port modem, gerg@moreton.com.au */
        {       PCI_VENDOR_ID_MORETON, PCI_DEVICE_ID_RASTEL_2PORT,
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 115200 },
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b2_bt_2_115200 },
+
+       /* EKF addition for i960 Boards form EKF with serial port */
+       {       PCI_VENDOR_ID_INTEL, 0x1960,
+               0xE4BF, PCI_ANY_ID, 0, 0,
+               pbn_intel_i960 },
+
+       /* Xircom Cardbus/Ethernet combos */
+       {       PCI_VENDOR_ID_XIRCOM, PCI_DEVICE_ID_XIRCOM_X3201_MDM,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_xircom_combo },
+
        /*
         * Untested PCI modems, sent in from various folks...
         */
+
        /* Elsa Model 56K PCI Modem, from Andreas Rath <arh@01019freenet.de> */
        {       PCI_VENDOR_ID_ROCKWELL, 0x1004,
-               0x1048, 0x1500, 
-               SPCI_FL_BASE1, 1, 115200 },
+               0x1048, 0x1500, 0, 0,
+               pbn_b1_1_115200 },
+
        {       PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3,
-               0xFF00, 0, SPCI_FL_BASE0 | SPCI_FL_IRQRESOURCE,
-               1, 458333, 0, 0, 0, 0x20178 },
-#if CONFIG_DDB5074
+               0xFF00, 0, 0, 0,
+               pbn_sgi_ioc3 },
+
+#ifdef CONFIG_DDB5074
        /*
         * NEC Vrc-5074 (Nile 4) builtin UART.
         * Conditionally compiled in since this is a motherboard device.
         */
        {       PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_NILE4,
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE0, 1, 520833,
-               64, 3, NULL, 0x300 },
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_nec_nile4 },
 #endif
+
 #if 0  /* PCI_DEVICE_ID_DCI_PCCOM8 ? */
        {       PCI_VENDOR_ID_DCI, PCI_DEVICE_ID_DCI_PCCOM8,
-               PCI_ANY_ID, PCI_ANY_ID,
-               SPCI_FL_BASE3, 8, 115200,
-               8 },
-#endif
-       /* Generic serial board */
-       {       0, 0,
-               0, 0,
-               SPCI_FL_BASE0, 1, 115200 },
-};
-
-/*
- * Given a complete unknown PCI device, try to use some heuristics to
- * guess what the configuration might be, based on the pitiful PCI
- * serial specs.  Returns 0 on success, 1 on failure.
- */
-static int _INLINE_ serial_pci_guess_board(struct pci_dev *dev,
-                                          struct pci_board *board)
-{
-       int     num_iomem = 0, num_port = 0, first_port = -1;
-       int     i;
-       
-       /*
-        * If it is not a communications device or the programming
-        * interface is greater than 6, give up.
-        *
-        * (Should we try to make guesses for multiport serial devices
-        * later?) 
-        */
-       if ((((dev->class >> 8) != PCI_CLASS_COMMUNICATION_SERIAL) &&
-           ((dev->class >> 8) != PCI_CLASS_COMMUNICATION_MODEM)) ||
-           (dev->class & 0xff) > 6)
-               return 1;
-
-       for (i=0; i < 6; i++) {
-               if (IS_PCI_REGION_IOPORT(dev, i)) {
-                       num_port++;
-                       if (first_port == -1)
-                               first_port = i;
-               }
-               if (IS_PCI_REGION_IOMEM(dev, i))
-                       num_iomem++;
-       }
-
-       /*
-        * If there is 1 or 0 iomem regions, and exactly one port, use
-        * it.
-        */
-       if (num_iomem <= 1 && num_port == 1) {
-               board->flags = first_port;
-               return 0;
-       }
-       return 1;
-}
-
-static int __devinit serial_init_one(struct pci_dev *dev,
-                                    const struct pci_device_id *ent)
-{
-       struct pci_board *board, tmp;
-       int rc;
-
-       for (board = pci_boards; board->vendor; board++) {
-               if (board->vendor != (unsigned short) PCI_ANY_ID &&
-                   dev->vendor != board->vendor)
-                       continue;
-               if (board->device != (unsigned short) PCI_ANY_ID &&
-                   dev->device != board->device)
-                       continue;
-               if (board->subvendor != (unsigned short) PCI_ANY_ID &&
-                   pci_get_subvendor(dev) != board->subvendor)
-                       continue;
-               if (board->subdevice != (unsigned short) PCI_ANY_ID &&
-                   pci_get_subdevice(dev) != board->subdevice)
-                       continue;
-               break;
-       }
-
-       rc = pci_enable_device(dev);
-       if (rc) return rc;
-
-       if (board->vendor == 0 && serial_pci_guess_board(dev, board))
-               return -ENODEV;
-       else if (serial_pci_guess_board(dev, &tmp) == 0) {
-               printk(KERN_INFO "Redundant entry in serial pci_table.  "
-                      "Please send the output of\n"
-                      "lspci -vv, this message (%d,%d,%d,%d)\n"
-                      "and the manufacturer and name of "
-                      "serial board or modem board\n"
-                      "to serial-pci-info@lists.sourceforge.net.\n",
-                      dev->vendor, dev->device,
-                      pci_get_subvendor(dev), pci_get_subdevice(dev));
-       }
-                      
-       start_pci_pnp_board(dev, board);
-
-       return 0;
-}
-
-static void __devexit serial_remove_one(struct pci_dev *dev)
-{
-       int     i;
-
-       /*
-        * Iterate through all of the ports finding those that belong
-        * to this PCI device.
-        */
-       for(i = 0; i < NR_PORTS; i++) {
-               if (rs_table[i].dev != dev)
-                       continue;
-               unregister_serial(i);
-               rs_table[i].dev = 0;
-       }
-       /*
-        * Now execute any board-specific shutdown procedure
-        */
-       for (i=0; i < NR_PCI_BOARDS; i++) {
-               struct pci_board_inst *brd = &serial_pci_board[i];
-
-               if (serial_pci_board[i].dev != dev)
-                       continue;
-               if (brd->board.init_fn)
-                       (brd->board.init_fn)(brd->dev, &brd->board, 0);
-               if (DEACTIVATE_FUNC(brd->dev))
-                       (DEACTIVATE_FUNC(brd->dev))(brd->dev);
-               serial_pci_board[i].dev = 0;
-       }
-}
-
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_dci_pccom8 },
+#endif
 
-static struct pci_device_id serial_pci_tbl[] __devinitdata = {
        { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
         PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xffff00, },
        { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
@@ -4746,7 +4877,7 @@ static void __devinit probe_serial_pci(void)
         * not to attempt to unregister the driver later
         */
        if (pci_module_init (&serial_pci_driver) != 0)
-               serial_pci_driver.name[0] = 0;
+               serial_pci_driver.name = "";
 
 #ifdef SERIAL_DEBUG_PCI
        printk(KERN_DEBUG "Leaving probe_serial_pci() (probe finished)\n");
@@ -5153,11 +5284,9 @@ static void __devinit probe_serial_pnp(void)
                               break;
 
               if (pnp_board->vendor) {
-                      board.vendor = pnp_board->vendor;
-                      board.device = pnp_board->device;
                       /* Special case that's more efficient to hardcode */
-                      if ((board.vendor == ISAPNP_VENDOR('A', 'K', 'Y') &&
-                           board.device == ISAPNP_DEVICE(0x1021)))
+                      if ((pnp_board->vendor == ISAPNP_VENDOR('A', 'K', 'Y') &&
+                           pnp_board->device == ISAPNP_DEVICE(0x1021)))
                               board.flags |= SPCI_FL_NO_SHIRQ;
               } else {
                       if (serial_pnp_guess_board(dev, &board))
index 83512a85469ae828be834a5dde064f19115d1fcd..e2a6c4c378b8d473221525c8d0ed076f39bd3db8 100644 (file)
@@ -770,15 +770,19 @@ static int BusLogic_InitializeMultiMasterProbeInfo(BusLogic_HostAdapter_T
       BusLogic_ModifyIOAddressRequest_T ModifyIOAddressRequest;
       unsigned char Bus = PCI_Device->bus->number;
       unsigned char Device = PCI_Device->devfn >> 3;
-      unsigned int IRQ_Channel = PCI_Device->irq;
-      unsigned long BaseAddress0 = pci_resource_start(PCI_Device, 0);
-      unsigned long BaseAddress1 = pci_resource_start(PCI_Device, 1);
-      BusLogic_IO_Address_T IO_Address = BaseAddress0;
-      BusLogic_PCI_Address_T PCI_Address = BaseAddress1;
+      unsigned int IRQ_Channel;
+      unsigned long BaseAddress0;
+      unsigned long BaseAddress1;
+      BusLogic_IO_Address_T IO_Address;
+      BusLogic_PCI_Address_T PCI_Address;
 
       if (pci_enable_device(PCI_Device))
        continue;
       
+      IRQ_Channel = PCI_Device->irq;
+      IO_Address  = BaseAddress0 = pci_resource_start(PCI_Device, 0);
+      PCI_Address = BaseAddress1 = pci_resource_start(PCI_Device, 1);
+
       if (pci_resource_flags(PCI_Device, 0) & IORESOURCE_MEM)
        {
          BusLogic_Error("BusLogic: Base Address0 0x%X not I/O for "
@@ -2547,7 +2551,7 @@ static void BusLogic_ReportTargetDeviceInfo(BusLogic_HostAdapter_T
          int SynchronousTransferRate = 0;
          if (BusLogic_FlashPointHostAdapterP(HostAdapter))
            {
-             boolean WideTransfersActive;
+             unsigned char WideTransfersActive;
              FlashPoint_InquireTargetInfo(
                HostAdapter->CardHandle, TargetID,
                &HostAdapter->SynchronousPeriod[TargetID],
index 87fc92f25531a4a382ce36a06cfbbc200614892f..8ec1d1391527cb7dc8a22829d7e837605ced32c2 100644 (file)
@@ -78,6 +78,7 @@ extern int BusLogic_ProcDirectoryInfo(char *, char **, off_t, int, int, int);
     reset:          BusLogic_ResetCommand,       /* Reset Command Function */ \
     bios_param:     BusLogic_BIOSDiskParameters,  /* BIOS Disk Parameters   */ \
     unchecked_isa_dma: 1,                        /* Default Initial Value  */ \
+    max_sectors:    128,                         /* I/O queue len limit    */ \
     use_clustering: ENABLE_CLUSTERING }                  /* Enable Clustering      */
 
 
index 2906798dd661a0febae5dfb491e0f3b90be56b09..c91e792cab278e33811d377018b4251fa9887f29 100644 (file)
@@ -1,3 +1,9 @@
+Sat May 12 12:00 2001 Gerard Roudier (groudier@club-internet.fr)
+       * version ncr53c8xx-3.4.3b
+       - Ensure LEDC bit in GPCNTL is cleared when reading the NVRAM.
+         Fix sent by Stig Telfer <stig@api-networks.com>.
+       - Define scsi_set_pci_device() as nil for kernel < 2.4.4.
+
 Mon Feb 12 22:30 2001 Gerard Roudier (groudier@club-internet.fr)
        * version ncr53c8xx-3.4.3
        - Call pci_enable_device() as AC wants this to be done.
@@ -238,7 +244,7 @@ Wed Oct 21 21:00 1998 Gerard Roudier (groudier@club-internet.fr)
        - Changes from Eddie Dost for Sparc and Alpha:
          ioremap/iounmap support for Sparc.
          pcivtophys changed to bus_dvma_to_phys.
-       - Add the 53c876 description to the chip table. This is only usefull 
+       - Add the 53c876 description to the chip table. This is only useful 
          for printing the right name of the controller.
        - DEL-441 Item 2 work-around for the 53c876 rev <= 5 (0x15).
        - Add additionnal checking of INQUIRY data:
@@ -304,7 +310,7 @@ Sun Jun 28 12:00 1998 Gerard Roudier (groudier@club-internet.fr)
 Sat Jun 20 20:00 1998 Gerard Roudier (groudier@club-internet.fr)
        * revision 3.0c
        - Add a boot setup option that allows to set up device queue depths 
-         at boot-up. This option is very usefull since Linux does not 
+         at boot-up. This option is very useful since Linux does not 
          allow to change scsi device queue depth once the system has been 
          booted up.
 
@@ -333,7 +339,7 @@ Tue Jun 10 23:00 1998 Gerard Roudier (groudier@club-internet.fr)
          kernel version >= 2.1.105.
        - Replace all printf(s) by printk(s). After all, the ncr53c8xx is 
          a driver for Linux.
-       - Perform auto-sense on COMMAND TERMINATED. Not sure it is usefull.
+       - Perform auto-sense on COMMAND TERMINATED. Not sure it is useful.
        - Some other minor changes.
 
 Tue Jun 4 23:00 1998 Gerard Roudier (groudier@club-internet.fr)
@@ -341,7 +347,7 @@ Tue Jun 4 23:00 1998 Gerard Roudier (groudier@club-internet.fr)
        - Code cleanup and simplification:
          Remove kernel 1.2.X and 1.3.X support.
          Remove the _old_ target capabilities table.
-         Remove the error recovery code that have'nt been really usefull.
+         Remove the error recovery code that have'nt been really useful.
          Use a single alignment boundary (CACHE_LINE_SIZE) for data 
          structures.
        - Several aggressive SCRIPTS optimizations and changes:
index bab83c1ea01f6e0347a583dede992843ba96a0c9..423ceecfd9f30d02818209c2c799428671677894 100644 (file)
@@ -1,3 +1,24 @@
+Sat May 12 12:00 2001 Gerard Roudier (groudier@club-internet.fr)
+       * version sym53c8xx-1.7.3c
+       - Ensure LEDC bit in GPCNTL is cleared when reading the NVRAM.
+         Fix sent by Stig Telfer <stig@api-networks.com>.
+       - Backport from SYM-2 the work-around that allows to support 
+         hardwares that fail PCI parity checking.
+       - Check that we received at least 8 bytes of INQUIRY response 
+         for byte 7, that contains device capabilities, to be valid.
+       - Define scsi_set_pci_device() as nil for kernel < 2.4.4.
+       - + A couple of minor changes.
+         
+Sat Apr 7 19:30 2001 Gerard Roudier (groudier@club-internet.fr)
+       * version sym53c8xx-1.7.3b
+       - Fix an unaligned LOAD from scripts (was used as dummy read).
+       - In ncr_soft_reset(), only try to ABORT the current operation 
+         for chips that support SRUN bit in ISTAT1 and if SCRIPTS are 
+         currently running, as 896 and 1010 manuals suggest.
+       - In the CCB abort path, donnot assume that the CCB is currently 
+         queued to SCRIPTS. This is not always true, notably after a 
+         QUEUE FULL status or when using untagged commands.
+
 Sun Mar 4 18:30 2001 Gerard Roudier (groudier@club-internet.fr)
        * version sym53c8xx-1.7.3a
        - Fix an issue in the ncr_int_udc() (unexpected disconnect)
@@ -338,7 +359,7 @@ Sun May 9  11:00 1999 Gerard Roudier (groudier@club-internet.fr)
 Tue Apr 15  10:00 1999 Gerard Roudier (groudier@club-internet.fr)
        * version sym53c8xx-1.3e
        - Support for any number of LUNs (64) (SPI2-compliant).
-         (Btw, this may only be ever usefull under linux-2.2 ;-))
+         (Btw, this may only be ever useful under linux-2.2 ;-))
 
 Sun Apr 11  10:00 1999 Gerard Roudier (groudier@club-internet.fr)
        * version sym53c8xx-1.3d
index da09031973bdf440e917a57c6b23b22582b9b1e9..d77f242d81aeb7e62c0f2a1710c361b195648654 100644 (file)
@@ -198,6 +198,30 @@ if [ "$CONFIG_MIPS_JAZZ" = "y" ]; then
    bool 'MIPS JAZZ FAS216 SCSI support' CONFIG_JAZZ_ESP
 fi
 
+if [ "$CONFIG_AMIGA" = "y" ]; then
+   dep_tristate 'A3000 WD33C93A support' CONFIG_A3000_SCSI $CONFIG_SCSI
+   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+      bool 'A4000T SCSI support (EXPERIMENTAL)' CONFIG_A4000T_SCSI
+   fi
+fi
+if [ "$CONFIG_ZORRO" = "y" ]; then
+   dep_tristate 'A2091/A590 WD33C93A support' CONFIG_A2091_SCSI $CONFIG_SCSI
+   dep_tristate 'GVP Series II WD33C93A support' CONFIG_GVP11_SCSI $CONFIG_SCSI
+   dep_tristate 'CyberStorm SCSI support' CONFIG_CYBERSTORM_SCSI $CONFIG_SCSI
+   dep_tristate 'CyberStorm Mk II SCSI support' CONFIG_CYBERSTORMII_SCSI $CONFIG_SCSI
+   dep_tristate 'Blizzard 2060 SCSI support' CONFIG_BLZ2060_SCSI $CONFIG_SCSI
+   dep_tristate 'Blizzard 1230IV/1260 SCSI support' CONFIG_BLZ1230_SCSI $CONFIG_SCSI
+   dep_tristate 'Fastlane SCSI support' CONFIG_FASTLANE_SCSI $CONFIG_SCSI
+   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+      bool 'A4091 SCSI support (EXPERIMENTAL)' CONFIG_A4091_SCSI
+      bool 'WarpEngine SCSI support (EXPERIMENTAL)' CONFIG_WARPENGINE_SCSI
+      bool 'Blizzard PowerUP 603e+ SCSI (EXPERIMENTAL)' CONFIG_BLZ603EPLUS_SCSI
+      dep_tristate 'BSC Oktagon SCSI support (EXPERIMENTAL)' CONFIG_OKTAGON_SCSI $CONFIG_SCSI
+#      bool 'Cyberstorm Mk III SCSI support (EXPERIMENTAL)' CONFIG_CYBERSTORMIII_SCSI
+#      bool 'GVP Turbo 040/060 SCSI support (EXPERIMENTAL)' CONFIG_GVP_TURBO_SCSI
+   fi
+fi
+
 endmenu
 
 if [ "$CONFIG_HOTPLUG" = "y" -a "$CONFIG_PCMCIA" != "n" ]; then
index 7c0232fa91d64a6842860c968c78ec8cb491bef5..9b07421da52b57e99fb4b2a8893110919c50e474 100644 (file)
@@ -629,7 +629,7 @@ typedef struct _SCCB {
 #if (FW_TYPE==_UCB_MGR_)  
    #define  HBA_AUTO_SENSE_FAIL        0x1B  
    #define  HBA_TQ_REJECTED            0x1C  
-   #define  HBA_UNSUPORTED_MSG         0x1D  
+   #define  HBA_UNSUPPORTED_MSG         0x1D  
    #define  HBA_HW_ERROR               0x20  
    #define  HBA_ATN_NOT_RESPONDED      0x21  
    #define  HBA_SCSI_RESET_BY_ADAPTER  0x22
diff --git a/drivers/scsi/README.aic7xxx b/drivers/scsi/README.aic7xxx
new file mode 100644 (file)
index 0000000..9088d77
--- /dev/null
@@ -0,0 +1,477 @@
+                           AIC7xxx Driver for Linux
+
+Introduction
+----------------------------
+The AIC7xxx SCSI driver adds support for Adaptec (http://www.adaptec.com)
+SCSI controllers and chipsets. Major portions of the driver and driver
+development are shared between both Linux and FreeBSD. Support for the
+AIC-7xxx chipsets have been in the default Linux kernel since approximately
+linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD
+2.1.0 or later.
+
+  Supported cards/chipsets
+  ----------------------------
+    Adaptec Cards
+    ----------------------------
+    AHA-274x
+    AHA-274xT
+    AHA-274xW
+    AHA-284x
+    AHA-284xW
+    All PCI based cards using any of the chipsets listed under motherboard
+    chipsets.  In general, this means *all* of the Adaptec SCSI controllers
+    except the ones specifically excluded later on in this document.
+
+    Motherboard Chipsets
+    ----------------------------
+    AIC-777x
+    AIC-785x
+    AIC-786x
+    AIC-787x
+    AIC-788x
+    AIC-789x
+    AIC-3860
+
+    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.
+    U3- Ultra 3 SCSI, transfer rates up to 160MB/s.
+    D - Differential SCSI.
+    T - Twin Channel SCSI. Up to 14 SCSI devices.
+
+    AHA-274x - EISA SCSI controller
+    AHA-284x - VLB SCSI controller
+    AHA-29xx - PCI SCSI controller
+    AHA-39xx - PCI controllers with multiple separate SCSI channels on-board.
+
+  Not Supported Devices
+  ------------------------------
+    Adaptec Cards
+    ----------------------------
+    AHA-2920 (Only the cards that use the Future Domain chipset are not
+              supported, any 2920 cards based on Adaptec AIC chipsets,
+             such as the 2920C, are supported)
+    AAA-13x Raid Adapters
+    AAA-113x Raid Port Card
+
+    Motherboard Chipsets
+    ----------------------------
+    AIC-781x
+
+    Bus Types
+    ----------------------------
+    R - Raid Port busses are not supported.
+
+    The hardware RAID devices sold by Adaptec are *NOT* supported by this
+    driver (and will people please stop emailing me about them, they are
+    a totally separate beast from the bare SCSI controllers and this driver
+    can not be retrofitted in any sane manner to support the hardware RAID
+    features on those cards - Doug Ledford).
+    
+
+  People
+  ------------------------------
+    Justin T Gibbs  gibbs@plutotech.com
+      (BSD Driver Author)
+    Dan Eischen     deischen@iworks.InterWorks.org
+      (Original Linux Driver Co-maintainer)
+    Dean Gehnert    deang@teleport.com
+      (Original Linux FTP/patch maintainer)
+    Jess Johnson    jester@frenzy.com
+      (AIC7xxx FAQ author)
+    Doug Ledford    dledford@redhat.com
+      (Current Linux aic7xxx-5.x.x Driver/Patch/FTP maintainer)
+    
+    Special thanks go to John Aycock (aycock@cpsc.ucalgary.ca), the original
+    author of the driver. John has since retired from the project. Thanks
+    again for all his work!
+    
+  Mailing list
+  ------------------------------
+    There is a mailing list available for users who want to track development
+    and converse with other users and developers. This list is for both
+    FreeBSD and Linux support of the AIC7xxx chipsets.
+
+    To subscribe to the AIC7xxx mailing list send mail to the list server,
+    with "subscribe AIC7xxx" in the body (no Subject: required):
+        To: majordomo@FreeBSD.ORG
+        ---
+        subscribe AIC7xxx
+
+    To unsubscribe from the list, send mail to the list server with:
+        To: majordomo@FreeBSD.ORG
+        ---
+        unsubscribe AIC7xxx
+
+    Send regular messages and replies to: AIC7xxx@FreeBSD.ORG
+    
+  Boot Command line options
+  ------------------------------
+    "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=scbram" - Some cards have external SCB RAM that can be used to
+        give the card more hardware SCB slots.  This allows the driver to use
+       that SCB RAM.  Without this option, the driver won't touch the SCB
+       RAM because it is known to cause problems on a few cards out there
+       (such as 3985 class cards).
+       
+    "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=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
+        with no value afterwords.  To reverse the parity from even to odd,
+        supply any number other than 0 or 255.  In short:
+          pci_parity     - Even parity checking (even is the normal PCI parity)
+          pci_parity:x   - Where x > 0, Odd parity checking
+          pci_parity:0   - No check (default)
+        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=seltime:2" - This option controls how long the card waits
+        during a device selection sequence for the device to respond.
+       The original SCSI spec says that this "should be" 256ms.  This
+       is generally not required with modern devices.  However, some
+       very old SCSI I devices need the full 256ms.  Most modern devices
+       can run fine with only 64ms.  The default for this option is
+       64ms.  If you need to change this option, then use the following
+       table to set the proper value in the example above:
+         0  -  256ms
+         1  -  128ms
+         2  -   64ms
+         3  -   32ms
+       
+    "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 disable
+        or enable Tagged Command Queueing (TCQ) on specific devices.  As of
+       driver version 5.1.11, TCQ is now either on or off by default
+       according to the setting you choose during the make config process.
+       In order to en/disable TCQ for certian devices at boot time, a user
+       may use this boot param.  The driver will then parse this message out
+        and en/disable the specific device entries that are present based upon
+        the value given.  The param line is parsed in the following manner:
+
+          { - first instance indicates the start of this parameter values
+              second instance is the start of entries for a particular
+              device entry
+          } - end the entries for a particular host adapter, or end the entire
+              set of parameter entries
+          , - move to next entry.  Inside of a set of device entries, this
+              moves us to the next device on the list.  Outside of device
+              entries, this moves us to the next host adapter
+          . - Same effect as , but is safe to use with insmod.
+          x - the number to enter into the array at this position.  
+              0 = Enable tagged queueing on this device and use the default
+                  queue depth
+              1-254 = Enable tagged queueing on this device and use this
+                      number as the queue depth
+              255 = Disable tagged queueing on this device.
+              Note: anything above 32 for an actual queue depth is wasteful
+                    and not recommended.
+
+        A few examples of how this can be used:
+
+        tag_info:{{8,12,,0,,255,4}}
+          This line will only effect the first aic7xxx card registered.  It
+          will set scsi id 0 to a queue depth of 8, id 1 to 12, leave id 2
+          at the default, set id 3 to tagged queueing enabled and use the
+          default queue depth, id 4 default, id 5 disabled, and id 6 to 4.
+          Any not specified entries stay at the default value, repeated
+          commas with no value specified will simply increment to the next id
+          without changing anything for the missing values.
+
+        tag_info:{,,,{,,,255}}
+          First, second, and third adapters at default values.  Fourth
+          adapter, id 3 is disabled.  Notice that leading commas simply
+         increment what the first number effects, and there are no need
+         for trailing commas.  When you close out an adapter, or the
+         entire entry, anything not explicitly set stays at the default
+         value.
+
+        A final note on this option.  The scanner I used for this isn't
+        perfect or highly robust.  If you mess the line up, the worst that
+        should happen is that the line will get ignored.  If you don't
+        close out the entire entry with the final bracket, then any other
+        aic7xxx options after this will get ignored.  So, in general, be
+        sure of what you are entering, and after you have it right, just
+        add it to the lilo.conf file so there won't be any mistakes.  As
+        a means of checking this parser, the entire tag_info array for
+        each card is now printed out in the /proc/scsi/aic7xxx/x file.  You
+        can use that to verify that your options were parsed correctly. 
+        
+    Boot command line options may be combined to form the proper set of options
+    a user might need.  For example, the following is valid:
+    
+    aic7xxx=verbose,extended,irq_trigger:1
+    
+    The only requirement is that individual options be separated by a comma or
+    a period on the command line.
+        
+  Module Loading command options
+  ------------------------------
+    When loading the aic7xxx driver as a module, the exact same options are
+    available to the user.  However, the syntax to specify the options changes
+    slightly.  For insmod, you need to wrap the aic7xxx= argument in quotes
+    and replace all ',' with '.'.  So, for example, a valid insmod line
+    would be:
+
+    insmod aic7xxx aic7xxx='verbose.irq_trigger:1.extended'
+
+    This line should result in the *exact* same behaviour as if you typed
+    it in at the lilo prompt and the driver was compiled into the kernel
+    instead of being a module.  The reason for the single quote is so that
+    the shell won't try to interpret anything in the line, such as {. 
+    Insmod assumes any options starting with a letter instead of a number
+    is a character string (which is what we want) and by switching all of
+    the commas to periods, insmod won't interpret this as more than one
+    string and write junk into our binary image.  I consider it a bug in
+    the insmod program that even if you wrap your string in quotes (quotes
+    that pass the shell mind you and that insmod sees) it still treates
+    a comma inside of those quotes as starting a new variable, resulting
+    in memory scribbles if you don't switch the commas to periods.
+
+
+  Kernel Compile options
+  ------------------------------
+    The various kernel compile time options for this driver are now fairly
+    well documented in the file Documentation/Configure.help.  In order to
+    see this documentation, you need to use one of the advanced configuration
+    programs (menuconfig and xconfig).  If you are using the "make menuconfig"
+    method of configuring your kernel, then you would simply highlight the
+    option in question and hit the ? key.  If you are using the "make xconfig"
+    method of configuring your kernel, then simply click on the help button
+    next to the option you have questions about.  The help information from
+    the Configure.help file will then get automatically displayed.
+
+  /proc support
+  ------------------------------
+    The /proc support for the AIC7xxx can be found in the /proc/scsi/aic7xxx/
+    directory. That directory contains a file for each SCSI controller in
+    the system. Each file presents the current configuration and transfer
+    statistics (enabled with #define in aic7xxx.c) for each controller.
+
+    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 useful 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 useful 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.redhat.com/pub/aic/
+      - Out of date.  I used to keep stuff here, but too many people
+        complained about having a hard time getting into Red Hat's ftp
+       server.  So use the web site below instead.
+    ftp://ftp.pcnet.com/users/eischen/Linux/
+      - Dan Eischen's driver distribution area
+    ftp://ekf2.vsb.cz/pub/linux/kernel/aic7xxx/ftp.teleport.com/
+      - European Linux mirror of Teleport site
+
+  Web sites
+  ------------------------------
+    http://people.redhat.com/dledford/
+      - My web site, also the primary aic7xxx site with several related
+        pages.
+
+Dean W. Gehnert
+deang@teleport.com
+
+$Revision: 3.0 $
+
+Modified by Doug Ledford 1998-2000
+
index e1d965b1a5f4f2898e359891007a8b8fdf9d905a..206233d1af2da78b5792992f6d5118f3d1c7cf59 100644 (file)
@@ -508,7 +508,7 @@ Available commands:
     clearprof
 
     The profile counters are automatically cleared when the amount of
-    data transfered reaches 1000 GB in order to avoid overflow.
+    data transferred reaches 1000 GB in order to avoid overflow.
     The "clearprof" command allows you to clear these counters at any time.
 
 
@@ -1042,7 +1042,7 @@ SCSI BUS bandwidth if the SCRIPTS execution lasts more than 4 micro-seconds.
 
 The use of IARB needs the SCSI_NCR_IARB_SUPPORT option to have been defined 
 at compile time and the 'iarb' boot option to have been set to a non zero 
-value at boot time. It is not that usefull for real work, but can be used 
+value at boot time. It is not that useful for real work, but can be used 
 to stress SCSI devices or for some applications that can gain advantage of 
 it. By the way, if you experience badnesses like 'unexpected disconnections', 
 'bad reselections', etc... when using IARB on heavy IO load, you should not 
@@ -1350,7 +1350,7 @@ Field C : SIST io register (SCSI Interrupt Status)
   Bit 0x04 : UDC  Undexpected Disconnection
              Indicates that the device released the SCSI BUS when the chip 
              was not expecting this to happen. A device may behave so to 
-             indicate the SCSI initiator that an error condition not reportable              using the SCSI protocol has occured.
+             indicate the SCSI initiator that an error condition not reportable              using the SCSI protocol has occurred.
   Bit 0x02 : RST  SCSI BUS Reset
              Generally SCSI targets donnot reset the SCSI BUS, although any 
              device on the BUS can reset it at any time.
index 34148c29fd345d3cc2eadf578a7da6eee66c4807..6961d6e7c8d155debd0a88653834eae25a04706b 100644 (file)
@@ -42,9 +42,13 @@ struct pci_device_id
 static int     ahc_linux_pci_dev_probe(struct pci_dev *pdev,
                                        const struct pci_device_id *ent);
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+#include <linux/module.h>
+
 static void    ahc_linux_pci_dev_remove(struct pci_dev *pdev);
 
-/* We do our own ID filtering.  So, grab all SCSI storage class devices. */
+/* We do our own ID filtering.  So we grab all Adaptec SCSI storage class
+ * devices here.
+ */
 static struct pci_device_id ahc_linux_pci_id_table[] = {
        {
                0x9004, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
@@ -56,6 +60,7 @@ static struct pci_device_id ahc_linux_pci_id_table[] = {
        },
        { 0 }
 };
+MODULE_DEVICE_TABLE(pci,ahc_linux_pci_id_table);
 
 struct pci_driver aic7xxx_pci_driver = {
        name:           "aic7xxx",
index 11741b8bb24e61321f53a4e29cece4723734a032..a6ec97b5c5436a4ff254138fd52a6ac80be56092 100644 (file)
 #include <scsi/scsicam.h>
 
 #include <linux/stat.h>
-#include <linux/malloc.h>        /* for kmalloc() */
+#include <linux/slab.h>        /* for kmalloc() */
 
 #include <linux/config.h>        /* for CONFIG_PCI */
 
  */
 #define VIRT_TO_BUS(a) (unsigned int)virt_to_bus((void *)(a))
 
-#define AIC7XXX_C_VERSION  "5.2.1"
+#define AIC7XXX_C_VERSION  "5.2.4"
 
 #define NUMBER(arr)     (sizeof(arr) / sizeof(arr[0]))
 #define MIN(a,b)        (((a) < (b)) ? (a) : (b))
  * You can try raising me if tagged queueing is enabled, or lowering
  * me if you only have 4 SCBs.
  */
-#ifdef CONFIG_AIC7XXX_OLD_CMDS_PER_DEVICE
-#define AIC7XXX_CMDS_PER_DEVICE CONFIG_AIC7XXX_OLD_CMDS_PER_DEVICE
+#ifdef CONFIG_AIC7XXX_CMDS_PER_DEVICE
+#define AIC7XXX_CMDS_PER_DEVICE CONFIG_AIC7XXX_CMDS_PER_DEVICE
 #else
 #define AIC7XXX_CMDS_PER_DEVICE 8
 #endif
  * NOTE: Do NOT enable this when running on kernels version 1.2.x and below.
  * NOTE: This does affect performance since it has to maintain statistics.
  */
-#ifdef CONFIG_AIC7XXX_OLD_PROC_STATS
+#ifdef CONFIG_AIC7XXX_PROC_STATS
 #define AIC7XXX_PROC_STATS
 #endif
 
@@ -347,7 +347,7 @@ typedef struct
  * Make a define that will tell the driver not to use tagged queueing
  * by default.
  */
-#ifdef CONFIG_AIC7XXX_OLD_TCQ_ON_BY_DEFAULT
+#ifdef CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT
 #define DEFAULT_TAG_COMMANDS {0, 0, 0, 0, 0, 0, 0, 0,\
                               0, 0, 0, 0, 0, 0, 0, 0}
 #else
@@ -706,13 +706,14 @@ struct aic7xxx_hwscb {
 /*28*/  unsigned int pad;           /*
                                      * Unused by the kernel, but we require
                                      * the padding so that the array of
-                                     * hardware SCBs is alligned on 32 byte
+                                     * hardware SCBs is aligned on 32 byte
                                      * boundaries so the sequencer can index
                                      */
 };
 
 typedef enum {
         SCB_FREE                = 0x0000,
+        SCB_DTR_SCB             = 0x0001,
         SCB_WAITINGQ            = 0x0002,
         SCB_ACTIVE              = 0x0004,
         SCB_SENSE               = 0x0008,
@@ -830,6 +831,17 @@ struct aic7xxx_scb_dma {
        unsigned int           dma_len;       /* DMA length */
 };
 
+typedef enum {
+  AHC_BUG_NONE            = 0x0000,
+  AHC_BUG_TMODE_WIDEODD   = 0x0001,
+  AHC_BUG_AUTOFLUSH       = 0x0002,
+  AHC_BUG_CACHETHEN       = 0x0004,
+  AHC_BUG_CACHETHEN_DIS   = 0x0008,
+  AHC_BUG_PCI_2_1_RETRY   = 0x0010,
+  AHC_BUG_PCI_MWI         = 0x0020,
+  AHC_BUG_SCBCHAN_UPLOAD  = 0x0040,
+} ahc_bugs;
+
 struct aic7xxx_scb {
         struct aic7xxx_hwscb  *hscb;          /* corresponding hardware scb */
         Scsi_Cmnd             *cmd;              /* Scsi_Cmnd for this scb */
@@ -942,7 +954,6 @@ struct aic7xxx_host {
   unsigned long            isr_count;        /* Interrupt count */
   unsigned long            spurious_int;
   scb_data_type           *scb_data;
-  volatile unsigned short  needdv;
   volatile unsigned short  needppr;
   volatile unsigned short  needsdtr;
   volatile unsigned short  needwdtr;
@@ -973,10 +984,9 @@ struct aic7xxx_host {
 #define  BUS_DEVICE_RESET_PENDING       0x02
 #define  DEVICE_RESET_DELAY             0x04
 #define  DEVICE_PRINT_DTR               0x08
-#define  DEVICE_PARITY_ERROR            0x10
-#define  DEVICE_WAS_BUSY                0x20
-#define  DEVICE_SCSI_3                  0x40
-#define  DEVICE_SCANNED                 0x80
+#define  DEVICE_WAS_BUSY                0x10
+#define  DEVICE_SCSI_3                  0x20
+#define  DEVICE_DTR_SCANNED             0x40
   volatile unsigned char   dev_flags[MAX_TARGETS];
   volatile unsigned char   dev_active_cmds[MAX_TARGETS];
   volatile unsigned char   dev_temp_queue_depth[MAX_TARGETS];
@@ -989,10 +999,6 @@ struct aic7xxx_host {
   spinlock_t               spin_lock;
   volatile unsigned char   cpu_lock_count[NR_CPUS];
 
-  Scsi_Cmnd               *dev_dtr_cmnd[MAX_TARGETS];
-
-  unsigned int             dev_checksum[MAX_TARGETS];
-  
   unsigned char            dev_last_queue_full[MAX_TARGETS];
   unsigned char            dev_last_queue_full_count[MAX_TARGETS];
   unsigned char            dev_max_queue_depth[MAX_TARGETS];
@@ -1040,6 +1046,7 @@ struct aic7xxx_host {
   int                      host_no;          /* SCSI host number */
   unsigned long            mbase;            /* I/O memory address */
   ahc_chip                 chip;             /* chip type */
+  ahc_bugs                 bugs;
   dma_addr_t              fifo_dma;         /* DMA handle for fifo arrays */
 
   /*
@@ -2821,138 +2828,98 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
   {
     p->flags &= ~AHC_ABORT_PENDING;
   }
-  if (scb->flags & SCB_RESET)
+  if (scb->flags & (SCB_RESET|SCB_ABORT))
   {
-      cmd->result = (DID_RESET << 16) | (cmd->result & 0xffff);
+    cmd->result |= (DID_RESET << 16);
   }
-  else if (scb->flags & SCB_ABORT)
-  {
-      cmd->result = (DID_RESET << 16) | (cmd->result & 0xffff);
-  }
-  else if (!(p->dev_flags[tindex] & DEVICE_SCANNED))
+
+  if (!(p->dev_flags[tindex] & DEVICE_PRESENT))
   {
     if ( (cmd->cmnd[0] == INQUIRY) && (cmd->result == DID_OK) )
     {
-      char *buffer;
-      
+    
       p->dev_flags[tindex] |= DEVICE_PRESENT;
-      if(cmd->use_sg)
-      {
-        struct scatterlist *sg;
-
-        sg = (struct scatterlist *)cmd->request_buffer;
-        buffer = (char *)sg[0].address;
-      }
-      else
-      {
-        buffer = (char *)cmd->request_buffer;
-      }
 #define WIDE_INQUIRY_BITS 0x60
 #define SYNC_INQUIRY_BITS 0x10
 #define SCSI_VERSION_BITS 0x07
 #define SCSI_DT_BIT       0x04
-      if ( (buffer[7] & WIDE_INQUIRY_BITS) &&
-           (p->features & AHC_WIDE) )
-      {
-        p->needwdtr |= (1<<tindex);
-        p->needwdtr_copy |= (1<<tindex);
-        p->transinfo[tindex].goal_width = p->transinfo[tindex].user_width;
-      }
-      else
-      {
-        p->needwdtr &= ~(1<<tindex);
-        p->needwdtr_copy &= ~(1<<tindex);
-        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->transinfo[tindex].user_offset )
-      {
-        p->transinfo[tindex].goal_period = p->transinfo[tindex].user_period;
-        p->transinfo[tindex].goal_options = p->transinfo[tindex].user_options;
-        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;
+      if(!(p->dev_flags[tindex] & DEVICE_DTR_SCANNED)) {
+        char *buffer;
+
+        if(cmd->use_sg)
+        {
+          struct scatterlist *sg;
+
+          sg = (struct scatterlist *)cmd->request_buffer;
+          buffer = (char *)sg[0].address;
+        }
+        else
+        {
+          buffer = (char *)cmd->request_buffer;
+        }
+
+
+        if ( (buffer[7] & WIDE_INQUIRY_BITS) &&
+             (p->features & AHC_WIDE) )
+        {
+          p->needwdtr |= (1<<tindex);
+          p->needwdtr_copy |= (1<<tindex);
+          p->transinfo[tindex].goal_width = p->transinfo[tindex].user_width;
+        }
         else
-          p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
-        if ( (((buffer[2] & SCSI_VERSION_BITS) == 3) ||
-               (buffer[56] & SCSI_DT_BIT) ||
-              (p->dev_flags[tindex] & DEVICE_SCSI_3) ) &&
-               (p->transinfo[tindex].user_period <= 9) &&
-               (p->transinfo[tindex].user_options) )
         {
-          p->needppr |= (1<<tindex);
-          p->needppr_copy |= (1<<tindex);
-          p->needsdtr &= ~(1<<tindex);
-          p->needsdtr_copy &= ~(1<<tindex);
           p->needwdtr &= ~(1<<tindex);
           p->needwdtr_copy &= ~(1<<tindex);
-          p->dev_flags[tindex] |= DEVICE_SCSI_3;
+          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->transinfo[tindex].user_offset )
+        {
+          p->transinfo[tindex].goal_period = p->transinfo[tindex].user_period;
+          p->transinfo[tindex].goal_options = p->transinfo[tindex].user_options;
+          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;
+          if ( (((buffer[2] & SCSI_VERSION_BITS) >= 3) ||
+                 (buffer[56] & SCSI_DT_BIT) ||
+                 (p->dev_flags[tindex] & DEVICE_SCSI_3) ) &&
+                 (p->transinfo[tindex].user_period <= 9) &&
+                 (p->transinfo[tindex].user_options) )
+          {
+            p->needppr |= (1<<tindex);
+            p->needppr_copy |= (1<<tindex);
+            p->needsdtr &= ~(1<<tindex);
+            p->needsdtr_copy &= ~(1<<tindex);
+            p->needwdtr &= ~(1<<tindex);
+            p->needwdtr_copy &= ~(1<<tindex);
+            p->dev_flags[tindex] |= DEVICE_SCSI_3;
+          }
+          else
+          {
+            p->needsdtr |= (1<<tindex);
+            p->needsdtr_copy |= (1<<tindex);
+            p->transinfo[tindex].goal_period = 
+              MAX(10, p->transinfo[tindex].goal_period);
+            p->transinfo[tindex].goal_options = 0;
+          }
         }
         else
         {
-          p->needsdtr |= (1<<tindex);
-          p->needsdtr_copy |= (1<<tindex);
-          p->transinfo[tindex].goal_period = 
-            MAX(10, p->transinfo[tindex].goal_period);
+          p->needsdtr &= ~(1<<tindex);
+          p->needsdtr_copy &= ~(1<<tindex);
+          p->transinfo[tindex].goal_period = 255;
+          p->transinfo[tindex].goal_offset = 0;
           p->transinfo[tindex].goal_options = 0;
         }
-      }
-      else
-      {
-        p->needsdtr &= ~(1<<tindex);
-        p->needsdtr_copy &= ~(1<<tindex);
-        p->transinfo[tindex].goal_period = 255;
-        p->transinfo[tindex].goal_offset = 0;
-        p->transinfo[tindex].goal_options = 0;
-      }
-      /*
-       * This is needed to work around a sequencer bug for now.  Regardless
-       * of the controller in use, if we have a Quantum drive, we need to
-       * limit the speed to 80MByte/sec.  As soon as I get a fixed version
-       * of the sequencer, this code will get yanked.
-       */
-      if(!strncmp(buffer + 8, "QUANTUM", 7) &&
-         p->transinfo[tindex].goal_options )
-      {
-        p->transinfo[tindex].goal_period = 
-          MAX(p->transinfo[tindex].goal_period, 10);
-        p->transinfo[tindex].goal_options = 0;
-        p->needppr &= ~(1<<tindex);
-        p->needppr_copy &= ~(1<<tindex);
-        p->needsdtr |= (1<<tindex);
-        p->needsdtr_copy |= (1<<tindex);
-        p->needwdtr |= (1<<tindex);
-        p->needwdtr_copy |= (1<<tindex);
-      }
-      /*
-       * Get the INQUIRY checksum.  We use this on Ultra 160/m
-       * and older devices both.  It allows us to drop speed on any bus type
-       * while at the same time giving us the needed domain validation for
-       * Ultra 160/m
-       *
-       * Note: We only get the checksum and set the SCANNED bit if this is
-       * one of our dtr commands.  If we don't do this, then we end up
-       * getting bad checksum results on the mid-level SCSI code's INQUIRY
-       * commands.
-       */
-      if(p->dev_dtr_cmnd[tindex] == cmd) {
-        unsigned int checksum = 0;
-        int *ibuffer;
-        int i=0;
-
-        ibuffer = (int *)buffer;
-        for( i = 0; i < (cmd->request_bufflen >> 2); i++)
-        {
-          checksum += ibuffer[i];
-        }
-        p->dev_checksum[tindex] = checksum;
-        p->dev_flags[tindex] |= DEVICE_SCANNED;
+        p->dev_flags[tindex] |= DEVICE_DTR_SCANNED;
         p->dev_flags[tindex] |= DEVICE_PRINT_DTR;
       }
 #undef WIDE_INQUIRY_BITS
@@ -2961,7 +2928,8 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
 #undef SCSI_DT_BIT
     }
   }
-  else if ((scb->flags & SCB_MSGOUT_BITS) != 0)
+
+  if ((scb->flags & SCB_MSGOUT_BITS) != 0)
   {
     unsigned short mask;
     int message_error = FALSE;
@@ -2981,7 +2949,6 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
 
     if (scb->flags & SCB_MSGOUT_WDTR)
     {
-      p->dtr_pending &= ~mask;
       if (message_error)
       {
         if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
@@ -3000,7 +2967,6 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
     }
     if (scb->flags & SCB_MSGOUT_SDTR)
     {
-      p->dtr_pending &= ~mask;
       if (message_error)
       {
         if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
@@ -3020,7 +2986,6 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
     }
     if (scb->flags & SCB_MSGOUT_PPR)
     {
-      p->dtr_pending &= ~mask;
       if(message_error)
       {
         if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
@@ -3045,6 +3010,7 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
       }
     }
   }
+
   queue_depth = p->dev_temp_queue_depth[tindex];
   if (queue_depth >= p->dev_active_cmds[tindex])
   {
@@ -3078,9 +3044,18 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
       }
     }
   }
-  if ( !(scb->tag_action) && (p->tagenable & (1<<tindex)) )
+  if (!(scb->tag_action))
+  {
+    aic7xxx_index_busy_target(p, scb->hscb->target_channel_lun,
+                              /* unbusy */ TRUE);
+    if (p->tagenable & (1<<tindex))
+    {
+      p->dev_temp_queue_depth[tindex] = p->dev_max_queue_depth[tindex];
+    }
+  }
+  if(scb->flags & SCB_DTR_SCB)
   {
-    p->dev_temp_queue_depth[tindex] = p->dev_max_queue_depth[tindex];
+    p->dtr_pending &= ~(1 << tindex);
   }
   p->dev_active_cmds[tindex]--;
   p->activescbs--;
@@ -3189,6 +3164,14 @@ aic7xxx_run_done_queue(struct aic7xxx_host *p, /*complete*/ int complete)
         printk(INFO_LEAD "Aborting scb %d\n",
              p->host_no, CTL_OF_SCB(scb), scb->hscb->tag);
       found++;
+      /*
+       * Clear any residual information since the normal aic7xxx_done() path
+       * doesn't touch the residuals.
+       */
+      scb->hscb->residual_SG_segment_count = 0;
+      scb->hscb->residual_data_count[0] = 0;
+      scb->hscb->residual_data_count[1] = 0;
+      scb->hscb->residual_data_count[2] = 0;
       aic7xxx_done(p, scb);
     }
   }
@@ -3401,8 +3384,22 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, int channel,
   active_scb = aic_inb(p, SCBPTR);
 
   if (aic7xxx_verbose & (VERBOSE_RESET_PROCESS | VERBOSE_ABORT_PROCESS))
+  {
     printk(INFO_LEAD "Reset device, active_scb %d\n",
          p->host_no, channel, target, lun, active_scb);
+    printk(INFO_LEAD "Current scb_tag %d, SEQADDR 0x%x, LASTPHASE "
+           "0x%x\n",
+         p->host_no, channel, target, lun, aic_inb(p, SCB_TAG),
+         aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8),
+         aic_inb(p, LASTPHASE));
+    printk(INFO_LEAD "SG_CACHEPTR 0x%x, SG_COUNT %d, SCSISIGI 0x%x\n",
+         p->host_no, channel, target, lun,
+         (p->features & AHC_ULTRA2) ?  aic_inb(p, SG_CACHEPTR) : 0,
+         aic_inb(p, SG_COUNT), aic_inb(p, SCSISIGI));
+    printk(INFO_LEAD "SSTAT0 0x%x, SSTAT1 0x%x, SSTAT2 0x%x\n",
+         p->host_no, channel, target, lun, aic_inb(p, SSTAT0),
+         aic_inb(p, SSTAT1), aic_inb(p, SSTAT2));
+  }
   /*
    * Deal with the busy target and linked next issues.
    */
@@ -3446,11 +3443,11 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, int channel,
       if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
         printk(INFO_LEAD "Cleaning up status information "
           "and delayed_scbs.\n", p->host_no, channel, i, lun);
-      p->dev_flags[i] &= ~(BUS_DEVICE_RESET_PENDING | DEVICE_PARITY_ERROR);
+      p->dev_flags[i] &= ~BUS_DEVICE_RESET_PENDING;
       if ( tag == SCB_LIST_NULL )
       {
         p->dev_flags[i] |= DEVICE_PRINT_DTR | DEVICE_RESET_DELAY;
-        p->dev_expires[i] = jiffies + (4 * HZ);
+        p->dev_expires[i] = jiffies + (1 * HZ);
         p->dev_timer_active |= (0x01 << i);
         p->dev_last_queue_full_count[i] = 0;
         p->dev_last_queue_full[i] = 0;
@@ -3495,7 +3492,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->maxscbs + 1) )
+      if ( j > (p->scb_data->numscbs + 1) )
       {
         if (aic7xxx_verbose & (VERBOSE_ABORT | VERBOSE_RESET))
           printk(WARN_LEAD "Yikes!! There's a loop in the "
@@ -3554,7 +3551,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->maxscbs + 1) )
+    if ( j > (p->scb_data->numscbs + 1) )
     {
       if (aic7xxx_verbose & (VERBOSE_ABORT | VERBOSE_RESET))
         printk(WARN_LEAD "Yikes!! There's a loop in the "
@@ -4300,11 +4297,25 @@ aic7xxx_calculate_residual (struct aic7xxx_host *p, struct aic7xxx_scb *scb)
     if (actual < cmd->underflow)
     {
       if (aic7xxx_verbose & VERBOSE_MINOR_ERROR)
+      {
         printk(INFO_LEAD "Underflow - Wanted %u, %s %u, residual SG "
           "count %d.\n", p->host_no, CTL_OF_SCB(scb), cmd->underflow,
           (cmd->request.cmd == WRITE) ? "wrote" : "read", actual,
           hscb->residual_SG_segment_count);
+        printk(INFO_LEAD "status 0x%x.\n", p->host_no, CTL_OF_SCB(scb),
+          hscb->target_status);
+      }
+      /*
+       * In 2.4, only send back the residual information, don't flag this
+       * as an error.  Before 2.4 we had to flag this as an error because
+       * the mid layer didn't check residual data counts to see if the
+       * command needs retried.
+       */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+      cmd->resid = scb->sg_length - actual;
+#else
       aic7xxx_error(cmd) = DID_RETRY_COMMAND;
+#endif
       aic7xxx_status(cmd) = hscb->target_status;
     }
   }
@@ -4623,7 +4634,6 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
            */
           p->needwdtr &= ~target_mask;
           p->needwdtr_copy &= ~target_mask;
-          p->dtr_pending &= ~target_mask;
           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));
@@ -4643,8 +4653,7 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
           */
           p->needsdtr &= ~target_mask;
           p->needsdtr_copy &= ~target_mask;
-          p->dtr_pending &= ~target_mask;
-          scb->flags &= ~SCB_MSGOUT_SDTR;
+          scb->flags &= ~SCB_MSGOUT_BITS;
           aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0, 0,
             (AHC_TRANS_CUR|AHC_TRANS_ACTIVE|AHC_TRANS_GOAL));
           if(aic7xxx_verbose & VERBOSE_NEGOTIATION2)
@@ -4778,6 +4787,8 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
                 aic7xxx_error(cmd) = DID_OK;
                 break;
               }  /* first time sense, no errors */
+              printk(INFO_LEAD "CHECK_CONDITION on REQUEST_SENSE, returning "
+                     "an error.\n", p->host_no, CTL_OF_SCB(scb));
               aic7xxx_error(cmd) = DID_ERROR;
               scb->flags &= ~SCB_SENSE;
               break;
@@ -5136,12 +5147,21 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
           printk(KERN_WARNING "  %s seen Data Phase. Length=%d, NumSGs=%d.\n",
             (aic_inb(p, SEQ_FLAGS) & DPHASE) ? "Have" : "Haven't",
             scb->sg_length, scb->sg_count);
-          for (i = 0; i < scb->sg_count; i++)
+          printk(KERN_WARNING "  Raw SCSI Command: 0x");
+          for (i = 0; i < scb->hscb->SCSI_cmd_length; i++)
+          {
+            printk("%02x ", scb->cmd->cmnd[i]);
+          }
+          printk("\n");
+          if(aic7xxx_verbose > 0xffff)
           {
-            printk(KERN_WARNING "     sg[%d] - Addr 0x%x : Length %d\n",
+            for (i = 0; i < scb->sg_count; i++)
+            {
+              printk(KERN_WARNING "     sg[%d] - Addr 0x%x : Length %d\n",
                  i, 
                  le32_to_cpu(scb->sg_list[i].address),
                  le32_to_cpu(scb->sg_list[i].length) );
+            }
           }
           aic7xxx_error(scb->cmd) = DID_ERROR;
         }
@@ -5156,7 +5176,7 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
         unsigned char resid_sgcnt, index;
         unsigned char scb_index = aic_inb(p, SCB_TAG);
         unsigned int cur_addr, resid_dcnt;
-        unsigned int native_addr, native_length;
+        unsigned int native_addr, native_length, sg_addr;
         int i;
 
         if(scb_index > p->scb_data->numscbs)
@@ -5176,6 +5196,9 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
                  scb->flags, (unsigned long)scb->cmd);
           break;
         }
+        if(aic7xxx_verbose & VERBOSE_MINOR_ERROR)
+          printk(INFO_LEAD "Got WIDE_RESIDUE message, patching up data "
+                 "pointer.\n", p->host_no, CTL_OF_SCB(scb));
 
         /*
          * We have a valid scb to use on this WIDE_RESIDUE message, so
@@ -5188,132 +5211,87 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
          */
         cur_addr = aic_inb(p, SHADDR) | (aic_inb(p, SHADDR + 1) << 8) |
           (aic_inb(p, SHADDR + 2) << 16) | (aic_inb(p, SHADDR + 3) << 24);
+        sg_addr = aic_inb(p, SG_COUNT + 1) | (aic_inb(p, SG_COUNT + 2) << 8) |
+          (aic_inb(p, SG_COUNT + 3) << 16) | (aic_inb(p, SG_COUNT + 4) << 24);
         resid_sgcnt = aic_inb(p, SCB_RESID_SGCNT);
         resid_dcnt = aic_inb(p, SCB_RESID_DCNT) |
           (aic_inb(p, SCB_RESID_DCNT + 1) << 8) |
           (aic_inb(p, SCB_RESID_DCNT + 2) << 16);
-        index = scb->sg_count - (resid_sgcnt + 1);
+        index = scb->sg_count - ((resid_sgcnt) ? resid_sgcnt : 1);
         native_addr = le32_to_cpu(scb->sg_list[index].address);
         native_length = le32_to_cpu(scb->sg_list[index].length);
         /*
-         * Make sure this is a valid sg_seg for the given pointer
+         * If resid_dcnt == native_length, then we just loaded this SG
+         * segment and we need to back it up one...
          */
-        if(cur_addr < native_addr ||
-           cur_addr > (native_addr + native_length + 1))
-        {
-          printk(WARN_LEAD "invalid cur_addr:0x%x during WIDE_RESIDUE\n",
-                 p->host_no, CTL_OF_SCB(scb), cur_addr);
-          if(index > 0)
-            printk(WARN_LEAD "  sg_address[-1]:0x%x sg_length[-1]:%d\n",
-                   p->host_no, CTL_OF_SCB(scb),
-                   le32_to_cpu(scb->sg_list[index - 1].address),
-                   le32_to_cpu(scb->sg_list[index - 1].length));
-          printk(WARN_LEAD "  sg_address:0x%x sg_length:%d\n",
-                 p->host_no, CTL_OF_SCB(scb),
-                 native_addr, native_length);
-          if(resid_sgcnt > 1)
-            printk(WARN_LEAD "  sg_address[1]:0x%x sg_length[1]:%d\n",
-                   p->host_no, CTL_OF_SCB(scb),
-                   le32_to_cpu(scb->sg_list[index + 1].address),
-                   le32_to_cpu(scb->sg_list[index + 1].length));
-          printk(WARN_LEAD "  cur_address:0x%x resid_dcnt:0x%06x\n",
-                 p->host_no, CTL_OF_SCB(scb),
-                 cur_addr, resid_dcnt);
-          break;
-        }
-
-        if( (resid_sgcnt == 0) &&
-            ((resid_dcnt == 0) || (resid_dcnt == 0xffffff)))
-        {
-          /*
-           * We are at the end of the transfer and this is about a byte
-           * we ignored already (because the sequencer knew this was
-           * the last segment and set the adapter to ignore any wide
-           * residue bytes that might come through, which is only done
-           * on the last scatter gather segment of transfers).
-           */
-          break;
-        }
-        else if(cur_addr == native_addr)
+        if(resid_dcnt == native_length)
         {
-          /*
-           * If our current address matches the sg_seg->address then we
-           * have to back up the sg array to the previous segment and set
-           * it up to have only one byte of transfer left to go.
-           */
           if(index == 0)
           {
-            printk(WARN_LEAD "bogus WIDE_RESIDUE message, no data has been "
-                   "transferred.\n", p->host_no, CTL_OF_SCB(scb));
+            /*
+             * Oops, this isn't right, we can't back up to before the
+             * beginning.  This must be a bogus message, ignore it.
+             */
             break;
           }
-          resid_sgcnt++;
-          index--;
-          cur_addr = le32_to_cpu(scb->sg_list[index].address) + 
-            le32_to_cpu(scb->sg_list[index].length) - 1;
-          native_addr = aic_inb(p, SG_NEXT) | (aic_inb(p, SG_NEXT + 1) << 8)
-            | (aic_inb(p, SG_NEXT + 2) << 16) | (aic_inb(p, SG_NEXT + 3) << 24);
-          native_addr -= SG_SIZEOF;
-          aic_outb(p, resid_sgcnt, SG_COUNT);
-          aic_outb(p, resid_sgcnt, SCB_RESID_SGCNT);
-          aic_outb(p, native_addr & 0xff, SG_NEXT);
-          aic_outb(p, (native_addr >> 8) & 0xff, SG_NEXT + 1);
-          aic_outb(p, (native_addr >> 16) & 0xff, SG_NEXT + 2);
-          aic_outb(p, (native_addr >> 24) & 0xff, SG_NEXT + 3);
-          aic_outb(p, 1, SCB_RESID_DCNT); 
-          aic_outb(p, 0, SCB_RESID_DCNT + 1); 
-          aic_outb(p, 0, SCB_RESID_DCNT + 2); 
-          aic_outb(p, 1, HCNT); 
-          aic_outb(p, 0, HCNT + 1); 
-          aic_outb(p, 0, HCNT + 2); 
-          aic_outb(p, cur_addr & 0xff, HADDR);
-          aic_outb(p, (cur_addr >> 8) & 0xff, HADDR + 1);
-          aic_outb(p, (cur_addr >> 16) & 0xff, HADDR + 2);
-          aic_outb(p, (cur_addr >> 24) & 0xff, HADDR + 3);
+          resid_dcnt = 1;
+          resid_sgcnt += 1;
+          native_addr = le32_to_cpu(scb->sg_list[index - 1].address);
+          native_length = le32_to_cpu(scb->sg_list[index - 1].length);
+          cur_addr = native_addr + (native_length - 1);
+          sg_addr -= sizeof(struct hw_scatterlist);
         }
         else
         {
           /*
-           * Back the data pointer up by one and add one to the remaining
-           * byte count.  Then store that in the HCNT and HADDR registers.
+           * resid_dcnt != native_length, so we are in the middle of a SG
+           * element.  Back it up one byte and leave the rest alone.
            */
-          cur_addr--;
-          resid_dcnt++;
-          aic_outb(p, resid_dcnt & 0xff, SCB_RESID_DCNT); 
-          aic_outb(p, (resid_dcnt >> 8) & 0xff, SCB_RESID_DCNT + 1); 
-          aic_outb(p, (resid_dcnt >> 16) & 0xff, SCB_RESID_DCNT + 2); 
-          aic_outb(p, resid_dcnt & 0xff, HCNT); 
-          aic_outb(p, (resid_dcnt >> 8) & 0xff, HCNT + 1); 
-          aic_outb(p, (resid_dcnt >> 16) & 0xff, HCNT + 2); 
-          aic_outb(p, cur_addr & 0xff, HADDR);
-          aic_outb(p, (cur_addr >> 8) & 0xff, HADDR + 1);
-          aic_outb(p, (cur_addr >> 16) & 0xff, HADDR + 2);
-          aic_outb(p, (cur_addr >> 24) & 0xff, HADDR + 3);
+          resid_dcnt += 1;
+          cur_addr -= 1;
         }
+        
+        /*
+         * Output the new addresses and counts to the right places on the
+         * card.
+         */
+        aic_outb(p, resid_sgcnt, SG_COUNT);
+        aic_outb(p, resid_sgcnt, SCB_RESID_SGCNT);
+        aic_outb(p, sg_addr & 0xff, SG_COUNT + 1);
+        aic_outb(p, (sg_addr >> 8) & 0xff, SG_COUNT + 2);
+        aic_outb(p, (sg_addr >> 16) & 0xff, SG_COUNT + 3);
+        aic_outb(p, (sg_addr >> 24) & 0xff, SG_COUNT + 4);
+        aic_outb(p, resid_dcnt & 0xff, SCB_RESID_DCNT);
+        aic_outb(p, (resid_dcnt >> 8) & 0xff, SCB_RESID_DCNT + 1);
+        aic_outb(p, (resid_dcnt >> 16) & 0xff, SCB_RESID_DCNT + 2);
+
         /*
-         * The sequencer actually wants to find the new address and byte
-         * count in the SHCNT and SHADDR register sets.  These registers
-         * are a shadow of the regular HCNT and HADDR registers.  On the
-         * Ultra2 controllers, these registers are read only and the way
-         * we have to set their values is to put the values we want into
-         * the HCNT and HADDR registers and then output PRELOADEN into
-         * the DFCNTRL register which causes the card to latch the current
-         * values in the HADDR and HCNT registers and drop it through to
-         * the shadow registers.  On older cards we copy them directly
-         * across by hand.
+         * The sequencer actually wants to find the new address
+         * in the SHADDR register set.  On the Ultra2 and later controllers
+         * this register set is readonly.  In order to get the right number
+         * into the register, you actually have to enter it in HADDR and then
+         * use the PRELOADEN bit of DFCNTRL to drop it through from the
+         * HADDR register to the SHADDR register.  On non-Ultra2 controllers,
+         * we simply write it direct.
          */
         if(p->features & AHC_ULTRA2)
         {
-          aic_outb(p, aic_inb(p, DMAPARAMS), DFCNTRL);
-          i=0;
+          /*
+           * We might as well be accurate and drop both the resid_dcnt and
+           * cur_addr into HCNT and HADDR and have both of them drop
+           * through to the shadow layer together.
+           */
+          aic_outb(p, resid_dcnt & 0xff, HCNT);
+          aic_outb(p, (resid_dcnt >> 8) & 0xff, HCNT + 1);
+          aic_outb(p, (resid_dcnt >> 16) & 0xff, HCNT + 2);
+          aic_outb(p, cur_addr & 0xff, HADDR);
+          aic_outb(p, (cur_addr >> 8) & 0xff, HADDR + 1);
+          aic_outb(p, (cur_addr >> 16) & 0xff, HADDR + 2);
+          aic_outb(p, (cur_addr >> 24) & 0xff, HADDR + 3);
+          aic_outb(p, aic_inb(p, DMAPARAMS) | PRELOADEN, DFCNTRL);
           udelay(1);
-          while(((aic_inb(p, SSTAT0) & SDONE) != 0) && (i++ < 1000))
-          {
-            udelay(1);
-          }
           aic_outb(p, aic_inb(p, DMAPARAMS) & ~(SCSIEN|HDMAEN), DFCNTRL);
           i=0;
-          udelay(1);
           while(((aic_inb(p, DFCNTRL) & (SCSIEN|HDMAEN)) != 0) && (i++ < 1000))
           {
             udelay(1);
@@ -5321,9 +5299,6 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
         }
         else
         {
-          aic_outb(p, resid_dcnt & 0xff, STCNT); 
-          aic_outb(p, (resid_dcnt >> 8) & 0xff, STCNT + 1); 
-          aic_outb(p, (resid_dcnt >> 16) & 0xff, STCNT + 2); 
           aic_outb(p, cur_addr & 0xff, SHADDR);
           aic_outb(p, (cur_addr >> 8) & 0xff, SHADDR + 1);
           aic_outb(p, (cur_addr >> 16) & 0xff, SHADDR + 2);
@@ -5332,15 +5307,82 @@ 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, target, lun);
+    case SEQ_SG_FIXUP:
+    {
+      unsigned char scb_index, tmp;
+      int sg_addr, sg_length;
+
+      scb_index = aic_inb(p, SCB_TAG);
+
+      if(scb_index > p->scb_data->numscbs)
+      {
+        printk(WARN_LEAD "invalid scb_index during SEQ_SG_FIXUP.\n",
+          p->host_no, -1, -1, -1);
+        printk(INFO_LEAD "SCSISIGI 0x%x, SEQADDR 0x%x, SSTAT0 0x%x, SSTAT1 "
+           "0x%x\n", p->host_no, -1, -1, -1,
+           aic_inb(p, SCSISIGI),
+           aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8),
+           aic_inb(p, SSTAT0), aic_inb(p, SSTAT1));
+        printk(INFO_LEAD "SG_CACHEPTR 0x%x, SSTAT2 0x%x, STCNT 0x%x\n",
+           p->host_no, -1, -1, -1, aic_inb(p, SG_CACHEPTR),
+           aic_inb(p, SSTAT2), aic_inb(p, STCNT + 2) << 16 |
+           aic_inb(p, STCNT + 1) << 8 | aic_inb(p, STCNT));
+        /*
+         * XXX: Add error handling here
+         */
+        break;
       }
-      break;
+      scb = p->scb_data->scb_array[scb_index];
+      if(!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL))
+      {
+        printk(WARN_LEAD "invalid scb during SEQ_SG_FIXUP flags:0x%x "
+               "scb->cmd:0x%x\n", p->host_no, CTL_OF_SCB(scb),
+               scb->flags, (unsigned int)scb->cmd);
+        printk(INFO_LEAD "SCSISIGI 0x%x, SEQADDR 0x%x, SSTAT0 0x%x, SSTAT1 "
+           "0x%x\n", p->host_no, CTL_OF_SCB(scb),
+           aic_inb(p, SCSISIGI),
+           aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8),
+           aic_inb(p, SSTAT0), aic_inb(p, SSTAT1));
+        printk(INFO_LEAD "SG_CACHEPTR 0x%x, SSTAT2 0x%x, STCNT 0x%x\n",
+           p->host_no, CTL_OF_SCB(scb), aic_inb(p, SG_CACHEPTR),
+           aic_inb(p, SSTAT2), aic_inb(p, STCNT + 2) << 16 |
+           aic_inb(p, STCNT + 1) << 8 | aic_inb(p, STCNT));
+        break;
+      }
+      if(aic7xxx_verbose & VERBOSE_MINOR_ERROR)
+        printk(INFO_LEAD "Fixing up SG address for sequencer.\n", p->host_no,
+               CTL_OF_SCB(scb));
+      /*
+       * Advance the SG pointer to the next element in the list
+       */
+      tmp = aic_inb(p, SG_NEXT);
+      tmp += SG_SIZEOF;
+      aic_outb(p, tmp, SG_NEXT);
+      if( tmp < SG_SIZEOF )
+        aic_outb(p, aic_inb(p, SG_NEXT + 1) + 1, SG_NEXT + 1);
+      tmp = aic_inb(p, SG_COUNT) - 1;
+      aic_outb(p, tmp, SG_COUNT);
+      sg_addr = le32_to_cpu(scb->sg_list[scb->sg_count - tmp].address);
+      sg_length = le32_to_cpu(scb->sg_list[scb->sg_count - tmp].length);
+      /*
+       * Now stuff the element we just advanced past down onto the
+       * card so it can be stored in the residual area.
+       */
+      aic_outb(p, sg_addr & 0xff, HADDR);
+      aic_outb(p, (sg_addr >> 8) & 0xff, HADDR + 1);
+      aic_outb(p, (sg_addr >> 16) & 0xff, HADDR + 2);
+      aic_outb(p, (sg_addr >> 24) & 0xff, HADDR + 3);
+      aic_outb(p, sg_length & 0xff, HCNT);
+      aic_outb(p, (sg_length >> 8) & 0xff, HCNT + 1);
+      aic_outb(p, (sg_length >> 16) & 0xff, HCNT + 2);
+      aic_outb(p, (tmp << 2) | ((tmp == 1) ? LAST_SEG : 0), SG_CACHEPTR);
+      aic_outb(p, aic_inb(p, DMAPARAMS), DFCNTRL);
+      while(aic_inb(p, SSTAT0) & SDONE) udelay(1);
+      while(aic_inb(p, DFCNTRL) & (HDMAEN|SCSIEN)) aic_outb(p, 0, DFCNTRL);
+    }
+    break;
 
+#if AIC7XXX_NOT_YET 
     case TRACEPOINT2:
       {
         printk(INFO_LEAD "Tracepoint #2 reached.\n", p->host_no,
@@ -5385,6 +5427,10 @@ aic7xxx_parse_msg(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
   unsigned char target_scsirate, tindex;
   unsigned short target_mask;
   unsigned char target, channel, lun;
+  unsigned char bus_width, new_bus_width;
+  unsigned char trans_options, new_trans_options;
+  unsigned int period, new_period, offset, new_offset, maxsync;
+  struct aic7xxx_syncrate *syncrate;
 
   target = scb->cmd->target;
   channel = scb->cmd->channel;
@@ -5407,6 +5453,35 @@ aic7xxx_parse_msg(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
     reject = TRUE;
   }
 
+  /*
+   * Even if we are an Ultra3 card, don't allow Ultra3 sync rates when
+   * using the SDTR messages.  We need the PPR messages to enable the
+   * higher speeds that include things like Dual Edge clocking.
+   */
+  if (p->features & AHC_ULTRA2)
+  {
+    if ( (aic_inb(p, SBLKCTL) & ENAB40) &&
+         !(aic_inb(p, SSTAT2) & EXP_ACTIVE) )
+    {
+      if (p->features & AHC_ULTRA3)
+        maxsync = AHC_SYNCRATE_ULTRA3;
+      else
+        maxsync = AHC_SYNCRATE_ULTRA2;
+    }
+    else
+    {
+      maxsync = AHC_SYNCRATE_ULTRA;
+    }
+  }
+  else if (p->features & AHC_ULTRA)
+  {
+    maxsync = AHC_SYNCRATE_ULTRA;
+  }
+  else
+  {
+    maxsync = AHC_SYNCRATE_FAST;
+  }
+
   /*
    * Just accept the length byte outright and perform
    * more checking once we know the message type.
@@ -5418,9 +5493,6 @@ aic7xxx_parse_msg(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
     {
       case MSG_EXT_SDTR:
       {
-        unsigned int period, offset;
-        unsigned char maxsync, saved_offset, options;
-        struct aic7xxx_syncrate *syncrate;
         
         if (p->msg_buf[1] != MSG_EXT_SDTR_LEN)
         {
@@ -5433,35 +5505,18 @@ aic7xxx_parse_msg(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
           break;
         }
 
-        period = p->msg_buf[3];
-        saved_offset = offset = p->msg_buf[4];
-        options = 0;
+        period = new_period = p->msg_buf[3];
+        offset = new_offset = p->msg_buf[4];
+        trans_options = new_trans_options = 0;
+        bus_width = new_bus_width = target_scsirate & WIDEXFER;
 
         /*
-         * Even if we are an Ultra3 card, don't allow Ultra3 sync rates when
-         * using the SDTR messages.  We need the PPR messages to enable the
-         * higher speeds that include things like Dual Edge clocking.
+         * If our current max syncrate is in the Ultra3 range, bump it back
+         * down to Ultra2 since we can't negotiate DT transfers using SDTR
          */
-        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)
-        {
-          maxsync = AHC_SYNCRATE_ULTRA;
-        }
-        else
-        {
-          maxsync = AHC_SYNCRATE_FAST;
-        }
+        if(maxsync == AHC_SYNCRATE_ULTRA3)
+          maxsync = AHC_SYNCRATE_ULTRA2;
+
         /*
          * We might have a device that is starting negotiation with us
          * before we can start up negotiation with it....be prepared to
@@ -5471,88 +5526,116 @@ aic7xxx_parse_msg(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
         if ( (scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) !=
              (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR) )
         {
-          if (!(p->dev_flags[tindex] & DEVICE_SCANNED) &&
-              !(p->needsdtr_copy & target_mask) &&
-               (p->transinfo[tindex].user_offset) )
+          if (!(p->dev_flags[tindex] & DEVICE_DTR_SCANNED))
           {
             /*
-             * Not only is the device starting this up, but it also hasn't
-             * been scanned yet, so this would likely be our TUR or our
-             * INQUIRY command at scan time, so we need to use the
-             * settings from the SEEPROM if they existed.  Of course, even
-             * if we didn't find a SEEPROM, we stuffed default values into
-             * the user settings anyway, so use those in all cases.
+             * We shouldn't get here unless this is a narrow drive, wide
+             * devices should trigger this same section of code in the WDTR
+             * handler first instead.
              */
-            p->transinfo[tindex].goal_period =
-              p->transinfo[tindex].user_period;
-            if(p->features & AHC_ULTRA2)
-            {
-              p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
-            }
-            else if (p->transinfo[tindex].cur_width)
+            p->transinfo[tindex].goal_width = MSG_EXT_WDTR_BUS_8_BIT;
+            p->transinfo[tindex].goal_options = 0;
+            if(p->transinfo[tindex].user_offset)
             {
-              p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT;
+              p->needsdtr_copy |= target_mask;
+              p->transinfo[tindex].goal_period =
+                MAX(10,p->transinfo[tindex].user_period);
+              if(p->features & AHC_ULTRA2)
+              {
+                p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
+              }
+              else
+              {
+                p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
+              }
             }
             else
             {
-              p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
+              p->needsdtr_copy &= ~target_mask;
+              p->transinfo[tindex].goal_period = 255;
+              p->transinfo[tindex].goal_offset = 0;
             }
-            p->needsdtr_copy |= target_mask;
+            p->dev_flags[tindex] |= DEVICE_DTR_SCANNED | DEVICE_PRINT_DTR;
+          }
+          else if ((p->needsdtr_copy & target_mask) == 0)
+          {
+            /*
+             * This is a preemptive message from the target, we've already
+             * scanned this target and set our options for it, and we
+             * don't need a WDTR with this target (for whatever reason),
+             * so reject this incoming WDTR
+             */
+            reject = TRUE;
+            break;
           }
+
+          /* The device is sending this message first and we have to reply */
+          reply = TRUE;
+          
           if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
           {
             printk(INFO_LEAD "Received pre-emptive SDTR message from "
                    "target.\n", p->host_no, CTL_OF_SCB(scb));
           }
-          if ( !p->transinfo[tindex].goal_offset )
-            period = 255;
-          if ( p->transinfo[tindex].goal_period > period )
-            period = p->transinfo[tindex].goal_period;
+          /*
+           * Validate the values the device passed to us against our SEEPROM
+           * settings.  We don't have to do this if we aren't replying since
+           * the device isn't allowed to send values greater than the ones
+           * we first sent to it.
+           */
+          new_period = MAX(period, p->transinfo[tindex].goal_period);
+          new_offset = MIN(offset, p->transinfo[tindex].goal_offset);
         }
-  
-        syncrate = aic7xxx_find_syncrate(p, &period, maxsync, &options);
-        aic7xxx_validate_offset(p, syncrate, &offset,
-                                target_scsirate & WIDEXFER);
-        aic7xxx_set_syncrate(p, syncrate, target, channel, period,
-                             offset, options, AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+        /*
+         * Use our new_period, new_offset, bus_width, and card options
+         * to determine the actual syncrate settings
+         */
+        syncrate = aic7xxx_find_syncrate(p, &new_period, maxsync,
+                                         &trans_options);
+        aic7xxx_validate_offset(p, syncrate, &new_offset, bus_width);
 
         /*
-         * Did we drop to async?  Or are we sending a reply?  If we are,
-         * then we have to make sure that the reply value reflects the proper
-         * settings so we need to set the goal values according to what
-         * we need to send.
+         * Did we drop to async?  If so, send a reply regardless of whether
+         * or not we initiated this negotiation.
          */
-        if ( (offset != saved_offset) ||
-             ((scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) !=
-              (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR) ) )
+        if ((new_offset == 0) && (new_offset != offset))
         {
-          aic7xxx_set_syncrate(p, syncrate, target, channel, period, offset,
-                               options, AHC_TRANS_GOAL|AHC_TRANS_QUITE);
+          p->needsdtr_copy &= ~target_mask;
+          reply = TRUE;
         }
         
         /*
-         * Did we start this, if not, or if we went to low and had to
+         * Did we start this, if not, or if we went too low and had to
          * go async, then send an SDTR back to the target
          */
-        p->needsdtr &= ~target_mask;
-        p->dtr_pending &= ~target_mask;
-        if ( ((scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) !=
-              (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) ||
-             (offset != saved_offset) )
+        if(reply)
         {
-          reply = TRUE;
-          p->dtr_pending |= target_mask;
+          /* when sending a reply, make sure that the goal settings are
+           * updated along with current and active since the code that
+           * will actually build the message for the sequencer uses the
+           * goal settings as its guidelines.
+           */
+          aic7xxx_set_syncrate(p, syncrate, target, channel, new_period,
+                               new_offset, trans_options,
+                               AHC_TRANS_GOAL|AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
           scb->flags &= ~SCB_MSGOUT_BITS;
           scb->flags |= SCB_MSGOUT_SDTR;
           aic_outb(p, HOST_MSG, MSG_OUT);
           aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
         }
+        else
+        {
+          aic7xxx_set_syncrate(p, syncrate, target, channel, new_period,
+                               new_offset, trans_options,
+                               AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+          p->needsdtr &= ~target_mask;
+        }
         done = TRUE;
         break;
       }
       case MSG_EXT_WDTR:
       {
-        unsigned char bus_width;
           
         if (p->msg_buf[1] != MSG_EXT_WDTR_LEN)
         {
@@ -5565,7 +5648,8 @@ aic7xxx_parse_msg(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
           break;
         }
 
-        bus_width = p->msg_buf[3];
+        bus_width = new_bus_width = p->msg_buf[3];
+
         if ( (scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_WDTR)) ==
              (SCB_MSGOUT_SENT|SCB_MSGOUT_WDTR) )
         {
@@ -5584,7 +5668,7 @@ aic7xxx_parse_msg(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
             } /* We fall through on purpose */
             case MSG_EXT_WDTR_BUS_8_BIT:
             {
-              bus_width = MSG_EXT_WDTR_BUS_8_BIT;
+              p->transinfo[tindex].goal_width = MSG_EXT_WDTR_BUS_8_BIT;
               p->needwdtr_copy &= ~target_mask;
               break;
             }
@@ -5593,29 +5677,40 @@ aic7xxx_parse_msg(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
               break;
             }
           }
-          p->dtr_pending &= ~target_mask;
           p->needwdtr &= ~target_mask;
+          aic7xxx_set_width(p, target, channel, lun, new_bus_width,
+                            AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
         }
         else
         {
-          if ( !(p->dev_flags[tindex] & DEVICE_SCANNED) )
+          if ( !(p->dev_flags[tindex] & DEVICE_DTR_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_period =
-              p->transinfo[tindex].user_period;
+            if( (p->features & AHC_WIDE) && p->transinfo[tindex].user_width )
+            {
+              p->transinfo[tindex].goal_width = MSG_EXT_WDTR_BUS_16_BIT;
+              p->needwdtr_copy |= target_mask;
+            }
+            
+            /*
+             * Devices that support DT transfers don't start WDTR requests
+             */
+            p->transinfo[tindex].goal_options = 0;
+
             if(p->transinfo[tindex].user_offset)
             {
+              p->needsdtr_copy |= target_mask;
+              p->transinfo[tindex].goal_period =
+                MAX(10,p->transinfo[tindex].user_period);
               if(p->features & AHC_ULTRA2)
               {
                 p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
               }
-              else if( p->transinfo[tindex].user_width &&
-                       (bus_width == MSG_EXT_WDTR_BUS_16_BIT) &&
-                       p->features & AHC_WIDE )
+              else if( p->transinfo[tindex].goal_width )
               {
                 p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT;
               }
@@ -5623,12 +5718,29 @@ aic7xxx_parse_msg(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
               {
                 p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
               }
+            } else {
+              p->needsdtr_copy &= ~target_mask;
+              p->transinfo[tindex].goal_period = 255;
+              p->transinfo[tindex].goal_offset = 0;
             }
-            p->transinfo[tindex].goal_width =
-              p->transinfo[tindex].user_width;
-            p->needwdtr_copy |= target_mask;
-            p->needsdtr_copy |= target_mask;
+            
+            p->dev_flags[tindex] |= DEVICE_DTR_SCANNED | DEVICE_PRINT_DTR;
+          }
+          else if ((p->needwdtr_copy & target_mask) == 0)
+          {
+            /*
+             * This is a preemptive message from the target, we've already
+             * scanned this target and set our options for it, and we
+             * don't need a WDTR with this target (for whatever reason),
+             * so reject this incoming WDTR
+             */
+            reject = TRUE;
+            break;
           }
+
+          /* The device is sending this message first and we have to reply */
+          reply = TRUE;
+
           if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
           {
             printk(INFO_LEAD "Received pre-emptive WDTR message from "
@@ -5636,35 +5748,46 @@ aic7xxx_parse_msg(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
           }
           switch(bus_width)
           {
-            default:
+            case MSG_EXT_WDTR_BUS_16_BIT:
             {
               if ( (p->features & AHC_WIDE) &&
                    (p->transinfo[tindex].goal_width ==
                     MSG_EXT_WDTR_BUS_16_BIT) )
               {
-                bus_width = MSG_EXT_WDTR_BUS_16_BIT;
+                new_bus_width = MSG_EXT_WDTR_BUS_16_BIT;
                 break;
               }
             } /* Fall through if we aren't a wide card */
+            default:
             case MSG_EXT_WDTR_BUS_8_BIT:
             {
               p->needwdtr_copy &= ~target_mask;
-              bus_width = MSG_EXT_WDTR_BUS_8_BIT;
-              aic7xxx_set_width(p, target, channel, lun, bus_width,
-                                AHC_TRANS_GOAL|AHC_TRANS_QUITE);
+              new_bus_width = MSG_EXT_WDTR_BUS_8_BIT;
               break;
             }
           }
-          reply = TRUE;
           scb->flags &= ~SCB_MSGOUT_BITS;
           scb->flags |= SCB_MSGOUT_WDTR;
           p->needwdtr &= ~target_mask;
-          p->dtr_pending |= target_mask;
+          if((p->dtr_pending & target_mask) == 0)
+          {
+            /* there is no other command with SCB_DTR_SCB already set that will
+             * trigger the release of the dtr_pending bit.  Both set the bit
+             * and set scb->flags |= SCB_DTR_SCB
+             */
+            p->dtr_pending |= target_mask;
+            scb->flags |= SCB_DTR_SCB;
+          }
           aic_outb(p, HOST_MSG, MSG_OUT);
           aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
+          /* when sending a reply, make sure that the goal settings are
+           * updated along with current and active since the code that
+           * will actually build the message for the sequencer uses the
+           * goal settings as its guidelines.
+           */
+          aic7xxx_set_width(p, target, channel, lun, new_bus_width,
+                          AHC_TRANS_GOAL|AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
         }
-        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
@@ -5681,10 +5804,6 @@ aic7xxx_parse_msg(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
       }
       case MSG_EXT_PPR:
       {
-        unsigned char bus_width, trans_options, new_trans_options;
-        unsigned int period, offset;
-        unsigned char maxsync, saved_offset;
-        struct aic7xxx_syncrate *syncrate;
         
         if (p->msg_buf[1] != MSG_EXT_PPR_LEN)
         {
@@ -5697,9 +5816,9 @@ aic7xxx_parse_msg(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
           break;
         }
 
-        period = p->msg_buf[3];
-        offset = saved_offset = p->msg_buf[5];
-        bus_width = p->msg_buf[6];
+        period = new_period = p->msg_buf[3];
+        offset = new_offset = p->msg_buf[5];
+        bus_width = new_bus_width = p->msg_buf[6];
         trans_options = new_trans_options = p->msg_buf[7] & 0xf;
 
         if(aic7xxx_verbose & VERBOSE_NEGOTIATION2)
@@ -5709,22 +5828,6 @@ aic7xxx_parse_msg(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
                  trans_options);
         }
 
-        if ( (aic_inb(p, SBLKCTL) & ENAB40) &&
-            !(aic_inb(p, SSTAT2) & EXP_ACTIVE) )
-        {
-          if(p->features & AHC_ULTRA3)
-          {
-            maxsync = AHC_SYNCRATE_ULTRA3;
-          }
-          else
-          {
-            maxsync = AHC_SYNCRATE_ULTRA2;
-          }
-        }
-        else
-        {
-          maxsync = AHC_SYNCRATE_ULTRA;
-        }
         /*
          * We might have a device that is starting negotiation with us
          * before we can start up negotiation with it....be prepared to
@@ -5733,13 +5836,22 @@ aic7xxx_parse_msg(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
          */
         if ( (scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_PPR)) !=
              (SCB_MSGOUT_SENT|SCB_MSGOUT_PPR) )
-        {
-          reply = TRUE;
-          scb->flags &= ~SCB_MSGOUT_BITS;
-          scb->flags |= SCB_MSGOUT_PPR;
-         p->dev_flags[tindex] |= DEVICE_SCSI_3;
-          if (!(p->dev_flags[tindex] & DEVICE_SCANNED))
+        { 
+          /* Have we scanned the device yet? */
+          if (!(p->dev_flags[tindex] & DEVICE_DTR_SCANNED))
           {
+            /* The device is electing to use PPR messages, so we will too until
+             * we know better */
+            p->needppr |= target_mask;
+            p->needppr_copy |= target_mask;
+            p->needsdtr &= ~target_mask;
+            p->needsdtr_copy &= ~target_mask;
+            p->needwdtr &= ~target_mask;
+            p->needwdtr_copy &= ~target_mask;
+          
+            /* We know the device is SCSI-3 compliant due to PPR */
+            p->dev_flags[tindex] |= DEVICE_SCSI_3;
+          
             /*
              * Not only is the device starting this up, but it also hasn't
              * been scanned yet, so this would likely be our TUR or our
@@ -5748,15 +5860,19 @@ aic7xxx_parse_msg(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
              * if we didn't find a SEEPROM, we stuffed default values into
              * the user settings anyway, so use those in all cases.
              */
-            p->transinfo[tindex].goal_period =
-              p->transinfo[tindex].user_period;
+            p->transinfo[tindex].goal_width =
+              p->transinfo[tindex].user_width;
             if(p->transinfo[tindex].user_offset)
             {
+              p->transinfo[tindex].goal_period =
+                p->transinfo[tindex].user_period;
+              p->transinfo[tindex].goal_options =
+                p->transinfo[tindex].user_options;
               if(p->features & AHC_ULTRA2)
               {
                 p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
               }
-              else if( p->transinfo[tindex].user_width &&
+              else if( p->transinfo[tindex].goal_width &&
                        (bus_width == MSG_EXT_WDTR_BUS_16_BIT) &&
                        p->features & AHC_WIDE )
               {
@@ -5767,117 +5883,142 @@ aic7xxx_parse_msg(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
                 p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
               }
             }
-            p->transinfo[tindex].goal_width =
-              p->transinfo[tindex].user_width;
-            p->transinfo[tindex].goal_options =
-              p->transinfo[tindex].user_options;
+            else
+            {
+              p->transinfo[tindex].goal_period = 255;
+              p->transinfo[tindex].goal_offset = 0;
+              p->transinfo[tindex].goal_options = 0;
+            }
+            p->dev_flags[tindex] |= DEVICE_DTR_SCANNED | DEVICE_PRINT_DTR;
+          }
+          else if ((p->needppr_copy & target_mask) == 0)
+          {
+            /*
+             * This is a preemptive message from the target, we've already
+             * scanned this target and set our options for it, and we
+             * don't need a PPR with this target (for whatever reason),
+             * so reject this incoming PPR
+             */
+            reject = TRUE;
+            break;
           }
+
+          /* The device is sending this message first and we have to reply */
+          reply = TRUE;
+          
           if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
           {
             printk(INFO_LEAD "Received pre-emptive PPR message from "
                    "target.\n", p->host_no, CTL_OF_SCB(scb));
           }
-          if ( !p->transinfo[tindex].goal_offset )
-            period = 255;
-          if ( p->transinfo[tindex].goal_period > period )
-            period = p->transinfo[tindex].goal_period;
-          if ( p->transinfo[tindex].goal_options == 0 )
-            new_trans_options = 0;
-          switch(bus_width)
+
+        }
+
+        switch(bus_width)
+        {
+          case MSG_EXT_WDTR_BUS_16_BIT:
           {
-            default:
+            if ( (p->transinfo[tindex].goal_width ==
+                  MSG_EXT_WDTR_BUS_16_BIT) && p->features & 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;
-                break;
-              }
-            } /* Fall through if we aren't a wide card */
-            case MSG_EXT_WDTR_BUS_8_BIT:
-            {
-              p->needwdtr_copy &= ~target_mask;
-              bus_width = MSG_EXT_WDTR_BUS_8_BIT;
-              aic7xxx_set_width(p, target, channel, lun, bus_width,
-                                AHC_TRANS_GOAL|AHC_TRANS_QUITE);
               break;
             }
           }
-          if ( (p->transinfo[tindex].goal_period > 9) ||
-               (p->transinfo[tindex].goal_options == 0) )
+          default:
           {
-            scb->flags &= ~SCB_MSGOUT_BITS;
-            reject = TRUE;
-            reply = FALSE;
-            p->needppr &= ~(1 << tindex);
-            p->needppr_copy &= ~(1 << tindex);
-            if ( p->transinfo[tindex].goal_offset )
-            {
-              p->needsdtr |= (1 << tindex);
-              p->needsdtr_copy |= (1 << tindex);
-            }
-            if ( p->transinfo[tindex].goal_width )
+            if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
+                 ((p->dev_flags[tindex] & DEVICE_PRINT_DTR) ||
+                  (aic7xxx_verbose > 0xffff)) )
             {
-              p->needwdtr |= (1 << tindex);
-              p->needwdtr_copy |= (1 << tindex);
+              reply = TRUE;
+              printk(INFO_LEAD "Requesting %d bit transfers, rejecting.\n",
+                p->host_no, CTL_OF_SCB(scb), 8 * (0x01 << bus_width));
             }
+          } /* We fall through on purpose */
+          case MSG_EXT_WDTR_BUS_8_BIT:
+          {
+            /*
+             * According to the spec, if we aren't wide, we also can't be
+             * Dual Edge so clear the options byte
+             */
+            new_trans_options = 0;
+            new_bus_width = MSG_EXT_WDTR_BUS_8_BIT;
+            break;
           }
         }
+
+        if(reply)
+        {
+          /* when sending a reply, make sure that the goal settings are
+           * updated along with current and active since the code that
+           * will actually build the message for the sequencer uses the
+           * goal settings as its guidelines.
+           */
+          aic7xxx_set_width(p, target, channel, lun, new_bus_width,
+                            AHC_TRANS_GOAL|AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+          syncrate = aic7xxx_find_syncrate(p, &new_period, maxsync,
+                                           &new_trans_options);
+          aic7xxx_validate_offset(p, syncrate, &new_offset, new_bus_width);
+          aic7xxx_set_syncrate(p, syncrate, target, channel, new_period,
+                               new_offset, new_trans_options,
+                               AHC_TRANS_GOAL|AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+        }
         else
         {
-          switch(bus_width)
+          aic7xxx_set_width(p, target, channel, lun, new_bus_width,
+                            AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+          syncrate = aic7xxx_find_syncrate(p, &new_period, maxsync,
+                                           &new_trans_options);
+          aic7xxx_validate_offset(p, syncrate, &new_offset, new_bus_width);
+          aic7xxx_set_syncrate(p, syncrate, target, channel, new_period,
+                               new_offset, new_trans_options,
+                               AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+        }
+
+        /*
+         * As it turns out, if we don't *have* to have PPR messages, then
+         * configure ourselves not to use them since that makes some
+         * external drive chassis work (those chassis can't parse PPR
+         * messages and they mangle the SCSI bus until you send a WDTR
+         * and SDTR that they can understand).
+         */
+        if(new_trans_options == 0)
+        {
+          p->needppr &= ~target_mask;
+          p->needppr_copy &= ~target_mask;
+          if(new_offset)
           {
-            default:
-            {
-              reject = TRUE;
-              if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
-                   ((p->dev_flags[tindex] & DEVICE_PRINT_DTR) ||
-                    (aic7xxx_verbose > 0xffff)) )
-              {
-                printk(INFO_LEAD "Requesting %d bit transfers, rejecting.\n",
-                  p->host_no, CTL_OF_SCB(scb), 8 * (0x01 << bus_width));
-              }
-            } /* We fall through on purpose */
-            case MSG_EXT_WDTR_BUS_8_BIT:
-            {
-              /*
-               * According to the spec, if we aren't wide, we also can't be
-               * Dual Edge so clear the options byte
-               */
-              new_trans_options = 0;
-              bus_width = MSG_EXT_WDTR_BUS_8_BIT;
-              break;
-            }
-            case MSG_EXT_WDTR_BUS_16_BIT:
-            {
-              break;
-            }
+            p->needsdtr |= target_mask;
+            p->needsdtr_copy |= target_mask;
+          }
+          if (new_bus_width)
+          {
+            p->needwdtr |= target_mask;
+            p->needwdtr_copy |= target_mask;
           }
         }
 
-        if ( !reject )
+        if((new_offset == 0) && (offset != 0))
         {
-          aic7xxx_set_width(p, target, channel, lun, bus_width,
-                            AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
-          syncrate = aic7xxx_find_syncrate(p, &period, maxsync,
-                                           &new_trans_options);
-          aic7xxx_validate_offset(p, syncrate, &offset, bus_width);
-          aic7xxx_set_syncrate(p, syncrate, target, channel, period,
-                               offset, new_trans_options,
-                               AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+          /*
+           * Oops, the syncrate went to low for this card and we fell off
+           * to async (should never happen with a device that uses PPR
+           * messages, but have to be complete)
+           */
+          reply = TRUE;
         }
 
-        p->dtr_pending &= ~target_mask;
-        p->needppr &= ~target_mask;
         if(reply)
         {
-          p->dtr_pending |= target_mask;
           scb->flags &= ~SCB_MSGOUT_BITS;
           scb->flags |= SCB_MSGOUT_PPR;
           aic_outb(p, HOST_MSG, MSG_OUT);
           aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
         }
+        else
+        {
+          p->needppr &= ~target_mask;
+        }
         done = TRUE;
         break;
       }
@@ -6115,16 +6256,14 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
         printerror = 0;
       }
     }
-    if ( (scb != NULL) &&
-         (scb->cmd == p->dev_dtr_cmnd[TARGET_INDEX(scb->cmd)]) )
+    if ( (scb != NULL) && (scb->flags & SCB_DTR_SCB) ) 
     {
       /*
-       * This might be a SCSI-3 device that is dropping the bus due to
-       * errors and signalling that we should reduce the transfer speed.
-       * All we have to do is complete this command (since it's a negotiation
-       * command already) and the checksum routine should flag an error and
-       * reduce the speed setting and renegotiate.  We call the reset routing
-       * just to clean out the hardware from this scb.
+       * Hmmm...error during a negotiation command.  Either we have a
+       * borken bus, or the device doesn't like our negotiation message.
+       * Since we check the INQUIRY data of a device before sending it
+       * negotiation messages, assume the bus is borken for whatever
+       * reason.  Complete the command.
        */
       printerror = 0;
       aic7xxx_reset_device(p, target, channel, ALL_LUNS, scb->hscb->tag);
@@ -6256,19 +6395,6 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
         cmd->result = 0;
         scb = NULL;
       }
-      else if (scb->cmd == p->dev_dtr_cmnd[TARGET_INDEX(scb->cmd)])
-      {
-        /*
-         * Turn off the needsdtr, needwdtr, and needppr bits since this device
-         * doesn't seem to exist.
-         */
-        p->needppr &= ~(0x01 << TARGET_INDEX(scb->cmd));
-        p->needppr_copy &= ~(0x01 << TARGET_INDEX(scb->cmd));
-        p->needsdtr &= ~(0x01 << TARGET_INDEX(scb->cmd));
-        p->needsdtr_copy &= ~(0x01 << TARGET_INDEX(scb->cmd));
-        p->needwdtr &= ~(0x01 << TARGET_INDEX(scb->cmd));
-        p->needwdtr_copy &= ~(0x01 << TARGET_INDEX(scb->cmd));
-      }
     }
     /*
      * Keep the sequencer from trying to restart any selections
@@ -6391,7 +6517,6 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
       }
     }
     else if( (lastphase == P_MESGOUT) &&
-             (cmd == p->dev_dtr_cmnd[tindex]) &&
              (scb->flags & SCB_MSGOUT_PPR) )
     {
       /*
@@ -6410,7 +6535,6 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
       aic7xxx_set_syncrate(p, NULL, scb->cmd->target, scb->cmd->channel, 0, 0,
                            0, AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE);
       p->transinfo[tindex].goal_options = 0;
-      p->dtr_pending &= ~(1 << tindex);
       scb->flags &= ~SCB_MSGOUT_BITS;
       if(aic7xxx_verbose & VERBOSE_NEGOTIATION2)
       {
@@ -6433,87 +6557,6 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
       }
       scb = NULL;
     }
-    else if(p->dev_flags[tindex] & DEVICE_PARITY_ERROR)
-    {
-      struct aic7xxx_syncrate *syncrate;
-      unsigned int period = p->transinfo[tindex].cur_period;
-      unsigned char options = p->transinfo[tindex].cur_options;
-      /*
-       * oops, we had a failure, lower the transfer rate and try again.  It's
-       * worth noting here that it might be wise to also check for typical
-       * wide setting on narrow cable type problems and try disabling wide
-       * instead of slowing down if those exist.  That's hard to do with simple
-       * checksums though.
-       */
-      printk(WARN_LEAD "Parity error during %s phase.\n",
-             p->host_no, CTL_OF_SCB(scb), phase);
-      if((syncrate = aic7xxx_find_syncrate(p, &period, 0, &options)) != NULL)
-      {
-        syncrate++;
-        if( (syncrate->rate[0] != NULL) &&
-            (!(p->features & AHC_ULTRA2) || (syncrate->sxfr_ultra2 == 0)) )
-        {
-          p->transinfo[tindex].goal_period = syncrate->period;
-          if( p->transinfo[tindex].goal_period > 9 )
-          {
-            p->transinfo[tindex].goal_options = 0;
-            p->needppr &= ~(1<<tindex);
-            p->needsdtr |= (1<<tindex);
-            p->needppr_copy &= ~(1<<tindex);
-            p->needsdtr_copy |= (1<<tindex);
-            if (p->transinfo[tindex].goal_width)
-            {
-              p->needwdtr |= (1<<tindex);
-              p->needwdtr_copy |= (1<<tindex);
-            }
-          }
-        }
-        else if (p->transinfo[tindex].goal_width)
-        {
-          p->transinfo[tindex].goal_width = 0;
-          p->needwdtr &= ~(1<<tindex);
-          p->needwdtr_copy &= ~(1<<tindex);
-          p->transinfo[tindex].goal_offset =
-            p->transinfo[tindex].user_offset;
-          p->transinfo[tindex].goal_period =
-            p->transinfo[tindex].user_period;
-          p->transinfo[tindex].goal_options =
-            p->transinfo[tindex].user_options;
-          if( p->transinfo[tindex].goal_period <= 9 )
-          {
-            p->needppr |= (1<<tindex);
-            p->needsdtr &= ~(1<<tindex);
-            p->needppr_copy |= (1<<tindex);
-            p->needsdtr_copy &= ~(1<<tindex);
-          }
-          else
-          {
-            p->needppr &= ~(1<<tindex);
-            p->needsdtr |= (1<<tindex);
-            p->needppr_copy &= ~(1<<tindex);
-            p->needsdtr_copy |= (1<<tindex);
-          }
-        }
-        else
-        {
-          p->transinfo[tindex].goal_offset = 0;
-          p->transinfo[tindex].goal_period = 255;
-          p->transinfo[tindex].goal_options = 0;
-          p->transinfo[tindex].goal_width = 0;
-          p->needppr &= ~(1<<tindex);
-          p->needsdtr &= ~(1<<tindex);
-          p->needwdtr &= ~(1<<tindex);
-          p->needppr_copy &= ~(1<<tindex);
-          p->needsdtr_copy &= ~(1<<tindex);
-          p->needwdtr_copy &= ~(1<<tindex);
-        }
-      }
-      p->dev_flags[tindex] &= ~DEVICE_PARITY_ERROR;
-    }
-    else
-    {
-      p->dev_flags[tindex] |= DEVICE_PARITY_ERROR;
-    }
 
     /*
      * We've set the hardware to assert ATN if we get a parity
@@ -6782,34 +6825,11 @@ aic7xxx_handle_command_completion_intr(struct aic7xxx_host *p)
     else if (scb->flags & SCB_SENSE)
     {
       char *buffer = &scb->cmd->sense_buffer[0];
-      if (scb->cmd == p->dev_dtr_cmnd[tindex])
-      {
-        struct aic7xxx_scb *old_scb;
-        /*
-         * We have valid sense data, send it back immediately.
-         */
-        old_scb = p->scb_data->scb_array[scb->cmd->next->tag];
-        *old_scb->cmd->sense_buffer = *scb->cmd->sense_buffer;
-        old_scb->hscb->target_status = scb->hscb->target_status;
-        old_scb->cmd->result = scb->hscb->target_status;
-        old_scb->cmd->result |= (DID_ERROR << 16);
-        aic7xxx_status(old_scb->cmd) = scb->hscb->target_status;
-        scbq_remove(&p->waiting_scbs, old_scb);
-        scbq_remove(&p->delayed_scbs[tindex], old_scb);
-        scb->cmd->next = NULL;
-       aic7xxx_done(p, scb);
-        aic7xxx_done(p, old_scb);
-       continue;
-      } 
-      else if (buffer[12] == 0x47 || buffer[12] == 0x54)
+
+      if (buffer[12] == 0x47 || buffer[12] == 0x54)
       {
         /*
-         * SCSI errors, run domain validation and re-run negotiation
-         */
-        p->needdv |= (1<<tindex);
-        /*
-         * Signal that we need to re-negotiate things, this also gets us our
-         * INQUIRY command to re-checksum off of.
+         * Signal that we need to re-negotiate things.
          */
         p->needppr |= (p->needppr_copy & (1<<tindex));
         p->needsdtr |= (p->needsdtr_copy & (1<<tindex));
@@ -6822,7 +6842,18 @@ aic7xxx_handle_command_completion_intr(struct aic7xxx_host *p)
       case BUSY:
         scb->hscb->target_status = 0;
         scb->cmd->result = 0;
+        scb->hscb->residual_SG_segment_count = 0;
+        scb->hscb->residual_data_count[0] = 0;
+        scb->hscb->residual_data_count[1] = 0;
+        scb->hscb->residual_data_count[2] = 0;
         aic7xxx_error(scb->cmd) = DID_OK;
+        aic7xxx_status(scb->cmd) = 0;
+        /*
+         * The QUEUE_FULL/BUSY handler in aic7xxx_seqint takes care of putting
+         * this command on a timer and allowing us to retry it.  Here, we
+         * just 0 out a few values so that they don't carry through to when
+         * the command finally does complete.
+         */
         break;
       default:
         cmd = scb->cmd;
@@ -6987,18 +7018,14 @@ do_aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
   if(!p)
     return;
   spin_lock_irqsave(&io_request_lock, cpu_flags);
-  if(test_and_set_bit(AHC_IN_ISR_BIT, (void *)&p->flags))
-  {
-    spin_unlock_irqrestore(&io_request_lock, cpu_flags);
-    return;
-  }
+  p->flags |= AHC_IN_ISR;
   do
   {
     aic7xxx_isr(irq, dev_id, regs);
   } while ( (aic_inb(p, INTSTAT) & INT_PEND) );
   aic7xxx_done_cmds_complete(p);
   aic7xxx_run_waiting_queues(p);
-  clear_bit(AHC_IN_ISR_BIT, (void *)&p->flags);
+  p->flags &= ~AHC_IN_ISR;
   spin_unlock_irqrestore(&io_request_lock, cpu_flags);
 }
 
@@ -8779,7 +8806,7 @@ 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.
+   * error handling.  Let's be nice and not do any unnecessary delays.
    */
   wait = 1000;  /* 1 msec (1000 * 1 msec) */
   while (--wait && !(aic_inb(p, HCNTRL) & CHIPRSTACK))
@@ -8923,22 +8950,6 @@ aic7xxx_free(struct aic7xxx_host *p)
     kfree(p->scb_data);
   }
 
-  /*
-   * Free any alloced Scsi_Cmnd structures that might be around for
-   * negotiation purposes....
-   */
-  for (i = 0; i < MAX_TARGETS; i++)
-  {
-    if(p->dev_dtr_cmnd[i])
-    {
-      if(p->dev_dtr_cmnd[i]->request_buffer)
-      {
-        kfree(p->dev_dtr_cmnd[i]->request_buffer);
-      }
-      kfree(p->dev_dtr_cmnd[i]);
-    }
-  }
-
   pci_free_consistent(p->pdev, 3*256, (void *)p->untagged_scbs, p->fifo_dma);
 }
 
@@ -9325,7 +9336,7 @@ aic7xxx_load_seeprom(struct aic7xxx_host *p, unsigned char *sxfrctl1)
   }
   aic_outb(p, ~(p->discenable & 0xFF), DISC_DSB);
   aic_outb(p, ~((p->discenable >> 8) & 0xFF), DISC_DSB + 1);
-  p->needppr = p->needppr_copy = p->needdv = 0;
+  p->needppr = p->needppr_copy = 0;
   p->needwdtr = p->needwdtr_copy;
   p->needsdtr = p->needsdtr_copy;
   p->dtr_pending = 0;
@@ -9381,6 +9392,81 @@ aic7xxx_load_seeprom(struct aic7xxx_host *p, unsigned char *sxfrctl1)
   }
 }
 
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_configure_bugs
+ *
+ * Description:
+ *   Take the card passed in and set the appropriate bug flags based upon
+ *   the card model.  Also make any changes needed to device registers or
+ *   PCI registers while we are here.
+ *-F*************************************************************************/
+static void
+aic7xxx_configure_bugs(struct aic7xxx_host *p)
+{
+  unsigned short tmp_word;
+  switch(p->chip & AHC_CHIPID_MASK)
+  {
+    case AHC_AIC7860:
+      p->bugs |= AHC_BUG_PCI_2_1_RETRY;
+      /* fall through */
+    case AHC_AIC7850:
+    case AHC_AIC7870:
+      p->bugs |= AHC_BUG_TMODE_WIDEODD | AHC_BUG_CACHETHEN | AHC_BUG_PCI_MWI;
+      break;
+    case AHC_AIC7880:
+      p->bugs |= AHC_BUG_TMODE_WIDEODD | AHC_BUG_PCI_2_1_RETRY |
+                 AHC_BUG_CACHETHEN | AHC_BUG_PCI_MWI;
+      break;
+    case AHC_AIC7890:
+      p->bugs |= AHC_BUG_AUTOFLUSH | AHC_BUG_CACHETHEN;
+      break;
+    case AHC_AIC7892:
+      p->bugs |= AHC_BUG_SCBCHAN_UPLOAD;
+      break;
+    case AHC_AIC7895:
+      p->bugs |= AHC_BUG_TMODE_WIDEODD | AHC_BUG_PCI_2_1_RETRY |
+                 AHC_BUG_CACHETHEN | AHC_BUG_PCI_MWI;
+      break;
+    case AHC_AIC7896:
+      p->bugs |= AHC_BUG_CACHETHEN_DIS;
+      break;
+    case AHC_AIC7899:
+      p->bugs |= AHC_BUG_SCBCHAN_UPLOAD;
+      break;
+    default:
+      /* Nothing to do */
+      break;
+  }
+
+  /*
+   * Now handle the bugs that require PCI register or card register tweaks
+   */
+  pci_read_config_word(p->pdev, PCI_COMMAND, &tmp_word);
+  if(p->bugs & AHC_BUG_PCI_MWI)
+  {
+    tmp_word &= ~PCI_COMMAND_INVALIDATE;
+  }
+  else
+  {
+    tmp_word |= PCI_COMMAND_INVALIDATE;
+  }
+  pci_write_config_word(p->pdev, PCI_COMMAND, tmp_word);
+
+  if(p->bugs & AHC_BUG_CACHETHEN)
+  {
+    aic_outb(p, aic_inb(p, DSCOMMAND0) & ~CACHETHEN, DSCOMMAND0);
+  }
+  else if (p->bugs & AHC_BUG_CACHETHEN_DIS)
+  {
+    aic_outb(p, aic_inb(p, DSCOMMAND0) | CACHETHEN, DSCOMMAND0);
+  }
+
+  return;
+}
+
+
 /*+F*************************************************************************
  * Function:
  *   aic7xxx_detect
@@ -10076,6 +10162,14 @@ aic7xxx_detect(Scsi_Host_Template *template)
             aic_outb(temp_p, DFTHRSH_100, DSPCISTATUS);
           }
 
+          /*
+           * Call our function to fixup any bugs that exist on this chipset.
+           * This may muck with PCI settings and other device settings, so
+           * make sure it's after all the other PCI and device register
+           * tweaks so it can back out bad settings on specific broken cards.
+           */
+          aic7xxx_configure_bugs(temp_p);
+
           if ( list_p == NULL )
           {
             list_p = current_p = temp_p;
@@ -10318,6 +10412,11 @@ aic7xxx_detect(Scsi_Host_Template *template)
              (temp_p->flags & AHC_EXTEND_TRANS_A) ? "en" : "dis");
     }
 
+    /*
+     * All the 7770 based chipsets have this bug
+     */
+    temp_p->bugs |= AHC_BUG_TMODE_WIDEODD;
+
     /*
      * Set the FIFO threshold and the bus off time.
      */
@@ -10537,298 +10636,6 @@ aic7xxx_detect(Scsi_Host_Template *template)
   return (found);
 }
 
-static void aic7xxx_build_negotiation_cmnd(struct aic7xxx_host *p,
-                                           Scsi_Cmnd *old_cmd, int tindex);
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_allocate_negotiation_command
- *
- * Description:
- *   allocate the actual command struct and fill in the gaps...
- *-F*************************************************************************/
-static Scsi_Cmnd *
-aic7xxx_allocate_negotiation_command(struct aic7xxx_host *p,
-                                     Scsi_Cmnd *old_cmd, int tindex)
-{
-  Scsi_Cmnd *cmd;
-  char *buffer;
-
-  if (!(p->dev_dtr_cmnd[tindex] = kmalloc(sizeof(Scsi_Cmnd), GFP_ATOMIC)) )
-  {
-    return(NULL);
-  }
-  if (!(buffer = kmalloc(256, GFP_ATOMIC)))
-  {
-    kfree(p->dev_dtr_cmnd[tindex]);
-    p->dev_dtr_cmnd[tindex] = NULL;
-    return(NULL);
-  }
-  cmd = p->dev_dtr_cmnd[tindex];
-  memset(cmd, 0, sizeof(Scsi_Cmnd));
-  memcpy(cmd, old_cmd, sizeof(Scsi_Cmnd));
-  memset(&cmd->cmnd[0], 0, sizeof(cmd->cmnd));
-  memset(&cmd->data_cmnd[0], 0, sizeof(cmd->data_cmnd));
-  cmd->lun = 0;
-  cmd->request_bufflen = 255;
-  cmd->request_buffer = buffer;
-  cmd->sc_data_direction = SCSI_DATA_READ;
-  cmd->use_sg = cmd->old_use_sg = cmd->sglist_len = 0;
-  cmd->bufflen = 0;
-  cmd->buffer = NULL;
-  cmd->underflow = 0;
-  cmd->cmd_len = 6;
-  cmd->cmnd[0] = cmd->data_cmnd[0] = INQUIRY;
-  cmd->cmnd[1] = cmd->data_cmnd[1] = 0;
-  cmd->cmnd[2] = cmd->data_cmnd[2] = 0;
-  cmd->cmnd[3] = cmd->data_cmnd[3] = 0;
-  cmd->cmnd[4] = cmd->data_cmnd[4] = 255; /* match what scsi.c does here */
-  cmd->cmnd[5] = cmd->data_cmnd[5] = 0;
-  return(cmd);
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_negotiation_complete
- *
- * Description:
- *   Handle completion events for our Negotiation commands.  Clear out the
- *   struct and get it ready for its next use.
- *-F*************************************************************************/
-static void
-aic7xxx_negotiation_complete(Scsi_Cmnd *cmd)
-{
-  unsigned int checksum;
-  int i;
-  int *ibuffer;
-  struct aic7xxx_host *p = (struct aic7xxx_host *)cmd->host->hostdata;
-  int tindex = TARGET_INDEX(cmd);
-  struct aic7xxx_syncrate *syncrate;
-
-  /*
-   * perform our minimalistic domain validation
-   */
-  if(p->dev_flags[tindex] & DEVICE_SCANNED)
-  {
-    ibuffer = (int *)cmd->request_buffer;
-    checksum = 0;
-    for(i = 0; i < (cmd->request_bufflen >> 2); i++)
-    {
-      checksum += ibuffer[i];
-    }
-    if( (checksum != p->dev_checksum[tindex]) &&
-        (p->transinfo[tindex].cur_offset != 0) )
-    {
-      unsigned int period = p->transinfo[tindex].cur_period;
-      unsigned char options = p->transinfo[tindex].cur_options;
-
-      if (p->needdv & (1<<tindex))
-      {
-        /*
-         * oops, we had a failure, lower the transfer rate and try again.  It's
-         * worth noting here that it might be wise to also check for typical
-         * wide setting on narrow cable type problems and try disabling wide
-         * instead of slowing down if those exist.  That's hard to do with simple
-         * checksums though.
-         */
-        if(aic7xxx_verbose & VERBOSE_NEGOTIATION2) 
-        {
-          printk(INFO_LEAD "reducing SCSI transfer speed due to Domain "
-                 "validation failure.\n", p->host_no, CTL_OF_CMD(cmd));
-        }
-        if((syncrate = aic7xxx_find_syncrate(p, &period, 0, &options)) != NULL)
-        {
-          syncrate++;
-          if( (syncrate->rate[0] != NULL) &&
-              (!(p->features & AHC_ULTRA2) || (syncrate->sxfr_ultra2 == 0)) )
-          {
-            p->transinfo[tindex].goal_period = syncrate->period;
-            if( p->transinfo[tindex].goal_period > 9 )
-            {
-              p->transinfo[tindex].goal_options = 0;
-              p->needppr &= ~(1<<tindex);
-              p->needsdtr |= (1<<tindex);
-              p->needppr_copy &= ~(1<<tindex);
-              p->needsdtr_copy |= (1<<tindex);
-              if (p->transinfo[tindex].goal_width)
-              {
-                p->needwdtr |= (1<<tindex);
-                p->needwdtr_copy |= (1<<tindex);
-              }
-            }
-          }
-          else if (p->transinfo[tindex].goal_width)
-          {
-            p->transinfo[tindex].goal_width = 0;
-            p->needwdtr &= ~(1<<tindex);
-            p->needwdtr_copy &= ~(1<<tindex);
-            p->transinfo[tindex].goal_offset =
-              p->transinfo[tindex].user_offset;
-            p->transinfo[tindex].goal_period =
-              p->transinfo[tindex].user_period;
-            p->transinfo[tindex].goal_options =
-              p->transinfo[tindex].user_options;
-            if( p->transinfo[tindex].goal_period <= 9 )
-            {
-              p->needppr |= (1<<tindex);
-              p->needsdtr &= ~(1<<tindex);
-              p->needppr_copy |= (1<<tindex);
-              p->needsdtr_copy &= ~(1<<tindex);
-            }
-            else
-            {
-              p->needppr &= ~(1<<tindex);
-              p->needsdtr |= (1<<tindex);
-              p->needppr_copy &= ~(1<<tindex);
-              p->needsdtr_copy |= (1<<tindex);
-            }
-          }
-          else
-          {
-            p->transinfo[tindex].goal_offset = 0;
-            p->transinfo[tindex].goal_period = 255;
-            p->transinfo[tindex].goal_options = 0;
-            p->transinfo[tindex].goal_width = 0;
-            p->needppr &= ~(1<<tindex);
-            p->needsdtr &= ~(1<<tindex);
-            p->needwdtr &= ~(1<<tindex);
-            p->needppr_copy &= ~(1<<tindex);
-            p->needsdtr_copy &= ~(1<<tindex);
-            p->needwdtr_copy &= ~(1<<tindex);
-          }
-        }
-        p->needdv &= ~(1<<tindex);
-      }
-      else
-      {
-        if(aic7xxx_verbose & VERBOSE_NEGOTIATION2) 
-        {
-          printk(INFO_LEAD "Performing Domain validation.\n",
-                 p->host_no, CTL_OF_CMD(cmd));
-        }
-        /*
-         * Update the checksum in case the INQUIRY data has changed, maybe
-         * in relation to a change in the mode pages, or whatever.
-         */
-        p->dev_checksum[tindex] = checksum;
-        /*
-         * Signal that we are trying out the domain validation
-         */
-        p->needdv |= (1<<tindex);
-        /*
-         * Signal that we need to re-negotiate things, this also gets us our
-         * INQUIRY command to re-checksum off of.
-         */
-        p->needppr |= (p->needppr_copy & (1<<tindex));
-        p->needsdtr |= (p->needsdtr_copy & (1<<tindex));
-        p->needwdtr |= (p->needwdtr_copy & (1<<tindex));
-      }
-    } 
-    else
-    {
-      if( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
-          (p->needdv & (1<<tindex)) )
-      {
-        printk(INFO_LEAD "Successfully completed Domain validation.\n",
-               p->host_no, CTL_OF_CMD(cmd));
-      }
-      /*
-       * We successfully did our checksum, so don't leave the needdv flag set
-       * in case we might have set it last time through.
-       */
-      p->needdv &= ~(1<<tindex);
-    }
-  }
-
-  p->dtr_pending &= ~(0x01 << tindex);
-  /*
-   * This looks recursive in the extreme, but if this was a WDTR negotiation
-   * and we didn't follow up with SDTR yet, then this will get it started.
-   * For all other cases, this should work out to be a no-op, unless we are
-   * doing domain validation and happen to need a new negotiation command.
-   *
-   * In case we don't want this to go any further, the cmdcmplt interrupt
-   * handler will NULL out the cmd->next entry so that the real SCSI command
-   * can be sent back to the mid layer code with SENSE data intact.  We'll
-   * finish things up when the cmd gets sent back down to us, so no worries.
-   */
-  if(cmd->next)
-  {
-    aic7xxx_build_negotiation_cmnd(p, cmd->next, tindex);
-  }
-  return;
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_build_negotiation_command
- *
- * Description:
- *   Build a Scsi_Cmnd structure to perform negotiation with or else send
- *   a pre-built command specifically for this purpose.
- *-F*************************************************************************/
-static void
-aic7xxx_build_negotiation_cmnd(struct aic7xxx_host *p, Scsi_Cmnd *old_cmd,
-  int tindex)
-{
-
-  if ( !(p->dtr_pending & (1<<tindex)) &&
-       ( (p->needppr & (1<<tindex)) ||
-         (p->needwdtr & (1<<tindex)) ||
-         (p->needsdtr & (1<<tindex)) ) )
-  {
-    if ( (p->dev_dtr_cmnd[tindex] == NULL) &&
-         (aic7xxx_allocate_negotiation_command(p, old_cmd, tindex) == NULL) )
-    {
-      return;
-    }
-    /*
-     * Before sending this thing out, we also make the cmd->next pointer
-     * point to the real command so we can stuff any possible SENSE data
-     * into 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_dtr_cmnd[tindex]->next = old_cmd;
-    /*
-     * Clear the buffer so checksums come out right....
-     */
-    memset(p->dev_dtr_cmnd[tindex]->request_buffer, 0,
-           p->dev_dtr_cmnd[tindex]->request_bufflen);
-    /*
-     * Remove any commands for this particular device that might be on the
-     * waiting_scbs queue or qinfifo so that this command goes out first.
-     * This is vital for our implementation of domain validation.
-     */
-    pause_sequencer(p);
-    aic7xxx_search_qinfifo(p, old_cmd->target, old_cmd->channel, ALL_LUNS,
-                SCB_LIST_NULL, 0, TRUE, &p->delayed_scbs[tindex]);
-    unpause_sequencer(p, FALSE);
-    {
-      struct aic7xxx_scb *scb, *next;
-
-      scb = p->waiting_scbs.head;
-      while(scb != NULL)
-      {
-        if( aic7xxx_match_scb(p, scb, old_cmd->target, old_cmd->channel,
-                              ALL_LUNS, SCB_LIST_NULL) )
-        {
-          next = scb->q_next;
-          scbq_remove(&p->waiting_scbs, scb);
-          scbq_insert_tail(&p->delayed_scbs[tindex], scb);
-          scb = next;
-        }
-        else
-        {
-          scb = scb->q_next;
-        }
-      }
-    }
-    aic7xxx_queue(p->dev_dtr_cmnd[tindex], 
-                  aic7xxx_negotiation_complete);
-  }
-}
-
 #ifdef AIC7XXX_VERBOSE_DEBUGGING
 /*+F*************************************************************************
  * Function:
@@ -10877,7 +10684,7 @@ aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
    */
   hscb->control = 0;
   scb->tag_action = 0;
-  cmd->tag = hscb->tag;
+
   if (p->discenable & mask)
   {
     hscb->control |= DISCENB;
@@ -10906,34 +10713,29 @@ aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
       }
     }
   }
-  if ( cmd == p->dev_dtr_cmnd[tindex] )
+  if ( !(p->dtr_pending & mask) &&
+        ( (p->needppr & mask) ||
+          (p->needwdtr & mask) ||
+          (p->needsdtr & mask) ) &&
+        (p->dev_flags[tindex] & DEVICE_DTR_SCANNED) )
   {
     p->dtr_pending |= mask;
     scb->tag_action = 0;
-    if (p->dev_flags[tindex] & DEVICE_SCANNED)
+    hscb->control &= DISCENB;
+    hscb->control |= MK_MESSAGE;
+    if(p->needppr & mask)
     {
-      hscb->control &= DISCENB;
-      hscb->control |= MK_MESSAGE;
-      if(p->needppr & mask)
-      {
-        scb->flags |= SCB_MSGOUT_PPR;
-      }
-      else if(p->needwdtr & mask)
-      {
-        scb->flags |= SCB_MSGOUT_WDTR;
-      }
-      else if(p->needsdtr & mask)
-      {
-        scb->flags |= SCB_MSGOUT_SDTR;
-      }
+      scb->flags |= SCB_MSGOUT_PPR;
     }
-  }
-  if ( !(p->dtr_pending & mask) &&
-        ( (p->needppr & mask) ||
-          (p->needwdtr & mask) ||
-          (p->needsdtr & mask) ) )
-  {
-    aic7xxx_build_negotiation_cmnd(p, cmd, tindex);
+    else if(p->needwdtr & mask)
+    {
+      scb->flags |= SCB_MSGOUT_WDTR;
+    }
+    else if(p->needsdtr & mask)
+    {
+      scb->flags |= SCB_MSGOUT_SDTR;
+    }
+    scb->flags |= SCB_DTR_SCB;
   }
   hscb->target_channel_lun = ((cmd->target << 4) & 0xF0) |
         ((cmd->channel & 0x01) << 3) | (cmd->lun & 0x07);
@@ -11079,50 +10881,58 @@ aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
     aic7xxx_allocate_scb(p);
     DRIVER_UNLOCK
     scb = scbq_remove_head(&p->scb_data->free_scbs);
+    if(scb == NULL)
+      printk(WARN_LEAD "Couldn't get a free SCB.\n", p->host_no,
+             CTL_OF_CMD(cmd));
   }
-  if (scb == NULL)
+  while (scb == NULL)
   {
-    printk(WARN_LEAD "Couldn't get a free SCB.\n", p->host_no,
-           CTL_OF_CMD(cmd));
-    cmd->result = (DID_BUS_BUSY << 16);
+    /*
+     * Well, all SCBs are currently active on the bus.  So, we spin here
+     * running the interrupt handler until one completes and becomes free.
+     * We can do this safely because we either A) hold the driver lock (in
+     * 2.0 kernels) or we have the io_request_lock held (in 2.2 and later
+     * kernels) and so either way, we won't take any other interrupts and
+     * the queue path will block until we release it.  Also, we would worry
+     * about running the completion queues, but obviously there are plenty
+     * of commands outstanding to trigger a later interrupt that will do
+     * that for us, so skip it here.
+     */
     DRIVER_LOCK
-    aic7xxx_queue_cmd_complete(p, cmd);
+    aic7xxx_isr(p->irq, p, NULL);
     DRIVER_UNLOCK
-    return 0;
+    scb = scbq_remove_head(&p->scb_data->free_scbs);
   }
-  else
-  {
-    scb->cmd = cmd;
-    aic7xxx_position(cmd) = scb->hscb->tag;
+  scb->cmd = cmd;
+  aic7xxx_position(cmd) = scb->hscb->tag;
 
-    /*
-     * Construct the SCB beforehand, so the sequencer is
-     * paused a minimal amount of time.
-     */
-    aic7xxx_buildscb(p, cmd, scb);
+  /*
+   * Make sure the Scsi_Cmnd pointer is saved, the struct it points to
+   * is set up properly, and the parity error flag is reset, then send
+   * 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->host_scribble = NULL;
 
-    /*
-     * Make sure the Scsi_Cmnd pointer is saved, the struct it points to
-     * is set up properly, and the parity error flag is reset, then send
-     * 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->host_scribble = NULL;
+  /*
+   * Construct the SCB beforehand, so the sequencer is
+   * paused a minimal amount of time.
+   */
+  aic7xxx_buildscb(p, cmd, scb);
 
-    scb->flags |= SCB_ACTIVE | SCB_WAITINGQ;
+  scb->flags |= SCB_ACTIVE | SCB_WAITINGQ;
 
-    DRIVER_LOCK
-    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);
-    }
-    DRIVER_UNLOCK
+  DRIVER_LOCK
+  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);
   }
+  DRIVER_UNLOCK
   return (0);
 }
 
@@ -11188,6 +10998,12 @@ aic7xxx_bus_device_reset(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
          aic_inb(p, SCSISIGI),
          aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8),
          aic_inb(p, SSTAT0), aic_inb(p, SSTAT1));
+    printk(INFO_LEAD "SG_CACHEPTR 0x%x, SSTAT2 0x%x, STCNT 0x%x\n", p->host_no,
+         CTL_OF_SCB(scb),
+         (p->features & AHC_ULTRA2) ? aic_inb(p, SG_CACHEPTR) : 0,
+         aic_inb(p, SSTAT2),
+         aic_inb(p, STCNT + 2) << 16 | aic_inb(p, STCNT + 1) << 8 |
+         aic_inb(p, STCNT));
   }
 
   channel = cmd->channel;
@@ -11358,7 +11174,6 @@ aic7xxx_abort(Scsi_Cmnd *cmd)
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
   unsigned long cpu_flags = 0;
 #endif
-  Scsi_Cmnd *cmd_next, *cmd_prev;
 
   p = (struct aic7xxx_host *) cmd->host->hostdata;
   scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
@@ -11367,7 +11182,7 @@ aic7xxx_abort(Scsi_Cmnd *cmd)
    * I added a new config option to the driver: "panic_on_abort" that will
    * cause the driver to panic and the machine to stop on the first abort
    * or reset call into the driver.  At that point, it prints out a lot of
-   * usefull information for me which I can then use to try and debug the
+   * useful information for me which I can then use to try and debug the
    * problem.  Simply enable the boot time prompt in order to activate this
    * code.
    */
@@ -11388,13 +11203,11 @@ aic7xxx_abort(Scsi_Cmnd *cmd)
   {
     aic7xxx_isr(p->irq, p, (void *)NULL);
     pause_sequencer(p);
-    aic7xxx_done_cmds_complete(p);
   }
+  aic7xxx_done_cmds_complete(p);
 
-  if ((scb == NULL) || (cmd->serial_number != cmd->serial_number_at_timeout))
-                      /*  Totally bogus cmd since it points beyond our  */
-  {                   /*  valid SCB range or doesn't even match it's own*/
-                      /*  timeout serial number.                        */
+  if (scb == NULL)
+  {
     if (aic7xxx_verbose & VERBOSE_ABORT_MID)
       printk(INFO_LEAD "Abort called with bogus Scsi_Cmnd "
         "pointer.\n", p->host_no, CTL_OF_CMD(cmd));
@@ -11413,28 +11226,6 @@ aic7xxx_abort(Scsi_Cmnd *cmd)
                         /*  finish successfully, or to indicate that we     */
                         /*  don't have this cmd any more and the mid level  */
                         /*  code needs to find it.                          */
-    cmd_next = p->completeq.head;
-    cmd_prev = NULL;
-    while (cmd_next != NULL) 
-    {
-      if (cmd_next == cmd) 
-      {
-        if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
-          printk(INFO_LEAD "Abort called for command "
-          "on completeq, completing.\n", p->host_no, CTL_OF_CMD(cmd));
-        if ( cmd_prev == NULL )
-          p->completeq.head = (Scsi_Cmnd *)cmd_next->host_scribble;
-        else
-          cmd_prev->host_scribble = cmd_next->host_scribble;
-        cmd_next->scsi_done(cmd_next);
-        unpause_sequencer(p, FALSE);
-        DRIVER_UNLOCK
-        return(SCSI_ABORT_NOT_RUNNING); /* It's already back as a successful
-                                         * completion */
-      }                                  
-      cmd_prev = cmd_next;
-      cmd_next = (Scsi_Cmnd *)cmd_next->host_scribble;
-    }
     if (aic7xxx_verbose & VERBOSE_ABORT_MID)
       printk(INFO_LEAD "Abort called for already completed"
         " command.\n", p->host_no, CTL_OF_CMD(cmd));
@@ -11492,8 +11283,20 @@ aic7xxx_abort(Scsi_Cmnd *cmd)
   found = 0;
   p->flags |= AHC_IN_ABORT;
   if (aic7xxx_verbose & VERBOSE_ABORT)
-    printk(INFO_LEAD "Aborting scb %d, flags 0x%x\n",
-         p->host_no, CTL_OF_SCB(scb), scb->hscb->tag, scb->flags);
+  {
+    printk(INFO_LEAD "Aborting scb %d, flags 0x%x, SEQADDR 0x%x, LASTPHASE "
+           "0x%x\n",
+         p->host_no, CTL_OF_SCB(scb), scb->hscb->tag, scb->flags,
+         aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8),
+         aic_inb(p, LASTPHASE));
+    printk(INFO_LEAD "SG_CACHEPTR 0x%x, SG_COUNT %d, SCSISIGI 0x%x\n",
+         p->host_no, CTL_OF_SCB(scb), (p->features & AHC_ULTRA2) ?
+         aic_inb(p, SG_CACHEPTR) : 0, aic_inb(p, SG_COUNT),
+         aic_inb(p, SCSISIGI));
+    printk(INFO_LEAD "SSTAT0 0x%x, SSTAT1 0x%x, SSTAT2 0x%x\n",
+         p->host_no, CTL_OF_SCB(scb), aic_inb(p, SSTAT0),
+         aic_inb(p, SSTAT1), aic_inb(p, SSTAT2));
+  }
 
 /*
  *   First, let's check to see if the currently running command is our target
@@ -11521,6 +11324,16 @@ aic7xxx_abort(Scsi_Cmnd *cmd)
         if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
           printk(INFO_LEAD "SCB is currently active.  "
                 "Waiting on completion.\n", p->host_no, CTL_OF_SCB(scb));
+        printk(INFO_LEAD "SCSISIGI 0x%x, SEQADDR 0x%x, SSTAT0 0x%x, SSTAT1 "
+           "0x%x\n", p->host_no, CTL_OF_SCB(scb),
+           aic_inb(p, SCSISIGI),
+           aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8),
+           aic_inb(p, SSTAT0), aic_inb(p, SSTAT1));
+        printk(INFO_LEAD "SG_CACHEPTR 0x%x, SSTAT2 0x%x, STCNT 0x%x\n",
+           p->host_no, CTL_OF_SCB(scb),
+           (p->features & AHC_ULTRA2) ? aic_inb(p, SG_CACHEPTR) : 0,
+           aic_inb(p, SSTAT2), aic_inb(p, STCNT + 2) << 16 |
+           aic_inb(p, STCNT + 1) << 8 | aic_inb(p, STCNT));
         unpause_sequencer(p, FALSE);
         p->flags &= ~AHC_IN_ABORT;
         scb->flags |= SCB_RECOVERY_SCB; /*  Note the fact that we've been  */
@@ -11536,35 +11349,7 @@ aic7xxx_abort(Scsi_Cmnd *cmd)
   if ((found == 0) && (scb->flags & SCB_WAITINGQ))
   {
     int tindex = TARGET_INDEX(cmd);
-    unsigned short mask;
 
-    mask = (1 << tindex);
-
-    if (p->dtr_pending & mask)
-    {
-      if (p->dev_dtr_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);
-    }
     if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS) 
       printk(INFO_LEAD "SCB found on waiting list and "
           "aborted.\n", p->host_no, CTL_OF_SCB(scb));
@@ -11721,10 +11506,8 @@ aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags)
 #define DEVICE_RESET 0x01
 #define BUS_RESET    0x02
 #define HOST_RESET   0x04
-#define FAIL         0x08
-#define RESET_DELAY  0x10
+#define RESET_DELAY  0x08
   int        action;
-  Scsi_Cmnd *cmd_prev, *cmd_next;
 
 
   if ( cmd == NULL )
@@ -11742,7 +11525,7 @@ aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags)
    * I added a new config option to the driver: "panic_on_abort" that will
    * cause the driver to panic and the machine to stop on the first abort
    * or reset call into the driver.  At that point, it prints out a lot of
-   * usefull information for me which I can then use to try and debug the
+   * useful information for me which I can then use to try and debug the
    * problem.  Simply enable the boot time prompt in order to activate this
    * code.
    */
@@ -11752,86 +11535,32 @@ aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags)
   DRIVER_LOCK
 
   pause_sequencer(p);
-  while ( (aic_inb(p, INTSTAT) & INT_PEND) && !(p->flags & AHC_IN_ISR))
-  {
-    aic7xxx_isr(p->irq, p, (void *)NULL );
-    pause_sequencer(p);
-    aic7xxx_done_cmds_complete(p);
-  }
 
-  if (scb == NULL)
+  if(flags & SCSI_RESET_SYNCHRONOUS)
   {
     if (aic7xxx_verbose & VERBOSE_RESET_MID)
-      printk(INFO_LEAD "Reset called with bogus Scsi_Cmnd"
-           "->SCB mapping, improvising.\n", p->host_no, CTL_OF_CMD(cmd));
-    if ( flags & SCSI_RESET_SUGGEST_HOST_RESET )
-    {
-      action = HOST_RESET;
-    }
-    else
-    {
-      action = BUS_RESET;
-    }
+      printk(INFO_LEAD "Reset called for a SYNCHRONOUS reset, flags 0x%x, "
+           "cmd->result 0x%x.\n", p->host_no, CTL_OF_CMD(cmd), flags,
+           cmd->result);
+    scb = NULL;
+    action = HOST_RESET;
   }
-  else if (scb->cmd != cmd) 
+  else if ((scb == NULL) || (scb->cmd != cmd))
   {
     if (aic7xxx_verbose & VERBOSE_RESET_MID)
-    printk(INFO_LEAD "Reset called with recycled SCB "
-        "for cmd.\n", p->host_no, CTL_OF_CMD(cmd));
-    cmd_prev = NULL;
-    cmd_next = p->completeq.head;
-    while ( cmd_next != NULL )
-    {
-      if (cmd_next == cmd)
-      {
-        if (aic7xxx_verbose & VERBOSE_RESET_RETURN)
-          printk(INFO_LEAD "Reset, found cmd on completeq"
-          ", completing.\n", p->host_no, CTL_OF_CMD(cmd));
-        unpause_sequencer(p, FALSE);
-        DRIVER_UNLOCK
-        return(SCSI_RESET_NOT_RUNNING);
-      }
-      cmd_prev = cmd_next;
-      cmd_next = (Scsi_Cmnd *)cmd_next->host_scribble;
-    }
-    if ( !(flags & SCSI_RESET_SYNCHRONOUS) )
-    {
-      if (aic7xxx_verbose & VERBOSE_RESET_RETURN)
-        printk(INFO_LEAD "Reset, cmd not found,"
-          " failing.\n", p->host_no, CTL_OF_CMD(cmd));
-      unpause_sequencer(p, FALSE);
-      DRIVER_UNLOCK
-      return(SCSI_RESET_NOT_RUNNING);
-    }
-    else
-    {
-      if (aic7xxx_verbose & VERBOSE_RESET_MID)
-        printk(INFO_LEAD "Reset called, no scb, "
-          "flags 0x%x\n", p->host_no, CTL_OF_CMD(cmd), flags);
-      scb = NULL;
-      action = HOST_RESET;
-    }
+      printk(INFO_LEAD "Reset called with bogus Scsi_Cmnd"
+           "->SCB mapping, failing.\n", p->host_no, CTL_OF_CMD(cmd));
+    aic7xxx_done_cmds_complete(p);
+    aic7xxx_run_waiting_queues(p);
+    unpause_sequencer(p, FALSE);
+    DRIVER_UNLOCK
+    return(SCSI_RESET_NOT_RUNNING);
   }
   else
   {
     if (aic7xxx_verbose & VERBOSE_RESET_MID)
       printk(INFO_LEAD "Reset called, scb %d, flags "
         "0x%x\n", p->host_no, CTL_OF_SCB(scb), scb->hscb->tag, scb->flags);
-    if ( aic7xxx_scb_on_qoutfifo(p, scb) )
-    {
-      if(aic7xxx_verbose & VERBOSE_RESET_RETURN)
-        printk(INFO_LEAD "SCB on qoutfifo, completing.\n", p->host_no,
-          CTL_OF_SCB(scb));
-      if ((aic_inb(p,INTSTAT) & CMDCMPLT) == 0)
-        printk(INFO_LEAD "missed CMDCMPLT interrupt!\n", p->host_no,
-          CTL_OF_SCB(scb));
-      aic7xxx_handle_command_completion_intr(p);
-      aic7xxx_done_cmds_complete(p);
-      aic7xxx_run_waiting_queues(p);
-      unpause_sequencer(p, FALSE);
-      DRIVER_UNLOCK
-      return(SCSI_RESET_SUCCESS);
-    }
     if ( flags & SCSI_RESET_SUGGEST_HOST_RESET )
     {
       action = HOST_RESET;
@@ -11845,6 +11574,26 @@ aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags)
       action = DEVICE_RESET;
     }
   }
+
+  while((aic_inb(p, INTSTAT) & INT_PEND) && !(p->flags & AHC_IN_ISR))
+  {
+    aic7xxx_isr(p->irq, p, (void *)NULL );
+    pause_sequencer(p);
+  }
+  aic7xxx_done_cmds_complete(p);
+
+  if(scb && (scb->cmd == NULL))
+  {
+    /*
+     * We just completed the command when we ran the isr stuff, so we no
+     * longer have it.
+     */
+    aic7xxx_run_waiting_queues(p);
+    unpause_sequencer(p, FALSE);
+    DRIVER_UNLOCK
+    return(SCSI_RESET_SUCCESS);
+  }
+    
   if ( (action & DEVICE_RESET) && 
         (p->dev_flags[tindex] & BUS_DEVICE_RESET_PENDING) )
   {
@@ -11904,14 +11653,13 @@ aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags)
   switch (action)
   {
     case RESET_DELAY:
+      aic7xxx_run_waiting_queues(p);
       unpause_sequencer(p, FALSE);
       DRIVER_UNLOCK
-      return(SCSI_RESET_PENDING);
-      break;
-    case FAIL:
-      unpause_sequencer(p, FALSE);
-      DRIVER_UNLOCK
-      return(SCSI_RESET_ERROR);
+      if(scb == NULL)
+        return(SCSI_RESET_PUNT);
+      else
+        return(SCSI_RESET_PENDING);
       break;
     case DEVICE_RESET:
       p->flags |= AHC_IN_RESET;
@@ -11929,7 +11677,7 @@ aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags)
     case HOST_RESET:
     default:
       p->flags |= AHC_IN_RESET | AHC_RESET_DELAY;
-      p->dev_expires[p->scsi_id] = jiffies + (3 * HZ);
+      p->dev_expires[p->scsi_id] = jiffies + (1 * HZ);
       p->dev_timer_active |= (0x01 << p->scsi_id);
       if ( !(p->dev_timer_active & (0x01 << MAX_TARGETS)) ||
             time_after_eq(p->dev_timer.expires, p->dev_expires[p->scsi_id]) )
@@ -11956,21 +11704,14 @@ aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags)
         p->msg_index = 0;
         p->msg_len = 0;
       }
-      aic7xxx_run_done_queue(p, TRUE);
-      /*
-       * If this a SCSI_RESET_SYNCHRONOUS then the command we were given is
-       * in need of being re-started, so send it on through to aic7xxx_queue
-       * and let it set until the delay is over.  This keeps it from dying
-       * entirely and avoids getting a bogus dead command back through the
-       * mid-level code due to too many retries.
-       */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,132)
-      if ( flags & SCSI_RESET_SYNCHRONOUS )
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+      if(flags & SCSI_RESET_SYNCHRONOUS)
       {
-        cmd->result = DID_BUS_BUSY << 16;
+        cmd->result = DID_RESET << 16;
         cmd->done(cmd);
       }
 #endif
+      aic7xxx_run_done_queue(p, TRUE);
       p->flags &= ~AHC_IN_RESET;
       /*
        * We can't rely on run_waiting_queues to unpause the sequencer for
@@ -11981,7 +11722,10 @@ aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags)
       aic7xxx_run_waiting_queues(p);
       unpause_sequencer(p, FALSE);
       DRIVER_UNLOCK
-      return(result);
+      if(scb == NULL)
+        return(SCSI_RESET_SUCCESS|SCSI_RESET_HOST_RESET);
+      else
+        return(result);
       break;
   }
 }
index 70ef93d9261b36a1f52052993938d5b1757d3529..79e5ac6cb6ff7c3a32d42f0f9c60586199b792f1 100644 (file)
@@ -478,10 +478,10 @@ linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD
     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
+    However, this can actually be very useful 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
+    the lockup.  This is really only useful 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.
 
index d300a68e61c797cda3c7bf3ff0151fc795521730..f67b4bced01c9459e5ba2c7e51292cd480fd163d 100644 (file)
@@ -703,7 +703,12 @@ register INTSTAT {
                                                 * it that it can fill the
                                                 * message buffer.
                                                 */
-       mask    TRACEPOINT      0xb0|SEQINT
+       mask    SEQ_SG_FIXUP    0xb0|SEQINT     /* need help with fixing up
+                                                * the sg array pointer after
+                                                * a phasemis with no valid
+                                                * sg elements in the shadow
+                                                * pipeline.
+                                                */
        mask    TRACEPOINT2     0xc0|SEQINT
        mask    MSGIN_PHASEMIS  0xd0|SEQINT     /*
                                                 * Target changed phase on us
index ddcd159a76ffe790e07cd80938772a0cbfbc764c..f6fc4b75b5a5f5308562054fd71063a28a4b1f78 100644 (file)
@@ -332,12 +332,15 @@ clear_target_state:
        /* clear target specific flags */
        clr     SEQ_FLAGS ret;
 
+
+data_phase_reinit:
 /*
  * If we re-enter the data phase after going through another phase, the
  * STCNT may have been cleared, so restore it from the residual field.
+ * On Ultra2, we have to put it into the HCNT field because we have to
+ * drop the data down into the shadow layer via the preload ability.
  */
-data_phase_reinit:
-       if ((p->features & AHC_ULTRA2) != 0) {
+       if ((p->features & AHC_ULTRA2) != 0) {
                bmov    HADDR, SHADDR, 4;
                bmov    HCNT, SCB_RESID_DCNT, 3;
        }
@@ -349,27 +352,24 @@ data_phase_reinit:
                mvi     SCB_RESID_DCNT  call bcopy_3;
        }
        jmp     data_phase_loop;
-
 p_data:
-       if ((p->features & AHC_ULTRA2) != 0) {
+       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.
-                                        */
+       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;
 
+       test    SEQ_FLAGS, DPHASE       jnz data_phase_reinit;
+       or      SEQ_FLAGS, DPHASE;      /* we've seen a data phase */
        /*
         * Initialize the DMA address and counter from the SCB.
         * Also set SG_COUNT and SG_NEXT in memory since we cannot
@@ -378,8 +378,10 @@ p_data:
         */
        if ((p->features & AHC_CMD_CHAN) != 0) {
                bmov    HADDR, SCB_DATAPTR, 7;
-               bmov    STCNT, HCNT, 3;
                bmov    SG_COUNT, SCB_SGCOUNT, 5;
+               if ((p->features & AHC_ULTRA2) == 0) {
+                       bmov    STCNT, HCNT, 3;
+               }
        } else {
                mvi     DINDEX, HADDR;
                mvi     SCB_DATAPTR     call bcopy_7;
@@ -387,9 +389,8 @@ p_data:
                mvi     DINDEX, SG_COUNT;
                mvi     SCB_SGCOUNT     call bcopy_5;
        }
-
 data_phase_loop:
-/* Guard against overruns */
+       /* Guard against overruns */
        test    SG_COUNT, 0xff jnz data_phase_inbounds;
 /*
  * Turn on 'Bit Bucket' mode, set the transfer count to
@@ -399,66 +400,62 @@ data_phase_loop:
  */
        or      SXFRCTL1,BITBUCKET;
        and     DMAPARAMS, ~(HDMAEN|SDMAEN);
-       if ((p->features & AHC_CMD_CHAN) != 0) {
-               if ((p->features & AHC_ULTRA2) != 0) {
-                       bmov    HCNT, ALLONES, 3;
-               }
+       if ((p->features & AHC_ULTRA2) != 0) {
+               bmov    HCNT, ALLONES, 3;
+       }
+       if ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) {
                bmov    STCNT, ALLONES, 3;
-       } else {
+       }
+       if ((p->features & AHC_CMD_CHAN) == 0) {
                mvi     STCNT[0], 0xFF;
                mvi     STCNT[1], 0xFF;
                mvi     STCNT[2], 0xFF;
        }
+
 data_phase_inbounds:
 /* If we are the last SG block, tell the hardware. */
-       cmp     SG_COUNT,0x01 jne data_phase_wideodd;
-       if ((p->features & AHC_ULTRA2) == 0) {
-               and     DMAPARAMS, ~WIDEODD;
+       if ((p->features & AHC_ULTRA2) != 0) {
+               shl     A, 2, SG_COUNT;
+               cmp     SG_COUNT,0x01 jne data_phase_wideodd;
+               or      A, LAST_SEG;
        } else {
-               mvi     SG_CACHEPTR, LAST_SEG;
+               cmp     SG_COUNT,0x01 jne data_phase_wideodd;
+               and     DMAPARAMS, ~WIDEODD;
        }
 data_phase_wideodd:
-       if ((p->features & AHC_ULTRA2) != 0) {
-               mov     SINDEX, ALLONES;
-               mov     DFCNTRL, DMAPARAMS;
-               test    SSTAT0, SDONE jnz .;
-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 data_phase_dma_done;
-               clr     SINDEX;                 /* Remember the phasemiss */
+       if ((p->features & AHC_ULTRA2) != 0) {  
+               mov     SG_CACHEPTR, A;
+               mov     DFCNTRL, DMAPARAMS; /* start the operation */
+               test    SXFRCTL1, BITBUCKET jnz data_phase_overrun;
+u2_preload_wait:
+               test    SSTAT1, PHASEMIS jnz u2_phasemis;
+               test    DFSTATUS, PRELOAD_AVAIL jz u2_preload_wait;
        } else {
                mov     DMAPARAMS  call dma;
-       }
-
 data_phase_dma_done:
 /* Go tell the host about any overruns */
-       test    SXFRCTL1,BITBUCKET jnz data_phase_overrun;
+               test    SXFRCTL1,BITBUCKET jnz data_phase_overrun;
 
 /* Exit if we had an underrun.  dma clears SINDEX in this case. */
-       test    SINDEX,0xff     jz data_phase_finish;
-
+               test    SINDEX,0xff     jz data_phase_finish;
+       }
 /*
- * Advance the scatter-gather pointers if needed 
+ * Advance the scatter-gather pointers 
  */
 sg_advance:
-       dec     SG_COUNT;       /* one less segment to go */
+       if ((p->features & AHC_ULTRA2) != 0) {
+               cmp     SG_COUNT, 0x01  je u2_data_phase_finish;
+       } else {
+               dec     SG_COUNT;
+               test    SG_COUNT, 0xff  jz data_phase_finish;
+       }
 
-       test    SG_COUNT, 0xff  jz data_phase_finish; /* Are we done? */
-/*
- * Load a struct scatter and set up the data address and length.
- * If the working value of the SG count is nonzero, then
- * we need to load a new set of values.
- *
- * This, like all DMA's, assumes little-endian host data storage.
- */
-sg_load:
        if ((p->features & AHC_CMD_CHAN) != 0) {
+
                /*
                 * Do we have any prefetch left???
                 */
-               cmp     CCSGADDR, CCSGADDR_MAX jne prefetched_segs_avail;
+               cmp     CCSGADDR, CCSGADDR_MAX jne prefetch_avail;
 
                /*
                 * Fetch MIN(CCSGADDR_MAX, (SG_COUNT * 8)) bytes.
@@ -474,10 +471,12 @@ sg_load:
                and     CCSGCTL, ~CCSGEN;
                test    CCSGCTL, CCSGEN jnz .;
                mvi     CCSGCTL, CCSGRESET;
-prefetched_segs_avail:
+prefetch_avail:
                bmov    HADDR, CCSGRAM, 8;
                if ((p->features & AHC_ULTRA2) == 0) {
                        bmov    STCNT, HCNT, 3;
+               } else {
+                       dec     SG_COUNT;
                }
        } else {
                mvi     DINDEX, HADDR;
@@ -491,30 +490,63 @@ prefetched_segs_avail:
 
                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;
+/*
+ * 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     DINDEX, HADDR;
+               call    dfdat_in_7;
                call    set_stcnt_from_hcnt;
        }
-
 /* Advance the SG pointer */
-       clr     A;                      /* add sizeof(struct scatter) */
+       clr     A;              /* add sizeof(struct scatter) */
        add     SG_NEXT[0],SG_SIZEOF;
        adc     SG_NEXT[1],A;
 
-       test    SSTAT1, REQINIT jz .;
-       test    SSTAT1,PHASEMIS jz data_phase_loop;
+       if ((p->features & AHC_ULTRA2) != 0) {
+               jmp     data_phase_loop;
+       } else {
+               test    SSTAT1, REQINIT jz .;
+               test    SSTAT1,PHASEMIS jz data_phase_loop;
+       }
 
-/* This drops the last SG segment down to the shadow layer for us */
+
+/*
+ * We've loaded all of our segments into the preload layer.  Now, we simply
+ * have to wait for it to finish or for us to get a phasemis.  And, since
+ * we'll get a phasemis if we do finish, all we really need to do is wait
+ * for a phasemis then check if we did actually complete all the segments.
+ */
        if ((p->features & AHC_ULTRA2) != 0) {
-               mov     DFCNTRL, DMAPARAMS;
-               test    SSTAT0, SDONE   jnz .;
+u2_data_phase_finish:
+               test    SSTAT1, PHASEMIS jnz u2_phasemis;
+               test    SG_CACHEPTR, LAST_SEG_DONE jz u2_data_phase_finish;
+               clr     SG_COUNT;
+               test    SSTAT1, REQINIT jz .;
+               test    SSTAT1, PHASEMIS jz data_phase_loop;
+u2_phasemis:
+               call    ultra2_dmafinish;
+               test    SG_CACHEPTR, LAST_SEG_DONE jnz data_phase_finish;
+               test    SSTAT2, SHVALID jnz u2_fixup_residual;
+               mvi     INTSTAT, SEQ_SG_FIXUP;
+               jmp     data_phase_finish;
+u2_fixup_residual:
+               shr     ARG_1, 2, SG_CACHEPTR;
+u2_phasemis_loop:
+               and     A, 0x3f, SG_COUNT;
+               cmp     ARG_1, A je data_phase_finish;
+/*
+ * Subtract SG_SIZEOF from the SG_NEXT pointer and add 1 to the SG_COUNT
+ */
+               clr     A;
+               add     SG_NEXT[0], -SG_SIZEOF;
+               adc     SG_NEXT[1], 0xff;
+               inc     SG_COUNT;
+               jmp     u2_phasemis_loop;
        }
 
 data_phase_finish:
@@ -523,64 +555,83 @@ data_phase_finish:
  * We use STCNT instead of HCNT, since it's a reflection of how many bytes 
  * were transferred on the SCSI (as opposed to the host) bus.
  */
-       if ((p->features & AHC_ULTRA2) != 0) {
-               call    ultra2_dmafinish;
-       }
-       if ((p->features & AHC_ULTRA2) == 0) {
-               if ((p->features & AHC_CMD_CHAN) != 0) {
-                       bmov    SCB_RESID_DCNT, STCNT, 3;
-                       mov     SCB_RESID_SGCNT, SG_COUNT;
-               } else {
-                       mov     SCB_RESID_DCNT[0],STCNT[0];
-                       mov     SCB_RESID_DCNT[1],STCNT[1];
-                       mov     SCB_RESID_DCNT[2],STCNT[2];
-                       mov     SCB_RESID_SGCNT, SG_COUNT;
+       if ((p->features & AHC_CMD_CHAN) != 0) {
+               bmov    SCB_RESID_DCNT, STCNT, 3;
+               mov     SCB_RESID_SGCNT, SG_COUNT;
+               if ((p->features & AHC_ULTRA2) != 0) {
+                       or      SXFRCTL0, CLRSTCNT|CLRCHN;
                }
+       } else {
+               mov     SCB_RESID_DCNT[0],STCNT[0];
+               mov     SCB_RESID_DCNT[1],STCNT[1];
+               mov     SCB_RESID_DCNT[2],STCNT[2];
+               mov     SCB_RESID_SGCNT, SG_COUNT;
        }
 
        jmp     ITloop;
 
 data_phase_overrun:
-       if ((p->features & AHC_ULTRA2) != 0) {
-               call    ultra2_dmafinish;
-       }
 /*
  * Turn off BITBUCKET mode and notify the host
  */
+       if ((p->features & AHC_ULTRA2) != 0) {
+/*
+ * Wait for the target to quit transferring data on the SCSI bus
+ */
+               test    SSTAT1, PHASEMIS jz .;
+               call    ultra2_dmafinish;
+       }
        and     SXFRCTL1, ~BITBUCKET;
        mvi     INTSTAT,DATA_OVERRUN;
        jmp     ITloop;
 
-ultra2_dmafinish:
+
+
+
+/*
+ * Actually turn off the DMA hardware, save our current position into the
+ * proper residual variables, wait for the next REQ signal, then jump to
+ * the ITloop.  Jumping to the ITloop ensures that if we happen to get
+ * brought into the data phase again (or are still in it after our last
+ * segment) that we will properly signal an overrun to the kernel.
+ */
        if ((p->features & AHC_ULTRA2) != 0) {
+ultra2_dmafinish:
                test    DFCNTRL, DIRECTION jnz ultra2_dmahalt;
                and     DFCNTRL, ~SCSIEN;
                test    DFCNTRL, SCSIEN jnz .;
+               if ((p->bugs & AHC_BUG_AUTOFLUSH) != 0) {
+                       or      DFCNTRL, FIFOFLUSH;
+               }
 ultra2_dmafifoflush:
-               or      DFCNTRL, FIFOFLUSH;
-               test    DFSTATUS, FIFOEMP jz . - 1;
-               /*
-                * hardware bug alert!  This needless set of jumps is to
-                * protect against a FIFOEMP status bit glitch in the
-                * silicon.
-                */
-               test    DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
-               test    DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
-               test    DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
-               test    DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
+               if ((p->bugs & AHC_BUG_AUTOFLUSH) != 0) {
+                       /*
+                        * hardware bug alert!  This needless set of jumps
+                        * works around a glitch in the silicon.  When the
+                        * PCI DMA fifo goes empty, but there is still SCSI
+                        * data to be flushed into the PCI DMA fifo (and from
+                        * there on into main memory), the FIFOEMP bit will
+                        * come on between the time when the PCI DMA buffer
+                        * went empty and the next bit of data is copied from
+                        * the SCSI fifo into the PCI fifo.  It should only
+                        * come on when both FIFOs (meaning the entire FIFO
+                        * chain) are emtpy.  Since it can take up to 4 cycles
+                        * for new data to be copied from the SCSI fifo into
+                        * the PCI fifo, testing for FIFOEMP status for 4
+                        * extra times gives the needed time for any
+                        * remaining SCSI fifo data to be put in the PCI fifo
+                        * before we declare it *truly* empty.
+                        */
+                       test    DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
+                       test    DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
+                       test    DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
+                       test    DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
+               }
                test    DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
                test    DFSTATUS, MREQPEND      jnz .;
 ultra2_dmahalt:
-               test    SCSIOFFSET, 0x7f        jnz ultra2_shutdown;
-ultra2_await_nreq:
-               test    SCSISIGI, REQI  jz ultra2_shutdown;
-               test    SSTAT1, (PHASEMIS|REQINIT)      jz ultra2_await_nreq;
-ultra2_shutdown:
                and     DFCNTRL, ~(HDMAEN|SCSIEN);
                test    DFCNTRL, (HDMAEN|SCSIEN) jnz .;
-               bmov    SCB_RESID_DCNT, STCNT, 3;
-               mov     SCB_RESID_SGCNT, SG_COUNT;
-               or      SXFRCTL0, CLRSTCNT|CLRCHN;
                ret;
        }
 
@@ -1021,6 +1072,7 @@ inb_first:
 inb_last:
        mov     NONE,SCSIDATL ret;              /*dummy read from latch to ACK*/
 
+       
 mesgin_phasemis:
 /*
  * We expected to receive another byte, but the target changed phase
@@ -1080,7 +1132,9 @@ dma_halt:
         * to drain the data fifo until there is space for the input
         * latch to drain and HDMAEN de-asserts.
         */
-       mov     NONE, DFDAT;
+       if ((p->bugs & AHC_BUG_PCI_2_1_RETRY) != 0) {
+               mov     NONE, DFDAT;
+       }
        test    DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz dma_halt;
 }
 return:
@@ -1306,20 +1360,30 @@ dma_scb:
                cmp     CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN|CCSCBDIR jne .;
                jmp     dma_scb_finish;
 dma_scb_tohost:
-               if ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) {
+               if ((p->features & AHC_ULTRA2) == 0) {
                        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 .;
+               }
+               if ((p->features & AHC_ULTRA2) != 0) {
+                       if ((p->bugs & AHC_BUG_SCBCHAN_UPLOAD) != 0) {
+                               mvi     CCSCBCTL, CCARREN|CCSCBRESET;
+                               cmp     CCSCBCTL, ARRDONE|CCARREN jne .;
+                               mvi     CCHCNT, 32;
+                               mvi     CCSCBCTL, CCSCBEN|CCSCBRESET;
+                               cmp     CCSCBCTL, CCSCBDONE|CCSCBEN jne .;
+                       } 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 {
+       }
+       if ((p->features & AHC_CMD_CHAN) == 0) {
                mvi     DINDEX, HADDR;
                mvi     HSCB_ADDR call set_32byte_addr;
                mvi     HCNT[0], 32;
@@ -1342,17 +1406,81 @@ copy_scb_tofifo_loop:
                mov     DFDAT,SINDIR;
                cmp     SINDEX, A jne copy_scb_tofifo_loop;
                or      DFCNTRL, HDMAEN|FIFOFLUSH;
+               jmp     dma_finish;
 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;
+               mvi     DINDEX, SCB_CONTROL;
+               if ((p->bugs & AHC_BUG_PCI_2_1_RETRY) != 0) {
+                       /*
+                        * Set the A to -24.  It it hits 0, then we let
+                        * our code fall through to dfdat_in_8 to complete
+                        * the last of the copy.
+                        *
+                        * Also, things happen 8 bytes at a time in this
+                        * case, so we may need to drain the fifo at most
+                        * 3 times to keep things flowing
+                        */
+                       mvi     A, -24;
+dma_scb_hang_fifo:
+                       /* Wait for the first bit of data to hit the fifo */
+                       test    DFSTATUS, FIFOEMP jnz .;
+dma_scb_hang_wait:
+                       /* OK, now they've started to transfer into the fifo,
+                        * so wait for them to stop trying to transfer any
+                        * more data.
+                        */
+                       test    DFSTATUS, MREQPEND jnz .;
+                       /*
+                        * OK, they started, then they stopped, now see if they
+                        * managed to complete the job before stopping.  Try
+                        * it multiple times to give the chip a few cycles to
+                        * set the flag if it did complete.
+                        */
+                       test    DFSTATUS, HDONE jnz dma_scb_hang_dma_done;
+                       test    DFSTATUS, HDONE jnz dma_scb_hang_dma_done;
+                       test    DFSTATUS, HDONE jnz dma_scb_hang_dma_done;
+                       /*
+                        * Too bad, the chip didn't complete the DMA, but there
+                        * aren't any more memory requests pending, so that
+                        * means it stopped part way through and hung.  That's
+                        * our bug, so now we drain what data there is in the
+                        * fifo in order to get things going again.
+                        */
+dma_scb_hang_empty_fifo:
+                       call    dfdat_in_8;
+                       add     A, 8;
+                       add     SINDEX, A, HCNT;
+                       /*
+                        * If there are another 8 bytes of data waiting in the
+                        * fifo, then the carry bit will be set as a result
+                        * of the above add command (unless A is non-negative,
+                        * in which case the carry bit won't be set).
+                        */
+                       jc      dma_scb_hang_empty_fifo;
+                       /*
+                        * We've emptied the fifo now, but we wouldn't have got
+                        * here if the memory transfer hadn't stopped part way
+                        * through, so go back up to the beginning of the
+                        * loop and start over.  When it succeeds in getting
+                        * all the data down, HDONE will be set and we'll
+                        * jump to the code just below here.
+                        */
+                       jmp     dma_scb_hang_fifo;
+dma_scb_hang_dma_done:
+                       and     DFCNTRL, ~HDMAEN;
+                       test    DFCNTRL, HDMAEN jnz .;
+                       call    dfdat_in_8;
+                       add     A, 8;
+                       cmp     A, 8 jne . - 2;
+                       ret;
+               } else {
+                       call    dma_finish;
+                       call    dfdat_in_8;
+                       call    dfdat_in_8;
+                       call    dfdat_in_8;
+               }
+dfdat_in_8:
+               mov     DINDIR,DFDAT;
 dfdat_in_7:
-               mov     DINDEX,SINDEX;
-dfdat_in_7_continued:
                mov     DINDIR,DFDAT;
                mov     DINDIR,DFDAT;
                mov     DINDIR,DFDAT;
index 14dcd389dad13525a6ab784b2592fab65ca4c203..7320eb6b6fa2cce3b81eff6cbe7922800db7e06e 100644 (file)
@@ -162,7 +162,7 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length,
   size += sprintf(BLS, "%s", AIC7XXX_H_VERSION);
   size += sprintf(BLS, "\n");
   size += sprintf(BLS, "Compile Options:\n");
-#ifdef CONFIG_AIC7XXX_OLD_TCQ_ON_BY_DEFAULT
+#ifdef CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT
   size += sprintf(BLS, "  TCQ Enabled By Default : Enabled\n");
 #else
   size += sprintf(BLS, "  TCQ Enabled By Default : Disabled\n");
index 4baa009116e43688a05727573d3b3608faced1c4..27f2334abc714c022ddc4324bf63a6865ac348b9 100644 (file)
 #define                BRDRW                   0x04
 #define                BRDRW_ULTRA2            0x02
 #define                BRDCTL1                 0x02
-#define                BRDCTL0                 0x01
 #define                BRDSTB_ULTRA2           0x01
+#define                BRDCTL0                 0x01
 
 #define        SEECTL                          0x1e
 #define                EXTARBACK               0x80
 #define                DATA_OVERRUN            0xe1
 #define                MSGIN_PHASEMIS          0xd1
 #define                TRACEPOINT2             0xc1
-#define                TRACEPOINT              0xb1
+#define                SEQ_SG_FIXUP            0xb1
 #define                AWAITING_MSG            0xa1
 #define                RESIDUAL                0x81
 #define                BAD_STATUS              0x71
 #define                TARGCRCENDEN            0x08
 #define                TARGCRCCNTEN            0x04
 
-#define        QOUTCNT                         0x9e
-
 #define        SCSIPHASE                       0x9e
 #define                SP_STATUS               0x20
 #define                SP_COMMAND              0x10
 #define                SP_DATA_IN              0x02
 #define                SP_DATA_OUT             0x01
 
+#define        QOUTCNT                         0x9e
+
 #define        SFUNCT                          0x9f
 #define                ALT_MODE                0x80
 
 #define                RD_DFTHRSH_63           0x03
 #define                RD_DFTHRSH_50           0x02
 #define                RD_DFTHRSH_25           0x01
-#define                RD_DFTHRSH_MIN          0x00
 #define                WR_DFTHRSH_MIN          0x00
+#define                RD_DFTHRSH_MIN          0x00
 
 #define        SG_CACHEPTR                     0xfc
 #define                SG_USER_DATA            0xfc
 #define                LAST_SEG_DONE           0x01
 
 
-#define        CMD_GROUP_CODE_SHIFT    0x05
-#define        BUS_8_BIT       0x00
-#define        QOUTFIFO_OFFSET 0x01
-#define        CCSGRAM_MAXSEGS 0x10
 #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
index 047a34de037c0c2c74d54a3af1ca6e0edf364b4f..e1bc140e97350c792d3cb90d61369d9c59a04569 100644 (file)
@@ -25,12 +25,12 @@ static unsigned char seqprog[] = {
        0x00, 0x4d, 0x10, 0x70,
        0x01, 0x4e, 0x9c, 0x18,
        0xbf, 0x60, 0xc0, 0x08,
-       0x00, 0x6a, 0x3e, 0x5c,
+       0x00, 0x6a, 0x86, 0x5c,
        0xff, 0x4e, 0xc8, 0x18,
-       0x02, 0x6a, 0x54, 0x5b,
+       0x02, 0x6a, 0x70, 0x5b,
        0xff, 0x52, 0x20, 0x09,
        0x0d, 0x6a, 0x6a, 0x00,
-       0x00, 0x52, 0xca, 0x5b,
+       0x00, 0x52, 0xe6, 0x5b,
        0x03, 0xb0, 0x52, 0x31,
        0xff, 0xb0, 0x52, 0x09,
        0xff, 0xb1, 0x54, 0x09,
@@ -87,13 +87,13 @@ static unsigned char seqprog[] = {
        0x08, 0x6a, 0x66, 0x58,
        0x80, 0x6a, 0x68, 0x00,
        0x80, 0x36, 0x6c, 0x00,
-       0x00, 0x65, 0x9e, 0x5b,
+       0x00, 0x65, 0xba, 0x5b,
        0xff, 0x3d, 0xc8, 0x08,
        0xbf, 0x64, 0xe2, 0x78,
-       0x80, 0x64, 0xac, 0x71,
-       0xa0, 0x64, 0xdc, 0x71,
-       0xc0, 0x64, 0xd4, 0x71,
-       0xe0, 0x64, 0x1c, 0x72,
+       0x80, 0x64, 0xc8, 0x71,
+       0xa0, 0x64, 0xf8, 0x71,
+       0xc0, 0x64, 0xf0, 0x71,
+       0xe0, 0x64, 0x38, 0x72,
        0x01, 0x6a, 0x22, 0x01,
        0x00, 0x65, 0xaa, 0x40,
        0xf7, 0x11, 0x22, 0x08,
@@ -113,24 +113,24 @@ static unsigned char seqprog[] = {
        0x03, 0xa9, 0x18, 0x31,
        0x03, 0xa9, 0x10, 0x30,
        0x08, 0x6a, 0xcc, 0x00,
-       0xa9, 0x6a, 0xb4, 0x5b,
+       0xa9, 0x6a, 0xd0, 0x5b,
        0x00, 0x65, 0x02, 0x41,
        0xa8, 0x6a, 0x6a, 0x00,
        0x79, 0x6a, 0x6a, 0x00,
        0x40, 0x3d, 0xea, 0x68,
        0x04, 0x35, 0x6a, 0x00,
-       0x00, 0x65, 0x0e, 0x5b,
+       0x00, 0x65, 0x2a, 0x5b,
        0x80, 0x6a, 0xd4, 0x01,
        0x10, 0x36, 0xd6, 0x68,
        0x10, 0x36, 0x6c, 0x00,
        0x07, 0xac, 0x10, 0x31,
-       0x03, 0x8c, 0x10, 0x30,
        0x05, 0xa3, 0x70, 0x30,
+       0x03, 0x8c, 0x10, 0x30,
        0x88, 0x6a, 0xcc, 0x00,
-       0xac, 0x6a, 0xac, 0x5b,
-       0x00, 0x65, 0xa6, 0x5b,
+       0xac, 0x6a, 0xc8, 0x5b,
+       0x00, 0x65, 0xc2, 0x5b,
        0x38, 0x6a, 0xcc, 0x00,
-       0xa3, 0x6a, 0xb0, 0x5b,
+       0xa3, 0x6a, 0xcc, 0x5b,
        0xff, 0x38, 0x12, 0x69,
        0x80, 0x02, 0x04, 0x00,
        0xe7, 0x35, 0x6a, 0x08,
@@ -139,334 +139,348 @@ static unsigned char seqprog[] = {
        0xff, 0x6a, 0x10, 0x00,
        0xff, 0x6a, 0x12, 0x00,
        0xff, 0x6a, 0x14, 0x00,
-       0x01, 0x38, 0x18, 0x61,
+       0x22, 0x38, 0xc8, 0x28,
+       0x01, 0x38, 0x1c, 0x61,
+       0x02, 0x64, 0xc8, 0x00,
+       0x01, 0x38, 0x1c, 0x61,
        0xbf, 0x35, 0x6a, 0x08,
-       0x02, 0x6a, 0xf8, 0x01,
-       0xff, 0x69, 0xca, 0x08,
+       0xff, 0x64, 0xf8, 0x09,
        0xff, 0x35, 0x26, 0x09,
-       0x04, 0x0b, 0x1c, 0x69,
-       0x04, 0x0b, 0x28, 0x69,
-       0x10, 0x0c, 0x1e, 0x79,
-       0x04, 0x0b, 0x28, 0x69,
-       0xff, 0x6a, 0xca, 0x08,
-       0x00, 0x35, 0xee, 0x5a,
-       0x80, 0x02, 0x7c, 0x69,
-       0xff, 0x65, 0x6c, 0x79,
+       0x80, 0x02, 0xa4, 0x69,
+       0x10, 0x0c, 0x7a, 0x69,
+       0x80, 0x94, 0x22, 0x79,
+       0x00, 0x35, 0x0a, 0x5b,
+       0x80, 0x02, 0xa4, 0x69,
+       0xff, 0x65, 0x94, 0x79,
+       0x01, 0x38, 0x70, 0x71,
        0xff, 0x38, 0x70, 0x18,
-       0xff, 0x38, 0x6c, 0x79,
-       0x80, 0xea, 0x48, 0x61,
+       0xff, 0x38, 0x94, 0x79,
+       0x80, 0xea, 0x4a, 0x61,
        0xef, 0x38, 0xc8, 0x18,
        0x80, 0x6a, 0xc8, 0x00,
-       0x00, 0x65, 0x3a, 0x49,
+       0x00, 0x65, 0x3c, 0x49,
        0x33, 0x38, 0xc8, 0x28,
        0xff, 0x64, 0xd0, 0x09,
        0x04, 0x39, 0xc0, 0x31,
        0x09, 0x6a, 0xd6, 0x01,
-       0x80, 0xeb, 0x40, 0x79,
+       0x80, 0xeb, 0x42, 0x79,
        0xf7, 0xeb, 0xd6, 0x09,
-       0x08, 0xeb, 0x44, 0x69,
+       0x08, 0xeb, 0x46, 0x69,
        0x01, 0x6a, 0xd6, 0x01,
        0x08, 0xe9, 0x10, 0x31,
        0x03, 0x8c, 0x10, 0x30,
+       0xff, 0x38, 0x70, 0x18,
        0x88, 0x6a, 0xcc, 0x00,
-       0x39, 0x6a, 0xb2, 0x5b,
+       0x39, 0x6a, 0xce, 0x5b,
        0x08, 0x6a, 0x18, 0x01,
        0xff, 0x6a, 0x1a, 0x09,
        0xff, 0x6a, 0x1c, 0x09,
        0x0d, 0x93, 0x26, 0x01,
-       0x00, 0x65, 0x30, 0x5c,
-       0x88, 0x6a, 0x20, 0x5c,
-       0x00, 0x65, 0xa6, 0x5b,
+       0x00, 0x65, 0x78, 0x5c,
+       0x88, 0x6a, 0xcc, 0x00,
+       0x00, 0x65, 0x6a, 0x5c,
+       0x00, 0x65, 0xc2, 0x5b,
        0xff, 0x6a, 0xc8, 0x08,
        0x08, 0x39, 0x72, 0x18,
        0x00, 0x3a, 0x74, 0x20,
-       0x01, 0x0c, 0x64, 0x79,
+       0x00, 0x65, 0x02, 0x41,
+       0x01, 0x0c, 0x6c, 0x79,
        0x10, 0x0c, 0x02, 0x79,
-       0xff, 0x35, 0x26, 0x09,
-       0x04, 0x0b, 0x6a, 0x69,
-       0x00, 0x65, 0x84, 0x59,
+       0x10, 0x0c, 0x7a, 0x69,
+       0x01, 0xfc, 0x70, 0x79,
+       0xff, 0x6a, 0x70, 0x08,
+       0x01, 0x0c, 0x76, 0x79,
+       0x10, 0x0c, 0x02, 0x79,
+       0x00, 0x65, 0xae, 0x59,
+       0x01, 0xfc, 0x94, 0x69,
+       0x40, 0x0d, 0x84, 0x69,
+       0xb1, 0x6a, 0x22, 0x01,
+       0x00, 0x65, 0x94, 0x41,
+       0x2e, 0xfc, 0xa2, 0x28,
+       0x3f, 0x38, 0xc8, 0x08,
+       0x00, 0x51, 0x94, 0x71,
+       0xff, 0x6a, 0xc8, 0x08,
+       0xf8, 0x39, 0x72, 0x18,
+       0xff, 0x3a, 0x74, 0x20,
+       0x01, 0x38, 0x70, 0x18,
+       0x00, 0x65, 0x86, 0x41,
        0x03, 0x08, 0x52, 0x31,
        0xff, 0x38, 0x50, 0x09,
+       0x12, 0x01, 0x02, 0x00,
        0xff, 0x08, 0x52, 0x09,
        0xff, 0x09, 0x54, 0x09,
        0xff, 0x0a, 0x56, 0x09,
        0xff, 0x38, 0x50, 0x09,
        0x00, 0x65, 0xaa, 0x40,
-       0x00, 0x65, 0x84, 0x59,
+       0x10, 0x0c, 0xa4, 0x79,
+       0x00, 0x65, 0xae, 0x59,
        0x7f, 0x02, 0x04, 0x08,
        0xe1, 0x6a, 0x22, 0x01,
        0x00, 0x65, 0xaa, 0x40,
-       0x04, 0x93, 0x9a, 0x69,
+       0x04, 0x93, 0xc2, 0x69,
        0xdf, 0x93, 0x26, 0x09,
-       0x20, 0x93, 0x88, 0x69,
+       0x20, 0x93, 0xb2, 0x69,
        0x02, 0x93, 0x26, 0x01,
-       0x01, 0x94, 0x8a, 0x79,
-       0x01, 0x94, 0x8a, 0x79,
-       0x01, 0x94, 0x8a, 0x79,
-       0x01, 0x94, 0x8a, 0x79,
-       0x01, 0x94, 0x8a, 0x79,
-       0x01, 0x94, 0x8a, 0x79,
-       0x10, 0x94, 0x98, 0x69,
-       0x7f, 0x05, 0xa0, 0x69,
-       0x02, 0x03, 0xa0, 0x79,
-       0x11, 0x0c, 0x9c, 0x79,
+       0x01, 0x94, 0xb6, 0x79,
+       0x01, 0x94, 0xb6, 0x79,
+       0x01, 0x94, 0xb6, 0x79,
+       0x01, 0x94, 0xb6, 0x79,
+       0x01, 0x94, 0xb6, 0x79,
+       0x10, 0x94, 0xc0, 0x69,
        0xd7, 0x93, 0x26, 0x09,
-       0x28, 0x93, 0xa2, 0x69,
-       0x03, 0x08, 0x52, 0x31,
-       0xff, 0x38, 0x50, 0x09,
-       0x12, 0x01, 0x02, 0x00,
+       0x28, 0x93, 0xc4, 0x69,
        0xff, 0x6a, 0xd4, 0x0c,
-       0x00, 0x65, 0x0e, 0x5b,
+       0x00, 0x65, 0x2a, 0x5b,
        0x05, 0xb4, 0x10, 0x31,
        0x02, 0x6a, 0x1a, 0x31,
        0x03, 0x8c, 0x10, 0x30,
        0x88, 0x6a, 0xcc, 0x00,
-       0xb4, 0x6a, 0xb0, 0x5b,
+       0xb4, 0x6a, 0xcc, 0x5b,
        0xff, 0x6a, 0x1a, 0x09,
        0xff, 0x6a, 0x1c, 0x09,
-       0x00, 0x65, 0xa6, 0x5b,
-       0x3d, 0x6a, 0xee, 0x5a,
+       0x00, 0x65, 0xc2, 0x5b,
+       0x3d, 0x6a, 0x0a, 0x5b,
        0xac, 0x6a, 0x26, 0x01,
-       0x04, 0x0b, 0xc2, 0x69,
-       0x04, 0x0b, 0xc8, 0x69,
-       0x10, 0x0c, 0xc4, 0x79,
-       0x02, 0x03, 0xcc, 0x79,
-       0x11, 0x0c, 0xc8, 0x79,
+       0x04, 0x0b, 0xde, 0x69,
+       0x04, 0x0b, 0xe4, 0x69,
+       0x10, 0x0c, 0xe0, 0x79,
+       0x02, 0x03, 0xe8, 0x79,
+       0x11, 0x0c, 0xe4, 0x79,
        0xd7, 0x93, 0x26, 0x09,
-       0x28, 0x93, 0xce, 0x69,
+       0x28, 0x93, 0xea, 0x69,
        0x12, 0x01, 0x02, 0x00,
        0x00, 0x65, 0xaa, 0x40,
-       0x00, 0x65, 0x0e, 0x5b,
+       0x00, 0x65, 0x2a, 0x5b,
        0xff, 0x06, 0x44, 0x09,
        0x00, 0x65, 0xaa, 0x40,
        0x10, 0x3d, 0x06, 0x00,
        0xff, 0x34, 0xca, 0x08,
-       0x80, 0x65, 0x00, 0x62,
+       0x80, 0x65, 0x1c, 0x62,
        0x0f, 0xa1, 0xca, 0x08,
        0x07, 0xa1, 0xca, 0x08,
        0x40, 0xa0, 0xc8, 0x08,
        0x00, 0x65, 0xca, 0x00,
        0x80, 0x65, 0xca, 0x00,
-       0x80, 0xa0, 0xf0, 0x79,
+       0x80, 0xa0, 0x0c, 0x7a,
        0xff, 0x65, 0x0c, 0x08,
-       0x00, 0x65, 0x02, 0x42,
-       0x20, 0xa0, 0x08, 0x7a,
+       0x00, 0x65, 0x1e, 0x42,
+       0x20, 0xa0, 0x24, 0x7a,
        0xff, 0x65, 0x0c, 0x08,
-       0x00, 0x65, 0x9e, 0x5b,
-       0xa0, 0x3d, 0x10, 0x62,
+       0x00, 0x65, 0xba, 0x5b,
+       0xa0, 0x3d, 0x2c, 0x62,
        0x23, 0xa0, 0x0c, 0x08,
-       0x00, 0x65, 0x9e, 0x5b,
-       0xa0, 0x3d, 0x10, 0x62,
-       0x00, 0xb9, 0x08, 0x42,
-       0xff, 0x65, 0x08, 0x62,
+       0x00, 0x65, 0xba, 0x5b,
+       0xa0, 0x3d, 0x2c, 0x62,
+       0x00, 0xb9, 0x24, 0x42,
+       0xff, 0x65, 0x24, 0x62,
        0xa1, 0x6a, 0x22, 0x01,
        0xff, 0x6a, 0xd4, 0x08,
-       0x10, 0x51, 0x10, 0x72,
+       0x10, 0x51, 0x2c, 0x72,
        0x40, 0x6a, 0x18, 0x00,
        0xff, 0x65, 0x0c, 0x08,
-       0x00, 0x65, 0x9e, 0x5b,
-       0xa0, 0x3d, 0xda, 0x71,
+       0x00, 0x65, 0xba, 0x5b,
+       0xa0, 0x3d, 0xf6, 0x71,
        0x40, 0x6a, 0x18, 0x00,
        0xff, 0x34, 0xa6, 0x08,
-       0x80, 0x34, 0x18, 0x62,
+       0x80, 0x34, 0x34, 0x62,
        0x7f, 0xa0, 0x40, 0x09,
        0x08, 0x6a, 0x68, 0x00,
        0x00, 0x65, 0xaa, 0x40,
-       0x64, 0x6a, 0xe4, 0x5a,
-       0x80, 0x64, 0x8e, 0x6a,
-       0x04, 0x64, 0x70, 0x72,
-       0x02, 0x64, 0x76, 0x72,
-       0x00, 0x6a, 0x38, 0x72,
-       0x03, 0x64, 0x8a, 0x72,
-       0x01, 0x64, 0x6c, 0x72,
-       0x07, 0x64, 0xcc, 0x72,
-       0x08, 0x64, 0x34, 0x72,
-       0x23, 0x64, 0xd0, 0x72,
+       0x64, 0x6a, 0x00, 0x5b,
+       0x80, 0x64, 0xaa, 0x6a,
+       0x04, 0x64, 0x8c, 0x72,
+       0x02, 0x64, 0x92, 0x72,
+       0x00, 0x6a, 0x54, 0x72,
+       0x03, 0x64, 0xa6, 0x72,
+       0x01, 0x64, 0x88, 0x72,
+       0x07, 0x64, 0xe8, 0x72,
+       0x08, 0x64, 0x50, 0x72,
+       0x23, 0x64, 0xec, 0x72,
        0x11, 0x6a, 0x22, 0x01,
-       0x07, 0x6a, 0xd6, 0x5a,
+       0x07, 0x6a, 0xf2, 0x5a,
        0xff, 0x06, 0xd4, 0x08,
        0x00, 0x65, 0xaa, 0x40,
-       0xff, 0xa8, 0x3c, 0x6a,
-       0xff, 0xa2, 0x54, 0x7a,
+       0xff, 0xa8, 0x58, 0x6a,
+       0xff, 0xa2, 0x70, 0x7a,
        0x01, 0x6a, 0x6a, 0x00,
-       0x00, 0xb9, 0xca, 0x5b,
-       0xff, 0xa2, 0x54, 0x7a,
+       0x00, 0xb9, 0xe6, 0x5b,
+       0xff, 0xa2, 0x70, 0x7a,
        0x71, 0x6a, 0x22, 0x01,
        0xff, 0x6a, 0xd4, 0x08,
-       0x40, 0x51, 0x54, 0x62,
+       0x40, 0x51, 0x70, 0x62,
        0x0d, 0x6a, 0x6a, 0x00,
-       0x00, 0xb9, 0xca, 0x5b,
+       0x00, 0xb9, 0xe6, 0x5b,
        0xff, 0x3e, 0x74, 0x09,
        0xff, 0x90, 0x7c, 0x08,
        0x00, 0x65, 0x4e, 0x58,
        0x00, 0x65, 0xbc, 0x40,
-       0x20, 0xa0, 0x5c, 0x6a,
+       0x20, 0xa0, 0x78, 0x6a,
        0xff, 0x37, 0xc8, 0x08,
-       0x00, 0x6a, 0x74, 0x5b,
-       0xff, 0x6a, 0x8a, 0x5b,
+       0x00, 0x6a, 0x90, 0x5b,
+       0xff, 0x6a, 0xa6, 0x5b,
        0xff, 0xf8, 0xc8, 0x08,
        0xff, 0x4f, 0xc8, 0x08,
-       0x01, 0x6a, 0x74, 0x5b,
-       0x00, 0xb9, 0x8a, 0x5b,
+       0x01, 0x6a, 0x90, 0x5b,
+       0x00, 0xb9, 0xa6, 0x5b,
        0x01, 0x4f, 0x9e, 0x18,
        0x02, 0x6a, 0x22, 0x01,
-       0x00, 0x65, 0x38, 0x5c,
+       0x00, 0x65, 0x80, 0x5c,
        0x00, 0x65, 0xbc, 0x40,
        0x41, 0x6a, 0x22, 0x01,
        0x00, 0x65, 0xaa, 0x40,
        0x04, 0xa0, 0x40, 0x01,
-       0x00, 0x65, 0x50, 0x5c,
+       0x00, 0x65, 0x98, 0x5c,
        0x00, 0x65, 0xbc, 0x40,
-       0x10, 0x36, 0x34, 0x7a,
+       0x10, 0x36, 0x50, 0x7a,
        0x05, 0x38, 0x46, 0x31,
        0x04, 0x14, 0x58, 0x31,
        0x03, 0xa9, 0x60, 0x31,
        0xa3, 0x6a, 0xcc, 0x00,
-       0x38, 0x6a, 0xb0, 0x5b,
+       0x38, 0x6a, 0xcc, 0x5b,
        0xac, 0x6a, 0xcc, 0x00,
-       0x14, 0x6a, 0xb2, 0x5b,
-       0xa9, 0x6a, 0xb4, 0x5b,
-       0x00, 0x65, 0x34, 0x42,
+       0x14, 0x6a, 0xce, 0x5b,
+       0xa9, 0x6a, 0xd0, 0x5b,
+       0x00, 0x65, 0x50, 0x42,
        0xef, 0x36, 0x6c, 0x08,
-       0x00, 0x65, 0x34, 0x42,
+       0x00, 0x65, 0x50, 0x42,
        0x0f, 0x64, 0xc8, 0x08,
        0x07, 0x64, 0xc8, 0x08,
        0x00, 0x37, 0x6e, 0x00,
        0xff, 0x6a, 0xa4, 0x00,
-       0x00, 0x65, 0x44, 0x5b,
-       0xff, 0x51, 0xa0, 0x72,
-       0x20, 0x36, 0xaa, 0x7a,
-       0x00, 0x90, 0x32, 0x5b,
-       0x00, 0x65, 0xac, 0x42,
+       0x00, 0x65, 0x60, 0x5b,
+       0xff, 0x51, 0xbc, 0x72,
+       0x20, 0x36, 0xc6, 0x7a,
+       0x00, 0x90, 0x4e, 0x5b,
+       0x00, 0x65, 0xc8, 0x42,
        0xff, 0x06, 0xd4, 0x08,
-       0x00, 0x65, 0x9e, 0x5b,
-       0xe0, 0x3d, 0xc6, 0x62,
-       0x20, 0x12, 0xc6, 0x62,
-       0x51, 0x6a, 0xda, 0x5a,
-       0x00, 0x65, 0x2c, 0x5b,
+       0x00, 0x65, 0xba, 0x5b,
+       0xe0, 0x3d, 0xe2, 0x62,
+       0x20, 0x12, 0xe2, 0x62,
+       0x51, 0x6a, 0xf6, 0x5a,
+       0x00, 0x65, 0x48, 0x5b,
        0xff, 0x37, 0xc8, 0x08,
-       0x00, 0xa1, 0xbe, 0x62,
-       0x04, 0xa0, 0xbe, 0x7a,
+       0x00, 0xa1, 0xda, 0x62,
+       0x04, 0xa0, 0xda, 0x7a,
        0xfb, 0xa0, 0x40, 0x09,
        0x80, 0x36, 0x6c, 0x00,
-       0x80, 0xa0, 0x34, 0x7a,
+       0x80, 0xa0, 0x50, 0x7a,
        0x7f, 0xa0, 0x40, 0x09,
-       0xff, 0x6a, 0xd6, 0x5a,
-       0x00, 0x65, 0x34, 0x42,
-       0x04, 0xa0, 0xc4, 0x7a,
-       0x00, 0x65, 0x50, 0x5c,
-       0x00, 0x65, 0xc6, 0x42,
-       0x00, 0x65, 0x38, 0x5c,
+       0xff, 0x6a, 0xf2, 0x5a,
+       0x00, 0x65, 0x50, 0x42,
+       0x04, 0xa0, 0xe0, 0x7a,
+       0x00, 0x65, 0x98, 0x5c,
+       0x00, 0x65, 0xe2, 0x42,
+       0x00, 0x65, 0x80, 0x5c,
        0x31, 0x6a, 0x22, 0x01,
-       0x0c, 0x6a, 0xd6, 0x5a,
-       0x00, 0x65, 0x34, 0x42,
+       0x0c, 0x6a, 0xf2, 0x5a,
+       0x00, 0x65, 0x50, 0x42,
        0x61, 0x6a, 0x22, 0x01,
-       0x00, 0x65, 0x34, 0x42,
-       0x51, 0x6a, 0xda, 0x5a,
+       0x00, 0x65, 0x50, 0x42,
+       0x51, 0x6a, 0xf6, 0x5a,
        0x51, 0x6a, 0x22, 0x01,
-       0x00, 0x65, 0x34, 0x42,
+       0x00, 0x65, 0x50, 0x42,
        0x10, 0x3d, 0x06, 0x00,
        0xff, 0x65, 0x68, 0x0c,
        0xff, 0x06, 0xd4, 0x08,
-       0x01, 0x0c, 0xdc, 0x7a,
-       0x04, 0x0c, 0xde, 0x6a,
+       0x01, 0x0c, 0xf8, 0x7a,
+       0x04, 0x0c, 0xfa, 0x6a,
        0xe0, 0x03, 0x7a, 0x08,
-       0xe0, 0x3d, 0xea, 0x62,
+       0xe0, 0x3d, 0x06, 0x63,
        0xff, 0x65, 0xcc, 0x08,
        0xff, 0x12, 0xda, 0x0c,
        0xff, 0x06, 0xd4, 0x0c,
        0xd1, 0x6a, 0x22, 0x01,
        0x00, 0x65, 0xaa, 0x40,
        0xff, 0x65, 0x26, 0x09,
-       0x01, 0x0b, 0xfe, 0x6a,
-       0x10, 0x0c, 0xf0, 0x7a,
-       0x04, 0x0b, 0xf8, 0x6a,
+       0x01, 0x0b, 0x1a, 0x6b,
+       0x10, 0x0c, 0x0c, 0x7b,
+       0x04, 0x0b, 0x14, 0x6b,
        0xff, 0x6a, 0xca, 0x08,
-       0x04, 0x93, 0xfc, 0x6a,
-       0x01, 0x94, 0xfa, 0x7a,
-       0x10, 0x94, 0xfc, 0x6a,
-       0x80, 0x3d, 0x02, 0x73,
-       0x0f, 0x04, 0x06, 0x6b,
-       0x02, 0x03, 0x06, 0x7b,
-       0x11, 0x0c, 0x02, 0x7b,
+       0x04, 0x93, 0x18, 0x6b,
+       0x01, 0x94, 0x16, 0x7b,
+       0x10, 0x94, 0x18, 0x6b,
+       0x80, 0x3d, 0x1e, 0x73,
+       0x0f, 0x04, 0x22, 0x6b,
+       0x02, 0x03, 0x22, 0x7b,
+       0x11, 0x0c, 0x1e, 0x7b,
        0xc7, 0x93, 0x26, 0x09,
        0xff, 0x99, 0xd4, 0x08,
-       0x38, 0x93, 0x08, 0x6b,
+       0x38, 0x93, 0x24, 0x6b,
        0xff, 0x6a, 0xd4, 0x0c,
-       0x80, 0x36, 0x0c, 0x6b,
+       0x80, 0x36, 0x28, 0x6b,
        0x21, 0x6a, 0x22, 0x05,
        0xff, 0x65, 0x20, 0x09,
-       0xff, 0x51, 0x1a, 0x63,
+       0xff, 0x51, 0x36, 0x63,
        0xff, 0x37, 0xc8, 0x08,
-       0xa1, 0x6a, 0x26, 0x43,
+       0xa1, 0x6a, 0x42, 0x43,
        0xff, 0x51, 0xc8, 0x08,
-       0xb9, 0x6a, 0x26, 0x43,
+       0xb9, 0x6a, 0x42, 0x43,
        0xff, 0x90, 0xa4, 0x08,
-       0xff, 0xba, 0x2a, 0x73,
+       0xff, 0xba, 0x46, 0x73,
        0xff, 0xba, 0x20, 0x09,
        0xff, 0x65, 0xca, 0x18,
-       0x00, 0x6c, 0x1e, 0x63,
+       0x00, 0x6c, 0x3a, 0x63,
        0xff, 0x90, 0xca, 0x0c,
        0xff, 0x6a, 0xca, 0x04,
-       0x20, 0x36, 0x3e, 0x7b,
-       0x00, 0x90, 0x12, 0x5b,
-       0xff, 0x65, 0x3e, 0x73,
-       0xff, 0x52, 0x3c, 0x73,
+       0x20, 0x36, 0x5a, 0x7b,
+       0x00, 0x90, 0x2e, 0x5b,
+       0xff, 0x65, 0x5a, 0x73,
+       0xff, 0x52, 0x58, 0x73,
        0xff, 0xba, 0xcc, 0x08,
        0xff, 0x52, 0x20, 0x09,
        0xff, 0x66, 0x74, 0x09,
        0xff, 0x65, 0x20, 0x0d,
        0xff, 0xba, 0x7e, 0x0c,
-       0x00, 0x6a, 0x3e, 0x5c,
+       0x00, 0x6a, 0x86, 0x5c,
        0x0d, 0x6a, 0x6a, 0x00,
-       0x00, 0x51, 0xca, 0x43,
-       0xff, 0x3f, 0x98, 0x73,
+       0x00, 0x51, 0xe6, 0x43,
+       0xff, 0x3f, 0xb4, 0x73,
        0xff, 0x6a, 0xa2, 0x00,
-       0x00, 0x3f, 0x12, 0x5b,
-       0xff, 0x65, 0x98, 0x73,
+       0x00, 0x3f, 0x2e, 0x5b,
+       0xff, 0x65, 0xb4, 0x73,
        0x20, 0x36, 0x6c, 0x00,
-       0x20, 0xa0, 0x52, 0x6b,
+       0x20, 0xa0, 0x6e, 0x6b,
        0xff, 0xb9, 0xa2, 0x0c,
        0xff, 0x6a, 0xa2, 0x04,
        0xff, 0x65, 0xa4, 0x08,
        0xe0, 0x6a, 0xcc, 0x00,
-       0x45, 0x6a, 0xbe, 0x5b,
+       0x45, 0x6a, 0xda, 0x5b,
        0x01, 0x6a, 0xd0, 0x01,
        0x09, 0x6a, 0xd6, 0x01,
-       0x80, 0xeb, 0x5e, 0x7b,
+       0x80, 0xeb, 0x7a, 0x7b,
        0x01, 0x6a, 0xd6, 0x01,
        0x01, 0xe9, 0xa4, 0x34,
        0x88, 0x6a, 0xcc, 0x00,
-       0x45, 0x6a, 0xbe, 0x5b,
+       0x45, 0x6a, 0xda, 0x5b,
        0x01, 0x6a, 0x18, 0x01,
        0xff, 0x6a, 0x1a, 0x09,
        0xff, 0x6a, 0x1c, 0x09,
        0x0d, 0x6a, 0x26, 0x01,
-       0x00, 0x65, 0x30, 0x5c,
+       0x00, 0x65, 0x78, 0x5c,
        0xff, 0x99, 0xa4, 0x0c,
        0xff, 0x65, 0xa4, 0x08,
        0xe0, 0x6a, 0xcc, 0x00,
-       0x45, 0x6a, 0xbe, 0x5b,
+       0x45, 0x6a, 0xda, 0x5b,
        0x01, 0x6a, 0xd0, 0x01,
        0x01, 0x6a, 0xdc, 0x05,
        0x88, 0x6a, 0xcc, 0x00,
-       0x45, 0x6a, 0xbe, 0x5b,
+       0x45, 0x6a, 0xda, 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, 0x8e, 0x7b,
+       0x80, 0xee, 0xaa, 0x7b,
        0xff, 0x6a, 0xdc, 0x0d,
        0xff, 0x65, 0x32, 0x09,
        0x0a, 0x93, 0x26, 0x01,
-       0x00, 0x65, 0x30, 0x44,
+       0x00, 0x65, 0x78, 0x44,
        0xff, 0x37, 0xc8, 0x08,
-       0x00, 0x6a, 0x54, 0x5b,
+       0x00, 0x6a, 0x70, 0x5b,
        0xff, 0x52, 0xa2, 0x0c,
-       0x01, 0x0c, 0x9e, 0x7b,
-       0x04, 0x0c, 0x9e, 0x6b,
+       0x01, 0x0c, 0xba, 0x7b,
+       0x04, 0x0c, 0xba, 0x6b,
        0xe0, 0x03, 0x06, 0x08,
        0xe0, 0x03, 0x7a, 0x0c,
        0xff, 0x8c, 0x10, 0x08,
@@ -489,29 +503,34 @@ static unsigned char seqprog[] = {
        0x00, 0x6c, 0xda, 0x24,
        0xff, 0x65, 0xc8, 0x08,
        0xe0, 0x6a, 0xcc, 0x00,
-       0x41, 0x6a, 0xba, 0x5b,
+       0x41, 0x6a, 0xd6, 0x5b,
        0xff, 0x90, 0xe2, 0x09,
        0x20, 0x6a, 0xd0, 0x01,
-       0x04, 0x35, 0xdc, 0x7b,
+       0x04, 0x35, 0xf8, 0x7b,
        0x1d, 0x6a, 0xdc, 0x01,
-       0xdc, 0xee, 0xd8, 0x63,
-       0x00, 0x65, 0xe8, 0x43,
+       0xdc, 0xee, 0xf4, 0x63,
+       0x00, 0x65, 0x0e, 0x44,
        0x01, 0x6a, 0xdc, 0x01,
        0x20, 0xa0, 0xd8, 0x31,
        0x09, 0xee, 0xdc, 0x01,
-       0x80, 0xee, 0xe2, 0x7b,
+       0x80, 0xee, 0xfe, 0x7b,
+       0x11, 0x6a, 0xdc, 0x01,
+       0x50, 0xee, 0x02, 0x64,
+       0x20, 0x6a, 0xd0, 0x01,
+       0x09, 0x6a, 0xdc, 0x01,
+       0x88, 0xee, 0x08, 0x64,
        0x19, 0x6a, 0xdc, 0x01,
-       0xd8, 0xee, 0xe6, 0x63,
+       0xd8, 0xee, 0x0c, 0x64,
        0xff, 0x6a, 0xdc, 0x09,
-       0x18, 0xee, 0xea, 0x6b,
+       0x18, 0xee, 0x10, 0x6c,
        0xff, 0x6a, 0xd4, 0x0c,
        0x88, 0x6a, 0xcc, 0x00,
-       0x41, 0x6a, 0xba, 0x5b,
+       0x41, 0x6a, 0xd6, 0x5b,
        0x20, 0x6a, 0x18, 0x01,
        0xff, 0x6a, 0x1a, 0x09,
        0xff, 0x6a, 0x1c, 0x09,
        0xff, 0x35, 0x26, 0x09,
-       0x04, 0x35, 0x14, 0x6c,
+       0x04, 0x35, 0x3c, 0x6c,
        0xa0, 0x6a, 0xca, 0x00,
        0x20, 0x65, 0xc8, 0x18,
        0xff, 0x6c, 0x32, 0x09,
@@ -522,15 +541,32 @@ static unsigned char seqprog[] = {
        0xff, 0x6c, 0x32, 0x09,
        0xff, 0x6c, 0x32, 0x09,
        0xff, 0x6c, 0x32, 0x09,
-       0x00, 0x65, 0x00, 0x64,
+       0x00, 0x65, 0x26, 0x64,
        0x0a, 0x93, 0x26, 0x01,
-       0x00, 0x65, 0x30, 0x5c,
-       0x04, 0x35, 0x0c, 0x7b,
-       0xa0, 0x6a, 0x20, 0x5c,
-       0x00, 0x65, 0x22, 0x5c,
-       0x00, 0x65, 0x22, 0x5c,
-       0x00, 0x65, 0x22, 0x44,
-       0xff, 0x65, 0xcc, 0x08,
+       0x00, 0x65, 0x78, 0x44,
+       0xa0, 0x6a, 0xcc, 0x00,
+       0xe8, 0x6a, 0xc8, 0x00,
+       0x01, 0x94, 0x40, 0x6c,
+       0x10, 0x94, 0x42, 0x6c,
+       0x08, 0x94, 0x54, 0x6c,
+       0x08, 0x94, 0x54, 0x6c,
+       0x08, 0x94, 0x54, 0x6c,
+       0x00, 0x65, 0x68, 0x5c,
+       0x08, 0x64, 0xc8, 0x18,
+       0x00, 0x8c, 0xca, 0x18,
+       0x00, 0x65, 0x4a, 0x4c,
+       0x00, 0x65, 0x40, 0x44,
+       0xf7, 0x93, 0x26, 0x09,
+       0x08, 0x93, 0x56, 0x6c,
+       0x00, 0x65, 0x68, 0x5c,
+       0x08, 0x64, 0xc8, 0x18,
+       0x08, 0x64, 0x58, 0x64,
+       0xff, 0x6a, 0xd4, 0x0c,
+       0x00, 0x65, 0x78, 0x5c,
+       0x00, 0x65, 0x68, 0x5c,
+       0x00, 0x65, 0x68, 0x5c,
+       0x00, 0x65, 0x68, 0x5c,
+       0xff, 0x99, 0xda, 0x08,
        0xff, 0x99, 0xda, 0x08,
        0xff, 0x99, 0xda, 0x08,
        0xff, 0x99, 0xda, 0x08,
@@ -538,19 +574,19 @@ static unsigned char seqprog[] = {
        0xff, 0x99, 0xda, 0x08,
        0xff, 0x99, 0xda, 0x08,
        0xff, 0x99, 0xda, 0x0c,
-       0x08, 0x94, 0x30, 0x7c,
+       0x08, 0x94, 0x78, 0x7c,
        0xf7, 0x93, 0x26, 0x09,
-       0x08, 0x93, 0x34, 0x6c,
+       0x08, 0x93, 0x7c, 0x6c,
        0xff, 0x6a, 0xd4, 0x0c,
        0xff, 0x40, 0x74, 0x09,
        0xff, 0x90, 0x80, 0x08,
        0xff, 0x6a, 0x72, 0x05,
-       0xff, 0x40, 0x4c, 0x64,
-       0xff, 0x3f, 0x44, 0x64,
+       0xff, 0x40, 0x94, 0x64,
+       0xff, 0x3f, 0x8c, 0x64,
        0xff, 0x6a, 0xca, 0x04,
        0xff, 0x3f, 0x20, 0x09,
        0x01, 0x6a, 0x6a, 0x00,
-       0x00, 0xb9, 0xca, 0x5b,
+       0x00, 0xb9, 0xe6, 0x5b,
        0xff, 0xba, 0x7e, 0x0c,
        0xff, 0x40, 0x20, 0x09,
        0xff, 0xba, 0x80, 0x0c,
@@ -558,12 +594,36 @@ static unsigned char seqprog[] = {
        0xff, 0x90, 0x7e, 0x0c,
 };
 
+static int aic7xxx_patch15_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch15_func(struct aic7xxx_host *p)
+{
+       return ((p->bugs & AHC_BUG_SCBCHAN_UPLOAD) != 0);
+}
+
+static int aic7xxx_patch14_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch14_func(struct aic7xxx_host *p)
+{
+       return ((p->bugs & AHC_BUG_PCI_2_1_RETRY) != 0);
+}
+
+static int aic7xxx_patch13_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch13_func(struct aic7xxx_host *p)
+{
+       return ((p->features & AHC_WIDE) != 0);
+}
+
 static int aic7xxx_patch12_func(struct aic7xxx_host *p);
 
 static int
 aic7xxx_patch12_func(struct aic7xxx_host *p)
 {
-       return ((p->features & AHC_WIDE) != 0);
+       return ((p->bugs & AHC_BUG_AUTOFLUSH) != 0);
 }
 
 static int aic7xxx_patch11_func(struct aic7xxx_host *p);
@@ -692,54 +752,66 @@ struct sequencer_patch {
        { aic7xxx_patch7_func, 113, 1, 2 },
        { aic7xxx_patch0_func, 114, 1, 1 },
        { aic7xxx_patch1_func, 118, 1, 1 },
-       { aic7xxx_patch1_func, 121, 3, 2 },
+       { aic7xxx_patch1_func, 121, 3, 3 },
+       { aic7xxx_patch11_func, 123, 1, 1 },
        { aic7xxx_patch0_func, 124, 5, 1 },
-       { aic7xxx_patch1_func, 132, 2, 3 },
        { aic7xxx_patch7_func, 132, 1, 1 },
-       { aic7xxx_patch0_func, 134, 3, 1 },
-       { aic7xxx_patch11_func, 138, 1, 2 },
-       { aic7xxx_patch0_func, 139, 1, 1 },
-       { aic7xxx_patch7_func, 140, 7, 2 },
-       { aic7xxx_patch0_func, 147, 1, 1 },
-       { aic7xxx_patch1_func, 152, 14, 3 },
-       { aic7xxx_patch11_func, 165, 1, 1 },
-       { aic7xxx_patch0_func, 166, 9, 1 },
-       { aic7xxx_patch7_func, 180, 2, 1 },
-       { aic7xxx_patch7_func, 182, 1, 1 },
-       { aic7xxx_patch11_func, 183, 6, 3 },
-       { aic7xxx_patch1_func, 183, 2, 2 },
-       { aic7xxx_patch0_func, 185, 4, 1 },
-       { aic7xxx_patch7_func, 190, 1, 1 },
-       { aic7xxx_patch7_func, 194, 20, 1 },
-       { aic7xxx_patch1_func, 215, 3, 3 },
-       { aic7xxx_patch11_func, 217, 1, 1 },
-       { aic7xxx_patch0_func, 218, 5, 1 },
-       { aic7xxx_patch11_func, 223, 1, 2 },
-       { aic7xxx_patch0_func, 224, 9, 1 },
-       { aic7xxx_patch12_func, 240, 1, 2 },
-       { aic7xxx_patch0_func, 241, 1, 1 },
-       { aic7xxx_patch4_func, 302, 1, 2 },
-       { aic7xxx_patch0_func, 303, 1, 1 },
-       { aic7xxx_patch2_func, 306, 1, 1 },
-       { aic7xxx_patch1_func, 316, 3, 2 },
-       { aic7xxx_patch0_func, 319, 5, 1 },
-       { aic7xxx_patch12_func, 327, 1, 2 },
-       { aic7xxx_patch0_func, 328, 1, 1 },
-       { aic7xxx_patch5_func, 333, 1, 1 },
-       { aic7xxx_patch11_func, 375, 15, 1 },
-       { aic7xxx_patch1_func, 427, 7, 2 },
-       { aic7xxx_patch0_func, 434, 8, 1 },
-       { aic7xxx_patch1_func, 443, 4, 2 },
-       { aic7xxx_patch0_func, 447, 6, 1 },
-       { aic7xxx_patch1_func, 453, 4, 2 },
-       { aic7xxx_patch0_func, 457, 3, 1 },
-       { aic7xxx_patch10_func, 467, 10, 1 },
-       { aic7xxx_patch1_func, 486, 17, 4 },
-       { aic7xxx_patch9_func, 494, 4, 2 },
-       { aic7xxx_patch0_func, 498, 2, 1 },
-       { aic7xxx_patch0_func, 503, 33, 1 },
-       { aic7xxx_patch10_func, 536, 4, 1 },
-       { aic7xxx_patch5_func, 540, 2, 1 },
-       { aic7xxx_patch5_func, 543, 9, 1 },
+       { aic7xxx_patch9_func, 133, 1, 1 },
+       { aic7xxx_patch10_func, 134, 3, 1 },
+       { aic7xxx_patch7_func, 137, 3, 2 },
+       { aic7xxx_patch0_func, 140, 2, 1 },
+       { aic7xxx_patch7_func, 142, 5, 2 },
+       { aic7xxx_patch0_func, 147, 3, 1 },
+       { aic7xxx_patch7_func, 150, 1, 2 },
+       { aic7xxx_patch0_func, 151, 2, 1 },
+       { aic7xxx_patch1_func, 153, 15, 4 },
+       { aic7xxx_patch11_func, 166, 1, 2 },
+       { aic7xxx_patch0_func, 167, 1, 1 },
+       { aic7xxx_patch0_func, 168, 10, 1 },
+       { aic7xxx_patch7_func, 181, 1, 2 },
+       { aic7xxx_patch0_func, 182, 2, 1 },
+       { aic7xxx_patch7_func, 184, 18, 1 },
+       { aic7xxx_patch1_func, 202, 3, 3 },
+       { aic7xxx_patch7_func, 204, 1, 1 },
+       { aic7xxx_patch0_func, 205, 4, 1 },
+       { aic7xxx_patch7_func, 210, 2, 1 },
+       { aic7xxx_patch7_func, 215, 13, 3 },
+       { aic7xxx_patch12_func, 218, 1, 1 },
+       { aic7xxx_patch12_func, 219, 4, 1 },
+       { aic7xxx_patch1_func, 229, 3, 3 },
+       { aic7xxx_patch11_func, 231, 1, 1 },
+       { aic7xxx_patch0_func, 232, 5, 1 },
+       { aic7xxx_patch11_func, 237, 1, 2 },
+       { aic7xxx_patch0_func, 238, 9, 1 },
+       { aic7xxx_patch13_func, 254, 1, 2 },
+       { aic7xxx_patch0_func, 255, 1, 1 },
+       { aic7xxx_patch4_func, 316, 1, 2 },
+       { aic7xxx_patch0_func, 317, 1, 1 },
+       { aic7xxx_patch2_func, 320, 1, 1 },
+       { aic7xxx_patch1_func, 330, 3, 2 },
+       { aic7xxx_patch0_func, 333, 5, 1 },
+       { aic7xxx_patch13_func, 341, 1, 2 },
+       { aic7xxx_patch0_func, 342, 1, 1 },
+       { aic7xxx_patch5_func, 347, 1, 1 },
+       { aic7xxx_patch11_func, 389, 15, 2 },
+       { aic7xxx_patch14_func, 402, 1, 1 },
+       { aic7xxx_patch1_func, 441, 7, 2 },
+       { aic7xxx_patch0_func, 448, 8, 1 },
+       { aic7xxx_patch1_func, 457, 4, 2 },
+       { aic7xxx_patch0_func, 461, 6, 1 },
+       { aic7xxx_patch1_func, 467, 4, 2 },
+       { aic7xxx_patch0_func, 471, 3, 1 },
+       { aic7xxx_patch10_func, 481, 10, 1 },
+       { aic7xxx_patch1_func, 500, 22, 5 },
+       { aic7xxx_patch11_func, 508, 4, 1 },
+       { aic7xxx_patch7_func, 512, 7, 3 },
+       { aic7xxx_patch15_func, 512, 5, 2 },
+       { aic7xxx_patch0_func, 517, 2, 1 },
+       { aic7xxx_patch10_func, 522, 50, 3 },
+       { aic7xxx_patch14_func, 543, 17, 2 },
+       { aic7xxx_patch0_func, 560, 4, 1 },
+       { aic7xxx_patch10_func, 572, 4, 1 },
+       { aic7xxx_patch5_func, 576, 2, 1 },
+       { aic7xxx_patch5_func, 579, 9, 1 },
 
 };
index 97b140e8486db82bc80aff28bd31bcab115a50a2..9a51418d74429ece5fe21e3a2895cbdb0cc4c4d1 100644 (file)
@@ -87,7 +87,7 @@ volatile unsigned char *scsi_pmaz_dma_ptrs_tc[ESP_NCMD];
 unsigned char scsi_pmaz_dma_buff_used[ESP_NCMD];
 unsigned char scsi_cur_buff = 1;       /* Leave space for command buffer */
 __u32 esp_virt_buffer;
-int scsi_current_length = 0;
+int scsi_current_length;
 
 volatile unsigned char cmd_buffer[16];
 volatile unsigned char pmaz_cmd_buffer[16];
@@ -181,10 +181,13 @@ int dec_esp_detect(Scsi_Host_Template * tpnt)
                esp->esp_command_dvma = (__u32) KSEG1ADDR((volatile unsigned char *) cmd_buffer);
        
                esp->irq = SCSI_INT;
-       request_irq(esp->irq, esp_intr, SA_INTERRUPT, "NCR 53C94 SCSI",
-                   NULL);
-               request_irq(SCSI_DMA_INT, scsi_dma_int, SA_INTERRUPT, "JUNKIO SCSI DMA",
-                           NULL);
+               if (request_irq(esp->irq, esp_intr, SA_INTERRUPT, 
+                               "NCR 53C94 SCSI", NULL))
+                       goto err_dealloc;
+               if (request_irq(SCSI_DMA_INT, scsi_dma_int, SA_INTERRUPT, 
+                               "JUNKIO SCSI DMA", NULL))
+                       goto err_free_irq;
+                       
 
        esp->scsi_id = 7;
                
@@ -257,7 +260,12 @@ int dec_esp_detect(Scsi_Host_Template * tpnt)
                        esp->dma_mmu_release_scsi_sgl = 0;
                        esp->dma_advance_sg = 0;
 
-                       request_irq(esp->irq, esp_intr, SA_INTERRUPT, "PMAZ_AA", NULL);
+                       if (request_irq(esp->irq, esp_intr, SA_INTERRUPT, 
+                                        "PMAZ_AA", NULL)) {
+                               esp_deallocate(esp);
+                               release_tc_card(slot);
+                               continue;
+                       }
                        esp->scsi_id = 7;
                        esp->diff = 0;
                        esp_initialize(esp);
@@ -267,10 +275,16 @@ int dec_esp_detect(Scsi_Host_Template * tpnt)
 
        if(nesps) {
                printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps, esps_in_use);
-       esps_running = esps_in_use;
-       return esps_in_use;
-       } else
-    return 0;
+               esps_running = esps_in_use;
+               return esps_in_use;
+       }
+       return 0;
+
+ err_free_irq:
+       free_irq(esp->irq, esp_intr);
+ err_dealloc:
+       esp_deallocate(esp);
+       return 0;
 }
 
 /************************************************************* DMA Functions */
@@ -524,4 +538,4 @@ static void pmaz_dma_mmu_get_scsi_one(struct NCR_ESP *esp, Scsi_Cmnd * sp)
            (char *) KSEG0ADDR((sp->request_buffer));
 }
 
-#endif
\ No newline at end of file
+#endif
index 95608d19645d29103b4a6facff37894bf73f325b..e37a7eb37f365e93a6694cbf4c30953384bdb02f 100644 (file)
@@ -237,6 +237,7 @@ struct Scsi_Host * scsi_register(Scsi_Host_Template * tpnt, int j){
     retval->use_clustering = tpnt->use_clustering;   
 
     retval->select_queue_depths = tpnt->select_queue_depths;
+    retval->max_sectors = tpnt->max_sectors;
 
     if(!scsi_hostlist)
        scsi_hostlist = retval;
index b0f8412cac2735bee892e9098a1fe0d66a8a3b39..e9e6e70a1b6febe18a5f8a2f95ab5dbc6f81f2bd 100644 (file)
@@ -242,6 +242,11 @@ typedef struct     SHT
      */
     short unsigned int sg_tablesize;
 
+    /*
+     * if the host adapter has limitations beside segment count
+     */
+    short unsigned int max_sectors;
+
     /*
      * True if this host adapter can make good use of linked commands.
      * This will allow more than one command to be queued to a given
@@ -380,6 +385,7 @@ struct Scsi_Host
     int can_queue;
     short cmd_per_lun;
     short unsigned int sg_tablesize;
+    short unsigned int max_sectors;
 
     unsigned in_recovery:1;
     unsigned unchecked_isa_dma:1;
@@ -523,7 +529,7 @@ int scsi_register_device(struct Scsi_Device_Template * sdpnt);
 
 /* These are used by loadable modules */
 extern int scsi_register_module(int, void *);
-extern void scsi_unregister_module(int, void *);
+extern int scsi_unregister_module(int, void *);
 
 /* The different types of modules that we can load and unload */
 #define MODULE_SCSI_HA 1
index 4df173a780b784916661ee40e80e03146ef85f7a..4b47827a258ce5f88e6c8cd15fb10301e5c44688 100644 (file)
 /*
 **     Name and version of the driver
 */
-#define SCSI_NCR_DRIVER_NAME   "ncr53c8xx-3.4.3-20010212"
+#define SCSI_NCR_DRIVER_NAME   "ncr53c8xx-3.4.3b-20010512"
 
 #define SCSI_NCR_DEBUG_FLAGS   (0)
 
@@ -3082,7 +3082,7 @@ struct host_data {
 };
 
 /*
-**     Print something which allows to retrieve the controler type, unit,
+**     Print something which allows to retrieve the controller type, unit,
 **     target, lun concerned by a kernel message.
 */
 
@@ -4302,7 +4302,7 @@ static int ncr_queue_command (ncb_p np, Scsi_Cmnd *cmd)
        **
        **----------------------------------------------------
        */
-#if 0  /* This stuff was only usefull for linux-1.2.13 */
+#if 0  /* This stuff was only useful for linux-1.2.13 */
        if (lp && !lp->numtags && cmd->device && cmd->device->tagged_queue) {
                lp->numtags = tp->usrtags;
                ncr_setup_tags (np, cmd->target, cmd->lun);
@@ -5701,7 +5701,7 @@ static void ncr_getsync(ncb_p np, u_char sfac, u_char *fakp, u_char *scntl3p)
        */
        fak = (kpc - 1) / div_10M[div] + 1;
 
-#if 0  /* This optimization does not seem very usefull */
+#if 0  /* This optimization does not seem very useful */
 
        per = (fak * div_10M[div]) / clk;
 
@@ -6647,7 +6647,7 @@ static void ncr_int_ma (ncb_p np)
                        delta=(INB (nc_dfifo) - rest) & 0x7f;
 
                /*
-               **      The data in the dma fifo has not been transfered to
+               **      The data in the dma fifo has not been transferred to
                **      the target -> add the amount to the rest
                **      and clear the data.
                **      Check the sstat2 register in case of wide transfer.
@@ -7153,7 +7153,7 @@ void ncr_int_sir (ncb_p np)
 **     Was Sie schon immer ueber transfermode negotiation wissen wollten ...
 **
 **     We try to negotiate sync and wide transfer only after
-**     a successfull inquire command. We look at byte 7 of the
+**     a successful inquire command. We look at byte 7 of the
 **     inquire data to determine the capabilities of the target.
 **
 **     When we try to negotiate, we append the negotiation message
@@ -7550,7 +7550,7 @@ out:
 /*==========================================================
 **
 **
-**     Aquire a control block
+**     Acquire a control block
 **
 **
 **==========================================================
index 1f81f1b448286987997a4edc80bf097cd589f225..e9fdcdf9dc642b0f75ba0a2cf2d8b9064e77c6f2 100644 (file)
@@ -704,6 +704,7 @@ int isp1020_detect(Scsi_Host_Template *tmpt)
                }
 
                host->this_id = hostdata->host_param.initiator_scsi_id;
+               host->max_sectors = 64;
 
                if (request_irq(host->irq, do_isp1020_intr_handler, SA_INTERRUPT | SA_SHIRQ,
                                "qlogicisp", host))
index 4773ba1389549fcd39a5f0fd0fa68b43b665d872..44c3edd0c921cb72efdd70e5bf736a17a0dea667 100644 (file)
@@ -737,6 +737,7 @@ static void __init qpti_get_scsi_id(struct qlogicpti *qpti)
                        prom_getintdefault(qpti->sdev->bus->prom_node,
                                           "scsi-initiator-id", 7);
        qpti->qhost->this_id = qpti->scsi_id;
+       qpti->qhost->max_sectors = 64;
 
        printk("SCSI ID %d ", qpti->scsi_id);
 }
index dd249b9bf95ac2232092ba7b5be4486a3fc02461..94cd238a99ae2490d1120d743daf8bcb502141d3 100644 (file)
@@ -53,6 +53,7 @@
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/smp_lock.h>
 
 #define __KERNEL_SYSCALLS__
 
@@ -1098,7 +1099,7 @@ void scsi_done(Scsi_Cmnd * SCpnt)
         * the response.  We treat it as if the command never finished.
         *
         * Since serial_number is now 0, the error handler cound detect this
-        * situation and avoid to call the the low level driver abort routine.
+        * situation and avoid to call the low level driver abort routine.
         * (DB)
          *
          * FIXME(eric) - I believe that this test is now redundant, due to
@@ -1373,7 +1374,7 @@ void scsi_finish_command(Scsi_Cmnd * SCpnt)
 }
 
 static int scsi_register_host(Scsi_Host_Template *);
-static void scsi_unregister_host(Scsi_Host_Template *);
+static int scsi_unregister_host(Scsi_Host_Template *);
 
 /*
  * Function:    scsi_release_commandblocks()
@@ -1569,12 +1570,17 @@ static int proc_scsi_gen_write(struct file * file, const char * buf,
 
        if (!(buffer = (char *) __get_free_page(GFP_KERNEL)))
                return -ENOMEM;
-       copy_from_user(buffer, buf, length);
+       if(copy_from_user(buffer, buf, length))
+       {
+               err =-EFAULT;
+               goto out;
+       }
 
        err = -EINVAL;
+
        if (length < PAGE_SIZE)
-               buffer[length] ='\0';
-       else if (buffer[length])
+               buffer[length] = '\0';
+       else if (buffer[PAGE_SIZE-1])
                goto out;
 
        if (length < 11 || strncmp("scsi", buffer, 4))
@@ -1821,6 +1827,11 @@ static int scsi_register_host(Scsi_Host_Template * tpnt)
                return 1;       /* Must be already loaded, or
                                 * no detect routine available
                                 */
+
+       /* If max_sectors isn't set, default to max */
+       if (!tpnt->max_sectors)
+               tpnt->max_sectors = MAX_SECTORS;
+
        pcount = next_scsi_host;
 
        /* The detect routine must carefully spinunlock/spinlock if 
@@ -1965,14 +1976,8 @@ static int scsi_register_host(Scsi_Host_Template * tpnt)
 /*
  * Similarly, this entry point should be called by a loadable module if it
  * is trying to remove a low level scsi driver from the system.
- *
- * Note - there is a fatal flaw in the deregister module function.
- * There is no way to return a code that says 'I cannot be unloaded now'.
- * The system relies entirely upon usage counts that are maintained,
- * and the assumption is that if the usage count is 0, then the module
- * can be unloaded.
  */
-static void scsi_unregister_host(Scsi_Host_Template * tpnt)
+static int scsi_unregister_host(Scsi_Host_Template * tpnt)
 {
        int online_status;
        int pcount0, pcount;
@@ -1984,6 +1989,9 @@ static void scsi_unregister_host(Scsi_Host_Template * tpnt)
        struct Scsi_Host *shpnt;
        char name[10];  /* host_no>=10^9? I don't think so. */
 
+       /* get the big kernel lock, so we don't race with open() */
+       lock_kernel();
+
        /*
         * First verify that this host adapter is completely free with no pending
         * commands 
@@ -1994,7 +2002,7 @@ static void scsi_unregister_host(Scsi_Host_Template * tpnt)
                        if (SDpnt->host->hostt == tpnt
                            && SDpnt->host->hostt->module
                            && GET_USE_COUNT(SDpnt->host->hostt->module))
-                               return;
+                               goto err_out;
                        /* 
                         * FIXME(eric) - We need to find a way to notify the
                         * low level driver that we are shutting down - via the
@@ -2046,7 +2054,7 @@ static void scsi_unregister_host(Scsi_Host_Template * tpnt)
                                        }
                                        SDpnt->online = online_status;
                                        printk(KERN_ERR "Device busy???\n");
-                                       return;
+                                       goto err_out;
                                }
                                /*
                                 * No, this device is really free.  Mark it as such, and
@@ -2072,7 +2080,7 @@ static void scsi_unregister_host(Scsi_Host_Template * tpnt)
                        /* If something still attached, punt */
                        if (SDpnt->attached) {
                                printk(KERN_ERR "Attached usage count = %d\n", SDpnt->attached);
-                               return;
+                               goto err_out;
                        }
                        devfs_unregister (SDpnt->de);
                }
@@ -2180,6 +2188,13 @@ static void scsi_unregister_host(Scsi_Host_Template * tpnt)
                }
        }
        MOD_DEC_USE_COUNT;
+
+       unlock_kernel();
+       return 0;
+
+err_out:
+       unlock_kernel();
+       return -1;
 }
 
 static int scsi_unregister_device(struct Scsi_Device_Template *tpnt);
@@ -2261,12 +2276,13 @@ static int scsi_unregister_device(struct Scsi_Device_Template *tpnt)
        struct Scsi_Host *shpnt;
        struct Scsi_Device_Template *spnt;
        struct Scsi_Device_Template *prev_spnt;
-
+       
+       lock_kernel();
        /*
         * If we are busy, this is not going to fly.
         */
        if (GET_USE_COUNT(tpnt->module) != 0)
-               return 0;
+               goto error_out;
 
        /*
         * Next, detach the devices from the driver.
@@ -2303,11 +2319,15 @@ static int scsi_unregister_device(struct Scsi_Device_Template *tpnt)
                prev_spnt->next = spnt->next;
 
        MOD_DEC_USE_COUNT;
+       unlock_kernel();
        /*
         * Final cleanup for the driver is done in the driver sources in the
         * cleanup function.
         */
        return 0;
+error_out:
+       unlock_kernel();
+       return -1;
 }
 
 
@@ -2344,22 +2364,24 @@ int scsi_register_module(int module_type, void *ptr)
 
 /* Reverse the actions taken above
  */
-void scsi_unregister_module(int module_type, void *ptr)
+int scsi_unregister_module(int module_type, void *ptr)
 {
+       int retval = 0;
+
        switch (module_type) {
        case MODULE_SCSI_HA:
-               scsi_unregister_host((Scsi_Host_Template *) ptr);
+               retval = scsi_unregister_host((Scsi_Host_Template *) ptr);
                break;
        case MODULE_SCSI_DEV:
-               scsi_unregister_device((struct Scsi_Device_Template *) ptr);
-               break;
+               retval = scsi_unregister_device((struct Scsi_Device_Template *)ptr);
+               break;
                /* The rest of these are not yet implemented. */
        case MODULE_SCSI_CONST:
        case MODULE_SCSI_IOCTL:
-       default:
                break;
+       default:;
        }
-       return;
+       return retval;
 }
 
 #ifdef CONFIG_PROC_FS
index ef8bd908ec346d5f48d284fcfc3f1a682fb8b021..0c7940953691ab9ace088389272a4e3e46cbde9d 100644 (file)
@@ -617,6 +617,9 @@ struct scsi_device {
        unsigned remap:1;       /* support remapping  */
        unsigned starved:1;     /* unable to process commands because
                                   host busy */
+
+       // Flag to allow revalidate to succeed in sd_open
+       int allow_revalidate;
 };
 
 
@@ -668,7 +671,7 @@ struct scsi_request {
        unsigned short sr_use_sg;       /* Number of pieces of scatter-gather */
        unsigned short sr_sglist_len;   /* size of malloc'd scatter-gather list */
        unsigned sr_underflow;  /* Return error if less than
-                                  this amount is transfered */
+                                  this amount is transferred */
 };
 
 /*
@@ -756,7 +759,7 @@ struct scsi_cmnd {
        void *buffer;           /* Data buffer */
 
        unsigned underflow;     /* Return error if less than
-                                  this amount is transfered */
+                                  this amount is transferred */
        unsigned old_underflow; /* save underflow here when reusing the
                                 * command for error handling */
 
index 7bc628ab73232005b0b05a3c7585697b112a0853..0d9343e7fd6033af30b4da76eb20551d7a8ac956 100644 (file)
@@ -427,7 +427,8 @@ STATIC int scsi_request_sense(Scsi_Cmnd * SCpnt)
        memcpy((void *) SCpnt->cmnd, (void *) generic_sense,
               sizeof(generic_sense));
 
-       SCpnt->cmnd[1] = SCpnt->lun << 5;
+       if (SCpnt->device->scsi_level <= SCSI_2)
+               SCpnt->cmnd[1] = SCpnt->lun << 5;
 
        scsi_result = (!SCpnt->host->hostt->unchecked_isa_dma)
            ? &scsi_result0[0] : kmalloc(512, GFP_ATOMIC | GFP_DMA);
@@ -496,7 +497,8 @@ STATIC int scsi_test_unit_ready(Scsi_Cmnd * SCpnt)
        memcpy((void *) SCpnt->cmnd, (void *) tur_command,
               sizeof(tur_command));
 
-       SCpnt->cmnd[1] = SCpnt->lun << 5;
+       if (SCpnt->device->scsi_level <= SCSI_2)
+               SCpnt->cmnd[1] = SCpnt->lun << 5;
 
        /*
         * Zero the sense buffer.  The SCSI spec mandates that any
@@ -1177,6 +1179,14 @@ STATIC int scsi_check_sense(Scsi_Cmnd * SCpnt)
                        SCpnt->device->expecting_cc_ua = 0;
                        return NEEDS_RETRY;
                }
+               /*
+                * If the device is in the process of becoming ready, we 
+                * should retry.
+                */
+               if ((SCpnt->sense_buffer[12] == 0x04) &&
+                       (SCpnt->sense_buffer[13] == 0x01)) {
+                       return NEEDS_RETRY;
+               }
                return SUCCESS;
 
                /* these three are not supported */
index 83bd597f8b8907933f1e0b58bf6fb3e6d366f7de..e3af0dbcfc29c87c5338501dd0f963294e2f5da1 100644 (file)
@@ -79,7 +79,7 @@ static int ioctl_probe(struct Scsi_Host *host, void *buffer)
  * 
  * *(char *) ((int *) arg)[2] the actual command byte.   
  * 
- * Note that if more than MAX_BUF bytes are requested to be transfered,
+ * Note that if more than MAX_BUF bytes are requested to be transferred,
  * the ioctl will fail with error EINVAL.  MAX_BUF can be increased in
  * the future by increasing the size that scsi_malloc will accept.
  * 
@@ -196,8 +196,8 @@ int scsi_ioctl_send_command(Scsi_Device * dev, Scsi_Ioctl_Command * sic)
        Scsi_Request *SRpnt;
        Scsi_Device *SDpnt;
        unsigned char opcode;
-       int inlen, outlen, cmdlen;
-       int needed, buf_needed;
+       unsigned int inlen, outlen, cmdlen;
+       unsigned int needed, buf_needed;
        int timeout, retries, result;
        int data_direction;
 
@@ -209,8 +209,11 @@ int scsi_ioctl_send_command(Scsi_Device * dev, Scsi_Ioctl_Command * sic)
        if (verify_area(VERIFY_READ, sic, sizeof(Scsi_Ioctl_Command)))
                return -EFAULT;
 
-       __get_user(inlen, &sic->inlen);
-       __get_user(outlen, &sic->outlen);
+       if(__get_user(inlen, &sic->inlen))
+               return -EFAULT;
+               
+       if(__get_user(outlen, &sic->outlen))
+               return -EFAULT;
 
        /*
         * We do not transfer more than MAX_BUF with this interface.
@@ -223,7 +226,8 @@ int scsi_ioctl_send_command(Scsi_Device * dev, Scsi_Ioctl_Command * sic)
                return -EINVAL;
 
        cmd_in = sic->data;
-       __get_user(opcode, cmd_in);
+       if(get_user(opcode, cmd_in))
+               return -EFAULT;
 
        needed = buf_needed = (inlen > outlen ? inlen : outlen);
        if (buf_needed) {
@@ -254,21 +258,27 @@ int scsi_ioctl_send_command(Scsi_Device * dev, Scsi_Ioctl_Command * sic)
         * Obtain the command from the user's address space.
         */
        cmdlen = COMMAND_SIZE(opcode);
+       
+       result = -EFAULT;
 
        if (verify_area(VERIFY_READ, cmd_in, cmdlen + inlen))
-               return -EFAULT;
+               goto error;
 
-       __copy_from_user(cmd, cmd_in, cmdlen);
+       if(__copy_from_user(cmd, cmd_in, cmdlen))
+               goto error;
 
        /*
         * Obtain the data to be sent to the device (if any).
         */
-       __copy_from_user(buf, cmd_in + cmdlen, inlen);
+
+       if(copy_from_user(buf, cmd_in + cmdlen, inlen))
+               goto error;
 
        /*
         * Set the lun field to the correct value.
         */
-       cmd[1] = (cmd[1] & 0x1f) | (dev->lun << 5);
+       if (dev->scsi_level <= SCSI_2)
+               cmd[1] = (cmd[1] & 0x1f) | (dev->lun << 5);
 
        switch (opcode) {
        case FORMAT_UNIT:
@@ -303,7 +313,8 @@ int scsi_ioctl_send_command(Scsi_Device * dev, Scsi_Ioctl_Command * sic)
        SRpnt = scsi_allocate_request(dev);
         if( SRpnt == NULL )
         {
-                return -EINTR;
+                result = -EINTR;
+                goto error;
         }
 
        SRpnt->sr_data_direction = data_direction;
@@ -312,7 +323,9 @@ int scsi_ioctl_send_command(Scsi_Device * dev, Scsi_Ioctl_Command * sic)
        /* 
         * If there was an error condition, pass the info back to the user. 
         */
+
        result = SRpnt->sr_result;
+
        if (SRpnt->sr_result) {
                int sb_len = sizeof(SRpnt->sr_sense_buffer);
 
@@ -322,12 +335,13 @@ int scsi_ioctl_send_command(Scsi_Device * dev, Scsi_Ioctl_Command * sic)
        } else {
                if (copy_to_user(cmd_in, buf, outlen))
                        result = -EFAULT;
-       }
+       }       
 
        SDpnt = SRpnt->sr_device;
        scsi_release_request(SRpnt);
        SRpnt = NULL;
 
+error:
        if (buf)
                scsi_free(buf, buf_needed);
 
@@ -379,6 +393,7 @@ scsi_ioctl_get_pci(Scsi_Device * dev, void *arg)
 int scsi_ioctl(Scsi_Device * dev, int cmd, void *arg)
 {
        char scsi_cmd[MAX_COMMAND_SIZE];
+       char cmd_byte1;
 
        /* No idea how this happens.... */
        if (!dev)
@@ -393,14 +408,16 @@ int scsi_ioctl(Scsi_Device * dev, int cmd, void *arg)
        if (!scsi_block_when_processing_errors(dev)) {
                return -ENODEV;
        }
+       cmd_byte1 = (dev->scsi_level <= SCSI_2) ? (dev->lun << 5) : 0;
+
        switch (cmd) {
        case SCSI_IOCTL_GET_IDLUN:
                if (verify_area(VERIFY_WRITE, arg, sizeof(Scsi_Idlun)))
                        return -EFAULT;
 
-               __put_user(dev->id
-                        + (dev->lun << 8)
-                        + (dev->channel << 16)
+               __put_user((dev->id & 0xff)
+                        + ((dev->lun & 0xff) << 8)
+                        + ((dev->channel & 0xff) << 16)
                         + ((dev->host->host_no & 0xff) << 24),
                         &((Scsi_Idlun *) arg)->dev_id);
                __put_user(dev->host->unique_id, &((Scsi_Idlun *) arg)->host_unique_id);
@@ -434,7 +451,7 @@ int scsi_ioctl(Scsi_Device * dev, int cmd, void *arg)
                if (!dev->removable || !dev->lockable)
                        return 0;
                scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL;
-               scsi_cmd[1] = dev->lun << 5;
+               scsi_cmd[1] = cmd_byte1;
                scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
                scsi_cmd[4] = SCSI_REMOVAL_PREVENT;
                return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd,
@@ -444,14 +461,14 @@ int scsi_ioctl(Scsi_Device * dev, int cmd, void *arg)
                if (!dev->removable || !dev->lockable)
                        return 0;
                scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL;
-               scsi_cmd[1] = dev->lun << 5;
+               scsi_cmd[1] = cmd_byte1;
                scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
                scsi_cmd[4] = SCSI_REMOVAL_ALLOW;
                return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd,
                                   IOCTL_NORMAL_TIMEOUT, NORMAL_RETRIES);
        case SCSI_IOCTL_TEST_UNIT_READY:
                scsi_cmd[0] = TEST_UNIT_READY;
-               scsi_cmd[1] = dev->lun << 5;
+               scsi_cmd[1] = cmd_byte1;
                scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
                scsi_cmd[4] = 0;
                return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd,
@@ -459,7 +476,7 @@ int scsi_ioctl(Scsi_Device * dev, int cmd, void *arg)
                break;
        case SCSI_IOCTL_START_UNIT:
                scsi_cmd[0] = START_STOP;
-               scsi_cmd[1] = dev->lun << 5;
+               scsi_cmd[1] = cmd_byte1;
                scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
                scsi_cmd[4] = 1;
                return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd,
@@ -467,7 +484,7 @@ int scsi_ioctl(Scsi_Device * dev, int cmd, void *arg)
                break;
        case SCSI_IOCTL_STOP_UNIT:
                scsi_cmd[0] = START_STOP;
-               scsi_cmd[1] = dev->lun << 5;
+               scsi_cmd[1] = cmd_byte1;
                scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
                scsi_cmd[4] = 0;
                return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd,
index 33c369210480962fdf43d979e7db3c0e3f6ea671..b05a380711a68e7dea40f7dba89381b51ccc6a10 100644 (file)
@@ -377,12 +377,15 @@ static Scsi_Cmnd *__scsi_end_request(Scsi_Cmnd * SCpnt,
                        nsect = bh->b_size >> 9;
                        blk_finished_io(nsect);
                        req->bh = bh->b_reqnext;
-                       req->nr_sectors -= nsect;
-                       req->sector += nsect;
                        bh->b_reqnext = NULL;
                        sectors -= nsect;
                        bh->b_end_io(bh, uptodate);
                        if ((bh = req->bh) != NULL) {
+                               req->hard_sector += nsect;
+                               req->hard_nr_sectors -= nsect;
+                               req->sector += nsect;
+                               req->nr_sectors -= nsect;
+
                                req->current_nr_sectors = bh->b_size >> 9;
                                if (req->nr_sectors < req->current_nr_sectors) {
                                        req->nr_sectors = req->current_nr_sectors;
index e7673c0803a2da88f676c83771d7246ef7ea4d79..40b9df4f31506faffb0b5ecaa077762d2788ec51 100644 (file)
@@ -417,6 +417,9 @@ __inline static int __scsi_back_merge_fn(request_queue_t * q,
                max_segments = 64;
 #endif
 
+       if ((req->nr_sectors + (bh->b_size >> 9)) > SHpnt->max_sectors)
+               return 0;
+
        if (use_clustering) {
                /* 
                 * See if we can do this without creating another
@@ -473,6 +476,9 @@ __inline static int __scsi_front_merge_fn(request_queue_t * q,
                max_segments = 64;
 #endif
 
+       if ((req->nr_sectors + (bh->b_size >> 9)) > SHpnt->max_sectors)
+               return 0;
+
        if (use_clustering) {
                /* 
                 * See if we can do this without creating another
@@ -597,6 +603,13 @@ __inline static int __scsi_merge_requests_fn(request_queue_t * q,
        Scsi_Device *SDpnt;
        struct Scsi_Host *SHpnt;
 
+       /*
+        * First check if the either of the requests are re-queued
+        * requests.  Can't merge them if they are.
+        */
+       if (req->special || next->special)
+               return 0;
+
        SDpnt = (Scsi_Device *) q->queuedata;
        SHpnt = SDpnt->host;
 
@@ -624,6 +637,10 @@ __inline static int __scsi_merge_requests_fn(request_queue_t * q,
                return 0;
        }
 #endif
+
+       if ((req->nr_sectors + next->nr_sectors) > SHpnt->max_sectors)
+               return 0;
+
        /*
         * The main question is whether the two segments at the boundaries
         * would be considered one or two.
index 3b3990dfb0ef17bdf3fd639fd4d747744f0f90da..632548bc523620db8daf6af95597e9d49ccb8fd9 100644 (file)
@@ -223,7 +223,8 @@ static void scsi_request_sense(Scsi_Cmnd * SCpnt)
        memset((void *) SCpnt->sense_buffer, 0,
               sizeof(SCpnt->sense_buffer));
 
-       SCpnt->cmnd[1] = SCpnt->lun << 5;
+       if (SCpnt->device->scsi_level <= SCSI_2)
+               SCpnt->cmnd[1] = SCpnt->lun << 5;
        SCpnt->cmnd[4] = sizeof(SCpnt->sense_buffer);
 
        SCpnt->request_buffer = &SCpnt->sense_buffer;
index 25ba5a5cdd64ed4a10b4f2c136388e4d5abb9153..5cb0ab74414358d58310627a6fa5ab8e5d8dd1c1 100644 (file)
 #define BLIST_ISROM            0x200
 
 static void print_inquiry(unsigned char *data);
-static int scan_scsis_single(int channel, int dev, int lun, int *max_scsi_dev,
-               int *sparse_lun, Scsi_Device ** SDpnt,
-                            struct Scsi_Host *shpnt, char *scsi_result);
+static int scan_scsis_single(unsigned int channel, unsigned int dev,
+               unsigned int lun, int lun0_scsi_level, 
+               unsigned int *max_scsi_dev, unsigned int *sparse_lun, 
+               Scsi_Device ** SDpnt, struct Scsi_Host *shpnt, 
+               char *scsi_result);
+static int find_lun0_scsi_level(unsigned int channel, unsigned int dev,
+                               struct Scsi_Host *shpnt);
 
 struct dev_info {
        const char *vendor;
@@ -135,6 +139,7 @@ static struct dev_info device_list[] =
        {"nCipher", "Fastness Crypto", "*", BLIST_FORCELUN},
        {"DEC","HSG80","*", BLIST_FORCELUN},
        {"COMPAQ","LOGICAL VOLUME","*", BLIST_FORCELUN},
+       {"COMPAQ","CR3500","*", BLIST_FORCELUN},
        {"NEC", "PD-1 ODX654P", "*", BLIST_FORCELUN | BLIST_SINGLELUN},
        {"MATSHITA", "PD-1", "*", BLIST_FORCELUN | BLIST_SINGLELUN},
        {"iomega", "jaz 1GB", "J.86", BLIST_NOTQ | BLIST_NOLUN},
@@ -143,7 +148,11 @@ static struct dev_info device_list[] =
        {"MegaRAID", "LD", "*", BLIST_FORCELUN},
        {"DGC",  "RAID",      "*", BLIST_SPARSELUN}, // Dell PV 650F (tgt @ LUN 0)
        {"DGC",  "DISK",      "*", BLIST_SPARSELUN}, // Dell PV 650F (no tgt @ LUN 0) 
+       {"DELL", "PV660F",   "*", BLIST_SPARSELUN},
+       {"DELL", "PV660F   PSEUDO",   "*", BLIST_SPARSELUN},
+       {"DELL", "PSEUDO DEVICE .",   "*", BLIST_SPARSELUN}, // Dell PV 530F
        {"DELL", "PV530F",    "*", BLIST_SPARSELUN}, // Dell PV 530F
+       {"EMC", "SYMMETRIX", "*", BLIST_SPARSELUN},
        {"SONY", "TSL",       "*", BLIST_FORCELUN},  // DDS3 & DDS4 autoloaders
        {"DELL", "PERCRAID", "*", BLIST_FORCELUN},
        {"HP", "NetRAID-4M", "*", BLIST_FORCELUN},
@@ -154,29 +163,31 @@ static struct dev_info device_list[] =
        {NULL, NULL, NULL}
 };
 
+#define MAX_SCSI_LUNS 0xFFFFFFFF
+
 #ifdef CONFIG_SCSI_MULTI_LUN
-static int max_scsi_luns = 8;
+static unsigned int max_scsi_luns = MAX_SCSI_LUNS;
 #else
-static int max_scsi_luns = 1;
+static unsigned int max_scsi_luns = 1;
 #endif
 
 #ifdef MODULE
 
 MODULE_PARM(max_scsi_luns, "i");
-MODULE_PARM_DESC(max_scsi_luns, "last scsi LUN (should be between 1 and 8)");
+MODULE_PARM_DESC(max_scsi_luns, "last scsi LUN (should be between 1 and 2^32-1)");
 
 #else
 
 static int __init scsi_luns_setup(char *str)
 {
-       int tmp;
+       unsigned int tmp;
 
        if (get_option(&str, &tmp) == 1) {
                max_scsi_luns = tmp;
                return 1;
        } else {
                printk("scsi_luns_setup : usage max_scsi_luns=n "
-                      "(n should be between 1 and 8)\n");
+                      "(n should be between 1 and 2^32-1)\n");
                return 0;
        }
 }
@@ -264,14 +275,15 @@ void scan_scsis(struct Scsi_Host *shpnt,
                       uint hlun)
 {
        uint channel;
-       int dev;
-       int lun;
-       int max_dev_lun;
+       unsigned int dev;
+       unsigned int lun;
+       unsigned int max_dev_lun;
        unsigned char *scsi_result;
        unsigned char scsi_result0[256];
        Scsi_Device *SDpnt;
        Scsi_Device *SDtail;
-       int sparse_lun;
+       unsigned int sparse_lun;
+       int lun0_sl;
 
        scsi_result = NULL;
 
@@ -343,8 +355,12 @@ void scan_scsis(struct Scsi_Host *shpnt,
                lun = hlun;
                if (lun >= shpnt->max_lun)
                        goto leave;
-               scan_scsis_single(channel, dev, lun, &max_dev_lun, &sparse_lun,
-                                 &SDpnt, shpnt, scsi_result);
+               if ((0 == lun) || (lun > 7))
+                       lun0_sl = SCSI_3; /* actually don't care for 0 == lun */
+               else
+                       lun0_sl = find_lun0_scsi_level(channel, dev, shpnt);
+               scan_scsis_single(channel, dev, lun, lun0_sl, &max_dev_lun, 
+                                 &sparse_lun, &SDpnt, shpnt, scsi_result);
                if (SDpnt != oldSDpnt) {
 
                        /* it could happen the blockdevice hasn't yet been inited */
@@ -400,12 +416,14 @@ void scan_scsis(struct Scsi_Host *shpnt,
                                        max_dev_lun = (max_scsi_luns < shpnt->max_lun ?
                                         max_scsi_luns : shpnt->max_lun);
                                        sparse_lun = 0;
-                                       for (lun = 0; lun < max_dev_lun; ++lun) {
-                                               if (!scan_scsis_single(channel, order_dev, lun, &max_dev_lun,
-                                                                      &sparse_lun, &SDpnt, shpnt,
-                                                            scsi_result)
+                                       for (lun = 0, lun0_sl = SCSI_2; lun < max_dev_lun; ++lun) {
+                                               if (!scan_scsis_single(channel, order_dev, lun, lun0_sl,
+                                                                      &max_dev_lun, &sparse_lun, &SDpnt, shpnt,
+                                                                      scsi_result)
                                                    && !sparse_lun)
                                                        break;  /* break means don't probe further for luns!=0 */
+                                               if (SDpnt && (0 == lun))
+                                                       lun0_sl = SDpnt->scsi_level;
                                        }       /* for lun ends */
                                }       /* if this_id != id ends */
                        }       /* for dev ends */
@@ -461,9 +479,11 @@ void scan_scsis(struct Scsi_Host *shpnt,
  * Returning 0 means Please don't ask further for lun!=0, 1 means OK go on.
  * Global variables used : scsi_devices(linked list)
  */
-static int scan_scsis_single(int channel, int dev, int lun, int *max_dev_lun,
-              int *sparse_lun, Scsi_Device ** SDpnt2, 
-                     struct Scsi_Host *shpnt, char *scsi_result)
+static int scan_scsis_single(unsigned int channel, unsigned int dev,
+               unsigned int lun, int lun0_scsi_level,
+               unsigned int *max_dev_lun, unsigned int *sparse_lun, 
+               Scsi_Device ** SDpnt2, struct Scsi_Host *shpnt, 
+               char *scsi_result)
 {
        char devname[64];
        unsigned char scsi_cmd[MAX_COMMAND_SIZE];
@@ -509,7 +529,10 @@ static int scan_scsis_single(int channel, int dev, int lun, int *max_dev_lun,
         * Build an INQUIRY command block.
         */
        scsi_cmd[0] = INQUIRY;
-       scsi_cmd[1] = (lun << 5) & 0xe0;
+       if ((lun > 0) && (lun0_scsi_level <= SCSI_2))
+               scsi_cmd[1] = (lun << 5) & 0xe0;
+       else    
+               scsi_cmd[1] = 0;        /* SCSI_3 and higher, don't touch */
        scsi_cmd[2] = 0;
        scsi_cmd[3] = 0;
        scsi_cmd[4] = 255;
@@ -677,7 +700,9 @@ static int scan_scsis_single(int channel, int dev, int lun, int *max_dev_lun,
                printk("Unlocked floptical drive.\n");
                SDpnt->lockable = 0;
                scsi_cmd[0] = MODE_SENSE;
-               scsi_cmd[1] = (lun << 5) & 0xe0;
+               if (shpnt->max_lun <= 8)
+                       scsi_cmd[1] = (lun << 5) & 0xe0;
+               else    scsi_cmd[1] = 0;        /* any other idea? */
                scsi_cmd[2] = 0x2e;
                scsi_cmd[3] = 0;
                scsi_cmd[4] = 0x2a;
@@ -760,7 +785,19 @@ static int scan_scsis_single(int channel, int dev, int lun, int *max_dev_lun,
         * other settings, and scan all of them.
         */
        if (bflags & BLIST_SPARSELUN) {
-               *max_dev_lun = 8;
+               /*
+                * Scanning MAX_SCSI_LUNS units would be a bad idea.
+                * Any better idea?
+                * I think we need REPORT LUNS in future to avoid scanning
+                * of unused LUNs. But, that is another item.
+                *
+                * FIXME(eric) - perhaps this should be a kernel configurable?
+                */
+               if (*max_dev_lun < shpnt->max_lun)
+                       *max_dev_lun = shpnt->max_lun;
+               else    if ((max_scsi_luns >> 1) >= *max_dev_lun)
+                               *max_dev_lun += shpnt->max_lun;
+                       else    *max_dev_lun = max_scsi_luns;
                *sparse_lun = 1;
                return 1;
        }
@@ -769,7 +806,17 @@ static int scan_scsis_single(int channel, int dev, int lun, int *max_dev_lun,
         * settings, and scan all of them.
         */
        if (bflags & BLIST_FORCELUN) {
-               *max_dev_lun = 8;
+               /* 
+                * Scanning MAX_SCSI_LUNS units would be a bad idea.
+                * Any better idea?
+                * I think we need REPORT LUNS in future to avoid scanning
+                * of unused LUNs. But, that is another item.
+                */
+               if (*max_dev_lun < shpnt->max_lun)
+                       *max_dev_lun = shpnt->max_lun;
+               else    if ((max_scsi_luns >> 1) >= *max_dev_lun)
+                               *max_dev_lun += shpnt->max_lun;
+                       else    *max_dev_lun = max_scsi_luns;
                return 1;
        }
        /*
@@ -793,3 +840,23 @@ static int scan_scsis_single(int channel, int dev, int lun, int *max_dev_lun,
        return 1;
 }
 
+/*
+ * The worker for scan_scsis.
+ * Returns the scsi_level of lun0 on this host, channel and dev (if already
+ * known), otherwise returns SCSI_2.
+ */
+static int find_lun0_scsi_level(unsigned int channel, unsigned int dev,
+                               struct Scsi_Host *shpnt)
+{
+       int res = SCSI_2;
+       Scsi_Device *SDpnt;
+
+       for (SDpnt = shpnt->host_queue; SDpnt; SDpnt = SDpnt->next)
+       {
+               if ((0 == SDpnt->lun) && (dev == SDpnt->id) &&
+                   (channel == SDpnt->channel))
+                       return (int)SDpnt->scsi_level;
+       }
+       /* haven't found lun0, should send INQUIRY but take easy route */
+       return res;
+}
index 9b2c22e3b42ea23039acd42957e3c45c5a7a12eb..749f6f445c4aec87ed0148da6ac93b8e1be14fb1 100644 (file)
  *     
  *      Modified by Torben Mathiasen tmm@image.dk
  *       Resource allocation fixes in sd_init and cleanups.
+ *     
+ *      Modified by Alex Davis <letmein@erols.com>
+ *       Fix problem where partition info not being read in sd_open.
+ *     
+ *      Modified by Alex Davis <letmein@erols.com>
+ *       Fix problem where removable media could be ejected after sd_open.
  */
 
 #include <linux/config.h>
@@ -372,7 +378,8 @@ static int sd_init_command(Scsi_Cmnd * SCpnt)
                   (SCpnt->request.cmd == WRITE) ? "writing" : "reading",
                                 this_count, SCpnt->request.nr_sectors));
 
-       SCpnt->cmnd[1] = (SCpnt->lun << 5) & 0xe0;
+       SCpnt->cmnd[1] = (SCpnt->device->scsi_level <= SCSI_2) ?
+                        ((SCpnt->lun << 5) & 0xe0) : 0;
 
        if (((this_count > 0xff) || (block > 0x1fffff)) || SCpnt->device->ten) {
                if (this_count > 0xffff)
@@ -424,7 +431,7 @@ static int sd_init_command(Scsi_Cmnd * SCpnt)
 
 static int sd_open(struct inode *inode, struct file *filp)
 {
-       int target;
+       int target, retval = -ENXIO;
        Scsi_Device * SDev;
        target = DEVICE_NR(inode->i_rdev);
 
@@ -448,24 +455,40 @@ static int sd_open(struct inode *inode, struct file *filp)
 
        while (rscsi_disks[target].device->busy)
                barrier();
+       /*
+        * The following code can sleep.
+        * Module unloading must be prevented
+        */
+       SDev = rscsi_disks[target].device;
+       if (SDev->host->hostt->module)
+               __MOD_INC_USE_COUNT(SDev->host->hostt->module);
+       if (sd_template.module)
+               __MOD_INC_USE_COUNT(sd_template.module);
+       SDev->access_count++;
+
        if (rscsi_disks[target].device->removable) {
+               SDev->allow_revalidate = 1;
                check_disk_change(inode->i_rdev);
+               SDev->allow_revalidate = 0;
 
                /*
                 * If the drive is empty, just let the open fail.
                 */
-               if (!rscsi_disks[target].ready)
-                       return -ENXIO;
+               if ((!rscsi_disks[target].ready) && !(filp->f_flags & O_NDELAY)) {
+                       retval = -ENOMEDIUM;
+                       goto error_out;
+               }
 
                /*
                 * Similarly, if the device has the write protect tab set,
                 * have the open fail if the user expects to be able to write
                 * to the thing.
                 */
-               if ((rscsi_disks[target].write_prot) && (filp->f_mode & 2))
-                       return -EROFS;
+               if ((rscsi_disks[target].write_prot) && (filp->f_mode & 2)) {
+                       retval = -EROFS;
+                       goto error_out;
+               }
        }
-       SDev = rscsi_disks[target].device;
        /*
         * It is possible that the disk changing stuff resulted in the device
         * being taken offline.  If this is the case, report this to the user,
@@ -473,26 +496,31 @@ static int sd_open(struct inode *inode, struct file *filp)
         * the open actually succeeded.
         */
        if (!SDev->online) {
-               return -ENXIO;
+               goto error_out;
        }
        /*
         * See if we are requesting a non-existent partition.  Do this
         * after checking for disk change.
         */
-       if (sd_sizes[SD_PARTITION(inode->i_rdev)] == 0)
-               return -ENXIO;
+       if (sd_sizes[SD_PARTITION(inode->i_rdev)] == 0) {
+               goto error_out;
+       }
 
        if (SDev->removable)
-               if (!SDev->access_count)
+               if (SDev->access_count==1)
                        if (scsi_block_when_processing_errors(SDev))
                                scsi_ioctl(SDev, SCSI_IOCTL_DOORLOCK, NULL);
 
-       SDev->access_count++;
+       
+       return 0;
+
+error_out:
+       SDev->access_count--;
        if (SDev->host->hostt->module)
-               __MOD_INC_USE_COUNT(SDev->host->hostt->module);
+               __MOD_DEC_USE_COUNT(SDev->host->hostt->module);
        if (sd_template.module)
-               __MOD_INC_USE_COUNT(sd_template.module);
-       return 0;
+               __MOD_DEC_USE_COUNT(sd_template.module);
+       return retval;  
 }
 
 static int sd_release(struct inode *inode, struct file *file)
@@ -746,7 +774,8 @@ static int sd_init_onedisk(int i)
 
                while (retries < 3) {
                        cmd[0] = TEST_UNIT_READY;
-                       cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0;
+                       cmd[1] = (rscsi_disks[i].device->scsi_level <= SCSI_2) ?
+                                ((rscsi_disks[i].device->lun << 5) & 0xe0) : 0;
                        memset((void *) &cmd[2], 0, 8);
                        SRpnt->sr_cmd_len = 0;
                        SRpnt->sr_sense_buffer[0] = 0;
@@ -787,7 +816,8 @@ static int sd_init_onedisk(int i)
                        if (!spintime) {
                                printk("%s: Spinning up disk...", nbuff);
                                cmd[0] = START_STOP;
-                               cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0;
+                               cmd[1] = (rscsi_disks[i].device->scsi_level <= SCSI_2) ?
+                                        ((rscsi_disks[i].device->lun << 5) & 0xe0) : 0;
                                cmd[1] |= 1;    /* Return immediately */
                                memset((void *) &cmd[2], 0, 8);
                                cmd[4] = 1;     /* Start spin cycle */
@@ -820,7 +850,8 @@ static int sd_init_onedisk(int i)
        retries = 3;
        do {
                cmd[0] = READ_CAPACITY;
-               cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0;
+               cmd[1] = (rscsi_disks[i].device->scsi_level <= SCSI_2) ?
+                        ((rscsi_disks[i].device->lun << 5) & 0xe0) : 0;
                memset((void *) &cmd[2], 0, 8);
                memset((void *) buffer, 0, 8);
                SRpnt->sr_cmd_len = 0;
@@ -977,7 +1008,8 @@ static int sd_init_onedisk(int i)
 
                memset((void *) &cmd[0], 0, 8);
                cmd[0] = MODE_SENSE;
-               cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0;
+               cmd[1] = (rscsi_disks[i].device->scsi_level <= SCSI_2) ?
+                        ((rscsi_disks[i].device->lun << 5) & 0xe0) : 0;
                cmd[2] = 0x3f;  /* Get all pages */
                cmd[4] = 8;     /* But we only want the 8 byte header */
                SRpnt->sr_cmd_len = 0;
@@ -1183,16 +1215,9 @@ static void sd_finish()
 
 static int sd_detect(Scsi_Device * SDp)
 {
-       char nbuff[6];
        if (SDp->type != TYPE_DISK && SDp->type != TYPE_MOD)
                return 0;
-
-       sd_devname(sd_template.dev_noticed++, nbuff);
-       printk("Detected scsi %sdisk %s at scsi%d, channel %d, id %d, lun %d\n",
-              SDp->removable ? "removable " : "",
-              nbuff,
-              SDp->host->host_no, SDp->channel, SDp->id, SDp->lun);
-
+       sd_template.dev_noticed++;
        return 1;
 }
 
@@ -1201,6 +1226,7 @@ static int sd_attach(Scsi_Device * SDp)
         unsigned int devnum;
        Scsi_Disk *dpnt;
        int i;
+       char nbuff[6];
 
        if (SDp->type != TYPE_DISK && SDp->type != TYPE_MOD)
                return 0;
@@ -1224,10 +1250,15 @@ static int sd_attach(Scsi_Device * SDp)
         SD_GENDISK(i).de_arr[devnum] = SDp->de;
         if (SDp->removable)
                SD_GENDISK(i).flags[devnum] |= GENHD_FL_REMOVABLE;
+       sd_devname(i, nbuff);
+       printk("Attached scsi %sdisk %s at scsi%d, channel %d, id %d, lun %d\n",
+              SDp->removable ? "removable " : "",
+              nbuff, SDp->host->host_no, SDp->channel, SDp->id, SDp->lun);
        return 0;
 }
 
 #define DEVICE_BUSY rscsi_disks[target].device->busy
+#define ALLOW_REVALIDATE rscsi_disks[target].device->allow_revalidate
 #define USAGE rscsi_disks[target].device->access_count
 #define CAPACITY rscsi_disks[target].capacity
 #define MAYBE_REINIT  sd_init_onedisk(target)
@@ -1248,7 +1279,7 @@ int revalidate_scsidisk(kdev_t dev, int maxusage)
 
        target = DEVICE_NR(dev);
 
-       if (DEVICE_BUSY || USAGE > maxusage) {
+       if (DEVICE_BUSY || (ALLOW_REVALIDATE == 0 && USAGE > maxusage)) {
                printk("Device busy for revalidation (usage=%d)\n", USAGE);
                return -EBUSY;
        }
index 4baeb582d13ec1aca2e881f238f22afd1f060739..8024bcc5fe350e3a7a9ee081c9b263fac391914d 100644 (file)
@@ -88,6 +88,7 @@ Scsi_CD *scsi_CDs;
 static int *sr_sizes;
 
 static int *sr_blocksizes;
+static int *sr_hardsizes;
 
 static int sr_open(struct cdrom_device_info *, int);
 void get_sectorsize(int);
@@ -262,7 +263,7 @@ static request_queue_t *sr_find_queue(kdev_t dev)
 static int sr_scatter_pad(Scsi_Cmnd *SCpnt, int s_size)
 {
        struct scatterlist *sg, *old_sg = NULL;
-       int i, fsize, bsize, sg_ent;
+       int i, fsize, bsize, sg_ent, sg_count;
        char *front, *back;
 
        back = front = NULL;
@@ -290,17 +291,24 @@ static int sr_scatter_pad(Scsi_Cmnd *SCpnt, int s_size)
        /*
         * extend or allocate new scatter-gather table
         */
-       if (SCpnt->use_sg)
+       sg_count = SCpnt->use_sg;
+       if (sg_count)
                old_sg = (struct scatterlist *) SCpnt->request_buffer;
        else {
-               SCpnt->use_sg = 1;
+               sg_count = 1;
                sg_ent++;
        }
 
-       SCpnt->sglist_len = ((sg_ent * sizeof(struct scatterlist)) + 511) & ~511;
-       if ((sg = scsi_malloc(SCpnt->sglist_len)) == NULL)
+       i = ((sg_ent * sizeof(struct scatterlist)) + 511) & ~511;
+       if ((sg = scsi_malloc(i)) == NULL)
                goto no_mem;
 
+       /*
+        * no more failing memory allocs possible, we can safely assign
+        * SCpnt values now
+        */
+       SCpnt->sglist_len = i;
+       SCpnt->use_sg = sg_count;
        memset(sg, 0, SCpnt->sglist_len);
 
        i = 0;
@@ -343,12 +351,12 @@ no_mem:
 
 static int sr_init_command(Scsi_Cmnd * SCpnt)
 {
-       int dev, devm, block, this_count, s_size;
+       int dev, devm, block=0, this_count, s_size;
 
        devm = MINOR(SCpnt->request.rq_dev);
        dev = DEVICE_NR(SCpnt->request.rq_dev);
 
-       SCSI_LOG_HLQUEUE(1, printk("Doing sr request, dev = %d\n", devm));
+       SCSI_LOG_HLQUEUE(1, printk("Doing sr request, dev = %d, block = %d\n", devm, block));
 
        if (dev >= sr_template.nr_dev ||
            !scsi_CDs[dev].device ||
@@ -415,7 +423,8 @@ static int sr_init_command(Scsi_Cmnd * SCpnt)
                   (SCpnt->request.cmd == WRITE) ? "writing" : "reading",
                                 this_count, SCpnt->request.nr_sectors));
 
-       SCpnt->cmnd[1] = (SCpnt->lun << 5) & 0xe0;
+       SCpnt->cmnd[1] = (SCpnt->device->scsi_level <= SCSI_2) ?
+                        ((SCpnt->lun << 5) & 0xe0) : 0;
 
        if (this_count > 0xffff)
                this_count = 0xffff;
@@ -501,11 +510,7 @@ static int sr_detect(Scsi_Device * SDp)
 
        if (SDp->type != TYPE_ROM && SDp->type != TYPE_WORM)
                return 0;
-
-       printk("Detected scsi CD-ROM sr%d at scsi%d, channel %d, id %d, lun %d\n",
-              sr_template.dev_noticed++,
-              SDp->host->host_no, SDp->channel, SDp->id, SDp->lun);
-
+       sr_template.dev_noticed++;
        return 1;
 }
 
@@ -534,6 +539,9 @@ static int sr_attach(Scsi_Device * SDp)
        sr_template.nr_dev++;
        if (sr_template.nr_dev > sr_template.dev_max)
                panic("scsi_devices corrupt (sr)");
+
+       printk("Attached scsi CD-ROM sr%d at scsi%d, channel %d, id %d, lun %d\n",
+              i, SDp->host->host_no, SDp->channel, SDp->id, SDp->lun);
        return 0;
 }
 
@@ -564,7 +572,8 @@ void get_sectorsize(int i)
        retries = 3;
        do {
                cmd[0] = READ_CAPACITY;
-               cmd[1] = (scsi_CDs[i].device->lun << 5) & 0xe0;
+               cmd[1] = (scsi_CDs[i].device->scsi_level <= SCSI_2) ?
+                        ((scsi_CDs[i].device->lun << 5) & 0xe0) : 0;
                memset((void *) &cmd[2], 0, 8);
                SRpnt->sr_request.rq_status = RQ_SCSI_BUSY;     /* Mark as really busy */
                SRpnt->sr_cmd_len = 0;
@@ -593,7 +602,7 @@ void get_sectorsize(int i)
        } else {
 #if 0
                if (cdrom_get_last_written(MKDEV(MAJOR_NR, i),
-                                        (long *) &scsi_CDs[i].capacity))
+                                          &scsi_CDs[i].capacity))
 #endif
                        scsi_CDs[i].capacity = 1 + ((buffer[0] << 24) |
                                                    (buffer[1] << 16) |
@@ -656,8 +665,14 @@ void get_capabilities(int i)
        };
 
        buffer = (unsigned char *) scsi_malloc(512);
+       if (!buffer)
+       {
+               printk(KERN_ERR "sr: out of memory.\n");
+               return;
+       }
        cmd[0] = MODE_SENSE;
-       cmd[1] = (scsi_CDs[i].device->lun << 5) & 0xe0;
+       cmd[1] = (scsi_CDs[i].device->scsi_level <= SCSI_2) ?
+                ((scsi_CDs[i].device->lun << 5) & 0xe0) : 0;
        cmd[2] = 0x2a;
        cmd[4] = 128;
        cmd[3] = cmd[5] = 0;
@@ -734,7 +749,8 @@ static int sr_packet(struct cdrom_device_info *cdi, struct cdrom_generic_command
        Scsi_Device *device = scsi_CDs[MINOR(cdi->dev)].device;
 
        /* set the LUN */
-       cgc->cmd[1] |= device->lun << 5;
+       if (device->scsi_level <= SCSI_2)
+               cgc->cmd[1] |= device->lun << 5;
 
        cgc->stat = sr_do_ioctl(MINOR(cdi->dev), cgc->cmd, cgc->buffer, cgc->buflen, cgc->quiet, cgc->data_direction, cgc->sense);
 
@@ -775,16 +791,21 @@ static int sr_init()
        if (!sr_blocksizes)
                goto cleanup_sizes;
 
+       sr_hardsizes = kmalloc(sr_template.dev_max * sizeof(int), GFP_ATOMIC);
+       if (!sr_hardsizes)
+               goto cleanup_blocksizes;
        /*
         * These are good guesses for the time being.
-        * Don't set sr_hardsizes here! That will prevent reading anything smaller.
         */
        for (i = 0; i < sr_template.dev_max; i++) {
                sr_blocksizes[i] = 2048;
+               sr_hardsizes[i] = 2048;
         }
        blksize_size[MAJOR_NR] = sr_blocksizes;
+        hardsect_size[MAJOR_NR] = sr_hardsizes;
        return 0;
-
+cleanup_blocksizes:
+       kfree(sr_blocksizes);
 cleanup_sizes:
        kfree(sr_sizes);
 cleanup_cds:
@@ -830,6 +851,10 @@ void sr_finish()
                scsi_CDs[i].cdi.dev = MKDEV(MAJOR_NR, i);
                scsi_CDs[i].cdi.mask = 0;
                scsi_CDs[i].cdi.capacity = 1;
+               /*
+                *      FIXME: someone needs to handle a get_capabilities
+                *      failure properly ??
+                */
                get_capabilities(i);
                sr_vendor_init(i);
 
@@ -903,8 +928,11 @@ static void __exit exit_sr(void)
 
                kfree(sr_blocksizes);
                sr_blocksizes = NULL;
+               kfree(sr_hardsizes);
+               sr_hardsizes = NULL;
        }
        blksize_size[MAJOR_NR] = NULL;
+        hardsect_size[MAJOR_NR] = NULL;
        blk_size[MAJOR_NR] = NULL;
        read_ahead[MAJOR_NR] = 0;
 
index c2b7950344729a734518914d7568282165c8fb4a..65439514eeceeb15533de5c092e7949faedd3ed7 100644 (file)
@@ -195,7 +195,8 @@ static int test_unit_ready(int minor)
        u_char sr_cmd[10];
 
        sr_cmd[0] = GPCMD_TEST_UNIT_READY;
-       sr_cmd[1] = ((scsi_CDs[minor].device->lun) << 5);
+       sr_cmd[1] = (scsi_CDs[minor].device->scsi_level <= SCSI_2) ?
+                   ((scsi_CDs[minor].device->lun) << 5) : 0;
        sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0;
        return sr_do_ioctl(minor, sr_cmd, NULL, 0, 1, SCSI_DATA_NONE, NULL);
 }
@@ -205,7 +206,8 @@ int sr_tray_move(struct cdrom_device_info *cdi, int pos)
        u_char sr_cmd[10];
 
        sr_cmd[0] = GPCMD_START_STOP_UNIT;
-       sr_cmd[1] = ((scsi_CDs[MINOR(cdi->dev)].device->lun) << 5);
+       sr_cmd[1] = (scsi_CDs[MINOR(cdi->dev)].device->scsi_level <= SCSI_2) ?
+                   ((scsi_CDs[MINOR(cdi->dev)].device->lun) << 5) : 0;
        sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0;
        sr_cmd[4] = (pos == 0) ? 0x03 /* close */ : 0x02 /* eject */ ;
 
@@ -277,7 +279,8 @@ int sr_get_mcn(struct cdrom_device_info *cdi, struct cdrom_mcn *mcn)
        int result;
 
        sr_cmd[0] = GPCMD_READ_SUBCHANNEL;
-       sr_cmd[1] = ((scsi_CDs[MINOR(cdi->dev)].device->lun) << 5);
+       sr_cmd[1] = (scsi_CDs[MINOR(cdi->dev)].device->scsi_level <= SCSI_2) ?
+                   ((scsi_CDs[MINOR(cdi->dev)].device->lun) << 5) : 0;
        sr_cmd[2] = 0x40;       /* I do want the subchannel info */
        sr_cmd[3] = 0x02;       /* Give me medium catalog number info */
        sr_cmd[4] = sr_cmd[5] = 0;
@@ -311,7 +314,8 @@ int sr_select_speed(struct cdrom_device_info *cdi, int speed)
 
        memset(sr_cmd, 0, MAX_COMMAND_SIZE);
        sr_cmd[0] = GPCMD_SET_SPEED;    /* SET CD SPEED */
-       sr_cmd[1] = (scsi_CDs[MINOR(cdi->dev)].device->lun) << 5;
+       sr_cmd[1] = (scsi_CDs[MINOR(cdi->dev)].device->scsi_level <= SCSI_2) ?
+                   ((scsi_CDs[MINOR(cdi->dev)].device->lun) << 5) : 0;
        sr_cmd[2] = (speed >> 8) & 0xff;        /* MSB for speed (in kbytes/sec) */
        sr_cmd[3] = speed & 0xff;       /* LSB */
 
@@ -340,7 +344,8 @@ int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void *arg)
                        struct cdrom_tochdr *tochdr = (struct cdrom_tochdr *) arg;
 
                        sr_cmd[0] = GPCMD_READ_TOC_PMA_ATIP;
-                       sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5);
+                       sr_cmd[1] = (scsi_CDs[target].device->scsi_level <= SCSI_2) ?
+                                   ((scsi_CDs[target].device->lun) << 5) : 0;
                        sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0;
                        sr_cmd[8] = 12;         /* LSB of length */
 
@@ -357,8 +362,9 @@ int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void *arg)
                        struct cdrom_tocentry *tocentry = (struct cdrom_tocentry *) arg;
 
                        sr_cmd[0] = GPCMD_READ_TOC_PMA_ATIP;
-                       sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) |
-                           (tocentry->cdte_format == CDROM_MSF ? 0x02 : 0);
+                       sr_cmd[1] = (scsi_CDs[target].device->scsi_level <= SCSI_2) ?
+                                   ((scsi_CDs[target].device->lun) << 5) : 0;
+                       sr_cmd[1] |= (tocentry->cdte_format == CDROM_MSF) ? 0x02 : 0;
                        sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0;
                        sr_cmd[6] = tocentry->cdte_track;
                        sr_cmd[8] = 12;         /* LSB of length */
@@ -383,7 +389,8 @@ int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void *arg)
                struct cdrom_ti* ti = (struct cdrom_ti*)arg;
 
                sr_cmd[0] = GPCMD_PLAYAUDIO_TI;
-               sr_cmd[1] = scsi_CDs[target].device->lun << 5;
+               sr_cmd[1] = (scsi_CDs[target].device->scsi_level <= SCSI_2) ?
+                           (scsi_CDs[target].device->lun << 5) : 0;
                sr_cmd[4] = ti->cdti_trk0;
                sr_cmd[5] = ti->cdti_ind0;
                sr_cmd[7] = ti->cdti_trk1;
@@ -433,7 +440,9 @@ int sr_read_cd(int minor, unsigned char *dest, int lba, int format, int blksize)
 
        memset(cmd, 0, MAX_COMMAND_SIZE);
        cmd[0] = GPCMD_READ_CD; /* READ_CD */
-       cmd[1] = (scsi_CDs[minor].device->lun << 5) | ((format & 7) << 2);
+       cmd[1] = (scsi_CDs[minor].device->scsi_level <= SCSI_2) ?
+                (scsi_CDs[minor].device->lun << 5) : 0;
+       cmd[1] |= ((format & 7) << 2);
        cmd[2] = (unsigned char) (lba >> 24) & 0xff;
        cmd[3] = (unsigned char) (lba >> 16) & 0xff;
        cmd[4] = (unsigned char) (lba >> 8) & 0xff;
@@ -485,7 +494,8 @@ int sr_read_sector(int minor, int lba, int blksize, unsigned char *dest)
 
        memset(cmd, 0, MAX_COMMAND_SIZE);
        cmd[0] = GPCMD_READ_10;
-       cmd[1] = (scsi_CDs[minor].device->lun << 5);
+       cmd[1] = (scsi_CDs[minor].device->scsi_level <= SCSI_2) ?
+                (scsi_CDs[minor].device->lun << 5) : 0;
        cmd[2] = (unsigned char) (lba >> 24) & 0xff;
        cmd[3] = (unsigned char) (lba >> 16) & 0xff;
        cmd[4] = (unsigned char) (lba >> 8) & 0xff;
@@ -534,6 +544,8 @@ int sr_dev_ioctl(struct cdrom_device_info *cdi,
        target = MINOR(cdi->dev);
 
        switch (cmd) {
+       case BLKGETSIZE:
+               return put_user(scsi_CDs[target].capacity >> 1, (long *) arg);
        case BLKROSET:
        case BLKROGET:
        case BLKRASET:
index 9aec139e43aede7115c9b126c37a7b1744d8b99c..39bd3b6cb226435c40067fc11724767d05d429cf 100644 (file)
@@ -124,7 +124,9 @@ int sr_set_blocklength(int minor, int blocklength)
 #endif
        memset(cmd, 0, MAX_COMMAND_SIZE);
        cmd[0] = MODE_SELECT;
-       cmd[1] = (scsi_CDs[minor].device->lun << 5) | (1 << 4);
+       cmd[1] = (scsi_CDs[minor].device->scsi_level <= SCSI_2) ?
+                (scsi_CDs[minor].device->lun << 5) : 0;
+       cmd[1] |= (1 << 4);
        cmd[4] = 12;
        modesel = (struct ccs_modesel_head *) buffer;
        memset(modesel, 0, sizeof(*modesel));
@@ -173,7 +175,8 @@ int sr_cd_check(struct cdrom_device_info *cdi)
        case VENDOR_SCSI3:
                memset(cmd, 0, MAX_COMMAND_SIZE);
                cmd[0] = READ_TOC;
-               cmd[1] = (scsi_CDs[minor].device->lun << 5);
+               cmd[1] = (scsi_CDs[minor].device->scsi_level <= SCSI_2) ?
+                        (scsi_CDs[minor].device->lun << 5) : 0;
                cmd[8] = 12;
                cmd[9] = 0x40;
                rc = sr_do_ioctl(minor, cmd, buffer, 12, 1, SCSI_DATA_READ, NULL);
@@ -198,7 +201,9 @@ int sr_cd_check(struct cdrom_device_info *cdi)
                        unsigned long min, sec, frame;
                        memset(cmd, 0, MAX_COMMAND_SIZE);
                        cmd[0] = 0xde;
-                       cmd[1] = (scsi_CDs[minor].device->lun << 5) | 0x03;
+                       cmd[1] = (scsi_CDs[minor].device->scsi_level <= SCSI_2) ?
+                                (scsi_CDs[minor].device->lun << 5) : 0;
+                       cmd[1] |= 0x03;
                        cmd[2] = 0xb0;
                        rc = sr_do_ioctl(minor, cmd, buffer, 0x16, 1, SCSI_DATA_READ, NULL);
                        if (rc != 0)
@@ -223,7 +228,9 @@ int sr_cd_check(struct cdrom_device_info *cdi)
                         * where starts the last session ?) */
                        memset(cmd, 0, MAX_COMMAND_SIZE);
                        cmd[0] = 0xc7;
-                       cmd[1] = (scsi_CDs[minor].device->lun << 5) | 3;
+                       cmd[1] = (scsi_CDs[minor].device->scsi_level <= SCSI_2) ?
+                                (scsi_CDs[minor].device->lun << 5) : 0;
+                       cmd[1] |= 0x03;
                        rc = sr_do_ioctl(minor, cmd, buffer, 4, 1, SCSI_DATA_READ, NULL);
                        if (rc == -EINVAL) {
                                printk(KERN_INFO "sr%d: Hmm, seems the drive "
@@ -246,7 +253,8 @@ int sr_cd_check(struct cdrom_device_info *cdi)
        case VENDOR_WRITER:
                memset(cmd, 0, MAX_COMMAND_SIZE);
                cmd[0] = READ_TOC;
-               cmd[1] = (scsi_CDs[minor].device->lun << 5);
+               cmd[1] = (scsi_CDs[minor].device->scsi_level <= SCSI_2) ?
+                        (scsi_CDs[minor].device->lun << 5) : 0;
                cmd[8] = 0x04;
                cmd[9] = 0x40;
                rc = sr_do_ioctl(minor, cmd, buffer, 0x04, 1, SCSI_DATA_READ, NULL);
@@ -259,7 +267,8 @@ int sr_cd_check(struct cdrom_device_info *cdi)
                        break;
                }
                cmd[0] = READ_TOC;      /* Read TOC */
-               cmd[1] = (scsi_CDs[minor].device->lun << 5);
+               cmd[1] = (scsi_CDs[minor].device->scsi_level <= SCSI_2) ?
+                        (scsi_CDs[minor].device->lun << 5) : 0;
                cmd[6] = rc & 0x7f;     /* number of last session */
                cmd[8] = 0x0c;
                cmd[9] = 0x40;
index 2e4dbf1e38f7c8a62159545059d052929e7a0593..39cc6dfcf19a760cdafb5259fe9e01cdcfc4f729 100644 (file)
@@ -359,7 +359,8 @@ static Scsi_Request *
                }
        }
 
-       cmd[1] |= (SRpnt->sr_device->lun << 5) & 0xe0;
+       if (SRpnt->sr_device->scsi_level <= SCSI_2)
+               cmd[1] |= (SRpnt->sr_device->lun << 5) & 0xe0;
        init_MUTEX_LOCKED(&STp->sem);
        SRpnt->sr_use_sg = (bytes > (STp->buffer)->sg[0].length) ?
            (STp->buffer)->use_sg : 0;
@@ -3495,7 +3496,7 @@ static int st_attach(Scsi_Device * SDp)
        Scsi_Tape *tpnt;
        ST_mode *STm;
        ST_partstat *STps;
-       int i, mode, target_nbr;
+       int i, mode, target_nbr, dev_num;
        unsigned long flags = 0;
        char *stp;
 
@@ -3573,6 +3574,7 @@ static int st_attach(Scsi_Device * SDp)
        }
        memset(tpnt, 0, sizeof(Scsi_Tape));
        scsi_tapes[i] = tpnt;
+       dev_num = i;
 
        for (mode = 0; mode < ST_NBR_MODES; ++mode) {
            char name[8];
@@ -3653,6 +3655,9 @@ static int st_attach(Scsi_Device * SDp)
 
        st_template.nr_dev++;
        write_unlock_irqrestore(&st_dev_arr_lock, flags);
+       printk(KERN_WARNING
+       "Attached scsi tape st%d at scsi%d, channel %d, id %d, lun %d\n",
+              dev_num, SDp->host->host_no, SDp->channel, SDp->id, SDp->lun);
 
        /* See if we need to allocate more static buffers */
        target_nbr = st_template.nr_dev;
@@ -3673,12 +3678,7 @@ static int st_detect(Scsi_Device * SDp)
 {
        if (SDp->type != TYPE_TAPE || st_incompatible(SDp))
                return 0;
-
-       printk(KERN_WARNING
-       "Detected scsi tape st%d at scsi%d, channel %d, id %d, lun %d\n",
-              st_template.dev_noticed++,
-              SDp->host->host_no, SDp->channel, SDp->id, SDp->lun);
-
+        st_template.dev_noticed++;
        return 1;
 }
 
index 67b97b1024fc6d1958774f8389b3c07d1583d0e4..db21493e78ffaacfa20b3c19d4c7d80926d93795 100644 (file)
@@ -85,7 +85,7 @@
 /*
 **     Name and version of the driver
 */
-#define SCSI_NCR_DRIVER_NAME   "sym53c8xx-1.7.3a-20010304"
+#define SCSI_NCR_DRIVER_NAME   "sym53c8xx-1.7.3c-20010512"
 
 #define SCSI_NCR_DEBUG_FLAGS   (0)
 
@@ -584,6 +584,9 @@ pci_get_base_cookie(struct pci_dev *pdev, int offset)
 #if LINUX_VERSION_CODE < LinuxVersionCode(2,4,0)
 #define pci_enable_device(pdev)                (0)
 #endif
+#if LINUX_VERSION_CODE < LinuxVersionCode(2,4,4)
+#define        scsi_set_pci_device(inst, pdev) (0)
+#endif
 
 /*==========================================================
 **
@@ -3781,7 +3784,7 @@ static    struct scripth scripth0 __initdata = {
                SIR_MSG_RECEIVED,
 
 }/*-------------------------< MSG_WEIRD_SEEN >------------------*/,{
-       SCR_LOAD_REL (scratcha1, 4),    /* DUMMY READ */
+       SCR_LOAD_REL (scratcha, 4),     /* DUMMY READ */
                0,
        SCR_INT,
                SIR_MSG_WEIRD,
@@ -6591,7 +6594,7 @@ static int ncr_queue_command (ncb_p np, Scsi_Cmnd *cmd)
        **
        **----------------------------------------------------
        */
-#if 0  /* This stuff was only usefull for linux-1.2.13 */
+#if 0  /* This stuff was only useful for linux-1.2.13 */
        if (lp && !lp->numtags && cmd->device && cmd->device->tagged_queue) {
                lp->numtags = tp->usrtags;
                ncr_setup_tags (np, cp->target, cp->lun);
@@ -6991,22 +6994,26 @@ static void ncr_soft_reset(ncb_p np)
        u_char istat;
        int i;
 
+       if (!(np->features & FE_ISTAT1) || !(INB (nc_istat1) & SRUN))
+               goto do_chip_reset;
+
        OUTB (nc_istat, CABRT);
-       for (i = 1000000 ; i ; --i) {
+       for (i = 100000 ; i ; --i) {
                istat = INB (nc_istat);
                if (istat & SIP) {
                        INW (nc_sist);
-                       continue;
                }
-               if (istat & DIP) {
-                       OUTB (nc_istat, 0);
-                       INB (nc_dstat);
-                       break;
+               else if (istat & DIP) {
+                       if (INB (nc_dstat) & ABRT);
+                               break;
                }
+               UDELAY(5);
        }
+       OUTB (nc_istat, 0);
        if (!i)
-               printk("%s: unable to abort current chip operation.\n",
-                       ncr_name(np));
+               printk("%s: unable to abort current chip operation, "
+                      "ISTAT=0x%02x.\n", ncr_name(np), istat);
+do_chip_reset:
        ncr_chip_reset(np);
 }
 
@@ -7419,10 +7426,10 @@ void ncr_complete (ncb_p np, ccb_p cp)
                /*
                **      On standard INQUIRY response (EVPD and CmDt 
                **      not set), setup logical unit according to 
-               **      announced capabilities (we need the 1rst 7 bytes).
+               **      announced capabilities (we need the 1rst 8 bytes).
                */
                if (cmd->cmnd[0] == 0x12 && !(cmd->cmnd[1] & 0x3) &&
-                   cmd->cmnd[4] >= 7 && !cmd->use_sg) {
+                   cmd->request_bufflen - cp->resid > 7 && !cmd->use_sg) {
                        sync_scsi_data(np, cmd);        /* SYNC the data */
                        ncr_setup_lcb (np, cp->target, cp->lun,
                                       (char *) cmd->request_buffer);
@@ -7959,7 +7966,7 @@ static void ncr_getsync(ncb_p np, u_char sfac, u_char *fakp, u_char *scntl3p)
        */
        fak = (kpc - 1) / div_10M[div] + 1;
 
-#if 0  /* This optimization does not seem very usefull */
+#if 0  /* This optimization does not seem very useful */
 
        per = (fak * div_10M[div]) / clk;
 
@@ -8685,7 +8692,7 @@ static void ncr_timeout (ncb_p np)
 **             scntl3: (see the manual)
 **
 **     current script command:
-**             dsp:    script adress (relative to start of script).
+**             dsp:    script address (relative to start of script).
 **             dbc:    first word of script command.
 **
 **     First 24 register of the chip:
@@ -9535,7 +9542,7 @@ static void ncr_int_ma (ncb_p np)
 
 #ifdef  SYM_DEBUG_PM_WITH_WSR
                PRINT_ADDR(cp);
-               printf ("MA interrupt with WSR set - "
+               printk ("MA interrupt with WSR set - "
                        "pm->sg.addr=%x - pm->sg.size=%d\n",
                        pm->sg.addr, pm->sg.size);
 #endif
@@ -10167,14 +10174,16 @@ static void ncr_sir_task_recovery(ncb_p np, int num)
                                if (i >= MAX_START*2)
                                        i = 0;
                        }
-                       assert(k != -1);
-                       if (k != 1) {
+                       /*
+                       **      If job removed, repair the start queue.
+                       */
+                       if (k != -1) {
                                np->squeue[k] = np->squeue[i]; /* Idle task */
                                np->squeueput = k; /* Start queue pointer */
-                               cp->host_status = HS_ABORTED;
-                               cp->scsi_status = S_ILLEGAL;
-                               ncr_complete(np, cp);
                        }
+                       cp->host_status = HS_ABORTED;
+                       cp->scsi_status = S_ILLEGAL;
+                       ncr_complete(np, cp);
                }
                break;
        /*
@@ -10730,7 +10739,7 @@ static void ncr_print_msg (ccb_p cp, char *label, u_char *msg)
 **     Was Sie schon immer ueber transfermode negotiation wissen wollten ...
 **
 **     We try to negotiate sync and wide transfer only after
-**     a successfull inquire command. We look at byte 7 of the
+**     a successful inquire command. We look at byte 7 of the
 **     inquire data to determine the capabilities of the target.
 **
 **     When we try to negotiate, we append the negotiation message
@@ -11571,7 +11580,7 @@ out_stuck:
 /*==========================================================
 **
 **
-**     Aquire a control block
+**     Acquire a control block
 **
 **
 **==========================================================
@@ -12223,6 +12232,7 @@ static int __init ncr_regtest (struct ncb* np)
 static int __init ncr_snooptest (struct ncb* np)
 {
        u_int32 ncr_rd, ncr_wr, ncr_bk, host_rd, host_wr, pc;
+       u_char  dstat;
        int     i, err=0;
 #ifndef SCSI_NCR_IOMAPPED
        if (np->reg) {
@@ -12230,6 +12240,12 @@ static int __init ncr_snooptest (struct ncb* np)
             if (err) return (err);
        }
 #endif
+restart_test:
+       /*
+       **      Enable Master Parity Checking as we intend 
+       **      to enable it for normal operations.
+       */
+       OUTB (nc_ctest4, (np->rv_ctest4 & MPEE));
        /*
        **      init
        */
@@ -12252,6 +12268,27 @@ static int __init ncr_snooptest (struct ncb* np)
        for (i=0; i<NCR_SNOOP_TIMEOUT; i++)
                if (INB(nc_istat) & (INTF|SIP|DIP))
                        break;
+       if (i>=NCR_SNOOP_TIMEOUT) {
+               printk ("CACHE TEST FAILED: timeout.\n");
+               return (0x20);
+       };
+       /*
+       **      Check for fatal DMA errors.
+       */
+       dstat = INB (nc_dstat);
+#if 1  /* Band aiding for broken hardwares that fail PCI parity */
+       if ((dstat & MDPE) && (np->rv_ctest4 & MPEE)) {
+               printk ("%s: PCI DATA PARITY ERROR DETECTED - "
+                       "DISABLING MASTER DATA PARITY CHECKING.\n",
+                       ncr_name(np));
+               np->rv_ctest4 &= ~MPEE;
+               goto restart_test;
+       }
+#endif
+       if (dstat & (MDPE|BF|IID)) {
+               printk ("CACHE TEST FAILED: DMA error (dstat=0x%02x).", dstat);
+               return (0x80);
+       }
        /*
        **      Save termination position.
        */
@@ -12262,14 +12299,6 @@ static int __init ncr_snooptest (struct ncb* np)
        host_rd = scr_to_cpu(np->ncr_cache);
        ncr_rd  = INL (nc_scratcha);
        ncr_bk  = INL (nc_temp);
-
-       /*
-       **      check for timeout
-       */
-       if (i>=NCR_SNOOP_TIMEOUT) {
-               printk ("CACHE TEST FAILED: timeout.\n");
-               return (0x20);
-       };
        /*
        **      Check termination position.
        */
@@ -14381,7 +14410,7 @@ sym_read_S24C16_nvram (ncr_slot *np, int offset, u_char *data, int len)
        /* save current state of GPCNTL and GPREG */
        old_gpreg       = INB (nc_gpreg);
        old_gpcntl      = INB (nc_gpcntl);
-       gpcntl          = old_gpcntl & 0xfc;
+       gpcntl          = old_gpcntl & 0x1c;
 
        /* set up GPREG & GPCNTL to set GPIO0 and GPIO1 in to known state */
        OUTB (nc_gpreg,  old_gpreg);
index b2db90d8d3c9f30a44652047a3e1822391129cda..d7fa8beebb1c40c1fbcb5b0a6a6ee092d00ca3ea 100644 (file)
@@ -403,6 +403,9 @@ pci_get_base_cookie(struct pci_dev *pdev, int offset)
 #if LINUX_VERSION_CODE < LinuxVersionCode(2,4,0)
 #define pci_enable_device(pdev)                (0)
 #endif
+#if LINUX_VERSION_CODE < LinuxVersionCode(2,4,4)
+#define        scsi_set_pci_device(inst, pdev) (0)
+#endif
 
 /*==========================================================
 **
@@ -1311,7 +1314,7 @@ sym_read_S24C16_nvram (ncr_slot *np, int offset, u_char *data, int len)
        /* save current state of GPCNTL and GPREG */
        old_gpreg       = INB (nc_gpreg);
        old_gpcntl      = INB (nc_gpcntl);
-       gpcntl          = old_gpcntl & 0xfc;
+       gpcntl          = old_gpcntl & 0x1c;
 
        /* set up GPREG & GPCNTL to set GPIO0 and GPIO1 in to known state */
        OUTB (nc_gpreg,  old_gpreg);
index 6ac60f0b799151d42b8def630aec4e3585bbb758..c0c551c47b0649be71b72bebd7af1301a6f6c979 100644 (file)
 #endif
 
 /*
- * Use normal IO if configured. Forced for alpha and powerpc.
- * Powerpc fails copying to on-chip RAM using memcpy_toio().
+ * Use normal IO if configured. Forced for alpha.
  */
 #if defined(CONFIG_SCSI_NCR53C8XX_IOMAPPED)
 #define        SCSI_NCR_IOMAPPED
 #elif defined(__alpha__)
 #define        SCSI_NCR_IOMAPPED
 #elif defined(__powerpc__)
+#if LINUX_VERSION_CODE <= LinuxVersionCode(2,4,3)
 #define        SCSI_NCR_IOMAPPED
 #define SCSI_NCR_PCI_MEM_NOT_SUPPORTED
+#endif
 #elif defined(__sparc__)
 #undef SCSI_NCR_IOMAPPED
 #endif
@@ -734,7 +735,7 @@ typedef struct {
 #define FE_PFEN                (1<<12)   /* Prefetch enable */
 #define FE_LDSTR       (1<<13)   /* Load/Store supported */
 #define FE_RAM         (1<<14)   /* On chip RAM present */
-#define FE_VARCLK      (1<<15)   /* SCSI lock may vary */
+#define FE_VARCLK      (1<<15)   /* SCSI clock may vary */
 #define FE_RAM8K       (1<<16)   /* On chip RAM sized 8Kb */
 #define FE_64BIT       (1<<17)   /* Have a 64-bit PCI interface */
 #define FE_IO256       (1<<18)   /* Requires full 256 bytes in PCI space */
@@ -744,6 +745,7 @@ typedef struct {
 #define FE_ULTRA3      (1<<22)   /* Ultra-3 80Mtrans/sec */
 #define FE_66MHZ       (1<<23)   /* 66MHz PCI Support */
 #define FE_DAC         (1<<24)   /* Support DAC cycles (64 bit addressing) */
+#define FE_ISTAT1      (1<<25)   /* Have ISTAT1, MBOX0, MBOX1 registers */
 
 #define FE_CACHE_SET   (FE_ERL|FE_CLSE|FE_WRIE|FE_ERMP)
 #define FE_SCSI_SET    (FE_WIDE|FE_ULTRA|FE_ULTRA2|FE_DBLR|FE_QUAD|F_CLK80)
@@ -808,7 +810,7 @@ typedef struct {
  ,                                                                     \
  {PCI_DEVICE_ID_NCR_53C896, 0xff, "896",  6, 31, 7,                    \
  FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|        \
- FE_RAM|FE_RAM8K|FE_64BIT|FE_DAC|FE_IO256|FE_NOPM|FE_LEDC}             \
+ FE_RAM|FE_RAM8K|FE_64BIT|FE_DAC|FE_IO256|FE_NOPM|FE_LEDC|FE_ISTAT1}   \
  ,                                                                     \
  {PCI_DEVICE_ID_NCR_53C895A, 0xff, "895a",  6, 31, 7,                  \
  FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|        \
@@ -823,11 +825,11 @@ typedef struct {
  FE_RAM|FE_IO256}                                                      \
  ,                                                                     \
  {PCI_DEVICE_ID_LSI_53C1010, 0xff, "1010-33",  6, 62, 7,               \
- FE_WIDE|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|          \
+ FE_WIDE|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_ISTAT1|        \
  FE_RAM|FE_RAM8K|FE_64BIT|FE_DAC|FE_IO256|FE_NOPM|FE_LEDC|FE_ULTRA3}   \
  ,                                                                     \
  {PCI_DEVICE_ID_LSI_53C1010_66, 0xff, "1010-66",  6, 62, 7,            \
- FE_WIDE|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|          \
+ FE_WIDE|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_ISTAT1|        \
  FE_RAM|FE_RAM8K|FE_64BIT|FE_DAC|FE_IO256|FE_NOPM|FE_LEDC|FE_ULTRA3|   \
  FE_66MHZ}                                                             \
 }
@@ -1179,9 +1181,13 @@ struct ncr_reg {
         #define   SIP     0x02  /* sta: scsi-interrupt              */
         #define   DIP     0x01  /* sta: host/script interrupt       */
 
-/*15*/  u_char    nc_istat1;   /* 896 only */
-/*16*/  u_char    nc_mbox0;    /* 896 only */
-/*17*/  u_char    nc_mbox1;    /* 896 only */
+/*15*/  u_char    nc_istat1;   /* 896 and later cores only */
+        #define   FLSH    0x04  /* sta: chip is flushing            */
+        #define   SRUN    0x02  /* sta: scripts are running         */
+        #define   SIRQD   0x01  /* r/w: disable INT pin             */
+
+/*16*/  u_char    nc_mbox0;    /* 896 and later cores only */
+/*17*/  u_char    nc_mbox1;    /* 896 and later cores only */
 
 /*18*/ u_char    nc_ctest0;
 /*19*/  u_char    nc_ctest1;
index 6228059613092adc4530c8ae18cb1224752a63de..a81f29a20ae0813d50d5f7d6f92b2ecacc26c6cc 100644 (file)
@@ -1150,13 +1150,11 @@ static void fbcon_redraw(struct vc_data *conp, struct display *p,
                }
            }
            scr_writew(c, d);
-           console_conditional_schedule();
            s++;
            d++;
        } while (s < le);
        if (s > start)
            p->dispsw->putcs(conp, p, start, s - start, real_y(p, line), x);
-       console_conditional_schedule();
        if (offset > 0)
                line++;
        else {
index 7c93715d873c1ffb58dd4f387d1a9a461e3a35ea..a03dd6ade16002aff7cef107a234df6586ec6ab4 100644 (file)
@@ -562,7 +562,7 @@ void shrink_dcache_memory(int priority, unsigned int gfp_mask)
         * We should make sure we don't hold the superblock lock over
         * block allocations, but for now:
         */
-       if (!(gfp_mask & __GFP_IO))
+       if (!(gfp_mask & __GFP_FS))
                return;
 
        if (priority)
index eb92db84a07a481dfa9c0acc373c2b520db314be..1645c8043ba7528f4ad04f5d716fa614a459062b 100644 (file)
@@ -692,7 +692,7 @@ void shrink_icache_memory(int priority, int gfp_mask)
         * want to recurse into the FS that called us
         * in clear_inode() and friends..
         */
-       if (!(gfp_mask & __GFP_IO))
+       if (!(gfp_mask & __GFP_FS))
                return;
 
        if (priority)
index ce20e4989b20f9f4f1a36ded04042e1b66046c6e..9fff64fe6fecfa49cbd39ee315733ed79d9adb06 100644 (file)
@@ -142,10 +142,6 @@ struct rs_multiport_struct {
  */
 struct pci_dev;
 struct pci_board {
-       unsigned short vendor;
-       unsigned short device;
-       unsigned short subvendor;
-       unsigned short subdevice;
        int flags;
        int num_ports;
        int base_baud;
index e356977156fa1eb70ae878ed70b2b24c920c5ef1..3738697133d483c86d2e58d66940018a956bdcdd 100644 (file)
@@ -538,8 +538,8 @@ asmlinkage void __init start_kernel(void)
        trap_init();
        init_IRQ();
        sched_init();
-       time_init();
        softirq_init();
+       time_init();
 
        /*
         * HACK ALERT! This is early. We're enabling the console before
index 01e10608716f84a29e2b5dee08b0519b83013e64..5647e933608ede68e7d97a5fa031dc4768a65ce4 100644 (file)
@@ -613,7 +613,7 @@ page_active:
         * loads, flush out the dirty pages before we have to wait on
         * IO.
         */
-       if ((CAN_DO_IO || CAN_DO_FS) && !launder_loop && free_shortage()) {
+       if (CAN_DO_IO && !launder_loop && free_shortage()) {
                launder_loop = 1;
                /* If we cleaned pages, never do synchronous IO. */
                if (cleaned_pages)