]> git.neil.brown.name Git - history.git/commitdiff
Linux 2.1.95 2.1.95
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:15:10 +0000 (15:15 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:15:10 +0000 (15:15 -0500)
This is finally the kind of feature-freeze patch I like: it only contains
fixes for outright bugs. The fixes are:
 - SMP-safe disk drivers (more on this below)
 - various PCI fixes: /proc/bus/pci works again, and it should compile and
   work on Alpha with TGA.
 - parport interrupt detection uses the standard probe routines, and
   doesn't leave bogus "probe" entries hanging around to confuse people
   (and make other device registration fail)
 - the ever-popular PCI ne netdriver fix
 - the getcwd() system call works again.
 - "mb()" does the right thing on x86 too. Few drivers use it, but more of
   them should. Right now there are drivers that depend on luck making
   sure that the memory accesses will be in the same order outside the CPU
   as inside it.

The conceptually big one is the SMP-safe disk driver change: it's not a
very big patch, but it's fairly subtle. And it still requires help from
the disk drivers themselves, although all of them should be safe in UP,
and I made sure the BusLogic and the NCR driver are safe on SMP.
The change is really a change in locking defaults: we used to default to
no locking, and depended on the disk driver getting the locking right.
None of them did so on SMP, for understandable reasons (there really
wasn't any support for getting it right).

The new default is to do the locking for the driver, and the driver
actually has to do some work if it wants to do anything outside the lock.
This has the obvious advantage that it _defaults_ to being safe, and
people who know what they are doing can choose to thread the driver if
they want to.

The only change needed to drivers is to make sure they get the lock on an
interrupt, which usually involves just doing the following around the
low/level interrupt handler (the same handler that you register using
"request_irq()"):

        void handle_irq(int irq, void *dev, struct pt_regs *regs)
        {
+               unsigned long flags;
+               spin_lock_irqsave(&io_request_lock, flags);
                ... call to the proper action routines ...
+               spin_unlock_irqrestore(&io_request_lock, flags);
        }

which guarantees that everything inside the driver is correctly locked
from the outside world (with the exception of ioctl's etc things that the
driver traps - they need to be protected too).

                Linus

drivers/misc/parport_pc.c
drivers/scsi/eata.c
drivers/scsi/eata.h
drivers/scsi/u14-34f.c
drivers/scsi/u14-34f.h
include/asm-i386/system.h

index 89f38ff72716053e4ed1536df3aa8875c7fcfe29..5852b775dcf49ab15c19c5085b5370c135957e33 100644 (file)
@@ -641,61 +641,6 @@ static int parport_ECPPS2_supported(struct parport *pb)
 
 /* --- IRQ detection -------------------------------------- */
 
-/* This code is for detecting ECP interrupts (due to problems with the
- * monolithic interrupt probing routines).
- *
- * In short this is a voting system where the interrupt with the most
- * "votes" is the elected interrupt (it SHOULD work...)
- *
- * This is horribly x86-specific at the moment.  I'm not convinced it
- * belongs at all.
- */
-
-static int intr_vote[16];
-
-static void parport_vote_intr_func(int irq, void *dev_id, struct pt_regs *regs)
-{
-       intr_vote[irq]++;
-       return;
-}
-
-static long open_intr_election(void)
-{
-       long tmp = 0;
-       int i;
-
-       /* We ignore the timer - irq 0 */
-       for (i = 1; i < 16; i++) {
-               intr_vote[i] = 0;
-               if (request_irq(i, parport_vote_intr_func,
-                      SA_INTERRUPT, "probe", intr_vote) == 0)
-                       tmp |= 1 << i;
-       }
-       return tmp;
-}
-
-static int close_intr_election(long tmp)
-{
-       int irq = PARPORT_IRQ_NONE;
-       int i, valid = 1;
-
-       /* We ignore the timer - irq 0 */
-       for (i = 1; i < 16; i++)
-               if (tmp & (1 << i)) {
-                       if (intr_vote[i]) {
-                               if (irq != PARPORT_IRQ_NONE)
-                                       /* More than one interrupt */
-                                       valid = 0;
-                               irq = i;
-                       }
-                       free_irq(i, intr_vote);
-               }
-       if(valid)
-               return irq;
-       else
-               return PARPORT_IRQ_NONE;
-}
-
 /* Only if supports ECP mode */
 static int programmable_irq_support(struct parport *pb)
 {
@@ -717,20 +662,23 @@ static int programmable_irq_support(struct parport *pb)
 static int irq_probe_ECP(struct parport *pb)
 {
        int irqs, i;
-       unsigned char oecr = parport_pc_read_econtrol(pb);
                
-       probe_irq_off(probe_irq_on());  /* Clear any interrupts */
-       irqs = open_intr_election();
+       sti();
+       irqs = probe_irq_on();
                
-       parport_pc_write_econtrol(pb, 0x00);        /* Reset FIFO */
-       parport_pc_write_econtrol(pb, 0xd0);        /* TEST FIFO + nErrIntrEn */
+       parport_pc_write_econtrol(pb, 0x00);    /* Reset FIFO */
+       parport_pc_write_econtrol(pb, 0xd0);    /* TEST FIFO + nErrIntrEn */
 
        /* If Full FIFO sure that WriteIntrThresold is generated */
        for (i=0; i < 1024 && !(parport_pc_read_econtrol(pb) & 0x02) ; i++) 
                parport_pc_write_fifo(pb, 0xaa);
                
-       pb->irq = close_intr_election(irqs);
-       parport_pc_write_econtrol(pb, oecr);
+       pb->irq = probe_irq_off(irqs);
+       parport_pc_write_econtrol(pb, 0x00);
+
+       if (pb->irq <= 0)
+               pb->irq = PARPORT_IRQ_NONE;
+
        return pb->irq;
 }
 
@@ -748,26 +696,30 @@ static int irq_probe_EPP(struct parport *pb)
        return PARPORT_IRQ_NONE;
 #endif
        
-       probe_irq_off(probe_irq_on());  /* Clear any interrupts */
-       irqs = open_intr_election();
+       sti();
+       irqs = probe_irq_on();
 
        if (pb->modes & PARPORT_MODE_PCECR)
-               parport_pc_write_econtrol(pb, parport_pc_read_econtrol(pb) | 0x10);
+               parport_pc_frob_econtrol (pb, 0x10, 0x10);
        
        epp_clear_timeout(pb);
-       parport_pc_write_control(pb, parport_pc_read_control(pb) | 0x20);
-       parport_pc_write_control(pb, parport_pc_read_control(pb) | 0x10);
+       parport_pc_frob_control (pb, 0x20, 0x20);
+       parport_pc_frob_control (pb, 0x10, 0x10);
        epp_clear_timeout(pb);
 
-       /*  Device isn't expecting an EPP read
+       /* Device isn't expecting an EPP read
         * and generates an IRQ.
         */
        parport_pc_read_epp(pb);
        udelay(20);
 
-       pb->irq = close_intr_election(irqs);
+       pb->irq = probe_irq_off (irqs);
        parport_pc_write_econtrol(pb, oecr);
        parport_pc_write_control(pb, octr);
+
+       if (pb->irq <= 0)
+               pb->irq = PARPORT_IRQ_NONE;
+
        return pb->irq;
 }
 
@@ -818,16 +770,19 @@ static int irq_probe_SPP(struct parport *pb)
  */
 static int parport_irq_probe(struct parport *pb)
 {
-       if (pb->modes & PARPORT_MODE_PCECR)
+       unsigned char oecr = parport_pc_read_econtrol (pb);
+
+       if (pb->modes & PARPORT_MODE_PCECR) {
                pb->irq = programmable_irq_support(pb);
+               if (pb->irq != PARPORT_IRQ_NONE)
+                       goto out;
+       }
 
        if (pb->modes & PARPORT_MODE_PCECP)
                pb->irq = irq_probe_ECP(pb);
-                       
+
        if (pb->irq == PARPORT_IRQ_NONE && 
            (pb->modes & PARPORT_MODE_PCECPEPP)) {
-               unsigned char oecr = parport_pc_read_econtrol(pb);
-               parport_pc_write_econtrol(pb, 0x80);
                pb->irq = irq_probe_EPP(pb);
                parport_pc_write_econtrol(pb, oecr);
        }
@@ -842,6 +797,8 @@ static int parport_irq_probe(struct parport *pb)
        if (pb->irq == PARPORT_IRQ_NONE)
                pb->irq = irq_probe_SPP(pb);
 
+out:
+       parport_pc_write_econtrol (pb, oecr);
        return pb->irq;
 }
 
index 33c43e44cc0ac61e07f4df02c772bfeb85dd8562..86a29fd5d66e656dc2c1d3c5718eeecdf808c3d9 100644 (file)
@@ -1,6 +1,14 @@
 /*
  *      eata.c - Low-level driver for EATA/DMA SCSI host adapters.
  *   
+ *      10 Apr 1998 rev. 4.04 for linux 2.0.33 and 2.1.95
+ *          Improved SMP support (if linux version >= 2.1.95).
+ *
+ *       9 Apr 1998 rev. 4.03 for linux 2.0.33 and 2.1.94
+ *          Added support for new PCI code and IO-APIC remapping of irqs.
+ *          Performance improvement: when sequential i/o is detected,
+ *          always use direct sort instead of reverse sort.
+ *   
  *       4 Apr 1998 rev. 4.02 for linux 2.0.33 and 2.1.92
  *          io_port is now unsigned long.
  *
  *  the driver sets host->wish_block = TRUE for all ISA boards.
  */
 
+#include <linux/version.h>
+
 #define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
 #define MAX_INT_PARAM 10
+
 #if defined(MODULE)
 #include <linux/module.h>
-#include <linux/version.h>
+
 #if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,26)
 MODULE_PARM(io_port, "1-" __MODULE_STRING(MAX_INT_PARAM) "i");
 MODULE_PARM(linked_comm, "i");
@@ -294,6 +305,7 @@ MODULE_PARM(max_queue_depth, "i");
 MODULE_PARM(tag_mode, "i");
 MODULE_AUTHOR("Dario Ballabio");
 #endif
+
 #endif
 
 #include <linux/string.h>
@@ -314,9 +326,12 @@ MODULE_AUTHOR("Dario Ballabio");
 #include "eata.h"
 #include <linux/stat.h>
 #include <linux/config.h>
-#include <linux/bios32.h>
 #include <linux/pci.h>
 
+#if LINUX_VERSION_CODE < LinuxVersionCode(2,1,93)
+#include <linux/bios32.h>
+#endif
+
 #if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,36)
 #include <linux/init.h>
 #else
@@ -338,6 +353,7 @@ struct proc_dir_entry proc_scsi_eata2x = {
 
 #undef  DEBUG_LINKED_COMMANDS
 #undef  DEBUG_DETECT
+#undef  DEBUG_PCI_DETECT
 #undef  DEBUG_INTERRUPT
 #undef  DEBUG_RESET
 
@@ -583,7 +599,7 @@ static unsigned long io_port[] __initdata = {
 #define V2DEV(addr) ((addr) ? H2DEV(virt_to_bus((void *)addr)) : 0)
 #define DEV2V(addr) ((addr) ? DEV2H(bus_to_virt((unsigned long)addr)) : 0)
 
-static void eata2x_interrupt_handler(int, void *, struct pt_regs *);
+static void interrupt_handler(int, void *, struct pt_regs *);
 static void flush_dev(Scsi_Device *, unsigned long, unsigned int, unsigned int);
 static int do_trace = FALSE;
 static int setup_done = FALSE;
@@ -715,10 +731,48 @@ static inline int read_pio(unsigned long iobase, ushort *start, ushort *end) {
    return FALSE;
 }
 
+__initfunc (static inline int
+            get_pci_irq(unsigned long port_base, unsigned char *apic_irq)) {
+
+#if defined(CONFIG_PCI)
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,93)
+
+   unsigned int addr;
+   struct pci_dev *dev = NULL;
+
+   if (!pci_present()) return FALSE;
+
+   while((dev = pci_find_class(PCI_CLASS_STORAGE_SCSI << 8, dev))) {
+
+      if (pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &addr)) continue;
+
+#if defined(DEBUG_PCI_DETECT)
+      printk("%s: get_pci_irq, bus %d, devfn 0x%x, addr 0x%x, apic_irq %u.\n",
+             driver_name, dev->bus->number, dev->devfn, addr, dev->irq);
+#endif
+
+      if ((addr & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO)
+             continue;
+
+      if ((addr & PCI_BASE_ADDRESS_IO_MASK) + PCI_BASE_ADDRESS_0 == port_base) {
+         *apic_irq = dev->irq;
+         return TRUE;
+         }
+
+      }
+
+#endif /* end new style PCI code */
+
+#endif /* end CONFIG_PCI */
+
+   return FALSE;
+}
+
 __initfunc (static inline int port_detect \
       (unsigned long port_base, unsigned int j, Scsi_Host_Template *tpnt)) {
    unsigned char irq, dma_channel, subversion, i;
-   unsigned char protocol_rev;
+   unsigned char protocol_rev, apic_irq;
    struct eata_info info;
    char *bus_type, dma_name[16], tag_type;
 
@@ -812,8 +866,13 @@ __initfunc (static inline int port_detect \
       printk("%s: warning, LEVEL triggering is suggested for IRQ %u.\n",
              name, irq);
 
+   if (get_pci_irq(port_base, &apic_irq) && (irq != apic_irq)) {
+      printk("%s: IRQ %u mapped to IO-APIC IRQ %u.\n", name, irq, apic_irq);
+      irq = apic_irq;
+      }
+
    /* Board detected, allocate its IRQ */
-   if (request_irq(irq, eata2x_interrupt_handler,
+   if (request_irq(irq, interrupt_handler,
              SA_INTERRUPT | ((subversion == ESA) ? SA_SHIRQ : 0),
              driver_name, (void *) &sha[j])) {
       printk("%s: unable to allocate IRQ %u, detaching.\n", name, irq);
@@ -1016,12 +1075,40 @@ __initfunc (static void add_pci_ports(void)) {
 
 #if defined(CONFIG_PCI)
 
-   unsigned short i = 0;
-   unsigned char bus, devfn;
    unsigned int addr, k;
 
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,93)
+
+   struct pci_dev *dev = NULL;
+
    if (!pci_present()) return;
 
+   for (k = 0; k < MAX_PCI; k++) {
+
+      if (!(dev = pci_find_class(PCI_CLASS_STORAGE_SCSI << 8, dev))) break;
+
+      if (pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &addr)) continue;
+
+#if defined(DEBUG_PCI_DETECT)
+      printk("%s: detect, seq. %d, bus %d, devfn 0x%x, addr 0x%x.\n",
+             driver_name, k, dev->bus->number, dev->devfn, addr);
+#endif
+
+      if ((addr & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO)
+             continue;
+
+      /* Reverse the returned address order */
+      io_port[MAX_INT_PARAM + MAX_PCI - k] = 
+             (addr & PCI_BASE_ADDRESS_IO_MASK) + PCI_BASE_ADDRESS_0;
+      }
+
+#else  /* else old style PCI code */
+
+   unsigned short i = 0;
+   unsigned char bus, devfn;
+
+   if (!pcibios_present()) return;
+
    for (k = 0; k < MAX_PCI; k++) {
 
       if (pcibios_find_class(PCI_CLASS_STORAGE_SCSI << 8, i++, &bus, &devfn)
@@ -1030,7 +1117,7 @@ __initfunc (static void add_pci_ports(void)) {
       if (pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, &addr)
              != PCIBIOS_SUCCESSFUL) continue;
 
-#if defined(DEBUG_DETECT)
+#if defined(DEBUG_PCI_DETECT)
       printk("%s: detect, seq. %d, bus %d, devfn 0x%x, addr 0x%x.\n",
              driver_name, k, bus, devfn, addr);
 #endif
@@ -1042,7 +1129,10 @@ __initfunc (static void add_pci_ports(void)) {
       io_port[MAX_INT_PARAM + MAX_PCI - k] = 
              (addr & PCI_BASE_ADDRESS_IO_MASK) + PCI_BASE_ADDRESS_0;
       }
-#endif
+
+#endif /* end old style PCI code */
+
+#endif /* end CONFIG_PCI */
 
    return;
 }
@@ -1523,6 +1613,7 @@ static inline void reorder(unsigned int j, unsigned long cursec,
    unsigned int input_only = TRUE, overlap = FALSE;
    unsigned long sl[n_ready], pl[n_ready], ll[n_ready];
    unsigned long maxsec = 0, minsec = ULONG_MAX, seek = 0, iseek = 0;
+   unsigned long ioseek = 0;
 
    static unsigned int flushcount = 0, batchcount = 0, sortcount = 0;
    static unsigned int readycount = 0, ovlcount = 0, inputcount = 0;
@@ -1547,6 +1638,7 @@ static inline void reorder(unsigned int j, unsigned long cursec,
       if (SCpnt->request.sector > maxsec) maxsec = SCpnt->request.sector;
 
       sl[n] = SCpnt->request.sector;
+      ioseek += SCpnt->request.nr_sectors;
 
       if (!n) continue;
 
@@ -1568,6 +1660,8 @@ static inline void reorder(unsigned int j, unsigned long cursec,
 
    if (cursec > ((maxsec + minsec) / 2)) rev = TRUE;
 
+   if (ioseek > ((maxsec - minsec) / 2)) rev = FALSE;
+
    if (!((rev && r) || (!rev && s))) sort(sl, il, n_ready, rev);
 
    if (!input_only) for (n = 0; n < n_ready; n++) {
@@ -1644,8 +1738,7 @@ static void flush_dev(Scsi_Device *dev, unsigned long cursec, unsigned int j,
 
 }
 
-static void eata2x_interrupt_handler(int irq, void *shap,
-                                     struct pt_regs *regs) {
+static inline void ihdlr(int irq, void *shap, struct pt_regs *regs) {
    Scsi_Cmnd *SCpnt;
    unsigned int i, j, k, c, status, tstatus, reg;
    unsigned int n, n_ready, il[MAX_MAILBOXES];
@@ -1703,7 +1796,8 @@ static void eata2x_interrupt_handler(int irq, void *shap,
       else if (HD(j)->cp_stat[i] == IN_RESET)
          printk("%s: ihdlr, mbox %d is in reset.\n", BN(j), i);
       else if (HD(j)->cp_stat[i] != IN_USE) 
-         panic("%s: ihdlr, mbox %d, invalid cp_stat.\n", BN(j), i);
+         panic("%s: ihdlr, mbox %d, invalid cp_stat: %d.\n", 
+               BN(j), i, HD(j)->cp_stat[i]);
 
       HD(j)->cp_stat[i] = FREE;
       cpp = &HD(j)->cp[i];
@@ -1841,6 +1935,22 @@ static void eata2x_interrupt_handler(int irq, void *shap,
    return;
 }
 
+static void interrupt_handler(int irq, void *shap, struct pt_regs *regs) {
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,95)
+
+   unsigned long flags;
+   spin_lock_irqsave(&io_request_lock, flags);
+   ihdlr(irq, shap, regs);
+   spin_unlock_irqrestore(&io_request_lock, flags);
+
+#else
+
+   ihdlr(irq, shap, regs);
+
+#endif
+}
+
 int eata2x_release(struct Scsi_Host *shpnt) {
    unsigned long flags;
    unsigned int i, j;
index 3322a5eb512e9967b380af1c857ad3b92202f358..738f71ba2992214616187e889f1b01190ded3bf3 100644 (file)
@@ -5,6 +5,7 @@
 #define _EATA_H
 
 #include <scsi/scsicam.h>
+#include <linux/version.h>
 
 int eata2x_detect(Scsi_Host_Template *);
 int eata2x_release(struct Scsi_Host *);
@@ -12,7 +13,7 @@ int eata2x_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
 int eata2x_abort(Scsi_Cmnd *);
 int eata2x_reset(Scsi_Cmnd *, unsigned int);
 
-#define EATA_VERSION "4.02.00"
+#define EATA_VERSION "4.04.00"
 
 #define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
 
index 0095a6b0759b32211480dc600155b5a2f3085103..c55d80b93eb8f7b2f1354960adf4d742de15d22c 100644 (file)
@@ -1,6 +1,13 @@
 /*
  *      u14-34f.c - Low-level driver for UltraStor 14F/34F SCSI host adapters.
  *
+ *      10 Apr 1998 rev. 4.04 for linux 2.0.33 and 2.1.95
+ *          Improved SMP support (if linux version >= 2.1.95).
+ *
+ *       9 Apr 1998 rev. 4.03 for linux 2.0.33 and 2.1.94
+ *          Performance improvement: when sequential i/o is detected,
+ *          always use direct sort instead of reverse sort.
+ *   
  *       4 Apr 1998 rev. 4.02 for linux 2.0.33 and 2.1.92
  *          io_port is now unsigned long.
  *
  *  the driver sets host->wish_block = TRUE for all ISA boards.
  */
 
+#include <linux/version.h>
+
 #define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
 #define MAX_INT_PARAM 10
+
 #if defined(MODULE)
 #include <linux/module.h>
-#include <linux/version.h>
+
 #if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,26)
 MODULE_PARM(io_port, "1-" __MODULE_STRING(MAX_INT_PARAM) "i");
 MODULE_PARM(linked_comm, "i");
@@ -279,6 +289,7 @@ MODULE_PARM(link_statistics, "i");
 MODULE_PARM(max_queue_depth, "i");
 MODULE_AUTHOR("Dario Ballabio");
 #endif
+
 #endif
 
 #include <linux/string.h>
@@ -483,7 +494,7 @@ static unsigned long io_port[] __initdata = {
 #define V2DEV(addr) ((addr) ? H2DEV(virt_to_bus((void *)addr)) : 0)
 #define DEV2V(addr) ((addr) ? DEV2H(bus_to_virt((unsigned long)addr)) : 0)
 
-static void u14_34f_interrupt_handler(int, void *, struct pt_regs *);
+static void interrupt_handler(int, void *, struct pt_regs *);
 static void flush_dev(Scsi_Device *, unsigned long, unsigned int, unsigned int);
 static int do_trace = FALSE;
 static int setup_done = FALSE;
@@ -683,7 +694,7 @@ __initfunc (static inline int port_detect \
    subversion = (in_byte & 0x0f);
 
    /* Board detected, allocate its IRQ */
-   if (request_irq(irq, u14_34f_interrupt_handler,
+   if (request_irq(irq, interrupt_handler,
              SA_INTERRUPT | ((subversion == ESA) ? SA_SHIRQ : 0),
              driver_name, (void *) &sha[j])) {
       printk("%s: unable to allocate IRQ %u, detaching.\n", name, irq);
@@ -1309,6 +1320,7 @@ static inline void reorder(unsigned int j, unsigned long cursec,
    unsigned int input_only = TRUE, overlap = FALSE;
    unsigned long sl[n_ready], pl[n_ready], ll[n_ready];
    unsigned long maxsec = 0, minsec = ULONG_MAX, seek = 0, iseek = 0;
+   unsigned long ioseek = 0;
 
    static unsigned int flushcount = 0, batchcount = 0, sortcount = 0;
    static unsigned int readycount = 0, ovlcount = 0, inputcount = 0;
@@ -1333,6 +1345,7 @@ static inline void reorder(unsigned int j, unsigned long cursec,
       if (SCpnt->request.sector > maxsec) maxsec = SCpnt->request.sector;
 
       sl[n] = SCpnt->request.sector;
+      ioseek += SCpnt->request.nr_sectors;
 
       if (!n) continue;
 
@@ -1354,6 +1367,8 @@ static inline void reorder(unsigned int j, unsigned long cursec,
 
    if (cursec > ((maxsec + minsec) / 2)) rev = TRUE;
 
+   if (ioseek > ((maxsec - minsec) / 2)) rev = FALSE;
+
    if (!((rev && r) || (!rev && s))) sort(sl, il, n_ready, rev);
 
    if (!input_only) for (n = 0; n < n_ready; n++) {
@@ -1431,8 +1446,7 @@ static void flush_dev(Scsi_Device *dev, unsigned long cursec, unsigned int j,
       }
 }
 
-static void u14_34f_interrupt_handler(int irq, void *shap,
-                                               struct pt_regs *regs) {
+static inline void ihdlr(int irq, void *shap, struct pt_regs *regs) {
    Scsi_Cmnd *SCpnt;
    unsigned int i, j, k, c, status, tstatus, reg, ret;
    struct mscp *spp;
@@ -1479,7 +1493,8 @@ static void u14_34f_interrupt_handler(int irq, void *shap,
    else if (HD(j)->cp_stat[i] == IN_RESET)
       printk("%s: ihdlr, mbox %d is in reset.\n", BN(j), i);
    else if (HD(j)->cp_stat[i] != IN_USE) 
-      panic("%s: ihdlr, mbox %d, invalid cp_stat.\n", BN(j), i);
+      panic("%s: ihdlr, mbox %d, invalid cp_stat: %d.\n", 
+            BN(j), i, HD(j)->cp_stat[i]);
 
    HD(j)->cp_stat[i] = FREE;
    SCpnt = spp->SCpnt;
@@ -1610,6 +1625,22 @@ static void u14_34f_interrupt_handler(int irq, void *shap,
    return;
 }
 
+static void interrupt_handler(int irq, void *shap, struct pt_regs *regs) {
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,95)
+
+   unsigned long flags;
+   spin_lock_irqsave(&io_request_lock, flags);
+   ihdlr(irq, shap, regs);
+   spin_unlock_irqrestore(&io_request_lock, flags);
+
+#else
+
+   ihdlr(irq, shap, regs);
+
+#endif
+}
+
 int u14_34f_release(struct Scsi_Host *shpnt) {
    unsigned long flags;
    unsigned int i, j;
index 7420b6fc60d2d914d1ba3244c686f14a95258ce4..bf52c3d9da2d5c8436ea030ef1d72890da0d4dc2 100644 (file)
@@ -4,6 +4,8 @@
 #ifndef _U14_34F_H
 #define _U14_34F_H
 
+#include <linux/version.h>
+
 int u14_34f_detect(Scsi_Host_Template *);
 int u14_34f_release(struct Scsi_Host *);
 int u14_34f_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
@@ -11,7 +13,7 @@ int u14_34f_abort(Scsi_Cmnd *);
 int u14_34f_reset(Scsi_Cmnd *, unsigned int);
 int u14_34f_biosparam(Disk *, kdev_t, int *);
 
-#define U14_34F_VERSION "4.02.00"
+#define U14_34F_VERSION "4.04.00"
 
 #define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
 
index e940c7c6f222f963a00105df5e8f0b8085a94d95..a19d724764e26f94aebbf0af346ed5569b54657b 100644 (file)
@@ -215,7 +215,12 @@ static inline unsigned long __xchg(unsigned long x, void * ptr, int size)
        return x;
 }
 
-#define mb()  __asm__ __volatile__ (""   : : :"memory")
+/*
+ * Force strict CPU ordering.
+ * And yes, this is required on UP too when we're talking
+ * to devices.
+ */
+#define mb()   __asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory")
 
 /* interrupt control.. */
 #define __sti() __asm__ __volatile__ ("sti": : :"memory")