ucc_geth_ethtool: Add a missing HW stats counter
[safe/jmp/linux-2.6] / drivers / scsi / advansys.c
index ab91082..8591585 100644 (file)
 #define ASC_DCNT  __u32                /* Unsigned Data count type. */
 #define ASC_SDCNT __s32                /* Signed Data count type. */
 
-/*
- * These macros are used to convert a virtual address to a
- * 32-bit value. This currently can be used on Linux Alpha
- * which uses 64-bit virtual address but a 32-bit bus address.
- * This is likely to break in the future, but doing this now
- * will give us time to change the HW and FW to handle 64-bit
- * addresses.
- */
-#define ASC_VADDR_TO_U32   virt_to_bus
-#define ASC_U32_TO_VADDR   bus_to_virt
-
 typedef unsigned char uchar;
 
 #ifndef TRUE
@@ -131,7 +120,7 @@ typedef unsigned char uchar;
 #define CC_VERY_LONG_SG_LIST 0
 #define ASC_SRB2SCSIQ(srb_ptr)  (srb_ptr)
 
-#define PortAddr                 unsigned short        /* port address size  */
+#define PortAddr                 unsigned int  /* port address size  */
 #define inp(port)                inb(port)
 #define outp(port, byte)         outb((byte), (port))
 
@@ -540,7 +529,6 @@ typedef struct asc_dvc_cfg {
        ushort mcode_date;
        ushort mcode_version;
        uchar max_tag_qng[ASC_MAX_TID + 1];
-       uchar *overrun_buf;
        uchar sdtr_period_offset[ASC_MAX_TID + 1];
        uchar adapter_info[6];
 } ASC_DVC_CFG;
