Commit 1c6653fd authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Greg Kroah-Hartman

3w-sas: fix command completion race

commit 579d69bc upstream.

The 3w-sas driver needs to tear down the dma mappings before returning
the command to the midlayer, as there is no guarantee the sglist and
count are valid after that point.  Also remove the dma mapping helpers
which have another inherent race due to the request_id index.
Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Reported-by: default avatarTorsten Luettgert <ml-lkml@enda.eu>
Tested-by: default avatarBernd Kardatzki <Bernd.Kardatzki@med.uni-tuebingen.de>
Acked-by: default avatarAdam Radford <aradford@gmail.com>
Signed-off-by: default avatarJames Bottomley <JBottomley@Odin.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 457eb9e1
......@@ -290,26 +290,6 @@ static int twl_post_command_packet(TW_Device_Extension *tw_dev, int request_id)
return 0;
} /* End twl_post_command_packet() */
/* This function will perform a pci-dma mapping for a scatter gather list */
static int twl_map_scsi_sg_data(TW_Device_Extension *tw_dev, int request_id)
{
int use_sg;
struct scsi_cmnd *cmd = tw_dev->srb[request_id];
use_sg = scsi_dma_map(cmd);
if (!use_sg)
return 0;
else if (use_sg < 0) {
TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1, "Failed to map scatter gather list");
return 0;
}
cmd->SCp.phase = TW_PHASE_SGLIST;
cmd->SCp.have_data_in = use_sg;
return use_sg;
} /* End twl_map_scsi_sg_data() */
/* This function hands scsi cdb's to the firmware */
static int twl_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, char *cdb, int use_sg, TW_SG_Entry_ISO *sglistarg)
{
......@@ -357,8 +337,8 @@ static int twl_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id,
if (!sglistarg) {
/* Map sglist from scsi layer to cmd packet */
if (scsi_sg_count(srb)) {
sg_count = twl_map_scsi_sg_data(tw_dev, request_id);
if (sg_count == 0)
sg_count = scsi_dma_map(srb);
if (sg_count <= 0)
goto out;
scsi_for_each_sg(srb, sg, sg_count, i) {
......@@ -1102,15 +1082,6 @@ static int twl_initialize_device_extension(TW_Device_Extension *tw_dev)
return retval;
} /* End twl_initialize_device_extension() */
/* This function will perform a pci-dma unmap */
static void twl_unmap_scsi_data(TW_Device_Extension *tw_dev, int request_id)
{
struct scsi_cmnd *cmd = tw_dev->srb[request_id];
if (cmd->SCp.phase == TW_PHASE_SGLIST)
scsi_dma_unmap(cmd);
} /* End twl_unmap_scsi_data() */
/* This function will handle attention interrupts */
static int twl_handle_attention_interrupt(TW_Device_Extension *tw_dev)
{
......@@ -1251,11 +1222,11 @@ static irqreturn_t twl_interrupt(int irq, void *dev_instance)
}
/* Now complete the io */
scsi_dma_unmap(cmd);
cmd->scsi_done(cmd);
tw_dev->state[request_id] = TW_S_COMPLETED;
twl_free_request_id(tw_dev, request_id);
tw_dev->posted_request_count--;
tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
twl_unmap_scsi_data(tw_dev, request_id);
}
/* Check for another response interrupt */
......@@ -1400,10 +1371,12 @@ static int twl_reset_device_extension(TW_Device_Extension *tw_dev, int ioctl_res
if ((tw_dev->state[i] != TW_S_FINISHED) &&
(tw_dev->state[i] != TW_S_INITIAL) &&
(tw_dev->state[i] != TW_S_COMPLETED)) {
if (tw_dev->srb[i]) {
tw_dev->srb[i]->result = (DID_RESET << 16);
tw_dev->srb[i]->scsi_done(tw_dev->srb[i]);
twl_unmap_scsi_data(tw_dev, i);
struct scsi_cmnd *cmd = tw_dev->srb[i];
if (cmd) {
cmd->result = (DID_RESET << 16);
scsi_dma_unmap(cmd);
cmd->scsi_done(cmd);
}
}
}
......@@ -1507,9 +1480,6 @@ static int twl_scsi_queue_lck(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_
/* Save the scsi command for use by the ISR */
tw_dev->srb[request_id] = SCpnt;
/* Initialize phase to zero */
SCpnt->SCp.phase = TW_PHASE_INITIAL;
retval = twl_scsiop_execute_scsi(tw_dev, request_id, NULL, 0, NULL);
if (retval) {
tw_dev->state[request_id] = TW_S_COMPLETED;
......
......@@ -103,10 +103,6 @@ static char *twl_aen_severity_table[] =
#define TW_CURRENT_DRIVER_BUILD 0
#define TW_CURRENT_DRIVER_BRANCH 0
/* Phase defines */
#define TW_PHASE_INITIAL 0
#define TW_PHASE_SGLIST 2
/* Misc defines */
#define TW_SECTOR_SIZE 512
#define TW_MAX_UNITS 32
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment