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

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

diff -urN linux-2.4.18/drivers/scsi/eata.c linux-2.4.19/drivers/scsi/eata.c
@@ -1,6 +1,9 @@
 /*
  *      eata.c - Low-level driver for EATA/DMA SCSI host adapters.
  *
+ *      01 Jan 2002 Rev. 6.50 for linux 2.4.16
+ *        + Use the dynamic DMA mapping API.
+ *
  *       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)
@@ -220,7 +223,7 @@
  *          This driver is based on the CAM (Common Access Method Committee)
  *          EATA (Enhanced AT Bus Attachment) rev. 2.0A, using DMA protocol.
  *
- *  Copyright (C) 1994-2001 Dario Ballabio (ballabio_dario@emc.com)
+ *  Copyright (C) 1994-2002 Dario Ballabio (ballabio_dario@emc.com)
  *
  *  Alternate email: dario.ballabio@inwind.it, dario.ballabio@tiscalinet.it
  *
@@ -438,13 +441,6 @@
 #include <linux/ctype.h>
 #include <linux/spinlock.h>
 
-#define SPIN_FLAGS unsigned long spin_flags;
-#define SPIN_LOCK spin_lock_irq(&io_request_lock);
-#define SPIN_LOCK_SAVE spin_lock_irqsave(&io_request_lock, spin_flags);
-#define SPIN_UNLOCK spin_unlock_irq(&io_request_lock);
-#define SPIN_UNLOCK_RESTORE \
-                  spin_unlock_irqrestore(&io_request_lock, spin_flags);
-
 /* Subversion values */
 #define ISA  0
 #define ESA 1
@@ -638,7 +634,7 @@
    u_int32_t data_len;   /* If sg=0 Data Length, if sg=1 sglist length */
    u_int32_t cpp_index;  /* Index of address to be returned in sp */
    u_int32_t data_address; /* If sg=0 Data Address, if sg=1 sglist address */
-   u_int32_t sp_addr;    /* Address where sp is DMA'ed when cp completes */
+   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;
@@ -660,7 +656,11 @@
    unsigned long last_retried_pid;      /* Pid of last retried command */
    unsigned char subversion;            /* Bus type, either ISA or EISA/PCI */
    unsigned char protocol_rev;          /* EATA 2.0 rev., 'A' or 'B' or 'C' */
-   struct mssp sp[2];                   /* Returned status for this board */
+   unsigned char is_pci;                /* TRUE is bus type is PCI */
+   struct pci_dev *pdev;                /* pdev for PCI bus, NULL otherwise */
+   struct mssp *sp_cpu_addr;            /* cpu addr for DMA buffer sp */
+   dma_addr_t sp_dma_addr;              /* dma handle for DMA buffer sp */
+   struct mssp sp;                      /* Local copy of sp buffer */
    };
 
 static struct Scsi_Host *sh[MAX_BOARDS + 1];
@@ -697,10 +697,11 @@
 #define HD(board) ((struct hostdata *) &sh[board]->hostdata)
 #define BN(board) (HD(board)->board_name)
 
-#define H2DEV(x) htonl(x)
-#define DEV2H(x) H2DEV(x)
+/* Device is Big Endian */
+#define H2DEV(x) cpu_to_be32(x)
+#define DEV2H(x) be32_to_cpu(x)
+
 #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 do_interrupt_handler(int, void *, struct pt_regs *);
 static void flush_dev(Scsi_Device *, unsigned long, unsigned int, unsigned int);
@@ -859,7 +860,7 @@
 
 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 irq, dma_channel, subversion, i, is_pci = FALSE;
    unsigned char protocol_rev;
    struct eata_info info;
    char *bus_type, dma_name[16], tag_type;
