diff mbox series

[v2] scsi: qla2xxx: abort TMR commands

Message ID 20221205130800.15816-1-d.bogdanov@yadro.com
State New
Headers show
Series [v2] scsi: qla2xxx: abort TMR commands | expand

Commit Message

Dmitry Bogdanov Dec. 5, 2022, 1:08 p.m. UTC
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>
---
Changelog:
  v2:
     fix sparse warning 'expected restricted __le16' [usertype] control_flags
     fix checkpatch warning 'quoted string split across lines'
---
 drivers/scsi/qla2xxx/qla_target.c  | 120 ++++++++++++++++++++++++-----
 drivers/scsi/qla2xxx/qla_target.h  |   1 +
 drivers/scsi/qla2xxx/tcm_qla2xxx.c |   8 +-
 3 files changed, 110 insertions(+), 19 deletions(-)

Comments

Dmitry Bogdanov Feb. 1, 2023, 8:58 a.m. UTC | #1
On Mon, Dec 05, 2022 at 04:08:00PM +0300, Dmitry Bogdanov wrote:
> 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>
> ---
> Changelog:
>   v2:
>      fix sparse warning 'expected restricted __le16' [usertype] control_flags
>      fix checkpatch warning 'quoted string split across lines'

Nilesh, could you please take a look on the patch?
diff mbox series

Patch

diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c
index bb754a950802..7746d66cd01f 100644
--- a/drivers/scsi/qla2xxx/qla_target.c
+++ b/drivers/scsi/qla2xxx/qla_target.c
@@ -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 = cpu_to_le16(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
  */
@@ -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;
@@ -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,
@@ -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;
@@ -3739,14 +3791,22 @@  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);
 
@@ -3810,6 +3870,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;
@@ -5578,7 +5662,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;
diff --git a/drivers/scsi/qla2xxx/qla_target.h b/drivers/scsi/qla2xxx/qla_target.h
index 7df86578214f..7902f5b5f4aa 100644
--- a/drivers/scsi/qla2xxx/qla_target.h
+++ b/drivers/scsi/qla2xxx/qla_target.h
@@ -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);
diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
index 8fa0056b56dd..0ef09b43e0f7 100644
--- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c
+++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
@@ -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);