summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorBart Van Assche <bvanassche@acm.org>2019-08-08 20:02:06 -0700
committerMartin K. Petersen <martin.petersen@oracle.com>2019-08-12 21:34:08 -0400
commit85cffefa09e448906a6f0bc20f422d75a18675bd (patch)
tree514d00f532ba5e329c1c73307a59b2317deb283e /drivers
parentbdb61b9b944d1e5b7cee5a9fe21014363c55b811 (diff)
scsi: qla2xxx: Fix a race condition between aborting and completing a SCSI command
Instead of allocating a struct srb dynamically from inside .queuecommand(), set qla2xxx_driver_template.cmd_size such that struct scsi_cmnd and struct srb are contiguous. Do not call QLA_QPAIR_MARK_BUSY() / QLA_QPAIR_MARK_NOT_BUSY() for SRBs associated with SCSI commands. That is safe because scsi_remove_host() is called before queue pairs are deleted and scsi_remove_host() waits for all outstanding SCSI commands to finish. Cc: Himanshu Madhani <hmadhani@marvell.com> Signed-off-by: Bart Van Assche <bvanassche@acm.org> Tested-by: Himanshu Madhani <hmadhani@marvell.com> Reviewed-by: Himanshu Madhani <hmadhani@marvell.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/scsi/qla2xxx/qla_def.h1
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c45
2 files changed, 8 insertions, 38 deletions
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 65d79bcb7ccf..3ffe7661a25b 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -630,7 +630,6 @@ typedef struct srb {
} srb_t;
#define GET_CMD_SP(sp) (sp->u.scmd.cmd)
-#define SET_CMD_SP(sp, cmd) (sp->u.scmd.cmd = cmd)
#define GET_CMD_CTX_SP(sp) (sp->u.scmd.ctx)
#define GET_CMD_SENSE_LEN(sp) \
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 9ef59995f5d6..5ca7f7913258 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -713,7 +713,6 @@ void qla2x00_sp_compl(srb_t *sp, int res)
cmd->scsi_done(cmd);
if (comp)
complete(comp);
- qla2x00_rel_sp(sp);
}
void qla2xxx_qpair_sp_free_dma(srb_t *sp)
@@ -814,7 +813,6 @@ void qla2xxx_qpair_sp_compl(srb_t *sp, int res)
cmd->scsi_done(cmd);
if (comp)
complete(comp);
- qla2xxx_rel_qpair_sp(sp->qpair, sp);
}
static int
@@ -908,9 +906,8 @@ qla2xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
else
goto qc24_target_busy;
- sp = qla2x00_get_sp(vha, fcport, GFP_ATOMIC);
- if (!sp)
- goto qc24_host_busy;
+ sp = scsi_cmd_priv(cmd);
+ qla2xxx_init_sp(sp, vha, vha->hw->base_qpair, fcport);
sp->u.scmd.cmd = cmd;
sp->type = SRB_SCSI_CMD;
@@ -931,9 +928,6 @@ qla2xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
qc24_host_busy_free_sp:
sp->free(sp);
-qc24_host_busy:
- return SCSI_MLQUEUE_HOST_BUSY;
-
qc24_target_busy:
return SCSI_MLQUEUE_TARGET_BUSY;
@@ -994,9 +988,8 @@ qla2xxx_mqueuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd,
else
goto qc24_target_busy;
- sp = qla2xxx_get_qpair_sp(vha, qpair, fcport, GFP_ATOMIC);
- if (!sp)
- goto qc24_host_busy;
+ sp = scsi_cmd_priv(cmd);
+ qla2xxx_init_sp(sp, vha, qpair, fcport);
sp->u.scmd.cmd = cmd;
sp->type = SRB_SCSI_CMD;
@@ -1020,9 +1013,6 @@ qla2xxx_mqueuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd,
qc24_host_busy_free_sp:
sp->free(sp);
-qc24_host_busy:
- return SCSI_MLQUEUE_HOST_BUSY;
-
qc24_target_busy:
return SCSI_MLQUEUE_TARGET_BUSY;
@@ -1257,10 +1247,8 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
int ret;
unsigned int id;
uint64_t lun;
- unsigned long flags;
int rval;
struct qla_hw_data *ha = vha->hw;
- struct qla_qpair *qpair;
if (qla2x00_isp_reg_stat(ha)) {
ql_log(ql_log_info, vha, 0x8042,
@@ -1272,32 +1260,14 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
if (ret != 0)
return ret;
- sp = (srb_t *) CMD_SP(cmd);
- if (!sp)
- return SUCCESS;
-
- qpair = sp->qpair;
- if (!qpair)
- return SUCCESS;
+ sp = scsi_cmd_priv(cmd);
if (sp->fcport && sp->fcport->deleted)
return SUCCESS;
- spin_lock_irqsave(qpair->qp_lock_ptr, flags);
- if (sp->type != SRB_SCSI_CMD || GET_CMD_SP(sp) != cmd) {
- /* there's a chance an interrupt could clear
- the ptr as part of done & free */
- spin_unlock_irqrestore(qpair->qp_lock_ptr, flags);
- return SUCCESS;
- }
-
- /* Get a reference to the sp and drop the lock. */
- if (sp_get(sp)){
- /* ref_count is already 0 */
- spin_unlock_irqrestore(qpair->qp_lock_ptr, flags);
+ /* Return if the command has already finished. */
+ if (sp_get(sp))
return SUCCESS;
- }
- spin_unlock_irqrestore(qpair->qp_lock_ptr, flags);
id = cmd->device->id;
lun = cmd->device->lun;
@@ -7159,6 +7129,7 @@ struct scsi_host_template qla2xxx_driver_template = {
.supported_mode = MODE_INITIATOR,
.track_queue_depth = 1,
+ .cmd_size = sizeof(srb_t),
};
static const struct pci_error_handlers qla2xxx_err_handler = {