@@ -911,10 +912,12 @@
 
    if (!setup_done && j > 0 && j <= MAX_PCI) {
       bus_type = "PCI";
+      is_pci = TRUE;
       subversion = ESA;
       }
    else if (port_base > MAX_EISA_ADDR || (protocol_rev == 'C' && info.pci)) {
       bus_type = "PCI";
+      is_pci = TRUE;
       subversion = ESA;
       }
    else if (port_base >= MIN_EISA_ADDR || (protocol_rev == 'C' && info.eisa)) {
@@ -927,6 +930,7 @@
       }
    else if (port_base > MAX_ISA_ADDR) {
       bus_type = "PCI";
+      is_pci = TRUE;
       subversion = ESA;
       }
    else {
@@ -967,7 +971,13 @@
       printk("%s: warning, LEVEL triggering is suggested for IRQ %u.\n",
              name, irq);
 
-   pdev = get_pci_dev(port_base);
+   if (is_pci) {
+      pdev = get_pci_dev(port_base);
+      if (!pdev) 
+         printk("%s: warning, failed to get pci_dev structure.\n", name);
+      }
+   else
+      pdev = NULL;
 
    if (pdev && (irq != pdev->irq)) {
       printk("%s: IRQ %u mapped to IO-APIC IRQ %u.\n", name, irq, pdev->irq);
@@ -997,7 +1007,7 @@
 
    /* Set board configuration */
    memset((char *)&config, 0, sizeof(struct eata_config));
-   config.len = (ushort) htons((ushort)510);
+   config.len = (ushort) cpu_to_be16((ushort)510);
    config.ocena = TRUE;
 
    if (do_dma(port_base, (unsigned long)&config, SET_CONFIG_DMA)) {
@@ -1026,14 +1036,16 @@
    sh[j]->n_io_port = REGION_SIZE;
    sh[j]->dma_channel = dma_channel;
    sh[j]->irq = irq;
-   sh[j]->sg_tablesize = (ushort) ntohs(info.scatt_size);
+   sh[j]->sg_tablesize = (ushort) be16_to_cpu(info.scatt_size);
    sh[j]->this_id = (ushort) info.host_addr[3];
-   sh[j]->can_queue = (ushort) ntohs(info.queue_size);
+   sh[j]->can_queue = (ushort) be16_to_cpu(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));
    HD(j)->subversion = subversion;
    HD(j)->protocol_rev = protocol_rev;
+   HD(j)->is_pci = is_pci;
+   HD(j)->pdev = pdev;
    HD(j)->board_number = j;
 
    if (HD(j)->subversion == ESA)
@@ -1042,14 +1054,14 @@
       unsigned long flags;
       scsi_register_blocked_host(sh[j]);
       sh[j]->unchecked_isa_dma = TRUE;
-      
+
       flags=claim_dma_lock();
       disable_dma(dma_channel);
       clear_dma_ff(dma_channel);
       set_dma_mode(dma_channel, DMA_MODE_CASCADE);
       enable_dma(dma_channel);
       release_dma_lock(flags);
-      
+
       }
 
    strcpy(BN(j), name);
@@ -1098,6 +1110,13 @@
          return FALSE;
          }
 
+   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]);
+      return FALSE;
+      }
+
    if (max_queue_depth > MAX_TAGGED_CMD_PER_LUN)
        max_queue_depth = MAX_TAGGED_CMD_PER_LUN;
 
@@ -1112,7 +1131,7 @@
    else                                 tag_type = 'n';
 
    if (j == 0) {
-      printk("EATA/DMA 2.0x: Copyright (C) 1994-2001 Dario Ballabio.\n");
+      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));
@@ -1148,7 +1167,11 @@
              info.pci, info.eisa, info.raidnum);
 #endif
 
-   if (pdev) pci_set_master(pdev);
+   if (HD(j)->pdev) {
+      pci_set_master(HD(j)->pdev);
+      if (pci_set_dma_mask(HD(j)->pdev, 0xffffffff))
+         printk("%s: warning, pci_set_dma_mask failed.\n", BN(j));
+      }
 
    return TRUE;
 }
@@ -1275,25 +1298,92 @@
    return j;
 }
 
