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

Next file: linux-2.4.20/drivers/scsi/eata.h
Previous file: linux-2.4.20/drivers/scsi/dpt_i2o.c
Back to the patch index
Back to the overall index

diff -urN linux-2.4.19/drivers/scsi/eata.c linux-2.4.20/drivers/scsi/eata.c
@@ -1,9 +1,45 @@
 /*
  *      eata.c - Low-level driver for EATA/DMA SCSI host adapters.
  *
- *      01 Jan 2002 Rev. 6.50 for linux 2.4.16
+ *      25 Jun 2002 Rev. 6.70 for linux 2.4.19
+ *        + This release is the first one tested on a Big Endian platform:
+ *          fixed endian-ness problem due to bitfields;
+ *          fixed endian-ness problem in read_pio.
+ *        + Added new options for selectively probing ISA, EISA and PCI bus:
+ *
+ *          Boot option   Parameter name    Default according to
+ *
+ *          ip:[y|n]      isa_probe=[1|0]   CONFIG_ISA  defined
+ *          ep:[y|n]      eisa_probe=[1|0]  CONFIG_EISA defined
+ *          pp:[y|n]      pci_probe=[1|0]   CONFIG_PCI  defined
+ *
+ *          The default action is to perform probing if the corrisponding
+ *          bus is configured and to skip probing otherwise.
+ *
+ *        + If pci_probe is in effect and a list of I/O  ports is specified
+ *          as parameter or boot option, pci_enable_device() is performed
+ *          on all pci devices matching PCI_CLASS_STORAGE_SCSI.
+ *
+ *      21 Feb 2002 Rev. 6.52 for linux 2.4.18
+ *        + Backport from rev. 7.22 (use io_request_lock).
+ *
+ *      20 Feb 2002 Rev. 7.22 for linux 2.5.5
+ *        + Remove any reference to virt_to_bus().
+ *        + Fix pio hang while detecting multiple HBAs.
+ *        + Fixed a board detection bug: in a system with
+ *          multiple ISA/EISA boards, all but the first one
+ *          were erroneously detected as PCI.
+ *
+ *      01 Jan 2002 Rev. 7.20 for linux 2.5.1
  *        + Use the dynamic DMA mapping API.
  *
+ *      19 Dec 2001 Rev. 7.02 for linux 2.5.1
+ *        + Use SCpnt->sc_data_direction if set.
+ *        + Use sglist.page instead of sglist.address.
+ *
+ *      11 Dec 2001 Rev. 7.00 for linux 2.5.1
+ *        + Use host->host_lock instead of io_request_lock.
+ *
  *       1 May 2001 Rev. 6.05 for linux 2.4.4
  *        + Clean up all pci related routines.
  *        + Fix data transfer direction for opcode SEND_CUE_SHEET (0x5d)
@@ -22,7 +58,7 @@
  *          boot time.
  *        + Improved boot messages: all tagged capable device are
  *          indicated as "tagged" or "soft-tagged" :
- *          - "soft-tagged"  means that the driver is trying to do its 
+ *          - "soft-tagged"  means that the driver is trying to do its
  *            own tagging (i.e. the tc:y option is in effect);
  *          - "tagged" means that the device supports tagged commands,
  *            but the driver lets the HBA be responsible for tagging
@@ -33,7 +69,7 @@
  *        + When loaded as a module, accepts the new parameter boot_options
  *          which value is a string with the same format of the kernel boot
  *          command line options. A valid example is:
- *          modprobe eata boot_options=\"0x7410,0x230,lc:y,tc:n,mq:4\"
+ *          modprobe eata 'boot_options="0x7410,0x230,lc:y,tc:n,mq:4"'
  *
  *       9 Sep 1999 Rev. 5.10 for linux 2.2.12 and 2.3.17
  *        + 64bit cleanup for Linux/Alpha platform support
@@ -297,7 +333,7 @@
  *  include in the list of i/o ports to be probed all the PCI SCSI controllers.
  *
  *  Due to a DPT BIOS "feature", it might not be possible to force an EISA
- *  address on more then a single DPT PCI board, so in this case you have to
+ *  address on more than a single DPT PCI board, so in this case you have to
  *  let the PCI BIOS assign the addresses.
  *
  *  The sequence of detection probes is:
@@ -414,6 +450,9 @@
 MODULE_PARM(tag_mode, "i");
 MODULE_PARM(ext_tran, "i");
 MODULE_PARM(rev_scan, "i");
+MODULE_PARM(isa_probe, "i");
+MODULE_PARM(eisa_probe, "i");
+MODULE_PARM(pci_probe, "i");
 MODULE_AUTHOR("Dario Ballabio");
 
 #endif
@@ -441,11 +480,15 @@
 #include <linux/ctype.h>
 #include <linux/spinlock.h>
 
+#if !defined(__BIG_ENDIAN_BITFIELD) && !defined(__LITTLE_ENDIAN_BITFIELD)
+#error "Adjust your <asm/byteorder.h> defines"
+#endif
+
 /* Subversion values */
 #define ISA  0
 #define ESA 1
 
