Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 15e3d5a2 authored by Christoph Hellwig's avatar Christoph Hellwig Committed by James Bottomley
Browse files

3w-9xxx: don't unmap bounce buffered commands



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: default avatarTóth Attila <atoth@atoth.sote.hu>
Tested-by: default avatarTóth Attila <atoth@atoth.sote.hu>
Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Acked-by: default avatarAdam Radford <aradford@gmail.com>
Signed-off-by: default avatarJames Bottomley <JBottomley@Odin.com>
parent 1378889c
Loading
Loading
Loading
Loading
+21 −7
Original line number Diff line number Diff line
@@ -212,6 +212,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)
{
@@ -1339,6 +1350,7 @@ static irqreturn_t twa_interrupt(int irq, void *dev_instance)
				}

				/* Now complete the io */
				if (twa_command_mapped(cmd))
					scsi_dma_unmap(cmd);
				cmd->scsi_done(cmd);
				tw_dev->state[request_id] = TW_S_COMPLETED;
@@ -1582,6 +1594,7 @@ static int twa_reset_device_extension(TW_Device_Extension *tw_dev)
				struct scsi_cmnd *cmd = tw_dev->srb[i];

				cmd->result = (DID_RESET << 16);
				if (twa_command_mapped(cmd))
					scsi_dma_unmap(cmd);
				cmd->scsi_done(cmd);
			}
@@ -1765,11 +1778,13 @@ 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:
		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);
		if (twa_command_mapped(SCpnt))
			scsi_dma_unmap(SCpnt);
		done(SCpnt);
		tw_dev->state[request_id] = TW_S_COMPLETED;
@@ -1831,8 +1846,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,
@@ -1905,7 +1919,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) {