| From 15e3d5a285ab9283136dba34bbf72886d9146706 Mon Sep 17 00:00:00 2001 |
| From: Christoph Hellwig <hch@lst.de> |
| Date: Sat, 3 Oct 2015 19:16:07 +0200 |
| Subject: 3w-9xxx: don't unmap bounce buffered commands |
| MIME-Version: 1.0 |
| Content-Type: text/plain; charset=UTF-8 |
| Content-Transfer-Encoding: 8bit |
| |
| From: Christoph Hellwig <hch@lst.de> |
| |
| commit 15e3d5a285ab9283136dba34bbf72886d9146706 upstream. |
| |
| 3w controller don't dma map small single SGL entry commands but instead |
| bounce buffer them. Add a helper to identify these commands and don't |
| call scsi_dma_unmap for them. |
| |
| Based on an earlier patch from James Bottomley. |
| |
| Fixes: 118c85 ("3w-9xxx: fix command completion race") |
| Reported-by: Tóth Attila <atoth@atoth.sote.hu> |
| Tested-by: Tóth Attila <atoth@atoth.sote.hu> |
| Signed-off-by: Christoph Hellwig <hch@lst.de> |
| Acked-by: Adam Radford <aradford@gmail.com> |
| Signed-off-by: James Bottomley <JBottomley@Odin.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/scsi/3w-9xxx.c | 28 +++++++++++++++++++++------- |
| 1 file changed, 21 insertions(+), 7 deletions(-) |
| |
| --- a/drivers/scsi/3w-9xxx.c |
| +++ b/drivers/scsi/3w-9xxx.c |
| @@ -225,6 +225,17 @@ static const struct file_operations twa_ |
| .llseek = noop_llseek, |
| }; |
| |
| +/* |
| + * The controllers use an inline buffer instead of a mapped SGL for small, |
| + * single entry buffers. Note that we treat a zero-length transfer like |
| + * a mapped SGL. |
| + */ |
| +static bool twa_command_mapped(struct scsi_cmnd *cmd) |
| +{ |
| + return scsi_sg_count(cmd) != 1 || |
| + scsi_bufflen(cmd) >= TW_MIN_SGL_LENGTH; |
| +} |
| + |
| /* This function will complete an aen request from the isr */ |
| static int twa_aen_complete(TW_Device_Extension *tw_dev, int request_id) |
| { |
| @@ -1351,7 +1362,8 @@ static irqreturn_t twa_interrupt(int irq |
| } |
| |
| /* Now complete the io */ |
| - scsi_dma_unmap(cmd); |
| + if (twa_command_mapped(cmd)) |
| + scsi_dma_unmap(cmd); |
| cmd->scsi_done(cmd); |
| tw_dev->state[request_id] = TW_S_COMPLETED; |
| twa_free_request_id(tw_dev, request_id); |
| @@ -1594,7 +1606,8 @@ static int twa_reset_device_extension(TW |
| struct scsi_cmnd *cmd = tw_dev->srb[i]; |
| |
| cmd->result = (DID_RESET << 16); |
| - scsi_dma_unmap(cmd); |
| + if (twa_command_mapped(cmd)) |
| + scsi_dma_unmap(cmd); |
| cmd->scsi_done(cmd); |
| } |
| } |
| @@ -1777,12 +1790,14 @@ static int twa_scsi_queue_lck(struct scs |
| retval = twa_scsiop_execute_scsi(tw_dev, request_id, NULL, 0, NULL); |
| switch (retval) { |
| case SCSI_MLQUEUE_HOST_BUSY: |
| - scsi_dma_unmap(SCpnt); |
| + if (twa_command_mapped(SCpnt)) |
| + scsi_dma_unmap(SCpnt); |
| twa_free_request_id(tw_dev, request_id); |
| break; |
| case 1: |
| SCpnt->result = (DID_ERROR << 16); |
| - scsi_dma_unmap(SCpnt); |
| + if (twa_command_mapped(SCpnt)) |
| + scsi_dma_unmap(SCpnt); |
| done(SCpnt); |
| tw_dev->state[request_id] = TW_S_COMPLETED; |
| twa_free_request_id(tw_dev, request_id); |
| @@ -1843,8 +1858,7 @@ static int twa_scsiop_execute_scsi(TW_De |
| /* Map sglist from scsi layer to cmd packet */ |
| |
| if (scsi_sg_count(srb)) { |
| - if ((scsi_sg_count(srb) == 1) && |
| - (scsi_bufflen(srb) < TW_MIN_SGL_LENGTH)) { |
| + if (!twa_command_mapped(srb)) { |
| if (srb->sc_data_direction == DMA_TO_DEVICE || |
| srb->sc_data_direction == DMA_BIDIRECTIONAL) |
| scsi_sg_copy_to_buffer(srb, |
| @@ -1917,7 +1931,7 @@ static void twa_scsiop_execute_scsi_comp |
| { |
| struct scsi_cmnd *cmd = tw_dev->srb[request_id]; |
| |
| - if (scsi_bufflen(cmd) < TW_MIN_SGL_LENGTH && |
| + if (!twa_command_mapped(cmd) && |
| (cmd->sc_data_direction == DMA_FROM_DEVICE || |
| cmd->sc_data_direction == DMA_BIDIRECTIONAL)) { |
| if (scsi_sg_count(cmd) == 1) { |