Skip to content

Commit

Permalink
3w-9xxx: don't unmap bounce buffered commands
Browse files Browse the repository at this point in the history
[ Upstream commit 15e3d5a ]

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: Sasha Levin <sasha.levin@oracle.com>
  • Loading branch information
Christoph Hellwig authored and Sasha Levin committed Oct 28, 2015
1 parent cb4b2ae commit 4f1a98a
Showing 1 changed file with 21 additions and 7 deletions.
28 changes: 21 additions & 7 deletions drivers/scsi/3w-9xxx.c
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,17 @@ static const struct file_operations twa_fops = {
.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)
{
Expand Down Expand Up @@ -1351,7 +1362,8 @@ static irqreturn_t twa_interrupt(int irq, void *dev_instance)
}

/* 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);
Expand Down Expand Up @@ -1594,7 +1606,8 @@ static int twa_reset_device_extension(TW_Device_Extension *tw_dev)
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);
}
}
Expand Down Expand Up @@ -1777,12 +1790,14 @@ static int twa_scsi_queue_lck(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_
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);
Expand Down Expand Up @@ -1843,8 +1858,7 @@ static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id,
/* 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,
Expand Down Expand Up @@ -1917,7 +1931,7 @@ static void twa_scsiop_execute_scsi_complete(TW_Device_Extension *tw_dev, int re
{
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) {
Expand Down

0 comments on commit 4f1a98a

Please sign in to comment.