patch-2.0.31 linux/drivers/scsi/eata.c

Next file: linux/drivers/scsi/eata.h
Previous file: linux/drivers/scsi/dc390.h
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.0.30/linux/drivers/scsi/eata.c linux/drivers/scsi/eata.c
@@ -1,5 +1,21 @@
 /*
  *      eata.c - Low-level driver for EATA/DMA SCSI host adapters.
+ *   
+ *      12 Sep 1997 rev. 3.11 for linux 2.0.30 and 2.1.55
+ *          Use of udelay inside the wait loops to avoid timeout
+ *          problems with fast cpus.
+ *          Removed check about useless calls to the interrupt service
+ *          routine (reported on SMP systems only).
+ *          At initialization time "sorted/unsorted" is displayed instead
+ *          of "linked/unlinked" to reinforce the fact that "linking" is
+ *          nothing but "elevator sorting" in the actual implementation.
+ *
+ *      17 May 1997 rev. 3.10 for linux 2.0.30 and 2.1.38
+ *          Use of serial_number_at_timeout in abort and reset processing.
+ *          Use of the __initfunc and __initdata macro in setup code.
+ *          Minor cleanups in the list_statistics code.
+ *          Increased controller busy timeout in order to better support 
+ *          slow SCSI devices.
  *
  *      24 Feb 1997 rev. 3.00 for linux 2.0.29 and 2.1.26
  *          When loading as a module, parameter passing is now supported
@@ -202,8 +218,7 @@
  *  lc:n  disables linked commands;
  *  tc:y  enables tagged commands;
  *  tc:n  disables tagged commands;
- *  tm:0  use head/simple/ordered queue tag sequences for reads and ordered
- *        queue tags for writes;
+ *  tm:0  use head/simple/ordered queue tag sequences;
  *  tm:1  use only simple queue tags;
  *  tm:2  use only head of queue tags;
  *  tm:3  use only ordered queue tags;
@@ -232,10 +247,12 @@
  *  between increasing or decreasing by minimizing the seek distance between
  *  the sector of the commands just completed and the sector of the first 
  *  command in the list to be sorted. 
- *  Trivial math assures that if there are (Q-1) outstanding request for
- *  random seeks over S sectors, the unsorted average seek distance is S/2,
- *  while the sorted average seek distance is S/(Q-1). The seek distance is
- *  hence divided by a factor (Q-1)/2.
+ *  Trivial math assures that the unsorted average seek distance when doing
+ *  random seeks over S sectors is S/3.
+ *  When (Q-1) requests are uniformly distributed over S sectors, the average
+ *  distance between two adjacent requests is S/((Q-1) + 1), so the sorted
+ *  average seek distance for (Q-1) random requests over S sectors is S/Q.
+ *  The elevator sorting hence divides the seek distance by a factor Q/3.
  *  The above pure geometric remarks are valid in all cases and the 
  *  driver effectively reduces the seek distance by the predicted factor
  *  when there are Q concurrent read i/o operations on the device, but this
@@ -275,6 +292,7 @@
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/ioport.h>
+#include <linux/delay.h>
 #include <asm/io.h>
 #include <asm/system.h>
 #include <asm/byteorder.h>
@@ -286,10 +304,18 @@
 #include <asm/dma.h>
 #include <asm/irq.h>
 #include "eata.h"
-#include<linux/stat.h>
-#include<linux/config.h>
-#include<linux/bios32.h>
-#include<linux/pci.h>
+#include <linux/stat.h>
+#include <linux/config.h>
+#include <linux/bios32.h>
+#include <linux/pci.h>
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,36)
+#include <linux/init.h>
+#else
+#define __initfunc(A) A
+#define __initdata
+#define __init
+#endif
 
 struct proc_dir_entry proc_scsi_eata2x = {
     PROC_SCSI_EATA2X, 6, "eata2x",
@@ -307,6 +333,7 @@
 #undef  DEBUG_INTERRUPT
 #undef  DEBUG_STATISTICS
 #undef  DEBUG_RESET
+#undef  DEBUG_SMP
 
 #define MAX_ISA 4
 #define MAX_VESA 0 
@@ -335,7 +362,7 @@
 #define READY    5
 #define ABORTING 6
 #define NO_DMA  0xff
-#define MAXLOOP 200000
+#define MAXLOOP  10000
 #define TAG_MIXED    0
 #define TAG_SIMPLE   1
 #define TAG_HEAD     2
@@ -517,7 +544,7 @@
 static const char *driver_name = "EATA";
 static unsigned int irqlist[MAX_IRQ], calls[MAX_IRQ];
 
-static unsigned int io_port[] = { 
+static unsigned int io_port[] __initdata = { 
 
    /* Space for MAX_INT_PARAM ports usable while loading as a module */
    SKIP,    SKIP,   SKIP,   SKIP,   SKIP,   SKIP,   SKIP,   SKIP,
