[SCSI] buslogic: Added check for DMA mapping errors
authorKhalid Aziz <khalid.aziz@oracle.com>
Fri, 13 Sep 2013 19:44:06 +0000 (13:44 -0600)
committerJames Bottomley <JBottomley@Parallels.com>
Fri, 25 Oct 2013 08:57:57 +0000 (09:57 +0100)
Added check for DMA mapping errors for request sense data
buffer. Checking for mapping error can avoid potential wild
writes. This patch was prompted by the warning from
dma_unmap when kernel is compiled with CONFIG_DMA_API_DEBUG.

Signed-off-by: Khalid Aziz <khalid.aziz@oracle.com>
Tested-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
drivers/scsi/BusLogic.c

index 757eb0716d45d4f273519ca2e2dd2ed03486a4a8..972f8176665fd07d5b9c6bee25cea3e8e9286fc1 100644 (file)
@@ -26,8 +26,8 @@
 
 */
 
-#define blogic_drvr_version            "2.1.16"
-#define blogic_drvr_date               "18 July 2002"
+#define blogic_drvr_version            "2.1.17"
+#define blogic_drvr_date               "12 September 2013"
 
 #include <linux/module.h>
 #include <linux/init.h>
@@ -311,12 +311,14 @@ static struct blogic_ccb *blogic_alloc_ccb(struct blogic_adapter *adapter)
   caller.
 */
 
-static void blogic_dealloc_ccb(struct blogic_ccb *ccb)
+static void blogic_dealloc_ccb(struct blogic_ccb *ccb, int dma_unmap)
 {
        struct blogic_adapter *adapter = ccb->adapter;
 
-       scsi_dma_unmap(ccb->command);
-       pci_unmap_single(adapter->pci_device, ccb->sensedata,
+       if (ccb->command != NULL)
+               scsi_dma_unmap(ccb->command);
+       if (dma_unmap)
+               pci_unmap_single(adapter->pci_device, ccb->sensedata,
                         ccb->sense_datalen, PCI_DMA_FROMDEVICE);
 
        ccb->command = NULL;
@@ -2762,8 +2764,8 @@ static void blogic_process_ccbs(struct blogic_adapter *adapter)
                        /*
                           Place CCB back on the Host Adapter's free list.
                         */
-                       blogic_dealloc_ccb(ccb);
-#if 0                          /* this needs to be redone different for new EH */
+                       blogic_dealloc_ccb(ccb, 1);
+#if 0                  /* this needs to be redone different for new EH */
                        /*
                           Bus Device Reset CCBs have the command field
                           non-NULL only when a Bus Device Reset was requested
@@ -2791,7 +2793,7 @@ static void blogic_process_ccbs(struct blogic_adapter *adapter)
                                if (ccb->status == BLOGIC_CCB_RESET &&
                                                ccb->tgt_id == tgt_id) {
                                        command = ccb->command;
-                                       blogic_dealloc_ccb(ccb);
+                                       blogic_dealloc_ccb(ccb, 1);
                                        adapter->active_cmds[tgt_id]--;
                                        command->result = DID_RESET << 16;
                                        command->scsi_done(command);
@@ -2862,7 +2864,7 @@ static void blogic_process_ccbs(struct blogic_adapter *adapter)
                        /*
                           Place CCB back on the Host Adapter's free list.
                         */
-                       blogic_dealloc_ccb(ccb);
+                       blogic_dealloc_ccb(ccb, 1);
                        /*
                           Call the SCSI Command Completion Routine.
                         */
@@ -3034,6 +3036,7 @@ static int blogic_qcmd_lck(struct scsi_cmnd *command,
        int buflen = scsi_bufflen(command);
        int count;
        struct blogic_ccb *ccb;
+       dma_addr_t sense_buf;
 
        /*
           SCSI REQUEST_SENSE commands will be executed automatically by the
@@ -3179,10 +3182,17 @@ static int blogic_qcmd_lck(struct scsi_cmnd *command,
        }
        memcpy(ccb->cdb, cdb, cdblen);
        ccb->sense_datalen = SCSI_SENSE_BUFFERSIZE;
-       ccb->sensedata = pci_map_single(adapter->pci_device,
+       ccb->command = command;
+       sense_buf = pci_map_single(adapter->pci_device,
                                command->sense_buffer, ccb->sense_datalen,
                                PCI_DMA_FROMDEVICE);
-       ccb->command = command;
+       if (dma_mapping_error(&adapter->pci_device->dev, sense_buf)) {
+               blogic_err("DMA mapping for sense data buffer failed\n",
+                               adapter);
+               blogic_dealloc_ccb(ccb, 0);
+               return SCSI_MLQUEUE_HOST_BUSY;
+       }
+       ccb->sensedata = sense_buf;
        command->scsi_done = comp_cb;
        if (blogic_multimaster_type(adapter)) {
                /*
@@ -3203,7 +3213,7 @@ static int blogic_qcmd_lck(struct scsi_cmnd *command,
                        if (!blogic_write_outbox(adapter, BLOGIC_MBOX_START,
                                                ccb)) {
                                blogic_warn("Still unable to write Outgoing Mailbox - " "Host Adapter Dead?\n", adapter);
-                               blogic_dealloc_ccb(ccb);
+                               blogic_dealloc_ccb(ccb, 1);
                                command->result = DID_ERROR << 16;
                                command->scsi_done(command);
                        }
@@ -3337,7 +3347,7 @@ static int blogic_resetadapter(struct blogic_adapter *adapter, bool hard_reset)
 
        for (ccb = adapter->all_ccbs; ccb != NULL; ccb = ccb->next_all)
                if (ccb->status == BLOGIC_CCB_ACTIVE)
-                       blogic_dealloc_ccb(ccb);
+                       blogic_dealloc_ccb(ccb, 1);
        /*
         * Wait a few seconds between the Host Adapter Hard Reset which
         * initiates a SCSI Bus Reset and issuing any SCSI Commands.  Some