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);
 