-#undef FORCE_CONFIG
+#undef  FORCE_CONFIG
 
 #undef  DEBUG_LINKED_COMMANDS
 #undef  DEBUG_DETECT
@@ -498,7 +541,7 @@
 #define REG_LM          3
 #define REG_MID         4
 #define REG_MSB         5
-#define REGION_SIZE     9
+#define REGION_SIZE     9UL
 #define MAX_ISA_ADDR    0x03ff
 #define MIN_EISA_ADDR   0x1c88
 #define MAX_EISA_ADDR   0xfc88
@@ -522,7 +565,7 @@
 #define TLDEV(type) ((type) == TYPE_DISK || (type) == TYPE_ROM)
 
 /* "EATA", in Big Endian format */
-#define EATA_SIGNATURE 0x41544145
+#define EATA_SIG_BE 0x45415441
 
 /* Number of valid bytes in the board config structure for EATA 2.0x */
 #define EATA_2_0A_SIZE 28
@@ -533,6 +576,12 @@
 struct eata_info {
    u_int32_t data_len;  /* Number of valid bytes after this field */
    u_int32_t sign;      /* ASCII "EATA" signature */
+
+#if defined(__BIG_ENDIAN_BITFIELD)
+   unchar version:4, :4;
+   unchar  haaval:1, ata:1, drqvld:1, dmasup:1, morsup:1, trnxfr:1, tarsup:1,
+           ocsena:1;
+#else
    unchar        :4,    /* unused low nibble */
           version:4;    /* EATA version, should be 0x1 */
    unchar  ocsena:1,    /* Overlap Command Support Enabled */
@@ -543,6 +592,8 @@
            drqvld:1,    /* DRQ Index (DRQX) is valid */
               ata:1,    /* This is an ATA device */
            haaval:1;    /* Host Adapter Address Valid */
+#endif
+
    ushort cp_pad_len;   /* Number of pad bytes after cp_len */
    unchar host_addr[4]; /* Host Adapter SCSI ID for channels 3, 2, 1, 0 */
    u_int32_t cp_len;    /* Number of valid bytes in cp */
@@ -550,6 +601,15 @@
    ushort queue_size;   /* Max number of cp that can be queued */
    ushort unused;
    ushort scatt_size;   /* Max number of entries in scatter/gather table */
+
+#if defined(__BIG_ENDIAN_BITFIELD)
+   unchar    drqx:2, second:1, irq_tr:1, irq:4;
+   unchar  sync;
+   unchar         :4, res1:1, large_sg:1, forcaddr:1, isaena:1;
+   unchar max_chan:3, max_id:5;
+   unchar   max_lun;
+   unchar     eisa:1, pci:1, idquest:1, m1:1, :4;
+#else
    unchar     irq:4,    /* Interrupt Request assigned to this controller */
            irq_tr:1,    /* 0 for edge triggered, 1 for level triggered */
            second:1,    /* 1 if this is a secondary (not primary) controller */
@@ -572,6 +632,8 @@
           idquest:1,    /* RAIDNUM returned is questionable */
               pci:1,    /* This board is PCI */
              eisa:1;    /* This board is EISA */
+#endif
+
    unchar   raidnum;    /* Uniquely identifies this HBA in a system */
    unchar   notused;
 
@@ -581,18 +643,30 @@
 /* Board config structure */
 struct eata_config {
    ushort len;          /* Number of bytes following this field */
+
+#if defined(__BIG_ENDIAN_BITFIELD)
+   unchar     :4, tarena:1, mdpena:1, ocena:1, edis:1;
+#else
    unchar edis:1,       /* Disable EATA interface after config command */
          ocena:1,       /* Overlapped Commands Enabled */
         mdpena:1,       /* Transfer all Modified Data Pointer Messages */
         tarena:1,       /* Target Mode Enabled for this controller */
               :4;
+#endif
+
    unchar cpad[511];
    };
 
 /* Returned status packet structure */
 struct mssp {
+
+#if defined(__BIG_ENDIAN_BITFIELD)
+   unchar            eoc:1, adapter_status:7;
+#else
    unchar adapter_status:7,    /* State related to current command */
                      eoc:1;    /* End Of Command (1 = command completed) */
+#endif
+
    unchar target_status;       /* SCSI status received after data transfer */
    unchar unused[2];
    u_int32_t inv_res_len;      /* Number of bytes not transferred */
@@ -607,6 +681,16 @@
 
 /* MailBox SCSI Command Packet */
 struct mscp {
+
+#if defined(__BIG_ENDIAN_BITFIELD)
+   unchar     din:1, dout:1, interp:1, :1, sg:1, reqsen:1, init:1, sreset:1;
+   unchar sense_len;
+   unchar unused[3];
+   unchar        :7, fwnest:1;
+   unchar        :5, hbaci:1, iat:1, phsunit:1;
+   unchar channel:3, target:5;
+   unchar     one:1, dispri:1, luntar:1, lun:5;
+#else
    unchar  sreset:1,     /* SCSI Bus Reset Signal should be asserted */
              init:1,     /* Re-initialize controller and self test */
            reqsen:1,     /* Transfer Request Sense Data to addr using DMA */
@@ -629,6 +713,8 @@
            luntar:1,     /* This cp is for Target (not LUN) */
            dispri:1,     /* Disconnect Privilege granted */
               one:1;     /* 1 */
+#endif
+
    unchar mess[3];       /* Massage to/from Target */
    unchar cdb[12];       /* Command Descriptor Block */
    u_int32_t data_len;   /* If sg=0 Data Length, if sg=1 sglist length */
@@ -636,11 +722,18 @@
    u_int32_t data_address; /* If sg=0 Data Address, if sg=1 sglist address */
    u_int32_t sp_dma_addr;  /* Address where sp is DMA'ed when cp completes */
    u_int32_t sense_addr; /* Address where Sense Data is DMA'ed on error */
+
    /* Additional fields begin here. */
    Scsi_Cmnd *SCpnt;
-   struct sg_list *sglist;
+
+   /* All the cp structure is zero filled by queuecommand except the
+      following CP_TAIL_SIZE bytes, initialized by detect */
+   dma_addr_t cp_dma_addr; /* dma handle for this cp structure */
+   struct sg_list *sglist; /* pointer to the allocated SG list */
    };
 
+#define CP_TAIL_SIZE (sizeof(struct sglist *) + sizeof(dma_addr_t))
+
 struct hostdata {
    struct mscp cp[MAX_MAILBOXES];       /* Mailboxes for this board */
    unsigned int cp_stat[MAX_MAILBOXES]; /* FREE, IN_USE, LOCKED, IN_RESET */
@@ -648,7 +741,6 @@
    unsigned int iocount;                /* Total i/o done for this board */
    int board_number;                    /* Number of this board */
    char board_name[16];                 /* Name of this board */
-   char board_id[256];                  /* data from INQUIRY on this board */
    int in_reset;                        /* True if board is doing a reset */
    int target_to[MAX_TARGET][MAX_CHANNEL]; /* N. of timeout errors on target */
    int target_redo[MAX_TARGET][MAX_CHANNEL]; /* If TRUE redo i/o on target */
@@ -698,10 +790,13 @@
 #define BN(board) (HD(board)->board_name)
 
 /* Device is Big Endian */
-#define H2DEV(x) cpu_to_be32(x)
-#define DEV2H(x) be32_to_cpu(x)
+#define H2DEV(x)   cpu_to_be32(x)
+#define DEV2H(x)   be32_to_cpu(x)
+#define H2DEV16(x) cpu_to_be16(x)
+#define DEV2H16(x) be16_to_cpu(x)
 
-#define V2DEV(addr) ((addr) ? H2DEV(virt_to_bus((void *)addr)) : 0)
+/* But transfer orientation from the 16 bit data register is Little Endian */
+#define REG2H(x)   le16_to_cpu(x)
 
 static void do_interrupt_handler(int, void *, struct pt_regs *);
 static void flush_dev(Scsi_Device *, unsigned long, unsigned int, unsigned int);
@@ -731,6 +826,24 @@
 static int max_queue_depth = MAX_CMD_PER_LUN;
 #endif
 
+#if defined(CONFIG_ISA)
+static int isa_probe = TRUE;
+#else
+static int isa_probe = FALSE;
+#endif
+
+#if defined(CONFIG_EISA)
+static int eisa_probe = TRUE;
+#else
+static int eisa_probe = FALSE;
+#endif
+
+#if defined(CONFIG_PCI)
+static int pci_probe = TRUE;
+#else
+static int pci_probe = FALSE;
+#endif
+
 static void select_queue_depths(struct Scsi_Host *host, Scsi_Device *devlist) {
    Scsi_Device *dev;
    int j, ntag = 0, nuntag = 0, tqd, utqd;
@@ -801,14 +914,18 @@
 }
 
 static inline int do_dma(unsigned long iobase, unsigned long addr, unchar cmd) {
+   unsigned char *byaddr;
+   unsigned long devaddr;
 
    if (wait_on_busy(iobase, (addr ? MAXLOOP * 100 : MAXLOOP))) return TRUE;
 
-   if ((addr = V2DEV(addr))) {
-      outb((char) (addr >> 24), iobase + REG_LOW);
-      outb((char) (addr >> 16), iobase + REG_LM);
-      outb((char) (addr >> 8),  iobase + REG_MID);
-      outb((char)  addr,        iobase + REG_MSB);
+   if (addr) {
+      devaddr = H2DEV(addr);
+      byaddr = (unsigned char *) &devaddr;
+      outb(byaddr[3], iobase + REG_LOW);
+      outb(byaddr[2], iobase + REG_LM);
+      outb(byaddr[1], iobase + REG_MID);
+      outb(byaddr[0], iobase + REG_MSB);
       }
 
    outb(cmd, iobase + REG_CMD);
@@ -827,7 +944,7 @@
          }
 
       loop = MAXLOOP;
-      *p = inw(iobase);
+      *p = REG2H(inw(iobase));
       }
 
    return FALSE;
@@ -858,6 +975,29 @@
    return NULL;
 }
 
+static void enable_pci_ports(void) {
+
+#if defined(CONFIG_PCI)
+
+   struct pci_dev *dev = NULL;
+
+   if (!pci_present()) return;
+
+   while((dev = pci_find_class(PCI_CLASS_STORAGE_SCSI << 8, dev))) {
+
+#if defined(DEBUG_PCI_DETECT)
+      printk("%s: enable_pci_ports, bus %d, devfn 0x%x.\n",
+             driver_name, dev->bus->number, dev->devfn);
+#endif
+
+      if (pci_enable_device (dev))
+         printk("%s: warning, pci_enable_device failed, bus %d devfn 0x%x.\n",
+                driver_name, dev->bus->number, dev->devfn);
+      }
+
+#endif /* end CONFIG_PCI */
+}
+
 static inline int port_detect \
       (unsigned long port_base, unsigned int j, Scsi_Host_Template *tpnt) {
    unsigned char irq, dma_channel, subversion, i, is_pci = FALSE;
@@ -881,36 +1021,54 @@
       }
 
    if (do_dma(port_base, 0, READ_CONFIG_PIO)) {
+#if defined(DEBUG_DETECT)
+      printk("%s: detect, do_dma failed at 0x%03lx.\n", name, port_base);
+#endif
       release_region(port_base, REGION_SIZE);
       return FALSE;
       }
 
    /* Read the info structure */
    if (read_pio(port_base, (ushort *)&info, (ushort *)&info.ipad[0])) {
+#if defined(DEBUG_DETECT)
+      printk("%s: detect, read_pio failed at 0x%03lx.\n", name, port_base);
+#endif
       release_region(port_base, REGION_SIZE);
       return FALSE;
       }
 
+   info.data_len = DEV2H(info.data_len);
+   info.sign = DEV2H(info.sign);
+   info.cp_pad_len = DEV2H16(info.cp_pad_len);
+   info.cp_len = DEV2H(info.cp_len);
+   info.sp_len = DEV2H(info.sp_len);
+   info.scatt_size = DEV2H16(info.scatt_size);
+   info.queue_size = DEV2H16(info.queue_size);
+
    /* Check the controller "EATA" signature */
-   if (info.sign != EATA_SIGNATURE) {
+   if (info.sign != EATA_SIG_BE) {
+#if defined(DEBUG_DETECT)
+      printk("%s: signature 0x%04x discarded.\n", name, info.sign);
+#endif
       release_region(port_base, REGION_SIZE);
       return FALSE;
       }
 
-   if (DEV2H(info.data_len) < EATA_2_0A_SIZE) {
+   if (info.data_len < EATA_2_0A_SIZE) {
       printk("%s: config structure size (%d bytes) too short, detaching.\n",
-             name, DEV2H(info.data_len));
+             name, info.data_len);
       release_region(port_base, REGION_SIZE);
       return FALSE;
       }
-   else if (DEV2H(info.data_len) == EATA_2_0A_SIZE)
+   else if (info.data_len == EATA_2_0A_SIZE)
       protocol_rev = 'A';
-   else if (DEV2H(info.data_len) == EATA_2_0B_SIZE)
+   else if (info.data_len == EATA_2_0B_SIZE)
       protocol_rev = 'B';
    else
       protocol_rev = 'C';
 
-   if (!setup_done && j > 0 && j <= MAX_PCI) {
+   if (protocol_rev != 'A' && info.forcaddr) {
+      printk("%s: warning, port address has been forced.\n", name);
       bus_type = "PCI";
       is_pci = TRUE;
       subversion = ESA;
@@ -973,7 +1131,7 @@
 
    if (is_pci) {
       pdev = get_pci_dev(port_base);
-      if (!pdev) 
+      if (!pdev)
          printk("%s: warning, failed to get pci_dev structure.\n", name);
       }
    else
@@ -1003,18 +1161,29 @@
 
 #if defined(FORCE_CONFIG)
    {
-   struct eata_config config;
+   struct eata_config *cf;
+   dma_addr_t cf_dma_addr;
+
+   cf = pci_alloc_consistent(pdev, sizeof(struct eata_config), &cf_dma_addr);
+
+   if (!cf) {
+      printk("%s: config, pci_alloc_consistent failed, detaching.\n", name);
+      release_region(port_base, REGION_SIZE);
+      return FALSE;
+      }
 
    /* Set board configuration */
-   memset((char *)&config, 0, sizeof(struct eata_config));
-   config.len = (ushort) cpu_to_be16((ushort)510);
-   config.ocena = TRUE;
+   memset((char *)cf, 0, sizeof(struct eata_config));
+   cf->len = (ushort) H2DEV16((ushort)510);
+   cf->ocena = TRUE;
 
-   if (do_dma(port_base, (unsigned long)&config, SET_CONFIG_DMA)) {
+   if (do_dma(port_base, cf_dma_addr, SET_CONFIG_DMA)) {
       printk("%s: busy timeout sending configuration, detaching.\n", name);
+      pci_free_consistent(pdev, sizeof(struct eata_config), cf, cf_dma_addr);
       release_region(port_base, REGION_SIZE);
       return FALSE;
       }
+
    }
 #endif
 
@@ -1036,9 +1205,9 @@
    sh[j]->n_io_port = REGION_SIZE;
    sh[j]->dma_channel = dma_channel;
    sh[j]->irq = irq;
-   sh[j]->sg_tablesize = (ushort) be16_to_cpu(info.scatt_size);
+   sh[j]->sg_tablesize = (ushort) info.scatt_size;
    sh[j]->this_id = (ushort) info.host_addr[3];
-   sh[j]->can_queue = (ushort) be16_to_cpu(info.queue_size);
+   sh[j]->can_queue = (ushort) info.queue_size;
    sh[j]->cmd_per_lun = MAX_CMD_PER_LUN;
    sh[j]->select_queue_depths = select_queue_depths;
    memset(HD(j), 0, sizeof(struct hostdata));
@@ -1102,6 +1271,10 @@
    else                       sprintf(dma_name, "DMA %u", dma_channel);
 
    for (i = 0; i < sh[j]->can_queue; i++)
+      HD(j)->cp[i].cp_dma_addr = pci_map_single(HD(j)->pdev,
+            &HD(j)->cp[i], sizeof(struct mscp), PCI_DMA_BIDIRECTIONAL);
+
+   for (i = 0; i < sh[j]->can_queue; i++)
       if (! ((&HD(j)->cp[i])->sglist = kmalloc(
             sh[j]->sg_tablesize * sizeof(struct sg_list),
             (sh[j]->unchecked_isa_dma ? GFP_DMA : 0) | GFP_ATOMIC))) {
@@ -1110,7 +1283,7 @@
          return FALSE;
          }
 
-   if (! (HD(j)->sp_cpu_addr = pci_alloc_consistent(HD(j)->pdev, 
+   if (! (HD(j)->sp_cpu_addr = pci_alloc_consistent(HD(j)->pdev,
          sizeof(struct mssp), &HD(j)->sp_dma_addr))) {
       printk("%s: pci_alloc_consistent failed, detaching.\n", BN(j));
       eata2x_release(sh[j]);
@@ -1132,9 +1305,11 @@
 
    if (j == 0) {
       printk("EATA/DMA 2.0x: Copyright (C) 1994-2002 Dario Ballabio.\n");
-      printk("%s config options -> tc:%c, lc:%c, mq:%d, rs:%c, et:%c.\n",
-             driver_name, tag_type, YESNO(linked_comm), max_queue_depth,
-             YESNO(rev_scan), YESNO(ext_tran));
+      printk("%s config options -> tc:%c, lc:%c, mq:%d, rs:%c, et:%c, "\
+             "ip:%c, ep:%c, pp:%c.\n", driver_name, tag_type,
+             YESNO(linked_comm), max_queue_depth, YESNO(rev_scan),
+             YESNO(ext_tran), YESNO(isa_probe), YESNO(eisa_probe),
+             YESNO(pci_probe));
       }
 
    printk("%s: 2.0%c, %s 0x%03lx, IRQ %u, %s, SG %d, MB %d.\n",
@@ -1153,8 +1328,8 @@
    printk("%s: Vers. 0x%x, ocs %u, tar %u, trnxfr %u, more %u, SYNC 0x%x, "\
           "sec. %u, infol %d, cpl %d spl %d.\n", name, info.version,
           info.ocsena, info.tarsup, info.trnxfr, info.morsup, info.sync,
-          info.second, DEV2H(info.data_len), DEV2H(info.cp_len),
-          DEV2H(info.sp_len));
+          info.second, info.data_len, info.cp_len,
+          info.sp_len);
 
    if (protocol_rev == 'B' || protocol_rev == 'C')
       printk("%s: isaena %u, forcaddr %u, max_id %u, max_chan %u, "\
@@ -1204,6 +1379,9 @@
       else if (!strncmp(cur, "ls:", 3))  link_statistics = val;
       else if (!strncmp(cur, "et:", 3))  ext_tran = val;
       else if (!strncmp(cur, "rs:", 3))  rev_scan = val;
+      else if (!strncmp(cur, "ip:", 3))  isa_probe = val;
+      else if (!strncmp(cur, "ep:", 3))  eisa_probe = val;
+      else if (!strncmp(cur, "pp:", 3))  pci_probe = val;
 
       if ((cur = strchr(cur, ','))) ++cur;
       }
@@ -1285,7 +1463,19 @@
 
    for (k = 0; k < MAX_BOARDS + 1; k++) sh[k] = NULL;
 
-   if (!setup_done) add_pci_ports();
+   for (k = MAX_INT_PARAM; io_port[k]; k++)
+      if (io_port[k] == SKIP) continue;
+      else if (io_port[k] <= MAX_ISA_ADDR) {
+         if (!isa_probe) io_port[k] = SKIP;
+         }
+      else if (io_port[k] >= MIN_EISA_ADDR && io_port[k] <= MAX_EISA_ADDR) {
+         if (!eisa_probe) io_port[k] = SKIP;
+         }
+
+   if (pci_probe) {
+      if (!setup_done) add_pci_ports();
+      else          enable_pci_ports();
+      }
 
    for (k = 0; io_port[k]; k++) {
 
@@ -1315,10 +1505,10 @@
 
    if (!SCpnt->use_sg) {
 
-      if (!SCpnt->request_bufflen)
-         cpp->data_address = V2DEV(SCpnt->request_buffer);
+      /* If we get here with PCI_DMA_NONE, pci_map_single triggers a BUG() */
+      if (!SCpnt->request_bufflen) pci_dir = PCI_DMA_BIDIRECTIONAL;
 
-      else if (SCpnt->request_buffer)
+      if (SCpnt->request_buffer)
          cpp->data_address = H2DEV(pci_map_single(HD(j)->pdev,
                   SCpnt->request_buffer, SCpnt->request_bufflen, pci_dir));
 
@@ -1335,7 +1525,8 @@
       }
 
    cpp->sg = TRUE;
-   cpp->data_address = V2DEV(cpp->sglist);
+   cpp->data_address = H2DEV(pci_map_single(HD(j)->pdev, cpp->sglist,
+                             SCpnt->use_sg * sizeof(struct sg_list), pci_dir));
    cpp->data_len = H2DEV((SCpnt->use_sg * sizeof(struct sg_list)));
 }
 
@@ -1351,13 +1542,14 @@
       pci_unmap_single(HD(j)->pdev, DEV2H(cpp->sense_addr),
                        DEV2H(cpp->sense_len), PCI_DMA_FROMDEVICE);
 
-   if (SCpnt->use_sg) 
+   if (SCpnt->use_sg)
       pci_unmap_sg(HD(j)->pdev, SCpnt->request_buffer, SCpnt->use_sg, pci_dir);
 
-   else if (DEV2H(cpp->data_address) && DEV2H(cpp->data_len))
-      pci_unmap_single(HD(j)->pdev, DEV2H(cpp->data_address), 
-                       DEV2H(cpp->data_len), pci_dir);
+   if (!DEV2H(cpp->data_len)) pci_dir = PCI_DMA_BIDIRECTIONAL;
 
+   if (DEV2H(cpp->data_address))
+      pci_unmap_single(HD(j)->pdev, DEV2H(cpp->data_address),
+                       DEV2H(cpp->data_len), pci_dir);
 }
 
 static void sync_dma(unsigned int i, unsigned int j) {
@@ -1372,14 +1564,15 @@
       pci_dma_sync_single(HD(j)->pdev, DEV2H(cpp->sense_addr),
                           DEV2H(cpp->sense_len), PCI_DMA_FROMDEVICE);
 
-   if (SCpnt->use_sg) 
-      pci_dma_sync_sg(HD(j)->pdev, SCpnt->request_buffer, 
+   if (SCpnt->use_sg)
+      pci_dma_sync_sg(HD(j)->pdev, SCpnt->request_buffer,
                          SCpnt->use_sg, pci_dir);
 
-   else if (DEV2H(cpp->data_address) && DEV2H(cpp->data_len))
-      pci_dma_sync_single(HD(j)->pdev, DEV2H(cpp->data_address), 
-                          DEV2H(cpp->data_len), pci_dir);
+   if (!DEV2H(cpp->data_len)) pci_dir = PCI_DMA_BIDIRECTIONAL;
 
+   if (DEV2H(cpp->data_address))
+      pci_dma_sync_single(HD(j)->pdev, DEV2H(cpp->data_address),
+                       DEV2H(cpp->data_len), pci_dir);
 }
 
 static inline void scsi_to_dev_dir(unsigned int i, unsigned int j) {
@@ -1400,8 +1593,7 @@
    struct mscp *cpp;
    Scsi_Cmnd *SCpnt;
 
-   cpp = &HD(j)->cp[i];
-   SCpnt = cpp->SCpnt;
+   cpp = &HD(j)->cp[i]; SCpnt = cpp->SCpnt;
 
    if (SCpnt->sc_data_direction == SCSI_DATA_READ) {
       cpp->din  = TRUE;
@@ -1419,7 +1611,7 @@
       return;
       }
 
-   if (SCpnt->sc_data_direction != SCSI_DATA_UNKNOWN) 
+   if (SCpnt->sc_data_direction != SCSI_DATA_UNKNOWN)
       panic("%s: qcomm, invalid SCpnt->sc_data_direction.\n", BN(j));
 
    for (k = 0; k < ARRAY_SIZE(data_out_cmds); k++)
@@ -1470,7 +1662,7 @@
    /* Set pointer to control packet structure */
    cpp = &HD(j)->cp[i];
 
-   memset(cpp, 0, sizeof(struct mscp) - sizeof(struct sg_list *));
+   memset(cpp, 0, sizeof(struct mscp) - CP_TAIL_SIZE);
 
    /* Set pointer to status packet structure, Big Endian format */
    cpp->sp_dma_addr = H2DEV(HD(j)->sp_dma_addr);
@@ -1527,7 +1719,7 @@
       }
 
    /* Send control packet to the board */
-   if (do_dma(sh[j]->io_port, (unsigned long) cpp, SEND_CP_DMA)) {
+   if (do_dma(sh[j]->io_port, cpp->cp_dma_addr, SEND_CP_DMA)) {
       unmap_dma(i, j);
       SCpnt->host_scribble = NULL;
       printk("%s: qcomm, target %d.%d:%d, pid %ld, adapter busy.\n",
@@ -1926,7 +2118,7 @@
    for (n = 0; n < n_ready; n++) {
       k = il[n]; cpp = &HD(j)->cp[k]; SCpnt = cpp->SCpnt;
 
-      if (do_dma(sh[j]->io_port, (unsigned long) cpp, SEND_CP_DMA)) {
+      if (do_dma(sh[j]->io_port, cpp->cp_dma_addr, SEND_CP_DMA)) {
          printk("%s: %s, target %d.%d:%d, pid %ld, mbox %d, adapter"\
                 " busy, will abort.\n", BN(j), (ihdlr ? "ihdlr" : "qcomm"),
                 SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid, k);
@@ -1975,8 +2167,21 @@
    /* Read the status register to clear the interrupt indication */
    reg = inb(sh[j]->io_port + REG_STATUS);
 
+#if defined (DEBUG_INTERRUPT)
+   {
+   unsigned char *bytesp;
+   int cnt;
+   bytesp= (unsigned char *) spp;
+   if (HD(j)->iocount < 200) {
+      printk("sp[] =");
+      for (cnt=0; cnt < 15; cnt++) printk(" 0x%x", bytesp[cnt]);
+      printk("\n");
+      }
+   }
+#endif
+
    /* Reject any sp with supspect data */
-   if (spp->eoc == FALSE)
+   if (spp->eoc == FALSE && HD(j)->iocount > 1)
       printk("%s: ihdlr, spp->eoc == FALSE, irq %d, reg 0x%x, count %d.\n",
              BN(j), irq, reg, HD(j)->iocount);
    if (spp->cpp_index < 0 || spp->cpp_index >= sh[j]->can_queue)
@@ -2182,10 +2387,14 @@
    for (i = 0; i < sh[j]->can_queue; i++)
       if ((&HD(j)->cp[i])->sglist) kfree((&HD(j)->cp[i])->sglist);
 
-   if (HD(j)->sp_cpu_addr) 
+   for (i = 0; i < sh[j]->can_queue; i++)
+      pci_unmap_single(HD(j)->pdev, HD(j)->cp[i].cp_dma_addr,
+                     sizeof(struct mscp), PCI_DMA_BIDIRECTIONAL);
+
+   if (HD(j)->sp_cpu_addr)
       pci_free_consistent(HD(j)->pdev, sizeof(struct mssp),
                           HD(j)->sp_cpu_addr, HD(j)->sp_dma_addr);
-                       
+
    free_irq(sh[j]->irq, &sha[j]);
 
    if (sh[j]->dma_channel != NO_DMA) free_dma(sh[j]->dma_channel);

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)