@@ -562,6 +550,7 @@ typedef struct asc_dvc_cfg {
 #define ASC_BUG_FIX_ASYN_USE_SYN     0x0002
 #define ASC_MIN_TAGGED_CMD  7
 #define ASC_MAX_SCSI_RESET_WAIT      30
+#define ASC_OVERRUN_BSIZE              64
 
 struct asc_dvc_var;            /* Forward Declaration. */
 
@@ -577,6 +566,8 @@ typedef struct asc_dvc_var {
        ASC_SCSI_BIT_ID_TYPE unit_not_ready;
        ASC_SCSI_BIT_ID_TYPE queue_full_or_busy;
        ASC_SCSI_BIT_ID_TYPE start_motor;
+       uchar *overrun_buf;
+       dma_addr_t overrun_dma;
        uchar scsi_reset_wait;
        uchar chip_no;
        char is_in_int;
@@ -601,6 +592,8 @@ typedef struct asc_dvc_var {
        uchar min_sdtr_index;
        uchar max_sdtr_index;
        struct asc_board *drv_ptr;
+       int ptr_map_count;
+       void **ptr_map;
        ASC_DCNT uc_break;
 } ASC_DVC_VAR;
 
@@ -677,7 +670,6 @@ typedef struct asceep_config {
 #define ASC_EEP_CMD_WRITE         0x40
 #define ASC_EEP_CMD_WRITE_ABLE    0x30
 #define ASC_EEP_CMD_WRITE_DISABLE 0x00
-#define ASC_OVERRUN_BSIZE  0x00000048UL
 #define ASCV_MSGOUT_BEG         0x0000
 #define ASCV_MSGOUT_SDTR_PERIOD (ASCV_MSGOUT_BEG+3)
 #define ASCV_MSGOUT_SDTR_OFFSET (ASCV_MSGOUT_BEG+4)
@@ -2223,8 +2215,6 @@ do { \
        (((struct asc_board *) shost_priv(shost))->asc_stats.counter += (count))
 #endif /* ADVANSYS_STATS */
 
-#define ASC_CEILING(val, unit) (((val) + ((unit) - 1))/(unit))
-
 /* If the result wraps when calculating tenths, return 0. */
 #define ASC_TENTHS(num, den) \
     (((10 * ((num)/(den))) > (((num) * 10)/(den))) ? \
@@ -2356,11 +2346,9 @@ struct asc_stats {
        ADV_DCNT exe_error;     /* # ASC_ERROR returns. */
        ADV_DCNT exe_unknown;   /* # unknown returns. */
        /* Data Transfer Statistics */
-       ADV_DCNT cont_cnt;      /* # non-scatter-gather I/O requests received */
-       ADV_DCNT cont_xfer;     /* # contiguous transfer 512-bytes */
-       ADV_DCNT sg_cnt;        /* # scatter-gather I/O requests received */
-       ADV_DCNT sg_elem;       /* # scatter-gather elements */
-       ADV_DCNT sg_xfer;       /* # scatter-gather transfer 512-bytes */
+       ADV_DCNT xfer_cnt;      /* # I/O requests received */
+       ADV_DCNT xfer_elem;     /* # scatter-gather elements */
+       ADV_DCNT xfer_sect;     /* # 512-byte blocks */
 };
 #endif /* ADVANSYS_STATS */
 
@@ -2417,13 +2405,12 @@ struct asc_board {
        ushort bios_codelen;    /* BIOS Code Segment Length. */
 };
 
+#define asc_dvc_to_board(asc_dvc) container_of(asc_dvc, struct asc_board, \
+                                                       dvc_var.asc_dvc_var)
 #define adv_dvc_to_board(adv_dvc) container_of(adv_dvc, struct asc_board, \
                                                        dvc_var.adv_dvc_var)
 #define adv_dvc_to_pdev(adv_dvc) to_pci_dev(adv_dvc_to_board(adv_dvc)->dev)
 
-/* Overrun buffer used by all narrow boards. */
-static uchar overrun_buf[ASC_OVERRUN_BSIZE] = { 0 };
-
 #ifdef ADVANSYS_DEBUG
 static int asc_dbglvl = 3;
 
@@ -2478,8 +2465,8 @@ static void asc_prt_asc_dvc_cfg(ASC_DVC_CFG *h)
                "chip_version %d,\n", h->chip_scsi_id, h->isa_dma_speed,
                h->isa_dma_channel, h->chip_version);
 
-       printk(" mcode_date 0x%x, mcode_version %d, overrun_buf 0x%p\n",
-               h->mcode_date, h->mcode_version, h->overrun_buf);
+       printk(" mcode_date 0x%x, mcode_version %d\n",
+               h->mcode_date, h->mcode_version);
 }
 
 /*
@@ -2752,6 +2739,59 @@ static void asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *q)
 #endif /* ADVANSYS_DEBUG */
 
 /*
+ * The advansys chip/microcode contains a 32-bit identifier for each command
+ * known as the 'srb'.  I don't know what it stands for.  The driver used
+ * to encode the scsi_cmnd pointer by calling virt_to_bus and retrieve it
+ * with bus_to_virt.  Now the driver keeps a per-host map of integers to
+ * pointers.  It auto-expands when full, unless it can't allocate memory.
+ * Note that an srb of 0 is treated specially by the chip/firmware, hence
+ * the return of i+1 in this routine, and the corresponding subtraction in
+ * the inverse routine.
+ */
+#define BAD_SRB 0
+static u32 advansys_ptr_to_srb(struct asc_dvc_var *asc_dvc, void *ptr)
+{
+       int i;
+       void **new_ptr;
+
+       for (i = 0; i < asc_dvc->ptr_map_count; i++) {
+               if (!asc_dvc->ptr_map[i])
+                       goto out;
+       }
+
+       if (asc_dvc->ptr_map_count == 0)
+               asc_dvc->ptr_map_count = 1;
+       else
+               asc_dvc->ptr_map_count *= 2;
+
+       new_ptr = krealloc(asc_dvc->ptr_map,
+                       asc_dvc->ptr_map_count * sizeof(void *), GFP_ATOMIC);
+       if (!new_ptr)
+               return BAD_SRB;
+       asc_dvc->ptr_map = new_ptr;
+ out:
+       ASC_DBG(3, "Putting ptr %p into array offset %d\n", ptr, i);
+       asc_dvc->ptr_map[i] = ptr;
+       return i + 1;
+}
+
+static void * advansys_srb_to_ptr(struct asc_dvc_var *asc_dvc, u32 srb)
+{
+       void *ptr;
+
+       srb--;
+       if (srb >= asc_dvc->ptr_map_count) {
+               printk("advansys: bad SRB %u, max %u\n", srb,
+                                                       asc_dvc->ptr_map_count);
+               return NULL;
+       }
+       ptr = asc_dvc->ptr_map[srb];
+       asc_dvc->ptr_map[srb] = NULL;
+       ASC_DBG(3, "Returning ptr %p from array offset %d\n", ptr, srb);
+       return ptr;
+}
+
+/*
  * advansys_info()
  *
  * Return suitable for printing on the console with the argument
@@ -4057,57 +4097,32 @@ static int asc_prt_board_stats(struct Scsi_Host *shost, char *cp, int cplen)
        /*
         * Display data transfer statistics.
         */
-       if (s->cont_cnt > 0) {
-               len = asc_prt_line(cp, leftlen, " cont_cnt %lu, ", s->cont_cnt);
+       if (s->xfer_cnt > 0) {
+               len = asc_prt_line(cp, leftlen, " xfer_cnt %lu, xfer_elem %lu, ",
+                                  s->xfer_cnt, s->xfer_elem);
                ASC_PRT_NEXT();
 
-               len = asc_prt_line(cp, leftlen, "cont_xfer %lu.%01lu kb ",
-                                  s->cont_xfer / 2,
-                                  ASC_TENTHS(s->cont_xfer, 2));
-               ASC_PRT_NEXT();
-
-               /* Contiguous transfer average size */
-               len = asc_prt_line(cp, leftlen, "avg_xfer %lu.%01lu kb\n",
-                                  (s->cont_xfer / 2) / s->cont_cnt,
-                                  ASC_TENTHS((s->cont_xfer / 2), s->cont_cnt));
-               ASC_PRT_NEXT();
-       }
-
-       if (s->sg_cnt > 0) {
-
-               len = asc_prt_line(cp, leftlen, " sg_cnt %lu, sg_elem %lu, ",
-                                  s->sg_cnt, s->sg_elem);
-               ASC_PRT_NEXT();
-
-               len = asc_prt_line(cp, leftlen, "sg_xfer %lu.%01lu kb\n",
-                                  s->sg_xfer / 2, ASC_TENTHS(s->sg_xfer, 2));
+               len = asc_prt_line(cp, leftlen, "xfer_bytes %lu.%01lu kb\n",
+                                  s->xfer_sect / 2, ASC_TENTHS(s->xfer_sect, 2));
                ASC_PRT_NEXT();
 
                /* Scatter gather transfer statistics */
                len = asc_prt_line(cp, leftlen, " avg_num_elem %lu.%01lu, ",
-                                  s->sg_elem / s->sg_cnt,
-                                  ASC_TENTHS(s->sg_elem, s->sg_cnt));
+                                  s->xfer_elem / s->xfer_cnt,
+                                  ASC_TENTHS(s->xfer_elem, s->xfer_cnt));
                ASC_PRT_NEXT();
 
                len = asc_prt_line(cp, leftlen, "avg_elem_size %lu.%01lu kb, ",
-                                  (s->sg_xfer / 2) / s->sg_elem,
-                                  ASC_TENTHS((s->sg_xfer / 2), s->sg_elem));
+                                  (s->xfer_sect / 2) / s->xfer_elem,
+                                  ASC_TENTHS((s->xfer_sect / 2), s->xfer_elem));
                ASC_PRT_NEXT();
 
                len = asc_prt_line(cp, leftlen, "avg_xfer_size %lu.%01lu kb\n",
-                                  (s->sg_xfer / 2) / s->sg_cnt,
-                                  ASC_TENTHS((s->sg_xfer / 2), s->sg_cnt));
+                                  (s->xfer_sect / 2) / s->xfer_cnt,
+                                  ASC_TENTHS((s->xfer_sect / 2), s->xfer_cnt));
                ASC_PRT_NEXT();
        }
 