-static inline void build_sg_list(struct mscp *cpp, Scsi_Cmnd *SCpnt) {
-   unsigned int k;
+static inline void map_dma(unsigned int i, unsigned int j) {
+   unsigned int k, count, pci_dir;
    struct scatterlist *sgpnt;
+   struct mscp *cpp;
+   Scsi_Cmnd *SCpnt;
+
+   cpp = &HD(j)->cp[i]; SCpnt = cpp->SCpnt;
+   pci_dir = scsi_to_pci_dma_dir(SCpnt->sc_data_direction);
+
+   if (SCpnt->sense_buffer)
+      cpp->sense_addr = H2DEV(pci_map_single(HD(j)->pdev, SCpnt->sense_buffer,
+                           sizeof SCpnt->sense_buffer, PCI_DMA_FROMDEVICE));
+
+   cpp->sense_len = sizeof SCpnt->sense_buffer;
+
+   if (!SCpnt->use_sg) {
+
+      if (!SCpnt->request_bufflen)
+         cpp->data_address = V2DEV(SCpnt->request_buffer);
+
+      else if (SCpnt->request_buffer)
+         cpp->data_address = H2DEV(pci_map_single(HD(j)->pdev,
+                  SCpnt->request_buffer, SCpnt->request_bufflen, pci_dir));
+
+      cpp->data_len = H2DEV(SCpnt->request_bufflen);
+      return;
+      }
 
    sgpnt = (struct scatterlist *) SCpnt->request_buffer;
+   count = pci_map_sg(HD(j)->pdev, sgpnt, SCpnt->use_sg, pci_dir);
 
-   for (k = 0; k < SCpnt->use_sg; k++) {
-      cpp->sglist[k].address = V2DEV(sgpnt[k].address);
-      cpp->sglist[k].num_bytes = H2DEV(sgpnt[k].length);
+   for (k = 0; k < count; k++) {
+      cpp->sglist[k].address = H2DEV(sg_dma_address(&sgpnt[k]));
+      cpp->sglist[k].num_bytes = H2DEV(sg_dma_len(&sgpnt[k]));
       }
 
+   cpp->sg = TRUE;
    cpp->data_address = V2DEV(cpp->sglist);
    cpp->data_len = H2DEV((SCpnt->use_sg * sizeof(struct sg_list)));
 }
 
-static inline int do_qcomm(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
-   unsigned int i, j, k;
+static void unmap_dma(unsigned int i, unsigned int j) {
+   unsigned int pci_dir;
    struct mscp *cpp;
-   struct mssp *spp;
+   Scsi_Cmnd *SCpnt;
+
+   cpp = &HD(j)->cp[i]; SCpnt = cpp->SCpnt;
+   pci_dir = scsi_to_pci_dma_dir(SCpnt->sc_data_direction);
+
+   if (DEV2H(cpp->sense_addr))
+      pci_unmap_single(HD(j)->pdev, DEV2H(cpp->sense_addr),
+                       DEV2H(cpp->sense_len), PCI_DMA_FROMDEVICE);
+
+   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);
+
+}
+
+static void sync_dma(unsigned int i, unsigned int j) {
+   unsigned int pci_dir;
+   struct mscp *cpp;
+   Scsi_Cmnd *SCpnt;
+
+   cpp = &HD(j)->cp[i]; SCpnt = cpp->SCpnt;
+   pci_dir = scsi_to_pci_dma_dir(SCpnt->sc_data_direction);
+
+   if (DEV2H(cpp->sense_addr))
+      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, 
+                         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);
+
+}
+
+static inline void scsi_to_dev_dir(unsigned int i, unsigned int j) {
+   unsigned int k;
 
    static const unsigned char data_out_cmds[] = {
       0x0a, 0x2a, 0x15, 0x55, 0x04, 0x07, 0x18, 0x1d, 0x24, 0x2e,
@@ -1304,9 +1394,53 @@
    static const unsigned char data_none_cmds[] = {
       0x01, 0x0b, 0x10, 0x11, 0x13, 0x16, 0x17, 0x19, 0x2b, 0x1e,
       0x2c, 0xac, 0x2f, 0xaf, 0x33, 0xb3, 0x35, 0x36, 0x45, 0x47,
-      0x48, 0x49, 0xa9, 0x4b, 0xa5, 0xa6, 0xb5
+      0x48, 0x49, 0xa9, 0x4b, 0xa5, 0xa6, 0xb5, 0x00
       };
 
+   struct mscp *cpp;
+   Scsi_Cmnd *SCpnt;
+
+   cpp = &HD(j)->cp[i];
+   SCpnt = cpp->SCpnt;
+
+   if (SCpnt->sc_data_direction == SCSI_DATA_READ) {
+      cpp->din  = TRUE;
+      cpp->dout = FALSE;
+      return;
+      }
+   else if (SCpnt->sc_data_direction == SCSI_DATA_WRITE) {
+      cpp->din  = FALSE;
+      cpp->dout = TRUE;
+      return;
+      }
+   else if (SCpnt->sc_data_direction == SCSI_DATA_NONE) {
+      cpp->din  = FALSE;
+      cpp->dout = FALSE;
+      return;
+      }
+
+   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++)
+      if (SCpnt->cmnd[0] == data_out_cmds[k]) {
+         cpp->dout = TRUE;
+         break;
+         }
+
+   if ((cpp->din = !cpp->dout))
+      for (k = 0; k < ARRAY_SIZE(data_none_cmds); k++)
+         if (SCpnt->cmnd[0] == data_none_cmds[k]) {
+            cpp->din = FALSE;
+            break;
+            }
+
+}
+
+static inline int do_qcomm(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
+   unsigned int i, j, k;
+   struct mscp *cpp;
+
    /* j is the board number */
    j = ((struct hostdata *) SCpnt->host->hostdata)->board_number;
 
@@ -1338,11 +1472,8 @@
 
    memset(cpp, 0, sizeof(struct mscp) - sizeof(struct sg_list *));
 
-   /* Set pointer to status packet structure */
-   spp = &HD(j)->sp[0];
-
-   /* The EATA protocol uses Big Endian format */
-   cpp->sp_addr = V2DEV(spp);
+   /* Set pointer to status packet structure, Big Endian format */
+   cpp->sp_dma_addr = H2DEV(HD(j)->sp_dma_addr);
 
    SCpnt->scsi_done = done;
    cpp->cpp_index = i;
@@ -1352,19 +1483,6 @@
                         BN(j), i, SCpnt->channel, SCpnt->target,
                         SCpnt->lun, SCpnt->pid);
 
-   for (k = 0; k < ARRAY_SIZE(data_out_cmds); k++)
-     if (SCpnt->cmnd[0] == data_out_cmds[k]) {
-        cpp->dout = TRUE;
-        break;
-        }
-
-   if ((cpp->din = !cpp->dout))
-      for (k = 0; k < ARRAY_SIZE(data_none_cmds); k++)
-        if (SCpnt->cmnd[0] == data_none_cmds[k]) {
-           cpp->din = FALSE;
-           break;
-           }
-
    cpp->reqsen = TRUE;
    cpp->dispri = TRUE;
 #if 0
@@ -1375,8 +1493,13 @@
    cpp->target = SCpnt->target;
    cpp->lun = SCpnt->lun;
    cpp->SCpnt = SCpnt;
-   cpp->sense_addr = V2DEV(SCpnt->sense_buffer);
-   cpp->sense_len = sizeof SCpnt->sense_buffer;
+   memcpy(cpp->cdb, SCpnt->cmnd, SCpnt->cmd_len);
+
+   /* Use data transfer direction SCpnt->sc_data_direction */
+   scsi_to_dev_dir(i, j);
+
+   /* Map DMA buffers and SG list */
+   map_dma(i, j);
 
    if (SCpnt->device->tagged_queue) {
 
@@ -1396,17 +1519,6 @@
       cpp->mess[1] = SCpnt->device->current_tag++;
       }
 
-   if (SCpnt->use_sg) {
-      cpp->sg = TRUE;
-      build_sg_list(cpp, SCpnt);
-      }
-   else {
-      cpp->data_address = V2DEV(SCpnt->request_buffer);
-      cpp->data_len = H2DEV(SCpnt->request_bufflen);
-      }
-
-   memcpy(cpp->cdb, SCpnt->cmnd, SCpnt->cmd_len);
-
    if (linked_comm && SCpnt->device->queue_depth > 2
                                      && TLDEV(SCpnt->device->type)) {
       HD(j)->cp_stat[i] = READY;
@@ -1416,6 +1528,7 @@
 
    /* Send control packet to the board */
    if (do_dma(sh[j]->io_port, (unsigned long) cpp, SEND_CP_DMA)) {
+      unmap_dma(i, j);
       SCpnt->host_scribble = NULL;
       printk("%s: qcomm, target %d.%d:%d, pid %ld, adapter busy.\n",
              BN(j), SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid);
@@ -1472,6 +1585,7 @@
          printk("%s: abort, mbox %d, interrupt pending.\n", BN(j), i);
 
       if (SCarg->eh_state == SCSI_STATE_TIMEOUT) {
+         unmap_dma(i, j);
          SCarg->host_scribble = NULL;
          HD(j)->cp_stat[i] = FREE;
          printk("%s, abort, mbox %d, eh_state timeout, pid %ld.\n",
@@ -1493,6 +1607,7 @@
       }
 
    if (HD(j)->cp_stat[i] == READY || HD(j)->cp_stat[i] == ABORTING) {
+      unmap_dma(i, j);
       SCarg->result = DID_ABORT << 16;
       SCarg->host_scribble = NULL;
       HD(j)->cp_stat[i] = FREE;
@@ -1589,16 +1704,19 @@
 #endif
 
    HD(j)->in_reset = TRUE;
-   SPIN_UNLOCK
+
+   spin_unlock_irq(&io_request_lock);
    time = jiffies;
    while ((jiffies - time) < (10 * HZ) && limit++ < 200000) udelay(100L);
-   SPIN_LOCK
+   spin_lock_irq(&io_request_lock);
+
    printk("%s: reset, interrupts disabled, loops %d.\n", BN(j), limit);
 
    for (i = 0; i < sh[j]->can_queue; i++) {
 
       if (HD(j)->cp_stat[i] == IN_RESET) {
          SCpnt = HD(j)->cp[i].SCpnt;
+         unmap_dma(i, j);
          SCpnt->result = DID_RESET << 16;
          SCpnt->host_scribble = NULL;
 
@@ -1611,6 +1729,7 @@
 
       else if (HD(j)->cp_stat[i] == ABORTING) {
          SCpnt = HD(j)->cp[i].SCpnt;
+         unmap_dma(i, j);
          SCpnt->result = DID_RESET << 16;
          SCpnt->host_scribble = NULL;
 
@@ -1823,7 +1942,7 @@
 static inline void ihdlr(int irq, unsigned int j) {
    Scsi_Cmnd *SCpnt;
    unsigned int i, k, c, status, tstatus, reg;
-   struct mssp *dspp, *spp;
+   struct mssp *spp;
    struct mscp *cpp;
 
    if (sh[j]->irq != irq)
@@ -1845,14 +1964,13 @@
       return;
       }
 
-   dspp = &HD(j)->sp[0];
-   spp  = &HD(j)->sp[1];
+   spp  = &HD(j)->sp;
 
    /* Make a local copy just before clearing the interrupt indication */
-   memcpy(spp, dspp, sizeof(struct mssp));
+   memcpy(spp, HD(j)->sp_cpu_addr, sizeof(struct mssp));
 
    /* Clear the completion flag and cp pointer on the dynamic copy of sp */
-   memset(dspp, 0, sizeof(struct mssp));
+   memset(HD(j)->sp_cpu_addr, 0, sizeof(struct mssp));
 
    /* Read the status register to clear the interrupt indication */
    reg = inb(sh[j]->io_port + REG_STATUS);
@@ -1910,6 +2028,8 @@
       panic("%s: ihdlr, mbox %d, pid %ld, index mismatch %d.\n",
             BN(j), i, SCpnt->pid, *(unsigned int *)SCpnt->host_scribble);
 
+   sync_dma(i, j);
+
    if (linked_comm && SCpnt->device->queue_depth > 2
                                      && TLDEV(SCpnt->device->type))
       flush_dev(SCpnt->device, SCpnt->request.sector, j, TRUE);
@@ -1987,6 +2107,7 @@
 #else
             status = DID_BUS_BUSY << 16;
 #endif
+
             HD(j)->retries++;
             HD(j)->last_retried_pid = SCpnt->pid;
             }
@@ -2023,6 +2144,8 @@
              SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid,
              reg, HD(j)->iocount);
 
+   unmap_dma(i, j);
+
    /* Set the command state to inactive */
    SCpnt->host_scribble = NULL;
 
@@ -2036,14 +2159,14 @@
 
 static void do_interrupt_handler(int irq, void *shap, struct pt_regs *regs) {
    unsigned int j;
-   SPIN_FLAGS
+   unsigned long spin_flags;
 
    /* Check if the interrupt must be processed by this handler */
    if ((j = (unsigned int)((char *)shap - sha)) >= num_boards) return;
 
-   SPIN_LOCK_SAVE
+   spin_lock_irqsave(&io_request_lock, spin_flags);
    ihdlr(irq, j);
-   SPIN_UNLOCK_RESTORE
+   spin_unlock_irqrestore(&io_request_lock, spin_flags);
 }
 
 int eata2x_release(struct Scsi_Host *shpnt) {
@@ -2054,13 +2177,15 @@
    if (sh[j] == NULL) panic("%s: release, invalid Scsi_Host pointer.\n",
                             driver_name);
 
-   if( sh[j]->unchecked_isa_dma ) {
-	   scsi_deregister_blocked_host(sh[j]);
-   }
+   if(sh[j]->unchecked_isa_dma) scsi_deregister_blocked_host(sh[j]);
 
    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) 
+      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);
@@ -2077,4 +2202,4 @@
 #ifndef MODULE
 __setup("eata=", option_setup);
 #endif /* end MODULE */
-MODULE_LICENSE("Dual BSD/GPL");
+MODULE_LICENSE("GPL");

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