tree e33d19493190076f147912e40207f6956c290eb9
parent bdf796210e01145fd77bbb3ae644d04f982b6c3b
author <[EMAIL PROTECTED]> Mon, 18 Apr 2005 01:10:41 -0500
committer James Bottomley <[EMAIL PROTECTED]> Mon, 18 Apr 2005 23:48:12 -0500

[PATCH] qla2xxx: cleanup DMA mappings...

  Don't use cmd->request->nr_hw_segments as it may not be initialized
  (SG_IO in particular bypasses anything that initializes this and just
  uses scsi_do_req to insert a scsi_request directly on the head of the
  queue) and a bogus value here can trip up the checks to make sure that
  the number of segments will fit in the queue ring buffer, resulting in
  commands that are never completed.

  Fix up several issues with PCI DMA mapping and failure to check return
  values on the mappings.

  Make the check for space in the ring buffer happen after the DMA mapping
  is done since any checks done before the mapping has taken place are
  bogus.

  Doug Ledford <[EMAIL PROTECTED]>.

Signed-off-by: Andrew Vasquez <[EMAIL PROTECTED]>
Signed-off-by: James Bottomley <[EMAIL PROTECTED]>

 scsi/qla2xxx/qla_iocb.c |   72 ++++++++++++++++++++++--------------------------
 1 files changed, 33 insertions(+), 39 deletions(-)

Index: drivers/scsi/qla2xxx/qla_iocb.c
===================================================================
--- 92253748a63c51e76a70384d35119e107077b050/drivers/scsi/qla2xxx/qla_iocb.c  
(mode:100644 sha1:59d62cbb994e770341c9f5a08617cc54777b5644)
+++ e33d19493190076f147912e40207f6956c290eb9/drivers/scsi/qla2xxx/qla_iocb.c  
(mode:100644 sha1:af964bb3d87052c3f61807344f79135339471b9d)
@@ -216,18 +216,7 @@
                        cur_seg++;
                }
        } else {
-               dma_addr_t      req_dma;
-               struct page     *page;
-               unsigned long   offset;
-
-               page = virt_to_page(cmd->request_buffer);
-               offset = ((unsigned long)cmd->request_buffer & ~PAGE_MASK);
-               req_dma = pci_map_page(ha->pdev, page, offset,
-                   cmd->request_bufflen, cmd->sc_data_direction);
-
-               sp->dma_handle = req_dma;
-
-               *cur_dsd++ = cpu_to_le32(req_dma);
+               *cur_dsd++ = cpu_to_le32(sp->dma_handle);
                *cur_dsd++ = cpu_to_le32(cmd->request_bufflen);
        }
 }
@@ -299,19 +288,8 @@
                        cur_seg++;
                }
        } else {
-               dma_addr_t      req_dma;
-               struct page     *page;
-               unsigned long   offset;
-
-               page = virt_to_page(cmd->request_buffer);
-               offset = ((unsigned long)cmd->request_buffer & ~PAGE_MASK);
-               req_dma = pci_map_page(ha->pdev, page, offset,
-                   cmd->request_bufflen, cmd->sc_data_direction);
-
-               sp->dma_handle = req_dma;
-
-               *cur_dsd++ = cpu_to_le32(LSD(req_dma));
-               *cur_dsd++ = cpu_to_le32(MSD(req_dma));
+               *cur_dsd++ = cpu_to_le32(LSD(sp->dma_handle));
+               *cur_dsd++ = cpu_to_le32(MSD(sp->dma_handle));
                *cur_dsd++ = cpu_to_le32(cmd->request_bufflen);
        }
 }
@@ -345,6 +323,8 @@
        ha = sp->ha;
        reg = ha->iobase;
        cmd = sp->cmd;
+       /* So we know we haven't pci_map'ed anything yet */
+       tot_dsds = 0;
 
        /* Send marker if required */
        if (ha->marker_needed != 0) {
@@ -369,8 +349,27 @@
        if (index == MAX_OUTSTANDING_COMMANDS)
                goto queuing_error;
 
+       /* Map the sg table so we have an accurate count of sg entries needed */
+       if (cmd->use_sg) {
+               sg = (struct scatterlist *) cmd->request_buffer;
+               tot_dsds = pci_map_sg(ha->pdev, sg, cmd->use_sg,
+                   cmd->sc_data_direction);
+               if (tot_dsds == 0)
+                       goto queuing_error;
+       } else if (cmd->request_bufflen) {
+               dma_addr_t      req_dma;
+
+               req_dma = pci_map_single(ha->pdev, cmd->request_buffer,
+                   cmd->request_bufflen, cmd->sc_data_direction);
+               if (dma_mapping_error(req_dma))
+                       goto queuing_error;
+
+               sp->dma_handle = req_dma;
+               tot_dsds = 1;
+       }
+
        /* Calculate the number of request entries needed. */
-       req_cnt = (ha->calc_request_entries)(cmd->request->nr_hw_segments);
+       req_cnt = (ha->calc_request_entries)(tot_dsds);
        if (ha->req_q_cnt < (req_cnt + 2)) {
                cnt = RD_REG_WORD_RELAXED(ISP_REQ_Q_OUT(ha, reg));
                if (ha->req_ring_index < cnt)
@@ -382,19 +381,6 @@
        if (ha->req_q_cnt < (req_cnt + 2))
                goto queuing_error;
 
-       /* Finally, we have enough space, now perform mappings. */
-       tot_dsds = 0;
-       if (cmd->use_sg) {
-               sg = (struct scatterlist *) cmd->request_buffer;
-               tot_dsds = pci_map_sg(ha->pdev, sg, cmd->use_sg,
-                   cmd->sc_data_direction);
-               if (tot_dsds == 0)
-                       goto queuing_error;
-       } else if (cmd->request_bufflen) {
-           tot_dsds++;
-       }
-       req_cnt = (ha->calc_request_entries)(tot_dsds);
-
        /* Build command packet */
        ha->current_outstanding_cmd = handle;
        ha->outstanding_cmds[handle] = sp;
@@ -461,6 +447,14 @@
        return (QLA_SUCCESS);
 
 queuing_error:
+       if (cmd->use_sg && tot_dsds) {
+               sg = (struct scatterlist *) cmd->request_buffer;
+               pci_unmap_sg(ha->pdev, sg, cmd->use_sg,
+                   cmd->sc_data_direction);
+       } else if (tot_dsds) {
+               pci_unmap_single(ha->pdev, sp->dma_handle,
+                   cmd->request_bufflen, cmd->sc_data_direction);
+       }
        spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
        return (QLA_FUNCTION_FAILED);
-
To unsubscribe from this list: send the line "unsubscribe bk-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to