-       /*
-        * Display request queuing statistics.
-        */
-       len = asc_prt_line(cp, leftlen,
-                          " Active and Waiting Request Queues (Time Unit: %d HZ):\n",
-                          HZ);
-       ASC_PRT_NEXT();
-
        return totlen;
 }
 #endif /* ADVANSYS_STATS */
@@ -4301,18 +4316,8 @@ advansys_proc_info(struct Scsi_Host *shost, char *buffer, char **start,
 
 static void asc_scsi_done(struct scsi_cmnd *scp)
 {
-       struct asc_board *boardp = shost_priv(scp->device->host);
-
-       if (scp->use_sg)
-               dma_unmap_sg(boardp->dev,
-                            (struct scatterlist *)scp->request_buffer,
-                            scp->use_sg, scp->sc_data_direction);
-       else if (scp->request_bufflen)
-               dma_unmap_single(boardp->dev, scp->SCp.dma_handle,
-                                scp->request_bufflen, scp->sc_data_direction);
-
+       scsi_dma_unmap(scp);
        ASC_STATS(scp->device->host, done);
-
        scp->scsi_done(scp);
 }
 
@@ -6311,6 +6316,7 @@ static ushort AscInitMicroCodeVar(ASC_DVC_VAR *asc_dvc)
        PortAddr iop_base;
        ASC_PADDR phy_addr;
        ASC_DCNT phy_size;
+       struct asc_board *board = asc_dvc_to_board(asc_dvc);
 
        iop_base = asc_dvc->iop_base;
        warn_code = 0;
@@ -6325,12 +6331,14 @@ static ushort AscInitMicroCodeVar(ASC_DVC_VAR *asc_dvc)
        AscWriteLramByte(iop_base, ASCV_HOSTSCSI_ID_B,
                         ASC_TID_TO_TARGET_ID(asc_dvc->cfg->chip_scsi_id));
 
-       /* Align overrun buffer on an 8 byte boundary. */
-       phy_addr = virt_to_bus(asc_dvc->cfg->overrun_buf);
-       phy_addr = cpu_to_le32((phy_addr + 7) & ~0x7);
+       /* Ensure overrun buffer is aligned on an 8 byte boundary. */
+       BUG_ON((unsigned long)asc_dvc->overrun_buf & 7);
+       asc_dvc->overrun_dma = dma_map_single(board->dev, asc_dvc->overrun_buf,
+                                       ASC_OVERRUN_BSIZE, DMA_FROM_DEVICE);
+       phy_addr = cpu_to_le32(asc_dvc->overrun_dma);
        AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_PADDR_D,
                                 (uchar *)&phy_addr, 1);
-       phy_size = cpu_to_le32(ASC_OVERRUN_BSIZE - 8);
+       phy_size = cpu_to_le32(ASC_OVERRUN_BSIZE);
        AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_BSIZE_D,
                                 (uchar *)&phy_size, 1);
 