@@ -614,9 +641,9 @@
 
       if (TLDEV(dev->type)) {
          if (linked_comm && dev->queue_depth > 2)
-            link_suffix = ", linked";
+            link_suffix = ", sorted";
          else
-            link_suffix = ", unlinked";
+            link_suffix = ", unsorted";
          }
 
       if (tagged_comm && dev->tagged_supported && TLDEV(dev->type)) {
@@ -638,18 +665,19 @@
    return;
 }
 
-static inline int wait_on_busy(unsigned int iobase) {
-   unsigned int loop = MAXLOOP;
+static inline int wait_on_busy(unsigned int iobase, unsigned int loop) {
 
-   while (inb(iobase + REG_AUX_STATUS) & ABSY_ASSERTED)
+   while (inb(iobase + REG_AUX_STATUS) & ABSY_ASSERTED) {
+      udelay(1L);
       if (--loop == 0) return TRUE;
+      }
 
    return FALSE;
 }
 
 static inline int do_dma(unsigned int iobase, unsigned int addr, unchar cmd) {
 
-   if (wait_on_busy(iobase)) return TRUE;
+   if (wait_on_busy(iobase, (addr ? MAXLOOP * 100 : MAXLOOP))) return TRUE;
 
    if ((addr = V2DEV(addr))) {
       outb((char) (addr >> 24), iobase + REG_LOW);
@@ -668,8 +696,10 @@
 
    for (p = start; p <= end; p++) {
 
-      while (!(inb(iobase + REG_STATUS) & DRQ_ASSERTED)) 
+      while (!(inb(iobase + REG_STATUS) & DRQ_ASSERTED)) {
+         udelay(1L);
 	 if (--loop == 0) return TRUE;
+         }
 
       loop = MAXLOOP;
       *p = inw(iobase);
@@ -678,8 +708,8 @@
    return FALSE;
 }
 
-static inline int port_detect(unsigned int port_base, unsigned int j, 
-			      Scsi_Host_Template *tpnt) {
+__initfunc (static inline int port_detect \
+      (unsigned int port_base, unsigned int j, Scsi_Host_Template *tpnt)) {
    unsigned char irq, dma_channel, subversion, i;
    unsigned char protocol_rev;
    struct eata_info info;
@@ -882,7 +912,7 @@
          sh[j]->max_lun = info.max_lun + 1;
       }
 
-   if (dma_channel == NO_DMA) sprintf(dma_name, "%s", "NO DMA");
+   if (dma_channel == NO_DMA) sprintf(dma_name, "%s", "BMST");
    else                       sprintf(dma_name, "DMA %u", dma_channel);
 
    for (i = 0; i < sh[j]->can_queue; i++)
@@ -941,7 +971,7 @@
    return TRUE;
 }
 
-void eata2x_setup(char *str, int *ints) {
+__initfunc (void eata2x_setup(char *str, int *ints)) {
    int i, argc = ints[0];
    char *cur = str, *pc;
 
@@ -974,7 +1004,7 @@
    return;
 }
 
-static void add_pci_ports(void) {
+__initfunc (static void add_pci_ports(void)) {
 
 #if defined(CONFIG_PCI)
 
@@ -1009,7 +1039,7 @@
    return;
 }
 
-int eata2x_detect(Scsi_Host_Template *tpnt) {
+__initfunc (int eata2x_detect(Scsi_Host_Template *tpnt)) {
    unsigned long flags;
    unsigned int j = 0, k;
 
@@ -1166,6 +1196,9 @@
 
    cpp->reqsen = TRUE;
    cpp->dispri = TRUE;
+#if 0
+   if (SCpnt->device->type == TYPE_TAPE) cpp->hbaci = TRUE;
+#endif
    cpp->one = TRUE;
    cpp->channel = SCpnt->channel;
    cpp->target = SCpnt->target;
@@ -1182,14 +1215,12 @@
       else if (tag_mode == TAG_SIMPLE)  cpp->mess[0] = SIMPLE_QUEUE_TAG;
       else if (tag_mode == TAG_HEAD)    cpp->mess[0] = HEAD_OF_QUEUE_TAG;
       else if (tag_mode == TAG_ORDERED) cpp->mess[0] = ORDERED_QUEUE_TAG;
-      else if ((SCpnt->device->current_tag % SCpnt->device->queue_depth) == 0)
+      else if (SCpnt->device->current_tag == 0)
          cpp->mess[0] = ORDERED_QUEUE_TAG;
-      else if ((SCpnt->device->current_tag % SCpnt->device->queue_depth) == 1)
+      else if (SCpnt->device->current_tag == 1)
          cpp->mess[0] = HEAD_OF_QUEUE_TAG;
-      else if (cpp->din)
-         cpp->mess[0] = SIMPLE_QUEUE_TAG;
       else
-         cpp->mess[0] = ORDERED_QUEUE_TAG;
+         cpp->mess[0] = SIMPLE_QUEUE_TAG;
 
       cpp->mess[1] = SCpnt->device->current_tag++;
       }
@@ -1208,7 +1239,7 @@
    if (linked_comm && SCpnt->device->queue_depth > 2
                                      && TLDEV(SCpnt->device->type)) {
       HD(j)->cp_stat[i] = READY;
-      flush_dev(SCpnt->device, 0, j, FALSE);
+      flush_dev(SCpnt->device, SCpnt->request.sector, j, FALSE);
       restore_flags(flags);
       return 0;
       }
@@ -1238,7 +1269,8 @@
    cli();
    j = ((struct hostdata *) SCarg->host->hostdata)->board_number;
 
-   if (SCarg->host_scribble == NULL) {
+   if (SCarg->host_scribble == NULL
+       || SCarg->serial_number != SCarg->serial_number_at_timeout) {
       printk("%s: abort, target %d.%d:%d, pid %ld inactive.\n",
 	     BN(j), SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid);
       restore_flags(flags);
@@ -1252,7 +1284,7 @@
    if (i >= sh[j]->can_queue)
       panic("%s: abort, invalid SCarg->host_scribble.\n", BN(j));
 
-   if (wait_on_busy(sh[j]->io_port)) {
+   if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
       printk("%s: abort, timeout error.\n", BN(j));
       restore_flags(flags);
       return SCSI_ABORT_ERROR;
@@ -1321,13 +1353,19 @@
    if (SCarg->host_scribble == NULL)
       printk("%s: reset, pid %ld inactive.\n", BN(j), SCarg->pid);
 
+   if (SCarg->serial_number != SCarg->serial_number_at_timeout) {
+      printk("%s: reset, pid %ld, reset not running.\n", BN(j), SCarg->pid);
+      restore_flags(flags);
+      return SCSI_RESET_NOT_RUNNING;
+      }
+
    if (HD(j)->in_reset) {
       printk("%s: reset, exit, already in reset.\n", BN(j));
       restore_flags(flags);
       return SCSI_RESET_ERROR;
       }
 
-   if (wait_on_busy(sh[j]->io_port)) {
+   if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
       printk("%s: reset, exit, timeout error.\n", BN(j));
       restore_flags(flags);
       return SCSI_RESET_ERROR;
@@ -1393,7 +1431,7 @@
    HD(j)->in_reset = TRUE;
    sti();
    time = jiffies;
-   while ((jiffies - time) < HZ && limit++ < 100000000);
+   while ((jiffies - time) < (10 * HZ) && limit++ < 200000) udelay(100L);
    cli();
    printk("%s: reset, interrupts disabled, loops %d.\n", BN(j), limit);
 
@@ -1480,7 +1518,7 @@
    unsigned int rev = FALSE, s = TRUE, r = TRUE;
    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;
+   unsigned long maxsec = 0, minsec = ULONG_MAX, seek = 0, iseek = 0;
 
    static unsigned int flushcount = 0, batchcount = 0, sortcount = 0;
    static unsigned int readycount = 0, ovlcount = 0, inputcount = 0;
@@ -1491,8 +1529,8 @@
       printk("fc %d bc %d ic %d oc %d rc %d rs %d sc %d re %d"\
              " av %ldK as %ldK.\n", flushcount, batchcount, inputcount,
              ovlcount, readycount, readysorted, sortcount, revcount,
-             seeknosort / (readycount - batchcount + 1), 
-             seeksorted / (readycount - batchcount + 1));
+             seeknosort / (readycount + 1), 
+             seeksorted / (readycount + 1));
 
    if (n_ready <= 1) return;
 
@@ -1520,6 +1558,10 @@
 
       }
 
+   if (link_statistics) {
+      if (cursec > sl[0]) seek += cursec - sl[0]; else seek += sl[0] - cursec;
+      }
+
    if (cursec > ((maxsec + minsec) / 2)) rev = TRUE;
 
    if (!((rev && r) || (!rev && s))) sort(sl, il, n_ready, rev);
@@ -1537,10 +1579,11 @@
    if (overlap) sort(pl, il, n_ready, FALSE);
 
    if (link_statistics) {
+      if (cursec > sl[0]) iseek = cursec - sl[0]; else iseek = sl[0] - cursec;
       batchcount++; readycount += n_ready, seeknosort += seek / 1024; 
       if (input_only) inputcount++;
       if (overlap) { ovlcount++; seeksorted += seek / 1024; }
-      else seeksorted += (maxsec - minsec) / 1024;
+      else seeksorted += (iseek + maxsec - minsec) / 1024;
       if (rev && !r)     {  revcount++; readysorted += n_ready; }
       if (!rev && !s)    { sortcount++; readysorted += n_ready; }
       }
@@ -1803,9 +1846,11 @@
 
    calls[irq]++;
 
+#if defined (DEBUG_SMP)
    if (total_loops == 0) 
      printk("%s: ihdlr, irq %d, no command completed, calls %d.\n",
 	    driver_name, irq, calls[irq]);
+#endif
 
    if (do_trace) printk("%s: ihdlr, exit, irq %d, calls %d.\n", 
 			driver_name, irq, calls[irq]);

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov