mirror of
https://github.com/SCST-project/scst.git
synced 2026-05-20 12:11:26 +00:00
qla2x00t-32gbit: 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. [ commit 85cffefa09e448906a6f0bc20f422d75a18675bd upstream ] git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@8546 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
@@ -648,7 +648,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) \
|
||||
|
||||
@@ -733,7 +733,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)
|
||||
@@ -834,7 +833,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);
|
||||
}
|
||||
|
||||
#if defined(RHEL_MAJOR) && RHEL_MAJOR -0 == 6 && RHEL_MINOR -0 >= 2
|
||||
@@ -945,9 +943,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;
|
||||
@@ -968,9 +965,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;
|
||||
|
||||
@@ -1031,9 +1025,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;
|
||||
@@ -1057,9 +1050,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;
|
||||
|
||||
@@ -1301,10 +1291,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,
|
||||
@@ -1316,30 +1304,12 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
sp = (srb_t *) CMD_SP(cmd);
|
||||
if (!sp)
|
||||
return SUCCESS;
|
||||
sp = scsi_cmd_priv(cmd);
|
||||
|
||||
qpair = sp->qpair;
|
||||
if (!qpair)
|
||||
/* Return if the command has already finished. */
|
||||
if (sp_get(sp))
|
||||
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 SUCCESS;
|
||||
}
|
||||
spin_unlock_irqrestore(qpair->qp_lock_ptr, flags);
|
||||
|
||||
id = cmd->device->id;
|
||||
lun = cmd->device->lun;
|
||||
|
||||
@@ -1365,6 +1335,7 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
|
||||
uint32_t ratov = ha->r_a_tov/10;
|
||||
uint32_t ratov_j = msecs_to_jiffies(4 * ratov * 1000);
|
||||
|
||||
WARN_ON_ONCE(sp->comp);
|
||||
sp->comp = ∁
|
||||
if (!wait_for_completion_timeout(&comp, ratov_j)) {
|
||||
ql_dbg(ql_dbg_taskm, vha, 0xffff,
|
||||
@@ -7244,6 +7215,7 @@ struct scsi_host_template qla2xxx_driver_template = {
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)
|
||||
.track_queue_depth = 1,
|
||||
#endif
|
||||
.cmd_size = sizeof(srb_t),
|
||||
};
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0) && \
|
||||
|
||||
Reference in New Issue
Block a user