@@ -6431,7 +6439,7 @@ static int AdvLoadMicrocode(AdvPortAddr iop_base, unsigned char *buf, int size,
                        i += 2;
                        len += 2;
                } else {
-                       unsigned char off = buf[i] * 2;
+                       unsigned int off = buf[i] * 2;
                        unsigned short word = (buf[off + 1] << 8) | buf[off];
                        AdvWriteWordAutoIncLram(iop_base, word);
                        len += 2;
@@ -8210,11 +8218,11 @@ static void adv_isr_callback(ADV_DVC_VAR *adv_dvc_varp, ADV_SCSI_REQ_Q *scsiqp)
                 * then return the number of underrun bytes.
                 */
                resid_cnt = le32_to_cpu(scsiqp->data_cnt);
-               if (scp->request_bufflen != 0 && resid_cnt != 0 &&
-                   resid_cnt <= scp->request_bufflen) {
+               if (scsi_bufflen(scp) != 0 && resid_cnt != 0 &&
+                   resid_cnt <= scsi_bufflen(scp)) {
                        ASC_DBG(1, "underrun condition %lu bytes\n",
                                 (ulong)resid_cnt);
-                       scp->resid = resid_cnt;
+                       scsi_set_resid(scp, resid_cnt);
                }
                break;
 
@@ -8225,7 +8233,7 @@ static void adv_isr_callback(ADV_DVC_VAR *adv_dvc_varp, ADV_SCSI_REQ_Q *scsiqp)
                        if (scsiqp->scsi_status == SAM_STAT_CHECK_CONDITION) {
                                ASC_DBG(2, "SAM_STAT_CHECK_CONDITION\n");
                                ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
-                                                 sizeof(scp->sense_buffer));
+                                                 SCSI_SENSE_BUFFERSIZE);
                                /*
                                 * Note: The 'status_byte()' macro used by
                                 * target drivers defined in scsi.h shifts the
@@ -9114,17 +9122,10 @@ static void asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep)
        ASC_DBG(1, "asc_dvc_varp 0x%p, qdonep 0x%p\n", asc_dvc_varp, qdonep);
        ASC_DBG_PRT_ASC_QDONE_INFO(2, qdonep);
 
-       /*
-        * Get the struct scsi_cmnd structure and Scsi_Host structure for the
-        * command that has been completed.
-        */
-       scp = (struct scsi_cmnd *)ASC_U32_TO_VADDR(qdonep->d2.srb_ptr);
-       ASC_DBG(1, "scp 0x%p\n", scp);
-
-       if (scp == NULL) {
-               ASC_PRINT("asc_isr_callback: scp is NULL\n");
+       scp = advansys_srb_to_ptr(asc_dvc_varp, qdonep->d2.srb_ptr);
+       if (!scp)
                return;
-       }
+
        ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len);
 
        shost = scp->device->host;
@@ -9134,6 +9135,8 @@ static void asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep)
        boardp = shost_priv(shost);
        BUG_ON(asc_dvc_varp != &boardp->dvc_var.asc_dvc_var);
 
+       dma_unmap_single(boardp->dev, scp->SCp.dma_handle,
+                        SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE);
        /*
         * 'qdonep' contains the command's ending status.
         */
@@ -9148,11 +9151,11 @@ static void asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep)
                 * If there was no error and an underrun condition, then
                 * return the number of underrun bytes.
                 */
-               if (scp->request_bufflen != 0 && qdonep->remain_bytes != 0 &&
-                   qdonep->remain_bytes <= scp->request_bufflen) {
+               if (scsi_bufflen(scp) != 0 && qdonep->remain_bytes != 0 &&
+                   qdonep->remain_bytes <= scsi_bufflen(scp)) {
                        ASC_DBG(1, "underrun condition %u bytes\n",
                                 (unsigned)qdonep->remain_bytes);
-                       scp->resid = qdonep->remain_bytes;
+                       scsi_set_resid(scp, qdonep->remain_bytes);
                }
                break;
 
@@ -9163,7 +9166,7 @@ static void asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep)
                        if (qdonep->d3.scsi_stat == SAM_STAT_CHECK_CONDITION) {
                                ASC_DBG(2, "SAM_STAT_CHECK_CONDITION\n");
                                ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
-                                                 sizeof(scp->sense_buffer));
+                                                 SCSI_SENSE_BUFFERSIZE);
                                /*
                                 * Note: The 'status_byte()' macro used by
                                 * target drivers defined in scsi.h shifts the
@@ -9874,15 +9877,32 @@ static int advansys_slave_configure(struct scsi_device *sdev)
        return 0;
 }
 
+static __le32 advansys_get_sense_buffer_dma(struct scsi_cmnd *scp)
+{
+       struct asc_board *board = shost_priv(scp->device->host);
+       scp->SCp.dma_handle = dma_map_single(board->dev, scp->sense_buffer,
+                                            SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE);
+       dma_cache_sync(board->dev, scp->sense_buffer,
+                      SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE);
+       return cpu_to_le32(scp->SCp.dma_handle);
+}
+
 static int asc_build_req(struct asc_board *boardp, struct scsi_cmnd *scp,
                        struct asc_scsi_q *asc_scsi_q)
 {
+       struct asc_dvc_var *asc_dvc = &boardp->dvc_var.asc_dvc_var;
+       int use_sg;
+
        memset(asc_scsi_q, 0, sizeof(*asc_scsi_q));
 
        /*
         * Point the ASC_SCSI_Q to the 'struct scsi_cmnd'.
         */
