Skip to content

Commit

Permalink
scsi: qla2xxx: abort TMR commands
Browse files Browse the repository at this point in the history
TCM calls aborted_task callback for TMR too and then releases the
command. But qla2xx ignores that callback for TMR and leaks an FC
exchange.
Add terminating the exchange of task management IOCBs to free its
FW resources.

Signed-off-by: Dmitry Bogdanov <d.bogdanov@yadro.com>
  • Loading branch information
logost authored and intel-lab-lkp committed Nov 30, 2022
1 parent 4e80eef commit ab0162f
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 19 deletions.
121 changes: 103 additions & 18 deletions drivers/scsi/qla2xxx/qla_target.c
Original file line number Diff line number Diff line change
Expand Up @@ -1857,6 +1857,72 @@ static int qlt_build_abts_resp_iocb(struct qla_tgt_mgmt_cmd *mcmd)
return rc;
}

static int __qlt_send_term_abts_exchange(struct qla_qpair *qpair,
struct scsi_qla_host *vha,
struct abts_recv_from_24xx *abts)
{
struct qla_hw_data *ha = vha->hw;
struct abts_resp_to_24xx *resp;
__le32 f_ctl;
uint8_t *p;
int rc;

ql_dbg(ql_dbg_tgt, vha, 0xe006,
"Sending terminate exchange of ABTS (ha=%p)\n",
ha);

rc = qlt_check_reserve_free_req(qpair, 1);
if (rc) {
ql_dbg(ql_dbg_tgt, vha, 0xe04a,
"qla_target(%d): %s failed: unable to allocate request packet\n",
vha->vp_idx, __func__);
return -EAGAIN;
}

resp = (struct abts_resp_to_24xx *)qpair->req->ring_ptr;
memset(resp, 0, sizeof(*resp));

resp->entry_type = ABTS_RESP_24XX;
resp->entry_count = 1;
resp->handle = QLA_TGT_SKIP_HANDLE;
resp->nport_handle = abts->nport_handle;
resp->control_flags = ABTS_CONTR_FLG_TERM_EXCHG;
resp->vp_index = vha->vp_idx;
resp->sof_type = abts->sof_type;
resp->exchange_address = abts->exchange_address;
/*
* Although no basic accept/reject frame is sent to the wire, the basic
* accept/reject frame (from IOCB offsets 14h-37h) must be filled by the
* driver, because the QLogic ASIC firmware performs a cross-check
* before terminating the ABTS exchange.
*/
resp->fcp_hdr_le = abts->fcp_hdr_le;
f_ctl = cpu_to_le32(F_CTL_EXCH_CONTEXT_RESP |
F_CTL_LAST_SEQ | F_CTL_END_SEQ |
F_CTL_SEQ_INITIATIVE);
p = (uint8_t *)&f_ctl;
resp->fcp_hdr_le.f_ctl[0] = *p++;
resp->fcp_hdr_le.f_ctl[1] = *p++;
resp->fcp_hdr_le.f_ctl[2] = *p;

resp->fcp_hdr_le.d_id = abts->fcp_hdr_le.s_id;
resp->fcp_hdr_le.s_id = abts->fcp_hdr_le.d_id;
resp->fcp_hdr_le.r_ctl = R_CTL_BASIC_LINK_SERV | R_CTL_B_RJT;
resp->payload.ba_rjt.reason_code =
BA_RJT_REASON_CODE_UNABLE_TO_PERFORM;
resp->exchange_addr_to_abort = abts->exchange_addr_to_abort;

vha->vha_tgt.qla_tgt->abts_resp_expected++;

/* Memory Barrier */
wmb();
if (qpair->reqq_start_iocbs)
qpair->reqq_start_iocbs(qpair);
else
qla2x00_start_iocbs(vha, qpair->req);

return rc;
}
/*
* ha->hardware_lock supposed to be held on entry. Might drop it, then reaquire
*/
Expand Down Expand Up @@ -3666,10 +3732,9 @@ static void qlt_send_term_imm_notif(struct scsi_qla_host *vha,
* This function sends the appropriate CTIO to ISP 2xxx or 24xx
*/
static int __qlt_send_term_exchange(struct qla_qpair *qpair,
struct qla_tgt_cmd *cmd,
struct scsi_qla_host *vha,
struct atio_from_isp *atio)
{
struct scsi_qla_host *vha = qpair->vha;
struct ctio7_to_24xx *ctio24;
struct qla_hw_data *ha = vha->hw;
request_t *pkt;
Expand All @@ -3678,9 +3743,6 @@ static int __qlt_send_term_exchange(struct qla_qpair *qpair,

ql_dbg(ql_dbg_tgt, vha, 0xe009, "Sending TERM EXCH CTIO (ha=%p)\n", ha);

if (cmd)
vha = cmd->vha;

pkt = (request_t *)qla2x00_alloc_iocbs_ready(qpair, NULL);
if (pkt == NULL) {
ql_dbg(ql_dbg_tgt, vha, 0xe050,
Expand All @@ -3689,16 +3751,6 @@ static int __qlt_send_term_exchange(struct qla_qpair *qpair,
return -ENOMEM;
}

if (cmd != NULL) {
if (cmd->state < QLA_TGT_STATE_PROCESSED) {
ql_dbg(ql_dbg_tgt, vha, 0xe051,
"qla_target(%d): Terminating cmd %p with "
"incorrect state %d\n", vha->vp_idx, cmd,
cmd->state);
} else
ret = 1;
}

qpair->tgt_counters.num_term_xchg_sent++;
pkt->entry_count = 1;
pkt->handle = QLA_TGT_SKIP_HANDLE | CTIO_COMPLETION_HANDLE_MARK;
Expand Down Expand Up @@ -3739,14 +3791,23 @@ static void qlt_send_term_exchange(struct qla_qpair *qpair,
else
vha = qpair->vha;

if (cmd != NULL) {
if (cmd->state < QLA_TGT_STATE_PROCESSED) {
ql_dbg(ql_dbg_tgt, vha, 0xe051,
"qla_target(%d): Terminating cmd %p with "
"incorrect state %d\n", vha->vp_idx, cmd,
cmd->state);
}
}

if (ha_locked) {
rc = __qlt_send_term_exchange(qpair, cmd, atio);
rc = __qlt_send_term_exchange(qpair, vha, atio);
if (rc == -ENOMEM)
qlt_alloc_qfull_cmd(vha, atio, 0, 0);
goto done;
}
spin_lock_irqsave(qpair->qp_lock_ptr, flags);
rc = __qlt_send_term_exchange(qpair, cmd, atio);
rc = __qlt_send_term_exchange(qpair, vha, atio);
if (rc == -ENOMEM)
qlt_alloc_qfull_cmd(vha, atio, 0, 0);

Expand Down Expand Up @@ -3810,6 +3871,30 @@ static void qlt_chk_exch_leak_thresh_hold(struct scsi_qla_host *vha)

}

int qlt_abort_mcmd(struct qla_tgt_mgmt_cmd *mcmd)
{
struct scsi_qla_host *vha = mcmd->vha;
struct se_cmd *se_cmd = &mcmd->se_cmd;
unsigned long flags;
int rc = 0;

ql_dbg(ql_dbg_tgt_mgt, vha, 0xf022,
"qla_target(%d): terminating exchange for aborted mcmd=%p (se_cmd=%p, tag=%llu)",
vha->vp_idx, mcmd, se_cmd, se_cmd->tag);

spin_lock_irqsave(mcmd->qpair->qp_lock_ptr, flags);
if (mcmd->orig_iocb.atio.u.raw.entry_type == ABTS_RECV_24XX)
rc = __qlt_send_term_abts_exchange(mcmd->qpair, vha,
&mcmd->orig_iocb.abts);
else
rc = __qlt_send_term_exchange(mcmd->qpair, vha,
&mcmd->orig_iocb.atio);
spin_unlock_irqrestore(mcmd->qpair->qp_lock_ptr, flags);

return rc;
}
EXPORT_SYMBOL(qlt_abort_mcmd);

int qlt_abort_cmd(struct qla_tgt_cmd *cmd)
{
struct qla_tgt *tgt = cmd->tgt;
Expand Down Expand Up @@ -5578,7 +5663,7 @@ qlt_free_qfull_cmds(struct qla_qpair *qpair)
/* cmd->state is a borrowed field to hold status */
rc = __qlt_send_busy(qpair, &cmd->atio, cmd->state);
else if (cmd->term_exchg)
rc = __qlt_send_term_exchange(qpair, NULL, &cmd->atio);
rc = __qlt_send_term_exchange(qpair, vha, &cmd->atio);

if (rc == -ENOMEM)
break;
Expand Down
1 change: 1 addition & 0 deletions drivers/scsi/qla2xxx/qla_target.h
Original file line number Diff line number Diff line change
Expand Up @@ -1057,6 +1057,7 @@ extern void qlt_response_pkt_all_vps(struct scsi_qla_host *, struct rsp_que *,
extern int qlt_rdy_to_xfer(struct qla_tgt_cmd *);
extern int qlt_xmit_response(struct qla_tgt_cmd *, int, uint8_t);
extern int qlt_abort_cmd(struct qla_tgt_cmd *);
extern int qlt_abort_mcmd(struct qla_tgt_mgmt_cmd *mcmd);
extern void qlt_xmit_tm_rsp(struct qla_tgt_mgmt_cmd *);
extern void qlt_free_mcmd(struct qla_tgt_mgmt_cmd *);
extern void qlt_free_cmd(struct qla_tgt_cmd *cmd);
Expand Down
8 changes: 7 additions & 1 deletion drivers/scsi/qla2xxx/tcm_qla2xxx.c
Original file line number Diff line number Diff line change
Expand Up @@ -773,8 +773,14 @@ static void tcm_qla2xxx_aborted_task(struct se_cmd *se_cmd)
struct qla_tgt_cmd *cmd;
unsigned long flags;

if (se_cmd->se_cmd_flags & SCF_SCSI_TMR_CDB)
if (se_cmd->se_cmd_flags & SCF_SCSI_TMR_CDB) {
struct qla_tgt_mgmt_cmd *mcmd = container_of(se_cmd,
struct qla_tgt_mgmt_cmd, se_cmd);

qlt_abort_mcmd(mcmd);

return;
}

cmd = container_of(se_cmd, struct qla_tgt_cmd, se_cmd);

Expand Down

0 comments on commit ab0162f

Please sign in to comment.