-       asc_scsi_q->q2.srb_ptr = ASC_VADDR_TO_U32(scp);
+       asc_scsi_q->q2.srb_ptr = advansys_ptr_to_srb(asc_dvc, scp);
+       if (asc_scsi_q->q2.srb_ptr == BAD_SRB) {
+               scp->result = HOST_BYTE(DID_SOFT_ERROR);
+               return ASC_ERROR;
+       }
 
        /*
         * Build the ASC_SCSI_Q request.
@@ -9893,9 +9913,8 @@ static int asc_build_req(struct asc_board *boardp, struct scsi_cmnd *scp,
        asc_scsi_q->q1.target_lun = scp->device->lun;
        asc_scsi_q->q2.target_ix =
            ASC_TIDLUN_TO_IX(scp->device->id, scp->device->lun);
-       asc_scsi_q->q1.sense_addr =
-           cpu_to_le32(virt_to_bus(&scp->sense_buffer[0]));
-       asc_scsi_q->q1.sense_len = sizeof(scp->sense_buffer);
+       asc_scsi_q->q1.sense_addr = advansys_get_sense_buffer_dma(scp);
+       asc_scsi_q->q1.sense_len = SCSI_SENSE_BUFFERSIZE;
 
        /*
         * If there are any outstanding requests for the current target,
@@ -9908,62 +9927,33 @@ static int asc_build_req(struct asc_board *boardp, struct scsi_cmnd *scp,
         * started request.
         *
         */
-       if ((boardp->dvc_var.asc_dvc_var.cur_dvc_qng[scp->device->id] > 0) &&
+       if ((asc_dvc->cur_dvc_qng[scp->device->id] > 0) &&
            (boardp->reqcnt[scp->device->id] % 255) == 0) {
                asc_scsi_q->q2.tag_code = MSG_ORDERED_TAG;
        } else {
                asc_scsi_q->q2.tag_code = MSG_SIMPLE_TAG;
        }
 
-       /*
-        * Build ASC_SCSI_Q for a contiguous buffer or a scatter-gather
-        * buffer command.
-        */
-       if (scp->use_sg == 0) {
-               /*
-                * CDB request of single contiguous buffer.
-                */
-               ASC_STATS(scp->device->host, cont_cnt);
-               scp->SCp.dma_handle = scp->request_bufflen ?
-                   dma_map_single(boardp->dev, scp->request_buffer,
-                                  scp->request_bufflen,
-                                  scp->sc_data_direction) : 0;
-               asc_scsi_q->q1.data_addr = cpu_to_le32(scp->SCp.dma_handle);
-               asc_scsi_q->q1.data_cnt = cpu_to_le32(scp->request_bufflen);
-               ASC_STATS_ADD(scp->device->host, cont_xfer,
-                             ASC_CEILING(scp->request_bufflen, 512));
-               asc_scsi_q->q1.sg_queue_cnt = 0;
-               asc_scsi_q->sg_head = NULL;
-       } else {
-               /*
-                * CDB scatter-gather request list.
-                */
+       /* Build ASC_SCSI_Q */
+       use_sg = scsi_dma_map(scp);
+       if (use_sg != 0) {
                int sgcnt;
-               int use_sg;
                struct scatterlist *slp;
                struct asc_sg_head *asc_sg_head;
 
-               slp = (struct scatterlist *)scp->request_buffer;
-               use_sg = dma_map_sg(boardp->dev, slp, scp->use_sg,
-                                   scp->sc_data_direction);
-
                if (use_sg > scp->device->host->sg_tablesize) {
                        scmd_printk(KERN_ERR, scp, "use_sg %d > "
                                "sg_tablesize %d\n", use_sg,
                                scp->device->host->sg_tablesize);
-                       dma_unmap_sg(boardp->dev, slp, scp->use_sg,
-                                    scp->sc_data_direction);
+                       scsi_dma_unmap(scp);
                        scp->result = HOST_BYTE(DID_ERROR);
                        return ASC_ERROR;
                }
 
-               ASC_STATS(scp->device->host, sg_cnt);
-
                asc_sg_head = kzalloc(sizeof(asc_scsi_q->sg_head) +
                        use_sg * sizeof(struct asc_sg_list), GFP_ATOMIC);
                if (!asc_sg_head) {
-                       dma_unmap_sg(boardp->dev, slp, scp->use_sg,
-                                    scp->sc_data_direction);
+                       scsi_dma_unmap(scp);
                        scp->result = HOST_BYTE(DID_SOFT_ERROR);
                        return ASC_ERROR;
                }
@@ -9974,22 +9964,24 @@ static int asc_build_req(struct asc_board *boardp, struct scsi_cmnd *scp,
                asc_scsi_q->q1.data_addr = 0;
                /* This is a byte value, otherwise it would need to be swapped. */
                asc_sg_head->entry_cnt = asc_scsi_q->q1.sg_queue_cnt = use_sg;
-               ASC_STATS_ADD(scp->device->host, sg_elem,
+               ASC_STATS_ADD(scp->device->host, xfer_elem,
                              asc_sg_head->entry_cnt);
 
                /*
                 * Convert scatter-gather list into ASC_SG_HEAD list.
                 */
-               for (sgcnt = 0; sgcnt < use_sg; sgcnt++, slp++) {
+               scsi_for_each_sg(scp, slp, use_sg, sgcnt) {
                        asc_sg_head->sg_list[sgcnt].addr =
                            cpu_to_le32(sg_dma_address(slp));
                        asc_sg_head->sg_list[sgcnt].bytes =
                            cpu_to_le32(sg_dma_len(slp));
-                       ASC_STATS_ADD(scp->device->host, sg_xfer,
-                                     ASC_CEILING(sg_dma_len(slp), 512));
+                       ASC_STATS_ADD(scp->device->host, xfer_sect,
+                                     DIV_ROUND_UP(sg_dma_len(slp), 512));
                }
        }
 
+       ASC_STATS(scp->device->host, xfer_cnt);
+
        ASC_DBG_PRT_ASC_SCSI_Q(2, asc_scsi_q);
        ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);
 
@@ -10021,7 +10013,7 @@ adv_get_sglist(struct asc_board *boardp, adv_req_t *reqp, struct scsi_cmnd *scp,
        int i;
 
        scsiqp = (ADV_SCSI_REQ_Q *)ADV_32BALIGN(&reqp->scsi_req_q);
-       slp = (struct scatterlist *)scp->request_buffer;
+       slp = scsi_sglist(scp);
        sg_elem_cnt = use_sg;
        prev_sg_block = NULL;
        reqp->sgblkp = NULL;
@@ -10093,8 +10085,8 @@ adv_get_sglist(struct asc_board *boardp, adv_req_t *reqp, struct scsi_cmnd *scp,
                                        cpu_to_le32(sg_dma_address(slp));
                        sg_block->sg_list[i].sg_count =
                                        cpu_to_le32(sg_dma_len(slp));
-                       ASC_STATS_ADD(scp->device->host, sg_xfer,
-                                     ASC_CEILING(sg_dma_len(slp), 512));
+                       ASC_STATS_ADD(scp->device->host, xfer_sect,
+                                     DIV_ROUND_UP(sg_dma_len(slp), 512));
 
                        if (--sg_elem_cnt == 0) {       /* Last ADV_SG_BLOCK and scatter-gather entry. */
                                sg_block->sg_cnt = i + 1;
@@ -10126,6 +10118,7 @@ adv_build_req(struct asc_board *boardp, struct scsi_cmnd *scp,
        ADV_SCSI_REQ_Q *scsiqp;
        int i;
        int ret;
+       int use_sg;
 
        /*
         * Allocate an adv_req_t structure from the board to execute
@@ -10154,7 +10147,7 @@ adv_build_req(struct asc_board *boardp, struct scsi_cmnd *scp,
        /*
         * Set the ADV_SCSI_REQ_Q 'srb_ptr' to point to the adv_req_t structure.
         */
-       scsiqp->srb_ptr = ASC_VADDR_TO_U32(reqp);
+       scsiqp->srb_ptr = ADV_VADDR_TO_U32(reqp);
 
        /*
         * Set the adv_req_t 'cmndp' to point to the struct scsi_cmnd structure.
@@ -10180,56 +10173,26 @@ adv_build_req(struct asc_board *boardp, struct scsi_cmnd *scp,
        scsiqp->target_lun = scp->device->lun;
 
        scsiqp->sense_addr = cpu_to_le32(virt_to_bus(&scp->sense_buffer[0]));
-       scsiqp->sense_len = sizeof(scp->sense_buffer);
-
-       /*
-        * Build ADV_SCSI_REQ_Q for a contiguous buffer or a scatter-gather
-        * buffer command.
-        */
+       scsiqp->sense_len = SCSI_SENSE_BUFFERSIZE;
 
-       scsiqp->data_cnt = cpu_to_le32(scp->request_bufflen);
-       scsiqp->vdata_addr = scp->request_buffer;
-       scsiqp->data_addr = cpu_to_le32(virt_to_bus(scp->request_buffer));
+       /* Build ADV_SCSI_REQ_Q */
 
-       if (scp->use_sg == 0) {
-               /*
-                * CDB request of single contiguous buffer.
-                */
+       use_sg = scsi_dma_map(scp);
+       if (use_sg == 0) {
+               /* Zero-length transfer */
                reqp->sgblkp = NULL;
-               scsiqp->data_cnt = cpu_to_le32(scp->request_bufflen);
-               if (scp->request_bufflen) {
-                       scsiqp->vdata_addr = scp->request_buffer;
-                       scp->SCp.dma_handle =
-                           dma_map_single(boardp->dev, scp->request_buffer,
-                                          scp->request_bufflen,
-                                          scp->sc_data_direction);
-               } else {
-                       scsiqp->vdata_addr = NULL;
-                       scp->SCp.dma_handle = 0;
-               }
-               scsiqp->data_addr = cpu_to_le32(scp->SCp.dma_handle);
+               scsiqp->data_cnt = 0;
+               scsiqp->vdata_addr = NULL;
+
+               scsiqp->data_addr = 0;
                scsiqp->sg_list_ptr = NULL;
                scsiqp->sg_real_addr = 0;
-               ASC_STATS(scp->device->host, cont_cnt);
-               ASC_STATS_ADD(scp->device->host, cont_xfer,
-                             ASC_CEILING(scp->request_bufflen, 512));
        } else {
-               /*
-                * CDB scatter-gather request list.
-                */
-               struct scatterlist *slp;
-               int use_sg;
-
-               slp = (struct scatterlist *)scp->request_buffer;
-               use_sg = dma_map_sg(boardp->dev, slp, scp->use_sg,
-                                   scp->sc_data_direction);
-
                if (use_sg > ADV_MAX_SG_LIST) {
                        scmd_printk(KERN_ERR, scp, "use_sg %d > "
                                   "ADV_MAX_SG_LIST %d\n", use_sg,
                                   scp->device->host->sg_tablesize);
-                       dma_unmap_sg(boardp->dev, slp, scp->use_sg,
-                                    scp->sc_data_direction);
+                       scsi_dma_unmap(scp);
                        scp->result = HOST_BYTE(DID_ERROR);
 
                        /*
@@ -10242,6 +10205,8 @@ adv_build_req(struct asc_board *boardp, struct scsi_cmnd *scp,
                        return ASC_ERROR;
                }
 
+               scsiqp->data_cnt = cpu_to_le32(scsi_bufflen(scp));
+
                ret = adv_get_sglist(boardp, reqp, scp, use_sg);
                if (ret != ADV_SUCCESS) {
                        /*
@@ -10254,10 +10219,11 @@ adv_build_req(struct asc_board *boardp, struct scsi_cmnd *scp,
                        return ret;
                }
 
-               ASC_STATS(scp->device->host, sg_cnt);
-               ASC_STATS_ADD(scp->device->host, sg_elem, use_sg);
+               ASC_STATS_ADD(scp->device->host, xfer_elem, use_sg);
        }
 
+       ASC_STATS(scp->device->host, xfer_cnt);
+
        ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
        ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);
 
@@ -10955,48 +10921,6 @@ static int AdvExeScsiQueue(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq)
 
 /*
  * Execute a single 'Scsi_Cmnd'.
- *
- * The function 'done' is called when the request has been completed.
- *
- * Scsi_Cmnd:
- *
- *  host - board controlling device
- *  device - device to send command
- *  target - target of device
- *  lun - lun of device
- *  cmd_len - length of SCSI CDB
- *  cmnd - buffer for SCSI 8, 10, or 12 byte CDB
- *  use_sg - if non-zero indicates scatter-gather request with use_sg elements
- *
- *  if (use_sg == 0) {
- *    request_buffer - buffer address for request
- *    request_bufflen - length of request buffer
- *  } else {
- *    request_buffer - pointer to scatterlist structure
- *  }
- *
- *  sense_buffer - sense command buffer
- *
- *  result (4 bytes of an int):
- *    Byte Meaning
- *    0 SCSI Status Byte Code
- *    1 SCSI One Byte Message Code
- *    2 Host Error Code
- *    3 Mid-Level Error Code
- *
- *  host driver fields:
- *    SCp - Scsi_Pointer used for command processing status
- *    scsi_done - used to save caller's done function
- *    host_scribble - used for pointer to another struct scsi_cmnd
- *
- * If this function returns ASC_NOERROR the request will be completed
- * from the interrupt handler.
- *
- * If this function returns ASC_ERROR the host error code has been set,
- * and the called must call asc_scsi_done.
- *
- * If ASC_BUSY is returned the request will be returned to the midlayer
- * and re-tried later.
  */
 static int asc_execute_scsi_cmnd(struct scsi_cmnd *scp)
 {
@@ -12337,7 +12261,7 @@ static ushort __devinit AdvReadEEPWord(AdvPortAddr iop_base, int eep_word_addr)
 /*
  * Write the EEPROM from 'cfg_buf'.
  */
-void __devinit
+static void __devinit
 AdvSet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
 {
        ushort *wbuf;
@@ -12404,7 +12328,7 @@ AdvSet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
 /*
  * Write the EEPROM from 'cfg_buf'.
  */
-void __devinit
+static void __devinit
 AdvSet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf)
 {
        ushort *wbuf;
@@ -12471,7 +12395,7 @@ AdvSet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf)
 /*
  * Write the EEPROM from 'cfg_buf'.
  */
-void __devinit
+static void __devinit
 AdvSet38C1600EEPConfig(AdvPortAddr iop_base, ADVEEP_38C1600_CONFIG *cfg_buf)
 {
        ushort *wbuf;
@@ -13409,8 +13333,8 @@ static int __devinit advansys_wide_init_chip(struct Scsi_Host *shost)
 
        }
 
-       ASC_DBG(1, "sg_cnt %d * %u = %u bytes\n", sg_cnt, sizeof(adv_sgblk_t),
-                (unsigned)(sizeof(adv_sgblk_t) * sg_cnt));
+       ASC_DBG(1, "sg_cnt %d * %lu = %lu bytes\n", sg_cnt, sizeof(adv_sgblk_t),
+                sizeof(adv_sgblk_t) * sg_cnt);
 
        if (!board->adv_sgblkp)
                goto kmalloc_failed;
@@ -13483,7 +13407,6 @@ static int __devinit advansys_board_found(struct Scsi_Host *shost,
                asc_dvc_varp->bus_type = bus_type;
                asc_dvc_varp->drv_ptr = boardp;
                asc_dvc_varp->cfg = &boardp->dvc_cfg.asc_dvc_cfg;
-               asc_dvc_varp->cfg->overrun_buf = &overrun_buf[0];
                asc_dvc_varp->iop_base = iop;
        } else {
 #ifdef CONFIG_PCI
@@ -13505,9 +13428,9 @@ static int __devinit advansys_board_found(struct Scsi_Host *shost,
                boardp->ioremap_addr = ioremap(pci_resource_start(pdev, 1),
                                               boardp->asc_n_io_port);
                if (!boardp->ioremap_addr) {
-                       shost_printk(KERN_ERR, shost, "ioremap(%x, %d) "
+                       shost_printk(KERN_ERR, shost, "ioremap(%lx, %d) "
                                        "returned NULL\n",
-                                       pci_resource_start(pdev, 1),
+                                       (long)pci_resource_start(pdev, 1),
                                        boardp->asc_n_io_port);
                        ret = -ENODEV;
                        goto err_shost;
@@ -13910,6 +13833,12 @@ static int __devinit advansys_board_found(struct Scsi_Host *shost,
         */
        if (ASC_NARROW_BOARD(boardp)) {
                ASC_DBG(2, "AscInitAsc1000Driver()\n");
+
+               asc_dvc_varp->overrun_buf = kzalloc(ASC_OVERRUN_BSIZE, GFP_KERNEL);
+               if (!asc_dvc_varp->overrun_buf) {
+                       ret = -ENOMEM;
+                       goto err_free_wide_mem;
+               }
                warn_code = AscInitAsc1000Driver(asc_dvc_varp);
 
                if (warn_code || asc_dvc_varp->err_code) {
@@ -13917,8 +13846,10 @@ static int __devinit advansys_board_found(struct Scsi_Host *shost,
                                        "warn 0x%x, error 0x%x\n",
                                        asc_dvc_varp->init_state, warn_code,
                                        asc_dvc_varp->err_code);
-                       if (asc_dvc_varp->err_code)
+                       if (asc_dvc_varp->err_code) {
                                ret = -ENODEV;
+                               kfree(asc_dvc_varp->overrun_buf);
+                       }
                }
        } else {
                if (advansys_wide_init_chip(shost))
@@ -13959,19 +13890,24 @@ static int __devinit advansys_board_found(struct Scsi_Host *shost,
  */
 static int advansys_release(struct Scsi_Host *shost)
 {
-       struct asc_board *boardp = shost_priv(shost);
+       struct asc_board *board = shost_priv(shost);
        ASC_DBG(1, "begin\n");
        scsi_remove_host(shost);
-       free_irq(boardp->irq, shost);
+       free_irq(board->irq, shost);
        if (shost->dma_channel != NO_ISA_DMA) {
                ASC_DBG(1, "free_dma()\n");
                free_dma(shost->dma_channel);
        }
-       if (!ASC_NARROW_BOARD(boardp)) {
-               iounmap(boardp->ioremap_addr);
-               advansys_wide_free_mem(boardp);
+       if (ASC_NARROW_BOARD(board)) {
+               dma_unmap_single(board->dev,
+                                       board->dvc_var.asc_dvc_var.overrun_dma,
+                                       ASC_OVERRUN_BSIZE, DMA_FROM_DEVICE);
+               kfree(board->dvc_var.asc_dvc_var.overrun_buf);
+       } else {
+               iounmap(board->ioremap_addr);
+               advansys_wide_free_mem(board);
        }
-       kfree(boardp->prtbuf);
+       kfree(board->prtbuf);
        scsi_host_put(shost);
        ASC_DBG(1, "end\n");
        return 0;
@@ -13979,7 +13915,7 @@ static int advansys_release(struct Scsi_Host *shost)
 
 #define ASC_IOADR_TABLE_MAX_IX  11
 
-static PortAddr _asc_def_iop_base[ASC_IOADR_TABLE_MAX_IX] __devinitdata = {
+static PortAddr _asc_def_iop_base[ASC_IOADR_TABLE_MAX_IX] = {
        0x100, 0x0110, 0x120, 0x0130, 0x140, 0x0150, 0x0190,
        0x0210, 0x0230, 0x0250, 0x0330
 };