18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * QLogic iSCSI Offload Driver
48c2ecf20Sopenharmony_ci * Copyright (c) 2016 Cavium Inc.
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include <linux/blkdev.h>
88c2ecf20Sopenharmony_ci#include <scsi/scsi_tcq.h>
98c2ecf20Sopenharmony_ci#include <linux/delay.h>
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include "qedi.h"
128c2ecf20Sopenharmony_ci#include "qedi_iscsi.h"
138c2ecf20Sopenharmony_ci#include "qedi_gbl.h"
148c2ecf20Sopenharmony_ci#include "qedi_fw_iscsi.h"
158c2ecf20Sopenharmony_ci#include "qedi_fw_scsi.h"
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_cistatic int qedi_send_iscsi_tmf(struct qedi_conn *qedi_conn,
188c2ecf20Sopenharmony_ci			       struct iscsi_task *mtask);
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_civoid qedi_iscsi_unmap_sg_list(struct qedi_cmd *cmd)
218c2ecf20Sopenharmony_ci{
228c2ecf20Sopenharmony_ci	struct scsi_cmnd *sc = cmd->scsi_cmd;
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci	if (cmd->io_tbl.sge_valid && sc) {
258c2ecf20Sopenharmony_ci		cmd->io_tbl.sge_valid = 0;
268c2ecf20Sopenharmony_ci		scsi_dma_unmap(sc);
278c2ecf20Sopenharmony_ci	}
288c2ecf20Sopenharmony_ci}
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_cistatic void qedi_process_logout_resp(struct qedi_ctx *qedi,
318c2ecf20Sopenharmony_ci				     union iscsi_cqe *cqe,
328c2ecf20Sopenharmony_ci				     struct iscsi_task *task,
338c2ecf20Sopenharmony_ci				     struct qedi_conn *qedi_conn)
348c2ecf20Sopenharmony_ci{
358c2ecf20Sopenharmony_ci	struct iscsi_conn *conn = qedi_conn->cls_conn->dd_data;
368c2ecf20Sopenharmony_ci	struct iscsi_logout_rsp *resp_hdr;
378c2ecf20Sopenharmony_ci	struct iscsi_session *session = conn->session;
388c2ecf20Sopenharmony_ci	struct iscsi_logout_response_hdr *cqe_logout_response;
398c2ecf20Sopenharmony_ci	struct qedi_cmd *cmd;
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci	cmd = (struct qedi_cmd *)task->dd_data;
428c2ecf20Sopenharmony_ci	cqe_logout_response = &cqe->cqe_common.iscsi_hdr.logout_response;
438c2ecf20Sopenharmony_ci	spin_lock(&session->back_lock);
448c2ecf20Sopenharmony_ci	resp_hdr = (struct iscsi_logout_rsp *)&qedi_conn->gen_pdu.resp_hdr;
458c2ecf20Sopenharmony_ci	memset(resp_hdr, 0, sizeof(struct iscsi_hdr));
468c2ecf20Sopenharmony_ci	resp_hdr->opcode = cqe_logout_response->opcode;
478c2ecf20Sopenharmony_ci	resp_hdr->flags = cqe_logout_response->flags;
488c2ecf20Sopenharmony_ci	resp_hdr->hlength = 0;
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci	resp_hdr->itt = build_itt(cqe->cqe_solicited.itid, conn->session->age);
518c2ecf20Sopenharmony_ci	resp_hdr->statsn = cpu_to_be32(cqe_logout_response->stat_sn);
528c2ecf20Sopenharmony_ci	resp_hdr->exp_cmdsn = cpu_to_be32(cqe_logout_response->exp_cmd_sn);
538c2ecf20Sopenharmony_ci	resp_hdr->max_cmdsn = cpu_to_be32(cqe_logout_response->max_cmd_sn);
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	resp_hdr->t2wait = cpu_to_be32(cqe_logout_response->time_2_wait);
568c2ecf20Sopenharmony_ci	resp_hdr->t2retain = cpu_to_be32(cqe_logout_response->time_2_retain);
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_TID,
598c2ecf20Sopenharmony_ci		  "Freeing tid=0x%x for cid=0x%x\n",
608c2ecf20Sopenharmony_ci		  cmd->task_id, qedi_conn->iscsi_conn_id);
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	spin_lock(&qedi_conn->list_lock);
638c2ecf20Sopenharmony_ci	if (likely(cmd->io_cmd_in_list)) {
648c2ecf20Sopenharmony_ci		cmd->io_cmd_in_list = false;
658c2ecf20Sopenharmony_ci		list_del_init(&cmd->io_cmd);
668c2ecf20Sopenharmony_ci		qedi_conn->active_cmd_count--;
678c2ecf20Sopenharmony_ci	} else {
688c2ecf20Sopenharmony_ci		QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO,
698c2ecf20Sopenharmony_ci			  "Active cmd list node already deleted, tid=0x%x, cid=0x%x, io_cmd_node=%p\n",
708c2ecf20Sopenharmony_ci			  cmd->task_id, qedi_conn->iscsi_conn_id,
718c2ecf20Sopenharmony_ci			  &cmd->io_cmd);
728c2ecf20Sopenharmony_ci	}
738c2ecf20Sopenharmony_ci	spin_unlock(&qedi_conn->list_lock);
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	cmd->state = RESPONSE_RECEIVED;
768c2ecf20Sopenharmony_ci	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr, NULL, 0);
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	spin_unlock(&session->back_lock);
798c2ecf20Sopenharmony_ci}
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_cistatic void qedi_process_text_resp(struct qedi_ctx *qedi,
828c2ecf20Sopenharmony_ci				   union iscsi_cqe *cqe,
838c2ecf20Sopenharmony_ci				   struct iscsi_task *task,
848c2ecf20Sopenharmony_ci				   struct qedi_conn *qedi_conn)
858c2ecf20Sopenharmony_ci{
868c2ecf20Sopenharmony_ci	struct iscsi_conn *conn = qedi_conn->cls_conn->dd_data;
878c2ecf20Sopenharmony_ci	struct iscsi_session *session = conn->session;
888c2ecf20Sopenharmony_ci	struct e4_iscsi_task_context *task_ctx;
898c2ecf20Sopenharmony_ci	struct iscsi_text_rsp *resp_hdr_ptr;
908c2ecf20Sopenharmony_ci	struct iscsi_text_response_hdr *cqe_text_response;
918c2ecf20Sopenharmony_ci	struct qedi_cmd *cmd;
928c2ecf20Sopenharmony_ci	int pld_len;
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	cmd = (struct qedi_cmd *)task->dd_data;
958c2ecf20Sopenharmony_ci	task_ctx = qedi_get_task_mem(&qedi->tasks, cmd->task_id);
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	cqe_text_response = &cqe->cqe_common.iscsi_hdr.text_response;
988c2ecf20Sopenharmony_ci	spin_lock(&session->back_lock);
998c2ecf20Sopenharmony_ci	resp_hdr_ptr =  (struct iscsi_text_rsp *)&qedi_conn->gen_pdu.resp_hdr;
1008c2ecf20Sopenharmony_ci	memset(resp_hdr_ptr, 0, sizeof(struct iscsi_hdr));
1018c2ecf20Sopenharmony_ci	resp_hdr_ptr->opcode = cqe_text_response->opcode;
1028c2ecf20Sopenharmony_ci	resp_hdr_ptr->flags = cqe_text_response->flags;
1038c2ecf20Sopenharmony_ci	resp_hdr_ptr->hlength = 0;
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	hton24(resp_hdr_ptr->dlength,
1068c2ecf20Sopenharmony_ci	       (cqe_text_response->hdr_second_dword &
1078c2ecf20Sopenharmony_ci		ISCSI_TEXT_RESPONSE_HDR_DATA_SEG_LEN_MASK));
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	resp_hdr_ptr->itt = build_itt(cqe->cqe_solicited.itid,
1108c2ecf20Sopenharmony_ci				      conn->session->age);
1118c2ecf20Sopenharmony_ci	resp_hdr_ptr->ttt = cqe_text_response->ttt;
1128c2ecf20Sopenharmony_ci	resp_hdr_ptr->statsn = cpu_to_be32(cqe_text_response->stat_sn);
1138c2ecf20Sopenharmony_ci	resp_hdr_ptr->exp_cmdsn = cpu_to_be32(cqe_text_response->exp_cmd_sn);
1148c2ecf20Sopenharmony_ci	resp_hdr_ptr->max_cmdsn = cpu_to_be32(cqe_text_response->max_cmd_sn);
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	pld_len = cqe_text_response->hdr_second_dword &
1178c2ecf20Sopenharmony_ci		  ISCSI_TEXT_RESPONSE_HDR_DATA_SEG_LEN_MASK;
1188c2ecf20Sopenharmony_ci	qedi_conn->gen_pdu.resp_wr_ptr = qedi_conn->gen_pdu.resp_buf + pld_len;
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	memset(task_ctx, '\0', sizeof(*task_ctx));
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_TID,
1238c2ecf20Sopenharmony_ci		  "Freeing tid=0x%x for cid=0x%x\n",
1248c2ecf20Sopenharmony_ci		  cmd->task_id, qedi_conn->iscsi_conn_id);
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	spin_lock(&qedi_conn->list_lock);
1278c2ecf20Sopenharmony_ci	if (likely(cmd->io_cmd_in_list)) {
1288c2ecf20Sopenharmony_ci		cmd->io_cmd_in_list = false;
1298c2ecf20Sopenharmony_ci		list_del_init(&cmd->io_cmd);
1308c2ecf20Sopenharmony_ci		qedi_conn->active_cmd_count--;
1318c2ecf20Sopenharmony_ci	} else {
1328c2ecf20Sopenharmony_ci		QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO,
1338c2ecf20Sopenharmony_ci			  "Active cmd list node already deleted, tid=0x%x, cid=0x%x, io_cmd_node=%p\n",
1348c2ecf20Sopenharmony_ci			  cmd->task_id, qedi_conn->iscsi_conn_id,
1358c2ecf20Sopenharmony_ci			  &cmd->io_cmd);
1368c2ecf20Sopenharmony_ci	}
1378c2ecf20Sopenharmony_ci	spin_unlock(&qedi_conn->list_lock);
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	cmd->state = RESPONSE_RECEIVED;
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr_ptr,
1428c2ecf20Sopenharmony_ci			     qedi_conn->gen_pdu.resp_buf,
1438c2ecf20Sopenharmony_ci			     (qedi_conn->gen_pdu.resp_wr_ptr -
1448c2ecf20Sopenharmony_ci			      qedi_conn->gen_pdu.resp_buf));
1458c2ecf20Sopenharmony_ci	spin_unlock(&session->back_lock);
1468c2ecf20Sopenharmony_ci}
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_cistatic void qedi_tmf_resp_work(struct work_struct *work)
1498c2ecf20Sopenharmony_ci{
1508c2ecf20Sopenharmony_ci	struct qedi_cmd *qedi_cmd =
1518c2ecf20Sopenharmony_ci				container_of(work, struct qedi_cmd, tmf_work);
1528c2ecf20Sopenharmony_ci	struct qedi_conn *qedi_conn = qedi_cmd->conn;
1538c2ecf20Sopenharmony_ci	struct qedi_ctx *qedi = qedi_conn->qedi;
1548c2ecf20Sopenharmony_ci	struct iscsi_conn *conn = qedi_conn->cls_conn->dd_data;
1558c2ecf20Sopenharmony_ci	struct iscsi_session *session = conn->session;
1568c2ecf20Sopenharmony_ci	struct iscsi_tm_rsp *resp_hdr_ptr;
1578c2ecf20Sopenharmony_ci	int rval = 0;
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	set_bit(QEDI_CONN_FW_CLEANUP, &qedi_conn->flags);
1608c2ecf20Sopenharmony_ci	resp_hdr_ptr =  (struct iscsi_tm_rsp *)qedi_cmd->tmf_resp_buf;
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	rval = qedi_cleanup_all_io(qedi, qedi_conn, qedi_cmd->task, true);
1638c2ecf20Sopenharmony_ci	if (rval)
1648c2ecf20Sopenharmony_ci		goto exit_tmf_resp;
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	spin_lock(&session->back_lock);
1678c2ecf20Sopenharmony_ci	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr_ptr, NULL, 0);
1688c2ecf20Sopenharmony_ci	spin_unlock(&session->back_lock);
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ciexit_tmf_resp:
1718c2ecf20Sopenharmony_ci	kfree(resp_hdr_ptr);
1728c2ecf20Sopenharmony_ci	clear_bit(QEDI_CONN_FW_CLEANUP, &qedi_conn->flags);
1738c2ecf20Sopenharmony_ci}
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_cistatic void qedi_process_tmf_resp(struct qedi_ctx *qedi,
1768c2ecf20Sopenharmony_ci				  union iscsi_cqe *cqe,
1778c2ecf20Sopenharmony_ci				  struct iscsi_task *task,
1788c2ecf20Sopenharmony_ci				  struct qedi_conn *qedi_conn)
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci{
1818c2ecf20Sopenharmony_ci	struct iscsi_conn *conn = qedi_conn->cls_conn->dd_data;
1828c2ecf20Sopenharmony_ci	struct iscsi_session *session = conn->session;
1838c2ecf20Sopenharmony_ci	struct iscsi_tmf_response_hdr *cqe_tmp_response;
1848c2ecf20Sopenharmony_ci	struct iscsi_tm_rsp *resp_hdr_ptr;
1858c2ecf20Sopenharmony_ci	struct iscsi_tm *tmf_hdr;
1868c2ecf20Sopenharmony_ci	struct qedi_cmd *qedi_cmd = NULL;
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	cqe_tmp_response = &cqe->cqe_common.iscsi_hdr.tmf_response;
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	qedi_cmd = task->dd_data;
1918c2ecf20Sopenharmony_ci	qedi_cmd->tmf_resp_buf = kzalloc(sizeof(*resp_hdr_ptr), GFP_ATOMIC);
1928c2ecf20Sopenharmony_ci	if (!qedi_cmd->tmf_resp_buf) {
1938c2ecf20Sopenharmony_ci		QEDI_ERR(&qedi->dbg_ctx,
1948c2ecf20Sopenharmony_ci			 "Failed to allocate resp buf, cid=0x%x\n",
1958c2ecf20Sopenharmony_ci			  qedi_conn->iscsi_conn_id);
1968c2ecf20Sopenharmony_ci		return;
1978c2ecf20Sopenharmony_ci	}
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	spin_lock(&session->back_lock);
2008c2ecf20Sopenharmony_ci	resp_hdr_ptr =  (struct iscsi_tm_rsp *)qedi_cmd->tmf_resp_buf;
2018c2ecf20Sopenharmony_ci	memset(resp_hdr_ptr, 0, sizeof(struct iscsi_tm_rsp));
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	/* Fill up the header */
2048c2ecf20Sopenharmony_ci	resp_hdr_ptr->opcode = cqe_tmp_response->opcode;
2058c2ecf20Sopenharmony_ci	resp_hdr_ptr->flags = cqe_tmp_response->hdr_flags;
2068c2ecf20Sopenharmony_ci	resp_hdr_ptr->response = cqe_tmp_response->hdr_response;
2078c2ecf20Sopenharmony_ci	resp_hdr_ptr->hlength = 0;
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	hton24(resp_hdr_ptr->dlength,
2108c2ecf20Sopenharmony_ci	       (cqe_tmp_response->hdr_second_dword &
2118c2ecf20Sopenharmony_ci		ISCSI_TMF_RESPONSE_HDR_DATA_SEG_LEN_MASK));
2128c2ecf20Sopenharmony_ci	resp_hdr_ptr->itt = build_itt(cqe->cqe_solicited.itid,
2138c2ecf20Sopenharmony_ci				      conn->session->age);
2148c2ecf20Sopenharmony_ci	resp_hdr_ptr->statsn = cpu_to_be32(cqe_tmp_response->stat_sn);
2158c2ecf20Sopenharmony_ci	resp_hdr_ptr->exp_cmdsn  = cpu_to_be32(cqe_tmp_response->exp_cmd_sn);
2168c2ecf20Sopenharmony_ci	resp_hdr_ptr->max_cmdsn = cpu_to_be32(cqe_tmp_response->max_cmd_sn);
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	tmf_hdr = (struct iscsi_tm *)qedi_cmd->task->hdr;
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	spin_lock(&qedi_conn->list_lock);
2218c2ecf20Sopenharmony_ci	if (likely(qedi_cmd->io_cmd_in_list)) {
2228c2ecf20Sopenharmony_ci		qedi_cmd->io_cmd_in_list = false;
2238c2ecf20Sopenharmony_ci		list_del_init(&qedi_cmd->io_cmd);
2248c2ecf20Sopenharmony_ci		qedi_conn->active_cmd_count--;
2258c2ecf20Sopenharmony_ci	}
2268c2ecf20Sopenharmony_ci	spin_unlock(&qedi_conn->list_lock);
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	if (((tmf_hdr->flags & ISCSI_FLAG_TM_FUNC_MASK) ==
2298c2ecf20Sopenharmony_ci	      ISCSI_TM_FUNC_LOGICAL_UNIT_RESET) ||
2308c2ecf20Sopenharmony_ci	    ((tmf_hdr->flags & ISCSI_FLAG_TM_FUNC_MASK) ==
2318c2ecf20Sopenharmony_ci	      ISCSI_TM_FUNC_TARGET_WARM_RESET) ||
2328c2ecf20Sopenharmony_ci	    ((tmf_hdr->flags & ISCSI_FLAG_TM_FUNC_MASK) ==
2338c2ecf20Sopenharmony_ci	      ISCSI_TM_FUNC_TARGET_COLD_RESET)) {
2348c2ecf20Sopenharmony_ci		INIT_WORK(&qedi_cmd->tmf_work, qedi_tmf_resp_work);
2358c2ecf20Sopenharmony_ci		queue_work(qedi->tmf_thread, &qedi_cmd->tmf_work);
2368c2ecf20Sopenharmony_ci		goto unblock_sess;
2378c2ecf20Sopenharmony_ci	}
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr_ptr, NULL, 0);
2408c2ecf20Sopenharmony_ci	kfree(resp_hdr_ptr);
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ciunblock_sess:
2438c2ecf20Sopenharmony_ci	spin_unlock(&session->back_lock);
2448c2ecf20Sopenharmony_ci}
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_cistatic void qedi_process_login_resp(struct qedi_ctx *qedi,
2478c2ecf20Sopenharmony_ci				    union iscsi_cqe *cqe,
2488c2ecf20Sopenharmony_ci				    struct iscsi_task *task,
2498c2ecf20Sopenharmony_ci				    struct qedi_conn *qedi_conn)
2508c2ecf20Sopenharmony_ci{
2518c2ecf20Sopenharmony_ci	struct iscsi_conn *conn = qedi_conn->cls_conn->dd_data;
2528c2ecf20Sopenharmony_ci	struct iscsi_session *session = conn->session;
2538c2ecf20Sopenharmony_ci	struct e4_iscsi_task_context *task_ctx;
2548c2ecf20Sopenharmony_ci	struct iscsi_login_rsp *resp_hdr_ptr;
2558c2ecf20Sopenharmony_ci	struct iscsi_login_response_hdr *cqe_login_response;
2568c2ecf20Sopenharmony_ci	struct qedi_cmd *cmd;
2578c2ecf20Sopenharmony_ci	int pld_len;
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	cmd = (struct qedi_cmd *)task->dd_data;
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	cqe_login_response = &cqe->cqe_common.iscsi_hdr.login_response;
2628c2ecf20Sopenharmony_ci	task_ctx = qedi_get_task_mem(&qedi->tasks, cmd->task_id);
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	spin_lock(&session->back_lock);
2658c2ecf20Sopenharmony_ci	resp_hdr_ptr =  (struct iscsi_login_rsp *)&qedi_conn->gen_pdu.resp_hdr;
2668c2ecf20Sopenharmony_ci	memset(resp_hdr_ptr, 0, sizeof(struct iscsi_login_rsp));
2678c2ecf20Sopenharmony_ci	resp_hdr_ptr->opcode = cqe_login_response->opcode;
2688c2ecf20Sopenharmony_ci	resp_hdr_ptr->flags = cqe_login_response->flags_attr;
2698c2ecf20Sopenharmony_ci	resp_hdr_ptr->hlength = 0;
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	hton24(resp_hdr_ptr->dlength,
2728c2ecf20Sopenharmony_ci	       (cqe_login_response->hdr_second_dword &
2738c2ecf20Sopenharmony_ci		ISCSI_LOGIN_RESPONSE_HDR_DATA_SEG_LEN_MASK));
2748c2ecf20Sopenharmony_ci	resp_hdr_ptr->itt = build_itt(cqe->cqe_solicited.itid,
2758c2ecf20Sopenharmony_ci				      conn->session->age);
2768c2ecf20Sopenharmony_ci	resp_hdr_ptr->tsih = cqe_login_response->tsih;
2778c2ecf20Sopenharmony_ci	resp_hdr_ptr->statsn = cpu_to_be32(cqe_login_response->stat_sn);
2788c2ecf20Sopenharmony_ci	resp_hdr_ptr->exp_cmdsn = cpu_to_be32(cqe_login_response->exp_cmd_sn);
2798c2ecf20Sopenharmony_ci	resp_hdr_ptr->max_cmdsn = cpu_to_be32(cqe_login_response->max_cmd_sn);
2808c2ecf20Sopenharmony_ci	resp_hdr_ptr->status_class = cqe_login_response->status_class;
2818c2ecf20Sopenharmony_ci	resp_hdr_ptr->status_detail = cqe_login_response->status_detail;
2828c2ecf20Sopenharmony_ci	pld_len = cqe_login_response->hdr_second_dword &
2838c2ecf20Sopenharmony_ci		  ISCSI_LOGIN_RESPONSE_HDR_DATA_SEG_LEN_MASK;
2848c2ecf20Sopenharmony_ci	qedi_conn->gen_pdu.resp_wr_ptr = qedi_conn->gen_pdu.resp_buf + pld_len;
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	spin_lock(&qedi_conn->list_lock);
2878c2ecf20Sopenharmony_ci	if (likely(cmd->io_cmd_in_list)) {
2888c2ecf20Sopenharmony_ci		cmd->io_cmd_in_list = false;
2898c2ecf20Sopenharmony_ci		list_del_init(&cmd->io_cmd);
2908c2ecf20Sopenharmony_ci		qedi_conn->active_cmd_count--;
2918c2ecf20Sopenharmony_ci	}
2928c2ecf20Sopenharmony_ci	spin_unlock(&qedi_conn->list_lock);
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	memset(task_ctx, '\0', sizeof(*task_ctx));
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr_ptr,
2978c2ecf20Sopenharmony_ci			     qedi_conn->gen_pdu.resp_buf,
2988c2ecf20Sopenharmony_ci			     (qedi_conn->gen_pdu.resp_wr_ptr -
2998c2ecf20Sopenharmony_ci			     qedi_conn->gen_pdu.resp_buf));
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	spin_unlock(&session->back_lock);
3028c2ecf20Sopenharmony_ci	QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_TID,
3038c2ecf20Sopenharmony_ci		  "Freeing tid=0x%x for cid=0x%x\n",
3048c2ecf20Sopenharmony_ci		  cmd->task_id, qedi_conn->iscsi_conn_id);
3058c2ecf20Sopenharmony_ci	cmd->state = RESPONSE_RECEIVED;
3068c2ecf20Sopenharmony_ci}
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_cistatic void qedi_get_rq_bdq_buf(struct qedi_ctx *qedi,
3098c2ecf20Sopenharmony_ci				struct iscsi_cqe_unsolicited *cqe,
3108c2ecf20Sopenharmony_ci				char *ptr, int len)
3118c2ecf20Sopenharmony_ci{
3128c2ecf20Sopenharmony_ci	u16 idx = 0;
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN,
3158c2ecf20Sopenharmony_ci		  "pld_len [%d], bdq_prod_idx [%d], idx [%d]\n",
3168c2ecf20Sopenharmony_ci		  len, qedi->bdq_prod_idx,
3178c2ecf20Sopenharmony_ci		  (qedi->bdq_prod_idx % qedi->rq_num_entries));
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	/* Obtain buffer address from rqe_opaque */
3208c2ecf20Sopenharmony_ci	idx = cqe->rqe_opaque;
3218c2ecf20Sopenharmony_ci	if (idx > (QEDI_BDQ_NUM - 1)) {
3228c2ecf20Sopenharmony_ci		QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN,
3238c2ecf20Sopenharmony_ci			  "wrong idx %d returned by FW, dropping the unsolicited pkt\n",
3248c2ecf20Sopenharmony_ci			  idx);
3258c2ecf20Sopenharmony_ci		return;
3268c2ecf20Sopenharmony_ci	}
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN,
3298c2ecf20Sopenharmony_ci		  "rqe_opaque [0x%p], idx [%d]\n", cqe->rqe_opaque, idx);
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN,
3328c2ecf20Sopenharmony_ci		  "unsol_cqe_type = %d\n", cqe->unsol_cqe_type);
3338c2ecf20Sopenharmony_ci	switch (cqe->unsol_cqe_type) {
3348c2ecf20Sopenharmony_ci	case ISCSI_CQE_UNSOLICITED_SINGLE:
3358c2ecf20Sopenharmony_ci	case ISCSI_CQE_UNSOLICITED_FIRST:
3368c2ecf20Sopenharmony_ci		if (len)
3378c2ecf20Sopenharmony_ci			memcpy(ptr, (void *)qedi->bdq[idx].buf_addr, len);
3388c2ecf20Sopenharmony_ci		break;
3398c2ecf20Sopenharmony_ci	case ISCSI_CQE_UNSOLICITED_MIDDLE:
3408c2ecf20Sopenharmony_ci	case ISCSI_CQE_UNSOLICITED_LAST:
3418c2ecf20Sopenharmony_ci		break;
3428c2ecf20Sopenharmony_ci	default:
3438c2ecf20Sopenharmony_ci		break;
3448c2ecf20Sopenharmony_ci	}
3458c2ecf20Sopenharmony_ci}
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_cistatic void qedi_put_rq_bdq_buf(struct qedi_ctx *qedi,
3488c2ecf20Sopenharmony_ci				struct iscsi_cqe_unsolicited *cqe,
3498c2ecf20Sopenharmony_ci				int count)
3508c2ecf20Sopenharmony_ci{
3518c2ecf20Sopenharmony_ci	u16 idx = 0;
3528c2ecf20Sopenharmony_ci	struct scsi_bd *pbl;
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	/* Obtain buffer address from rqe_opaque */
3558c2ecf20Sopenharmony_ci	idx = cqe->rqe_opaque;
3568c2ecf20Sopenharmony_ci	if (idx > (QEDI_BDQ_NUM - 1)) {
3578c2ecf20Sopenharmony_ci		QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN,
3588c2ecf20Sopenharmony_ci			  "wrong idx %d returned by FW, dropping the unsolicited pkt\n",
3598c2ecf20Sopenharmony_ci			  idx);
3608c2ecf20Sopenharmony_ci		return;
3618c2ecf20Sopenharmony_ci	}
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	pbl = (struct scsi_bd *)qedi->bdq_pbl;
3648c2ecf20Sopenharmony_ci	pbl += (qedi->bdq_prod_idx % qedi->rq_num_entries);
3658c2ecf20Sopenharmony_ci	pbl->address.hi = cpu_to_le32(QEDI_U64_HI(qedi->bdq[idx].buf_dma));
3668c2ecf20Sopenharmony_ci	pbl->address.lo = cpu_to_le32(QEDI_U64_LO(qedi->bdq[idx].buf_dma));
3678c2ecf20Sopenharmony_ci	QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN,
3688c2ecf20Sopenharmony_ci		  "pbl [0x%p] pbl->address hi [0x%llx] lo [0x%llx] idx [%d]\n",
3698c2ecf20Sopenharmony_ci		  pbl, pbl->address.hi, pbl->address.lo, idx);
3708c2ecf20Sopenharmony_ci	pbl->opaque.iscsi_opaque.reserved_zero[0] = 0;
3718c2ecf20Sopenharmony_ci	pbl->opaque.iscsi_opaque.reserved_zero[1] = 0;
3728c2ecf20Sopenharmony_ci	pbl->opaque.iscsi_opaque.reserved_zero[2] = 0;
3738c2ecf20Sopenharmony_ci	pbl->opaque.iscsi_opaque.opaque = cpu_to_le32(idx);
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	/* Increment producer to let f/w know we've handled the frame */
3768c2ecf20Sopenharmony_ci	qedi->bdq_prod_idx += count;
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	writew(qedi->bdq_prod_idx, qedi->bdq_primary_prod);
3798c2ecf20Sopenharmony_ci	readw(qedi->bdq_primary_prod);
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	writew(qedi->bdq_prod_idx, qedi->bdq_secondary_prod);
3828c2ecf20Sopenharmony_ci	readw(qedi->bdq_secondary_prod);
3838c2ecf20Sopenharmony_ci}
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_cistatic void qedi_unsol_pdu_adjust_bdq(struct qedi_ctx *qedi,
3868c2ecf20Sopenharmony_ci				      struct iscsi_cqe_unsolicited *cqe,
3878c2ecf20Sopenharmony_ci				      u32 pdu_len, u32 num_bdqs,
3888c2ecf20Sopenharmony_ci				      char *bdq_data)
3898c2ecf20Sopenharmony_ci{
3908c2ecf20Sopenharmony_ci	QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN,
3918c2ecf20Sopenharmony_ci		  "num_bdqs [%d]\n", num_bdqs);
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	qedi_get_rq_bdq_buf(qedi, cqe, bdq_data, pdu_len);
3948c2ecf20Sopenharmony_ci	qedi_put_rq_bdq_buf(qedi, cqe, (num_bdqs + 1));
3958c2ecf20Sopenharmony_ci}
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_cistatic int qedi_process_nopin_mesg(struct qedi_ctx *qedi,
3988c2ecf20Sopenharmony_ci				   union iscsi_cqe *cqe,
3998c2ecf20Sopenharmony_ci				   struct iscsi_task *task,
4008c2ecf20Sopenharmony_ci				   struct qedi_conn *qedi_conn, u16 que_idx)
4018c2ecf20Sopenharmony_ci{
4028c2ecf20Sopenharmony_ci	struct iscsi_conn *conn = qedi_conn->cls_conn->dd_data;
4038c2ecf20Sopenharmony_ci	struct iscsi_session *session = conn->session;
4048c2ecf20Sopenharmony_ci	struct iscsi_nop_in_hdr *cqe_nop_in;
4058c2ecf20Sopenharmony_ci	struct iscsi_nopin *hdr;
4068c2ecf20Sopenharmony_ci	struct qedi_cmd *cmd;
4078c2ecf20Sopenharmony_ci	int tgt_async_nop = 0;
4088c2ecf20Sopenharmony_ci	u32 lun[2];
4098c2ecf20Sopenharmony_ci	u32 pdu_len, num_bdqs;
4108c2ecf20Sopenharmony_ci	char bdq_data[QEDI_BDQ_BUF_SIZE];
4118c2ecf20Sopenharmony_ci	unsigned long flags;
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci	spin_lock_bh(&session->back_lock);
4148c2ecf20Sopenharmony_ci	cqe_nop_in = &cqe->cqe_common.iscsi_hdr.nop_in;
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci	pdu_len = cqe_nop_in->hdr_second_dword &
4178c2ecf20Sopenharmony_ci		  ISCSI_NOP_IN_HDR_DATA_SEG_LEN_MASK;
4188c2ecf20Sopenharmony_ci	num_bdqs = pdu_len / QEDI_BDQ_BUF_SIZE;
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci	hdr = (struct iscsi_nopin *)&qedi_conn->gen_pdu.resp_hdr;
4218c2ecf20Sopenharmony_ci	memset(hdr, 0, sizeof(struct iscsi_hdr));
4228c2ecf20Sopenharmony_ci	hdr->opcode = cqe_nop_in->opcode;
4238c2ecf20Sopenharmony_ci	hdr->max_cmdsn = cpu_to_be32(cqe_nop_in->max_cmd_sn);
4248c2ecf20Sopenharmony_ci	hdr->exp_cmdsn = cpu_to_be32(cqe_nop_in->exp_cmd_sn);
4258c2ecf20Sopenharmony_ci	hdr->statsn = cpu_to_be32(cqe_nop_in->stat_sn);
4268c2ecf20Sopenharmony_ci	hdr->ttt = cpu_to_be32(cqe_nop_in->ttt);
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	if (cqe->cqe_common.cqe_type == ISCSI_CQE_TYPE_UNSOLICITED) {
4298c2ecf20Sopenharmony_ci		spin_lock_irqsave(&qedi->hba_lock, flags);
4308c2ecf20Sopenharmony_ci		qedi_unsol_pdu_adjust_bdq(qedi, &cqe->cqe_unsolicited,
4318c2ecf20Sopenharmony_ci					  pdu_len, num_bdqs, bdq_data);
4328c2ecf20Sopenharmony_ci		hdr->itt = RESERVED_ITT;
4338c2ecf20Sopenharmony_ci		tgt_async_nop = 1;
4348c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&qedi->hba_lock, flags);
4358c2ecf20Sopenharmony_ci		goto done;
4368c2ecf20Sopenharmony_ci	}
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci	/* Response to one of our nop-outs */
4398c2ecf20Sopenharmony_ci	if (task) {
4408c2ecf20Sopenharmony_ci		cmd = task->dd_data;
4418c2ecf20Sopenharmony_ci		hdr->flags = ISCSI_FLAG_CMD_FINAL;
4428c2ecf20Sopenharmony_ci		hdr->itt = build_itt(cqe->cqe_solicited.itid,
4438c2ecf20Sopenharmony_ci				     conn->session->age);
4448c2ecf20Sopenharmony_ci		lun[0] = 0xffffffff;
4458c2ecf20Sopenharmony_ci		lun[1] = 0xffffffff;
4468c2ecf20Sopenharmony_ci		memcpy(&hdr->lun, lun, sizeof(struct scsi_lun));
4478c2ecf20Sopenharmony_ci		QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_TID,
4488c2ecf20Sopenharmony_ci			  "Freeing tid=0x%x for cid=0x%x\n",
4498c2ecf20Sopenharmony_ci			  cmd->task_id, qedi_conn->iscsi_conn_id);
4508c2ecf20Sopenharmony_ci		cmd->state = RESPONSE_RECEIVED;
4518c2ecf20Sopenharmony_ci		spin_lock(&qedi_conn->list_lock);
4528c2ecf20Sopenharmony_ci		if (likely(cmd->io_cmd_in_list)) {
4538c2ecf20Sopenharmony_ci			cmd->io_cmd_in_list = false;
4548c2ecf20Sopenharmony_ci			list_del_init(&cmd->io_cmd);
4558c2ecf20Sopenharmony_ci			qedi_conn->active_cmd_count--;
4568c2ecf20Sopenharmony_ci		}
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci		spin_unlock(&qedi_conn->list_lock);
4598c2ecf20Sopenharmony_ci	}
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_cidone:
4628c2ecf20Sopenharmony_ci	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, bdq_data, pdu_len);
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci	spin_unlock_bh(&session->back_lock);
4658c2ecf20Sopenharmony_ci	return tgt_async_nop;
4668c2ecf20Sopenharmony_ci}
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_cistatic void qedi_process_async_mesg(struct qedi_ctx *qedi,
4698c2ecf20Sopenharmony_ci				    union iscsi_cqe *cqe,
4708c2ecf20Sopenharmony_ci				    struct iscsi_task *task,
4718c2ecf20Sopenharmony_ci				    struct qedi_conn *qedi_conn,
4728c2ecf20Sopenharmony_ci				    u16 que_idx)
4738c2ecf20Sopenharmony_ci{
4748c2ecf20Sopenharmony_ci	struct iscsi_conn *conn = qedi_conn->cls_conn->dd_data;
4758c2ecf20Sopenharmony_ci	struct iscsi_session *session = conn->session;
4768c2ecf20Sopenharmony_ci	struct iscsi_async_msg_hdr *cqe_async_msg;
4778c2ecf20Sopenharmony_ci	struct iscsi_async *resp_hdr;
4788c2ecf20Sopenharmony_ci	u32 lun[2];
4798c2ecf20Sopenharmony_ci	u32 pdu_len, num_bdqs;
4808c2ecf20Sopenharmony_ci	char bdq_data[QEDI_BDQ_BUF_SIZE];
4818c2ecf20Sopenharmony_ci	unsigned long flags;
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci	spin_lock_bh(&session->back_lock);
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci	cqe_async_msg = &cqe->cqe_common.iscsi_hdr.async_msg;
4868c2ecf20Sopenharmony_ci	pdu_len = cqe_async_msg->hdr_second_dword &
4878c2ecf20Sopenharmony_ci		ISCSI_ASYNC_MSG_HDR_DATA_SEG_LEN_MASK;
4888c2ecf20Sopenharmony_ci	num_bdqs = pdu_len / QEDI_BDQ_BUF_SIZE;
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci	if (cqe->cqe_common.cqe_type == ISCSI_CQE_TYPE_UNSOLICITED) {
4918c2ecf20Sopenharmony_ci		spin_lock_irqsave(&qedi->hba_lock, flags);
4928c2ecf20Sopenharmony_ci		qedi_unsol_pdu_adjust_bdq(qedi, &cqe->cqe_unsolicited,
4938c2ecf20Sopenharmony_ci					  pdu_len, num_bdqs, bdq_data);
4948c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&qedi->hba_lock, flags);
4958c2ecf20Sopenharmony_ci	}
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci	resp_hdr = (struct iscsi_async *)&qedi_conn->gen_pdu.resp_hdr;
4988c2ecf20Sopenharmony_ci	memset(resp_hdr, 0, sizeof(struct iscsi_hdr));
4998c2ecf20Sopenharmony_ci	resp_hdr->opcode = cqe_async_msg->opcode;
5008c2ecf20Sopenharmony_ci	resp_hdr->flags = 0x80;
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci	lun[0] = cpu_to_be32(cqe_async_msg->lun.lo);
5038c2ecf20Sopenharmony_ci	lun[1] = cpu_to_be32(cqe_async_msg->lun.hi);
5048c2ecf20Sopenharmony_ci	memcpy(&resp_hdr->lun, lun, sizeof(struct scsi_lun));
5058c2ecf20Sopenharmony_ci	resp_hdr->exp_cmdsn = cpu_to_be32(cqe_async_msg->exp_cmd_sn);
5068c2ecf20Sopenharmony_ci	resp_hdr->max_cmdsn = cpu_to_be32(cqe_async_msg->max_cmd_sn);
5078c2ecf20Sopenharmony_ci	resp_hdr->statsn = cpu_to_be32(cqe_async_msg->stat_sn);
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci	resp_hdr->async_event = cqe_async_msg->async_event;
5108c2ecf20Sopenharmony_ci	resp_hdr->async_vcode = cqe_async_msg->async_vcode;
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci	resp_hdr->param1 = cpu_to_be16(cqe_async_msg->param1_rsrv);
5138c2ecf20Sopenharmony_ci	resp_hdr->param2 = cpu_to_be16(cqe_async_msg->param2_rsrv);
5148c2ecf20Sopenharmony_ci	resp_hdr->param3 = cpu_to_be16(cqe_async_msg->param3_rsrv);
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ci	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr, bdq_data,
5178c2ecf20Sopenharmony_ci			     pdu_len);
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci	spin_unlock_bh(&session->back_lock);
5208c2ecf20Sopenharmony_ci}
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_cistatic void qedi_process_reject_mesg(struct qedi_ctx *qedi,
5238c2ecf20Sopenharmony_ci				     union iscsi_cqe *cqe,
5248c2ecf20Sopenharmony_ci				     struct iscsi_task *task,
5258c2ecf20Sopenharmony_ci				     struct qedi_conn *qedi_conn,
5268c2ecf20Sopenharmony_ci				     uint16_t que_idx)
5278c2ecf20Sopenharmony_ci{
5288c2ecf20Sopenharmony_ci	struct iscsi_conn *conn = qedi_conn->cls_conn->dd_data;
5298c2ecf20Sopenharmony_ci	struct iscsi_session *session = conn->session;
5308c2ecf20Sopenharmony_ci	struct iscsi_reject_hdr *cqe_reject;
5318c2ecf20Sopenharmony_ci	struct iscsi_reject *hdr;
5328c2ecf20Sopenharmony_ci	u32 pld_len, num_bdqs;
5338c2ecf20Sopenharmony_ci	unsigned long flags;
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci	spin_lock_bh(&session->back_lock);
5368c2ecf20Sopenharmony_ci	cqe_reject = &cqe->cqe_common.iscsi_hdr.reject;
5378c2ecf20Sopenharmony_ci	pld_len = cqe_reject->hdr_second_dword &
5388c2ecf20Sopenharmony_ci		  ISCSI_REJECT_HDR_DATA_SEG_LEN_MASK;
5398c2ecf20Sopenharmony_ci	num_bdqs = pld_len / QEDI_BDQ_BUF_SIZE;
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci	if (cqe->cqe_common.cqe_type == ISCSI_CQE_TYPE_UNSOLICITED) {
5428c2ecf20Sopenharmony_ci		spin_lock_irqsave(&qedi->hba_lock, flags);
5438c2ecf20Sopenharmony_ci		qedi_unsol_pdu_adjust_bdq(qedi, &cqe->cqe_unsolicited,
5448c2ecf20Sopenharmony_ci					  pld_len, num_bdqs, conn->data);
5458c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&qedi->hba_lock, flags);
5468c2ecf20Sopenharmony_ci	}
5478c2ecf20Sopenharmony_ci	hdr = (struct iscsi_reject *)&qedi_conn->gen_pdu.resp_hdr;
5488c2ecf20Sopenharmony_ci	memset(hdr, 0, sizeof(struct iscsi_hdr));
5498c2ecf20Sopenharmony_ci	hdr->opcode = cqe_reject->opcode;
5508c2ecf20Sopenharmony_ci	hdr->reason = cqe_reject->hdr_reason;
5518c2ecf20Sopenharmony_ci	hdr->flags = cqe_reject->hdr_flags;
5528c2ecf20Sopenharmony_ci	hton24(hdr->dlength, (cqe_reject->hdr_second_dword &
5538c2ecf20Sopenharmony_ci			      ISCSI_REJECT_HDR_DATA_SEG_LEN_MASK));
5548c2ecf20Sopenharmony_ci	hdr->max_cmdsn = cpu_to_be32(cqe_reject->max_cmd_sn);
5558c2ecf20Sopenharmony_ci	hdr->exp_cmdsn = cpu_to_be32(cqe_reject->exp_cmd_sn);
5568c2ecf20Sopenharmony_ci	hdr->statsn = cpu_to_be32(cqe_reject->stat_sn);
5578c2ecf20Sopenharmony_ci	hdr->ffffffff = cpu_to_be32(0xffffffff);
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr,
5608c2ecf20Sopenharmony_ci			     conn->data, pld_len);
5618c2ecf20Sopenharmony_ci	spin_unlock_bh(&session->back_lock);
5628c2ecf20Sopenharmony_ci}
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_cistatic void qedi_scsi_completion(struct qedi_ctx *qedi,
5658c2ecf20Sopenharmony_ci				 union iscsi_cqe *cqe,
5668c2ecf20Sopenharmony_ci				 struct iscsi_task *task,
5678c2ecf20Sopenharmony_ci				 struct iscsi_conn *conn)
5688c2ecf20Sopenharmony_ci{
5698c2ecf20Sopenharmony_ci	struct scsi_cmnd *sc_cmd;
5708c2ecf20Sopenharmony_ci	struct qedi_cmd *cmd = task->dd_data;
5718c2ecf20Sopenharmony_ci	struct iscsi_session *session = conn->session;
5728c2ecf20Sopenharmony_ci	struct iscsi_scsi_rsp *hdr;
5738c2ecf20Sopenharmony_ci	struct iscsi_data_in_hdr *cqe_data_in;
5748c2ecf20Sopenharmony_ci	int datalen = 0;
5758c2ecf20Sopenharmony_ci	struct qedi_conn *qedi_conn;
5768c2ecf20Sopenharmony_ci	u32 iscsi_cid;
5778c2ecf20Sopenharmony_ci	u8 cqe_err_bits = 0;
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci	iscsi_cid  = cqe->cqe_common.conn_id;
5808c2ecf20Sopenharmony_ci	qedi_conn = qedi->cid_que.conn_cid_tbl[iscsi_cid];
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci	cqe_data_in = &cqe->cqe_common.iscsi_hdr.data_in;
5838c2ecf20Sopenharmony_ci	cqe_err_bits =
5848c2ecf20Sopenharmony_ci		cqe->cqe_common.error_bitmap.error_bits.cqe_error_status_bits;
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_ci	spin_lock_bh(&session->back_lock);
5878c2ecf20Sopenharmony_ci	/* get the scsi command */
5888c2ecf20Sopenharmony_ci	sc_cmd = cmd->scsi_cmd;
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ci	if (!sc_cmd) {
5918c2ecf20Sopenharmony_ci		QEDI_WARN(&qedi->dbg_ctx, "sc_cmd is NULL!\n");
5928c2ecf20Sopenharmony_ci		goto error;
5938c2ecf20Sopenharmony_ci	}
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ci	if (!sc_cmd->SCp.ptr) {
5968c2ecf20Sopenharmony_ci		QEDI_WARN(&qedi->dbg_ctx,
5978c2ecf20Sopenharmony_ci			  "SCp.ptr is NULL, returned in another context.\n");
5988c2ecf20Sopenharmony_ci		goto error;
5998c2ecf20Sopenharmony_ci	}
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_ci	if (!sc_cmd->request) {
6028c2ecf20Sopenharmony_ci		QEDI_WARN(&qedi->dbg_ctx,
6038c2ecf20Sopenharmony_ci			  "sc_cmd->request is NULL, sc_cmd=%p.\n",
6048c2ecf20Sopenharmony_ci			  sc_cmd);
6058c2ecf20Sopenharmony_ci		goto error;
6068c2ecf20Sopenharmony_ci	}
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_ci	if (!sc_cmd->request->q) {
6098c2ecf20Sopenharmony_ci		QEDI_WARN(&qedi->dbg_ctx,
6108c2ecf20Sopenharmony_ci			  "request->q is NULL so request is not valid, sc_cmd=%p.\n",
6118c2ecf20Sopenharmony_ci			  sc_cmd);
6128c2ecf20Sopenharmony_ci		goto error;
6138c2ecf20Sopenharmony_ci	}
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ci	qedi_iscsi_unmap_sg_list(cmd);
6168c2ecf20Sopenharmony_ci
6178c2ecf20Sopenharmony_ci	hdr = (struct iscsi_scsi_rsp *)task->hdr;
6188c2ecf20Sopenharmony_ci	hdr->opcode = cqe_data_in->opcode;
6198c2ecf20Sopenharmony_ci	hdr->max_cmdsn = cpu_to_be32(cqe_data_in->max_cmd_sn);
6208c2ecf20Sopenharmony_ci	hdr->exp_cmdsn = cpu_to_be32(cqe_data_in->exp_cmd_sn);
6218c2ecf20Sopenharmony_ci	hdr->itt = build_itt(cqe->cqe_solicited.itid, conn->session->age);
6228c2ecf20Sopenharmony_ci	hdr->response = cqe_data_in->reserved1;
6238c2ecf20Sopenharmony_ci	hdr->cmd_status = cqe_data_in->status_rsvd;
6248c2ecf20Sopenharmony_ci	hdr->flags = cqe_data_in->flags;
6258c2ecf20Sopenharmony_ci	hdr->residual_count = cpu_to_be32(cqe_data_in->residual_count);
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_ci	if (hdr->cmd_status == SAM_STAT_CHECK_CONDITION) {
6288c2ecf20Sopenharmony_ci		datalen = cqe_data_in->reserved2 &
6298c2ecf20Sopenharmony_ci			  ISCSI_COMMON_HDR_DATA_SEG_LEN_MASK;
6308c2ecf20Sopenharmony_ci		memcpy((char *)conn->data, (char *)cmd->sense_buffer, datalen);
6318c2ecf20Sopenharmony_ci	}
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_ci	/* If f/w reports data underrun err then set residual to IO transfer
6348c2ecf20Sopenharmony_ci	 * length, set Underrun flag and clear Overrun flag explicitly
6358c2ecf20Sopenharmony_ci	 */
6368c2ecf20Sopenharmony_ci	if (unlikely(cqe_err_bits &&
6378c2ecf20Sopenharmony_ci		     GET_FIELD(cqe_err_bits, CQE_ERROR_BITMAP_UNDER_RUN_ERR))) {
6388c2ecf20Sopenharmony_ci		QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO,
6398c2ecf20Sopenharmony_ci			  "Under flow itt=0x%x proto flags=0x%x tid=0x%x cid 0x%x fw resid 0x%x sc dlen 0x%x\n",
6408c2ecf20Sopenharmony_ci			  hdr->itt, cqe_data_in->flags, cmd->task_id,
6418c2ecf20Sopenharmony_ci			  qedi_conn->iscsi_conn_id, hdr->residual_count,
6428c2ecf20Sopenharmony_ci			  scsi_bufflen(sc_cmd));
6438c2ecf20Sopenharmony_ci		hdr->residual_count = cpu_to_be32(scsi_bufflen(sc_cmd));
6448c2ecf20Sopenharmony_ci		hdr->flags |= ISCSI_FLAG_CMD_UNDERFLOW;
6458c2ecf20Sopenharmony_ci		hdr->flags &= (~ISCSI_FLAG_CMD_OVERFLOW);
6468c2ecf20Sopenharmony_ci	}
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ci	spin_lock(&qedi_conn->list_lock);
6498c2ecf20Sopenharmony_ci	if (likely(cmd->io_cmd_in_list)) {
6508c2ecf20Sopenharmony_ci		cmd->io_cmd_in_list = false;
6518c2ecf20Sopenharmony_ci		list_del_init(&cmd->io_cmd);
6528c2ecf20Sopenharmony_ci		qedi_conn->active_cmd_count--;
6538c2ecf20Sopenharmony_ci	}
6548c2ecf20Sopenharmony_ci	spin_unlock(&qedi_conn->list_lock);
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_ci	QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_TID,
6578c2ecf20Sopenharmony_ci		  "Freeing tid=0x%x for cid=0x%x\n",
6588c2ecf20Sopenharmony_ci		  cmd->task_id, qedi_conn->iscsi_conn_id);
6598c2ecf20Sopenharmony_ci	cmd->state = RESPONSE_RECEIVED;
6608c2ecf20Sopenharmony_ci	if (qedi_io_tracing)
6618c2ecf20Sopenharmony_ci		qedi_trace_io(qedi, task, cmd->task_id, QEDI_IO_TRACE_RSP);
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr,
6648c2ecf20Sopenharmony_ci			     conn->data, datalen);
6658c2ecf20Sopenharmony_cierror:
6668c2ecf20Sopenharmony_ci	spin_unlock_bh(&session->back_lock);
6678c2ecf20Sopenharmony_ci}
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_cistatic void qedi_mtask_completion(struct qedi_ctx *qedi,
6708c2ecf20Sopenharmony_ci				  union iscsi_cqe *cqe,
6718c2ecf20Sopenharmony_ci				  struct iscsi_task *task,
6728c2ecf20Sopenharmony_ci				  struct qedi_conn *conn, uint16_t que_idx)
6738c2ecf20Sopenharmony_ci{
6748c2ecf20Sopenharmony_ci	struct iscsi_conn *iscsi_conn;
6758c2ecf20Sopenharmony_ci	u32 hdr_opcode;
6768c2ecf20Sopenharmony_ci
6778c2ecf20Sopenharmony_ci	hdr_opcode = cqe->cqe_common.iscsi_hdr.common.hdr_first_byte;
6788c2ecf20Sopenharmony_ci	iscsi_conn = conn->cls_conn->dd_data;
6798c2ecf20Sopenharmony_ci
6808c2ecf20Sopenharmony_ci	switch (hdr_opcode) {
6818c2ecf20Sopenharmony_ci	case ISCSI_OPCODE_SCSI_RESPONSE:
6828c2ecf20Sopenharmony_ci	case ISCSI_OPCODE_DATA_IN:
6838c2ecf20Sopenharmony_ci		qedi_scsi_completion(qedi, cqe, task, iscsi_conn);
6848c2ecf20Sopenharmony_ci		break;
6858c2ecf20Sopenharmony_ci	case ISCSI_OPCODE_LOGIN_RESPONSE:
6868c2ecf20Sopenharmony_ci		qedi_process_login_resp(qedi, cqe, task, conn);
6878c2ecf20Sopenharmony_ci		break;
6888c2ecf20Sopenharmony_ci	case ISCSI_OPCODE_TMF_RESPONSE:
6898c2ecf20Sopenharmony_ci		qedi_process_tmf_resp(qedi, cqe, task, conn);
6908c2ecf20Sopenharmony_ci		break;
6918c2ecf20Sopenharmony_ci	case ISCSI_OPCODE_TEXT_RESPONSE:
6928c2ecf20Sopenharmony_ci		qedi_process_text_resp(qedi, cqe, task, conn);
6938c2ecf20Sopenharmony_ci		break;
6948c2ecf20Sopenharmony_ci	case ISCSI_OPCODE_LOGOUT_RESPONSE:
6958c2ecf20Sopenharmony_ci		qedi_process_logout_resp(qedi, cqe, task, conn);
6968c2ecf20Sopenharmony_ci		break;
6978c2ecf20Sopenharmony_ci	case ISCSI_OPCODE_NOP_IN:
6988c2ecf20Sopenharmony_ci		qedi_process_nopin_mesg(qedi, cqe, task, conn, que_idx);
6998c2ecf20Sopenharmony_ci		break;
7008c2ecf20Sopenharmony_ci	default:
7018c2ecf20Sopenharmony_ci		QEDI_ERR(&qedi->dbg_ctx, "unknown opcode\n");
7028c2ecf20Sopenharmony_ci	}
7038c2ecf20Sopenharmony_ci}
7048c2ecf20Sopenharmony_ci
7058c2ecf20Sopenharmony_cistatic void qedi_process_nopin_local_cmpl(struct qedi_ctx *qedi,
7068c2ecf20Sopenharmony_ci					  struct iscsi_cqe_solicited *cqe,
7078c2ecf20Sopenharmony_ci					  struct iscsi_task *task,
7088c2ecf20Sopenharmony_ci					  struct qedi_conn *qedi_conn)
7098c2ecf20Sopenharmony_ci{
7108c2ecf20Sopenharmony_ci	struct iscsi_conn *conn = qedi_conn->cls_conn->dd_data;
7118c2ecf20Sopenharmony_ci	struct iscsi_session *session = conn->session;
7128c2ecf20Sopenharmony_ci	struct qedi_cmd *cmd = task->dd_data;
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci	QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_UNSOL,
7158c2ecf20Sopenharmony_ci		  "itid=0x%x, cmd task id=0x%x\n",
7168c2ecf20Sopenharmony_ci		  cqe->itid, cmd->task_id);
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_ci	cmd->state = RESPONSE_RECEIVED;
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_ci	spin_lock_bh(&session->back_lock);
7218c2ecf20Sopenharmony_ci	__iscsi_put_task(task);
7228c2ecf20Sopenharmony_ci	spin_unlock_bh(&session->back_lock);
7238c2ecf20Sopenharmony_ci}
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_cistatic void qedi_process_cmd_cleanup_resp(struct qedi_ctx *qedi,
7268c2ecf20Sopenharmony_ci					  struct iscsi_cqe_solicited *cqe,
7278c2ecf20Sopenharmony_ci					  struct iscsi_task *task,
7288c2ecf20Sopenharmony_ci					  struct iscsi_conn *conn)
7298c2ecf20Sopenharmony_ci{
7308c2ecf20Sopenharmony_ci	struct qedi_work_map *work, *work_tmp;
7318c2ecf20Sopenharmony_ci	u32 proto_itt = cqe->itid;
7328c2ecf20Sopenharmony_ci	u32 ptmp_itt = 0;
7338c2ecf20Sopenharmony_ci	itt_t protoitt = 0;
7348c2ecf20Sopenharmony_ci	int found = 0;
7358c2ecf20Sopenharmony_ci	struct qedi_cmd *qedi_cmd = NULL;
7368c2ecf20Sopenharmony_ci	u32 iscsi_cid;
7378c2ecf20Sopenharmony_ci	struct qedi_conn *qedi_conn;
7388c2ecf20Sopenharmony_ci	struct qedi_cmd *dbg_cmd;
7398c2ecf20Sopenharmony_ci	struct iscsi_task *mtask;
7408c2ecf20Sopenharmony_ci	struct iscsi_tm *tmf_hdr = NULL;
7418c2ecf20Sopenharmony_ci
7428c2ecf20Sopenharmony_ci	iscsi_cid = cqe->conn_id;
7438c2ecf20Sopenharmony_ci	qedi_conn = qedi->cid_que.conn_cid_tbl[iscsi_cid];
7448c2ecf20Sopenharmony_ci	if (!qedi_conn) {
7458c2ecf20Sopenharmony_ci		QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO,
7468c2ecf20Sopenharmony_ci			  "icid not found 0x%x\n", cqe->conn_id);
7478c2ecf20Sopenharmony_ci		return;
7488c2ecf20Sopenharmony_ci	}
7498c2ecf20Sopenharmony_ci
7508c2ecf20Sopenharmony_ci	/* Based on this itt get the corresponding qedi_cmd */
7518c2ecf20Sopenharmony_ci	spin_lock_bh(&qedi_conn->tmf_work_lock);
7528c2ecf20Sopenharmony_ci	list_for_each_entry_safe(work, work_tmp, &qedi_conn->tmf_work_list,
7538c2ecf20Sopenharmony_ci				 list) {
7548c2ecf20Sopenharmony_ci		if (work->rtid == proto_itt) {
7558c2ecf20Sopenharmony_ci			/* We found the command */
7568c2ecf20Sopenharmony_ci			qedi_cmd = work->qedi_cmd;
7578c2ecf20Sopenharmony_ci			if (!qedi_cmd->list_tmf_work) {
7588c2ecf20Sopenharmony_ci				QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_SCSI_TM,
7598c2ecf20Sopenharmony_ci					  "TMF work not found, cqe->tid=0x%x, cid=0x%x\n",
7608c2ecf20Sopenharmony_ci					  proto_itt, qedi_conn->iscsi_conn_id);
7618c2ecf20Sopenharmony_ci				WARN_ON(1);
7628c2ecf20Sopenharmony_ci			}
7638c2ecf20Sopenharmony_ci			found = 1;
7648c2ecf20Sopenharmony_ci			mtask = qedi_cmd->task;
7658c2ecf20Sopenharmony_ci			tmf_hdr = (struct iscsi_tm *)mtask->hdr;
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_ci			list_del_init(&work->list);
7688c2ecf20Sopenharmony_ci			kfree(work);
7698c2ecf20Sopenharmony_ci			qedi_cmd->list_tmf_work = NULL;
7708c2ecf20Sopenharmony_ci		}
7718c2ecf20Sopenharmony_ci	}
7728c2ecf20Sopenharmony_ci	spin_unlock_bh(&qedi_conn->tmf_work_lock);
7738c2ecf20Sopenharmony_ci
7748c2ecf20Sopenharmony_ci	if (found) {
7758c2ecf20Sopenharmony_ci		QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_SCSI_TM,
7768c2ecf20Sopenharmony_ci			  "TMF work, cqe->tid=0x%x, tmf flags=0x%x, cid=0x%x\n",
7778c2ecf20Sopenharmony_ci			  proto_itt, tmf_hdr->flags, qedi_conn->iscsi_conn_id);
7788c2ecf20Sopenharmony_ci
7798c2ecf20Sopenharmony_ci		if ((tmf_hdr->flags & ISCSI_FLAG_TM_FUNC_MASK) ==
7808c2ecf20Sopenharmony_ci		    ISCSI_TM_FUNC_ABORT_TASK) {
7818c2ecf20Sopenharmony_ci			spin_lock_bh(&conn->session->back_lock);
7828c2ecf20Sopenharmony_ci
7838c2ecf20Sopenharmony_ci			protoitt = build_itt(get_itt(tmf_hdr->rtt),
7848c2ecf20Sopenharmony_ci					     conn->session->age);
7858c2ecf20Sopenharmony_ci			task = iscsi_itt_to_task(conn, protoitt);
7868c2ecf20Sopenharmony_ci
7878c2ecf20Sopenharmony_ci			spin_unlock_bh(&conn->session->back_lock);
7888c2ecf20Sopenharmony_ci
7898c2ecf20Sopenharmony_ci			if (!task) {
7908c2ecf20Sopenharmony_ci				QEDI_NOTICE(&qedi->dbg_ctx,
7918c2ecf20Sopenharmony_ci					    "IO task completed, tmf rtt=0x%x, cid=0x%x\n",
7928c2ecf20Sopenharmony_ci					    get_itt(tmf_hdr->rtt),
7938c2ecf20Sopenharmony_ci					    qedi_conn->iscsi_conn_id);
7948c2ecf20Sopenharmony_ci				return;
7958c2ecf20Sopenharmony_ci			}
7968c2ecf20Sopenharmony_ci
7978c2ecf20Sopenharmony_ci			dbg_cmd = task->dd_data;
7988c2ecf20Sopenharmony_ci
7998c2ecf20Sopenharmony_ci			QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_SCSI_TM,
8008c2ecf20Sopenharmony_ci				  "Abort tmf rtt=0x%x, i/o itt=0x%x, i/o tid=0x%x, cid=0x%x\n",
8018c2ecf20Sopenharmony_ci				  get_itt(tmf_hdr->rtt), get_itt(task->itt),
8028c2ecf20Sopenharmony_ci				  dbg_cmd->task_id, qedi_conn->iscsi_conn_id);
8038c2ecf20Sopenharmony_ci
8048c2ecf20Sopenharmony_ci			if (qedi_cmd->state == CLEANUP_WAIT_FAILED)
8058c2ecf20Sopenharmony_ci				qedi_cmd->state = CLEANUP_RECV;
8068c2ecf20Sopenharmony_ci
8078c2ecf20Sopenharmony_ci			spin_lock(&qedi_conn->list_lock);
8088c2ecf20Sopenharmony_ci			if (likely(dbg_cmd->io_cmd_in_list)) {
8098c2ecf20Sopenharmony_ci				dbg_cmd->io_cmd_in_list = false;
8108c2ecf20Sopenharmony_ci				list_del_init(&dbg_cmd->io_cmd);
8118c2ecf20Sopenharmony_ci				qedi_conn->active_cmd_count--;
8128c2ecf20Sopenharmony_ci			}
8138c2ecf20Sopenharmony_ci			spin_unlock(&qedi_conn->list_lock);
8148c2ecf20Sopenharmony_ci			qedi_cmd->state = CLEANUP_RECV;
8158c2ecf20Sopenharmony_ci			wake_up_interruptible(&qedi_conn->wait_queue);
8168c2ecf20Sopenharmony_ci		}
8178c2ecf20Sopenharmony_ci	} else if (qedi_conn->cmd_cleanup_req > 0) {
8188c2ecf20Sopenharmony_ci		spin_lock_bh(&conn->session->back_lock);
8198c2ecf20Sopenharmony_ci		qedi_get_proto_itt(qedi, cqe->itid, &ptmp_itt);
8208c2ecf20Sopenharmony_ci		protoitt = build_itt(ptmp_itt, conn->session->age);
8218c2ecf20Sopenharmony_ci		task = iscsi_itt_to_task(conn, protoitt);
8228c2ecf20Sopenharmony_ci		QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_SCSI_TM,
8238c2ecf20Sopenharmony_ci			  "cleanup io itid=0x%x, protoitt=0x%x, cmd_cleanup_cmpl=%d, cid=0x%x\n",
8248c2ecf20Sopenharmony_ci			  cqe->itid, protoitt, qedi_conn->cmd_cleanup_cmpl,
8258c2ecf20Sopenharmony_ci			  qedi_conn->iscsi_conn_id);
8268c2ecf20Sopenharmony_ci
8278c2ecf20Sopenharmony_ci		spin_unlock_bh(&conn->session->back_lock);
8288c2ecf20Sopenharmony_ci		if (!task) {
8298c2ecf20Sopenharmony_ci			QEDI_NOTICE(&qedi->dbg_ctx,
8308c2ecf20Sopenharmony_ci				    "task is null, itid=0x%x, cid=0x%x\n",
8318c2ecf20Sopenharmony_ci				    cqe->itid, qedi_conn->iscsi_conn_id);
8328c2ecf20Sopenharmony_ci			return;
8338c2ecf20Sopenharmony_ci		}
8348c2ecf20Sopenharmony_ci		qedi_conn->cmd_cleanup_cmpl++;
8358c2ecf20Sopenharmony_ci		wake_up(&qedi_conn->wait_queue);
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_ci		QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_TID,
8388c2ecf20Sopenharmony_ci			  "Freeing tid=0x%x for cid=0x%x\n",
8398c2ecf20Sopenharmony_ci			  cqe->itid, qedi_conn->iscsi_conn_id);
8408c2ecf20Sopenharmony_ci
8418c2ecf20Sopenharmony_ci	} else {
8428c2ecf20Sopenharmony_ci		qedi_get_proto_itt(qedi, cqe->itid, &ptmp_itt);
8438c2ecf20Sopenharmony_ci		protoitt = build_itt(ptmp_itt, conn->session->age);
8448c2ecf20Sopenharmony_ci		task = iscsi_itt_to_task(conn, protoitt);
8458c2ecf20Sopenharmony_ci		QEDI_ERR(&qedi->dbg_ctx,
8468c2ecf20Sopenharmony_ci			 "Delayed or untracked cleanup response, itt=0x%x, tid=0x%x, cid=0x%x, task=%p\n",
8478c2ecf20Sopenharmony_ci			 protoitt, cqe->itid, qedi_conn->iscsi_conn_id, task);
8488c2ecf20Sopenharmony_ci	}
8498c2ecf20Sopenharmony_ci}
8508c2ecf20Sopenharmony_ci
8518c2ecf20Sopenharmony_civoid qedi_fp_process_cqes(struct qedi_work *work)
8528c2ecf20Sopenharmony_ci{
8538c2ecf20Sopenharmony_ci	struct qedi_ctx *qedi = work->qedi;
8548c2ecf20Sopenharmony_ci	union iscsi_cqe *cqe = &work->cqe;
8558c2ecf20Sopenharmony_ci	struct iscsi_task *task = NULL;
8568c2ecf20Sopenharmony_ci	struct iscsi_nopout *nopout_hdr;
8578c2ecf20Sopenharmony_ci	struct qedi_conn *q_conn;
8588c2ecf20Sopenharmony_ci	struct iscsi_conn *conn;
8598c2ecf20Sopenharmony_ci	struct qedi_cmd *qedi_cmd;
8608c2ecf20Sopenharmony_ci	u32 comp_type;
8618c2ecf20Sopenharmony_ci	u32 iscsi_cid;
8628c2ecf20Sopenharmony_ci	u32 hdr_opcode;
8638c2ecf20Sopenharmony_ci	u16 que_idx = work->que_idx;
8648c2ecf20Sopenharmony_ci	u8 cqe_err_bits = 0;
8658c2ecf20Sopenharmony_ci
8668c2ecf20Sopenharmony_ci	comp_type = cqe->cqe_common.cqe_type;
8678c2ecf20Sopenharmony_ci	hdr_opcode = cqe->cqe_common.iscsi_hdr.common.hdr_first_byte;
8688c2ecf20Sopenharmony_ci	cqe_err_bits =
8698c2ecf20Sopenharmony_ci		cqe->cqe_common.error_bitmap.error_bits.cqe_error_status_bits;
8708c2ecf20Sopenharmony_ci
8718c2ecf20Sopenharmony_ci	QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN,
8728c2ecf20Sopenharmony_ci		  "fw_cid=0x%x, cqe type=0x%x, opcode=0x%x\n",
8738c2ecf20Sopenharmony_ci		  cqe->cqe_common.conn_id, comp_type, hdr_opcode);
8748c2ecf20Sopenharmony_ci
8758c2ecf20Sopenharmony_ci	if (comp_type >= MAX_ISCSI_CQES_TYPE) {
8768c2ecf20Sopenharmony_ci		QEDI_WARN(&qedi->dbg_ctx, "Invalid CqE type\n");
8778c2ecf20Sopenharmony_ci		return;
8788c2ecf20Sopenharmony_ci	}
8798c2ecf20Sopenharmony_ci
8808c2ecf20Sopenharmony_ci	iscsi_cid  = cqe->cqe_common.conn_id;
8818c2ecf20Sopenharmony_ci	q_conn = qedi->cid_que.conn_cid_tbl[iscsi_cid];
8828c2ecf20Sopenharmony_ci	if (!q_conn) {
8838c2ecf20Sopenharmony_ci		QEDI_WARN(&qedi->dbg_ctx,
8848c2ecf20Sopenharmony_ci			  "Session no longer exists for cid=0x%x!!\n",
8858c2ecf20Sopenharmony_ci			  iscsi_cid);
8868c2ecf20Sopenharmony_ci		return;
8878c2ecf20Sopenharmony_ci	}
8888c2ecf20Sopenharmony_ci
8898c2ecf20Sopenharmony_ci	conn = q_conn->cls_conn->dd_data;
8908c2ecf20Sopenharmony_ci
8918c2ecf20Sopenharmony_ci	if (unlikely(cqe_err_bits &&
8928c2ecf20Sopenharmony_ci		     GET_FIELD(cqe_err_bits,
8938c2ecf20Sopenharmony_ci			       CQE_ERROR_BITMAP_DATA_DIGEST_ERR))) {
8948c2ecf20Sopenharmony_ci		iscsi_conn_failure(conn, ISCSI_ERR_DATA_DGST);
8958c2ecf20Sopenharmony_ci		return;
8968c2ecf20Sopenharmony_ci	}
8978c2ecf20Sopenharmony_ci
8988c2ecf20Sopenharmony_ci	switch (comp_type) {
8998c2ecf20Sopenharmony_ci	case ISCSI_CQE_TYPE_SOLICITED:
9008c2ecf20Sopenharmony_ci	case ISCSI_CQE_TYPE_SOLICITED_WITH_SENSE:
9018c2ecf20Sopenharmony_ci		qedi_cmd = container_of(work, struct qedi_cmd, cqe_work);
9028c2ecf20Sopenharmony_ci		task = qedi_cmd->task;
9038c2ecf20Sopenharmony_ci		if (!task) {
9048c2ecf20Sopenharmony_ci			QEDI_WARN(&qedi->dbg_ctx, "task is NULL\n");
9058c2ecf20Sopenharmony_ci			return;
9068c2ecf20Sopenharmony_ci		}
9078c2ecf20Sopenharmony_ci
9088c2ecf20Sopenharmony_ci		/* Process NOPIN local completion */
9098c2ecf20Sopenharmony_ci		nopout_hdr = (struct iscsi_nopout *)task->hdr;
9108c2ecf20Sopenharmony_ci		if ((nopout_hdr->itt == RESERVED_ITT) &&
9118c2ecf20Sopenharmony_ci		    (cqe->cqe_solicited.itid != (u16)RESERVED_ITT)) {
9128c2ecf20Sopenharmony_ci			qedi_process_nopin_local_cmpl(qedi, &cqe->cqe_solicited,
9138c2ecf20Sopenharmony_ci						      task, q_conn);
9148c2ecf20Sopenharmony_ci		} else {
9158c2ecf20Sopenharmony_ci			cqe->cqe_solicited.itid =
9168c2ecf20Sopenharmony_ci					       qedi_get_itt(cqe->cqe_solicited);
9178c2ecf20Sopenharmony_ci			/* Process other solicited responses */
9188c2ecf20Sopenharmony_ci			qedi_mtask_completion(qedi, cqe, task, q_conn, que_idx);
9198c2ecf20Sopenharmony_ci		}
9208c2ecf20Sopenharmony_ci		break;
9218c2ecf20Sopenharmony_ci	case ISCSI_CQE_TYPE_UNSOLICITED:
9228c2ecf20Sopenharmony_ci		switch (hdr_opcode) {
9238c2ecf20Sopenharmony_ci		case ISCSI_OPCODE_NOP_IN:
9248c2ecf20Sopenharmony_ci			qedi_process_nopin_mesg(qedi, cqe, task, q_conn,
9258c2ecf20Sopenharmony_ci						que_idx);
9268c2ecf20Sopenharmony_ci			break;
9278c2ecf20Sopenharmony_ci		case ISCSI_OPCODE_ASYNC_MSG:
9288c2ecf20Sopenharmony_ci			qedi_process_async_mesg(qedi, cqe, task, q_conn,
9298c2ecf20Sopenharmony_ci						que_idx);
9308c2ecf20Sopenharmony_ci			break;
9318c2ecf20Sopenharmony_ci		case ISCSI_OPCODE_REJECT:
9328c2ecf20Sopenharmony_ci			qedi_process_reject_mesg(qedi, cqe, task, q_conn,
9338c2ecf20Sopenharmony_ci						 que_idx);
9348c2ecf20Sopenharmony_ci			break;
9358c2ecf20Sopenharmony_ci		}
9368c2ecf20Sopenharmony_ci		goto exit_fp_process;
9378c2ecf20Sopenharmony_ci	case ISCSI_CQE_TYPE_DUMMY:
9388c2ecf20Sopenharmony_ci		QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_SCSI_TM, "Dummy CqE\n");
9398c2ecf20Sopenharmony_ci		goto exit_fp_process;
9408c2ecf20Sopenharmony_ci	case ISCSI_CQE_TYPE_TASK_CLEANUP:
9418c2ecf20Sopenharmony_ci		QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_SCSI_TM, "CleanUp CqE\n");
9428c2ecf20Sopenharmony_ci		qedi_process_cmd_cleanup_resp(qedi, &cqe->cqe_solicited, task,
9438c2ecf20Sopenharmony_ci					      conn);
9448c2ecf20Sopenharmony_ci		goto exit_fp_process;
9458c2ecf20Sopenharmony_ci	default:
9468c2ecf20Sopenharmony_ci		QEDI_ERR(&qedi->dbg_ctx, "Error cqe.\n");
9478c2ecf20Sopenharmony_ci		break;
9488c2ecf20Sopenharmony_ci	}
9498c2ecf20Sopenharmony_ci
9508c2ecf20Sopenharmony_ciexit_fp_process:
9518c2ecf20Sopenharmony_ci	return;
9528c2ecf20Sopenharmony_ci}
9538c2ecf20Sopenharmony_ci
9548c2ecf20Sopenharmony_cistatic void qedi_ring_doorbell(struct qedi_conn *qedi_conn)
9558c2ecf20Sopenharmony_ci{
9568c2ecf20Sopenharmony_ci	struct iscsi_db_data dbell = { 0 };
9578c2ecf20Sopenharmony_ci
9588c2ecf20Sopenharmony_ci	dbell.agg_flags = 0;
9598c2ecf20Sopenharmony_ci
9608c2ecf20Sopenharmony_ci	dbell.params |= DB_DEST_XCM << ISCSI_DB_DATA_DEST_SHIFT;
9618c2ecf20Sopenharmony_ci	dbell.params |= DB_AGG_CMD_SET << ISCSI_DB_DATA_AGG_CMD_SHIFT;
9628c2ecf20Sopenharmony_ci	dbell.params |=
9638c2ecf20Sopenharmony_ci		   DQ_XCM_ISCSI_SQ_PROD_CMD << ISCSI_DB_DATA_AGG_VAL_SEL_SHIFT;
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_ci	dbell.sq_prod = qedi_conn->ep->fw_sq_prod_idx;
9668c2ecf20Sopenharmony_ci	writel(*(u32 *)&dbell, qedi_conn->ep->p_doorbell);
9678c2ecf20Sopenharmony_ci
9688c2ecf20Sopenharmony_ci	/* Make sure fw write idx is coherent, and include both memory barriers
9698c2ecf20Sopenharmony_ci	 * as a failsafe as for some architectures the call is the same but on
9708c2ecf20Sopenharmony_ci	 * others they are two different assembly operations.
9718c2ecf20Sopenharmony_ci	 */
9728c2ecf20Sopenharmony_ci	wmb();
9738c2ecf20Sopenharmony_ci	QEDI_INFO(&qedi_conn->qedi->dbg_ctx, QEDI_LOG_MP_REQ,
9748c2ecf20Sopenharmony_ci		  "prod_idx=0x%x, fw_prod_idx=0x%x, cid=0x%x\n",
9758c2ecf20Sopenharmony_ci		  qedi_conn->ep->sq_prod_idx, qedi_conn->ep->fw_sq_prod_idx,
9768c2ecf20Sopenharmony_ci		  qedi_conn->iscsi_conn_id);
9778c2ecf20Sopenharmony_ci}
9788c2ecf20Sopenharmony_ci
9798c2ecf20Sopenharmony_cistatic u16 qedi_get_wqe_idx(struct qedi_conn *qedi_conn)
9808c2ecf20Sopenharmony_ci{
9818c2ecf20Sopenharmony_ci	struct qedi_endpoint *ep;
9828c2ecf20Sopenharmony_ci	u16 rval;
9838c2ecf20Sopenharmony_ci
9848c2ecf20Sopenharmony_ci	ep = qedi_conn->ep;
9858c2ecf20Sopenharmony_ci	rval = ep->sq_prod_idx;
9868c2ecf20Sopenharmony_ci
9878c2ecf20Sopenharmony_ci	/* Increament SQ index */
9888c2ecf20Sopenharmony_ci	ep->sq_prod_idx++;
9898c2ecf20Sopenharmony_ci	ep->fw_sq_prod_idx++;
9908c2ecf20Sopenharmony_ci	if (ep->sq_prod_idx == QEDI_SQ_SIZE)
9918c2ecf20Sopenharmony_ci		ep->sq_prod_idx = 0;
9928c2ecf20Sopenharmony_ci
9938c2ecf20Sopenharmony_ci	return rval;
9948c2ecf20Sopenharmony_ci}
9958c2ecf20Sopenharmony_ci
9968c2ecf20Sopenharmony_ciint qedi_send_iscsi_login(struct qedi_conn *qedi_conn,
9978c2ecf20Sopenharmony_ci			  struct iscsi_task *task)
9988c2ecf20Sopenharmony_ci{
9998c2ecf20Sopenharmony_ci	struct iscsi_login_req_hdr login_req_pdu_header;
10008c2ecf20Sopenharmony_ci	struct scsi_sgl_task_params tx_sgl_task_params;
10018c2ecf20Sopenharmony_ci	struct scsi_sgl_task_params rx_sgl_task_params;
10028c2ecf20Sopenharmony_ci	struct iscsi_task_params task_params;
10038c2ecf20Sopenharmony_ci	struct e4_iscsi_task_context *fw_task_ctx;
10048c2ecf20Sopenharmony_ci	struct qedi_ctx *qedi = qedi_conn->qedi;
10058c2ecf20Sopenharmony_ci	struct iscsi_login_req *login_hdr;
10068c2ecf20Sopenharmony_ci	struct scsi_sge *resp_sge = NULL;
10078c2ecf20Sopenharmony_ci	struct qedi_cmd *qedi_cmd;
10088c2ecf20Sopenharmony_ci	struct qedi_endpoint *ep;
10098c2ecf20Sopenharmony_ci	s16 tid = 0;
10108c2ecf20Sopenharmony_ci	u16 sq_idx = 0;
10118c2ecf20Sopenharmony_ci	int rval = 0;
10128c2ecf20Sopenharmony_ci
10138c2ecf20Sopenharmony_ci	resp_sge = (struct scsi_sge *)qedi_conn->gen_pdu.resp_bd_tbl;
10148c2ecf20Sopenharmony_ci	qedi_cmd = (struct qedi_cmd *)task->dd_data;
10158c2ecf20Sopenharmony_ci	ep = qedi_conn->ep;
10168c2ecf20Sopenharmony_ci	login_hdr = (struct iscsi_login_req *)task->hdr;
10178c2ecf20Sopenharmony_ci
10188c2ecf20Sopenharmony_ci	tid = qedi_get_task_idx(qedi);
10198c2ecf20Sopenharmony_ci	if (tid == -1)
10208c2ecf20Sopenharmony_ci		return -ENOMEM;
10218c2ecf20Sopenharmony_ci
10228c2ecf20Sopenharmony_ci	fw_task_ctx =
10238c2ecf20Sopenharmony_ci	     (struct e4_iscsi_task_context *)qedi_get_task_mem(&qedi->tasks,
10248c2ecf20Sopenharmony_ci							       tid);
10258c2ecf20Sopenharmony_ci	memset(fw_task_ctx, 0, sizeof(struct e4_iscsi_task_context));
10268c2ecf20Sopenharmony_ci
10278c2ecf20Sopenharmony_ci	qedi_cmd->task_id = tid;
10288c2ecf20Sopenharmony_ci
10298c2ecf20Sopenharmony_ci	memset(&task_params, 0, sizeof(task_params));
10308c2ecf20Sopenharmony_ci	memset(&login_req_pdu_header, 0, sizeof(login_req_pdu_header));
10318c2ecf20Sopenharmony_ci	memset(&tx_sgl_task_params, 0, sizeof(tx_sgl_task_params));
10328c2ecf20Sopenharmony_ci	memset(&rx_sgl_task_params, 0, sizeof(rx_sgl_task_params));
10338c2ecf20Sopenharmony_ci	/* Update header info */
10348c2ecf20Sopenharmony_ci	login_req_pdu_header.opcode = login_hdr->opcode;
10358c2ecf20Sopenharmony_ci	login_req_pdu_header.version_min = login_hdr->min_version;
10368c2ecf20Sopenharmony_ci	login_req_pdu_header.version_max = login_hdr->max_version;
10378c2ecf20Sopenharmony_ci	login_req_pdu_header.flags_attr = login_hdr->flags;
10388c2ecf20Sopenharmony_ci	login_req_pdu_header.isid_tabc = swab32p((u32 *)login_hdr->isid);
10398c2ecf20Sopenharmony_ci	login_req_pdu_header.isid_d = swab16p((u16 *)&login_hdr->isid[4]);
10408c2ecf20Sopenharmony_ci
10418c2ecf20Sopenharmony_ci	login_req_pdu_header.tsih = login_hdr->tsih;
10428c2ecf20Sopenharmony_ci	login_req_pdu_header.hdr_second_dword = ntoh24(login_hdr->dlength);
10438c2ecf20Sopenharmony_ci
10448c2ecf20Sopenharmony_ci	qedi_update_itt_map(qedi, tid, task->itt, qedi_cmd);
10458c2ecf20Sopenharmony_ci	login_req_pdu_header.itt = qedi_set_itt(tid, get_itt(task->itt));
10468c2ecf20Sopenharmony_ci	login_req_pdu_header.cid = qedi_conn->iscsi_conn_id;
10478c2ecf20Sopenharmony_ci	login_req_pdu_header.cmd_sn = be32_to_cpu(login_hdr->cmdsn);
10488c2ecf20Sopenharmony_ci	login_req_pdu_header.exp_stat_sn = be32_to_cpu(login_hdr->exp_statsn);
10498c2ecf20Sopenharmony_ci	login_req_pdu_header.exp_stat_sn = 0;
10508c2ecf20Sopenharmony_ci
10518c2ecf20Sopenharmony_ci	/* Fill tx AHS and rx buffer */
10528c2ecf20Sopenharmony_ci	tx_sgl_task_params.sgl =
10538c2ecf20Sopenharmony_ci			       (struct scsi_sge *)qedi_conn->gen_pdu.req_bd_tbl;
10548c2ecf20Sopenharmony_ci	tx_sgl_task_params.sgl_phys_addr.lo =
10558c2ecf20Sopenharmony_ci					 (u32)(qedi_conn->gen_pdu.req_dma_addr);
10568c2ecf20Sopenharmony_ci	tx_sgl_task_params.sgl_phys_addr.hi =
10578c2ecf20Sopenharmony_ci			      (u32)((u64)qedi_conn->gen_pdu.req_dma_addr >> 32);
10588c2ecf20Sopenharmony_ci	tx_sgl_task_params.total_buffer_size = ntoh24(login_hdr->dlength);
10598c2ecf20Sopenharmony_ci	tx_sgl_task_params.num_sges = 1;
10608c2ecf20Sopenharmony_ci
10618c2ecf20Sopenharmony_ci	rx_sgl_task_params.sgl =
10628c2ecf20Sopenharmony_ci			      (struct scsi_sge *)qedi_conn->gen_pdu.resp_bd_tbl;
10638c2ecf20Sopenharmony_ci	rx_sgl_task_params.sgl_phys_addr.lo =
10648c2ecf20Sopenharmony_ci					(u32)(qedi_conn->gen_pdu.resp_dma_addr);
10658c2ecf20Sopenharmony_ci	rx_sgl_task_params.sgl_phys_addr.hi =
10668c2ecf20Sopenharmony_ci			     (u32)((u64)qedi_conn->gen_pdu.resp_dma_addr >> 32);
10678c2ecf20Sopenharmony_ci	rx_sgl_task_params.total_buffer_size = resp_sge->sge_len;
10688c2ecf20Sopenharmony_ci	rx_sgl_task_params.num_sges = 1;
10698c2ecf20Sopenharmony_ci
10708c2ecf20Sopenharmony_ci	/* Fill fw input params */
10718c2ecf20Sopenharmony_ci	task_params.context = fw_task_ctx;
10728c2ecf20Sopenharmony_ci	task_params.conn_icid = (u16)qedi_conn->iscsi_conn_id;
10738c2ecf20Sopenharmony_ci	task_params.itid = tid;
10748c2ecf20Sopenharmony_ci	task_params.cq_rss_number = 0;
10758c2ecf20Sopenharmony_ci	task_params.tx_io_size = ntoh24(login_hdr->dlength);
10768c2ecf20Sopenharmony_ci	task_params.rx_io_size = resp_sge->sge_len;
10778c2ecf20Sopenharmony_ci
10788c2ecf20Sopenharmony_ci	sq_idx = qedi_get_wqe_idx(qedi_conn);
10798c2ecf20Sopenharmony_ci	task_params.sqe = &ep->sq[sq_idx];
10808c2ecf20Sopenharmony_ci
10818c2ecf20Sopenharmony_ci	memset(task_params.sqe, 0, sizeof(struct iscsi_wqe));
10828c2ecf20Sopenharmony_ci	rval = init_initiator_login_request_task(&task_params,
10838c2ecf20Sopenharmony_ci						 &login_req_pdu_header,
10848c2ecf20Sopenharmony_ci						 &tx_sgl_task_params,
10858c2ecf20Sopenharmony_ci						 &rx_sgl_task_params);
10868c2ecf20Sopenharmony_ci	if (rval)
10878c2ecf20Sopenharmony_ci		return -1;
10888c2ecf20Sopenharmony_ci
10898c2ecf20Sopenharmony_ci	spin_lock(&qedi_conn->list_lock);
10908c2ecf20Sopenharmony_ci	list_add_tail(&qedi_cmd->io_cmd, &qedi_conn->active_cmd_list);
10918c2ecf20Sopenharmony_ci	qedi_cmd->io_cmd_in_list = true;
10928c2ecf20Sopenharmony_ci	qedi_conn->active_cmd_count++;
10938c2ecf20Sopenharmony_ci	spin_unlock(&qedi_conn->list_lock);
10948c2ecf20Sopenharmony_ci
10958c2ecf20Sopenharmony_ci	qedi_ring_doorbell(qedi_conn);
10968c2ecf20Sopenharmony_ci	return 0;
10978c2ecf20Sopenharmony_ci}
10988c2ecf20Sopenharmony_ci
10998c2ecf20Sopenharmony_ciint qedi_send_iscsi_logout(struct qedi_conn *qedi_conn,
11008c2ecf20Sopenharmony_ci			   struct iscsi_task *task)
11018c2ecf20Sopenharmony_ci{
11028c2ecf20Sopenharmony_ci	struct iscsi_logout_req_hdr logout_pdu_header;
11038c2ecf20Sopenharmony_ci	struct scsi_sgl_task_params tx_sgl_task_params;
11048c2ecf20Sopenharmony_ci	struct scsi_sgl_task_params rx_sgl_task_params;
11058c2ecf20Sopenharmony_ci	struct iscsi_task_params task_params;
11068c2ecf20Sopenharmony_ci	struct e4_iscsi_task_context *fw_task_ctx;
11078c2ecf20Sopenharmony_ci	struct iscsi_logout *logout_hdr = NULL;
11088c2ecf20Sopenharmony_ci	struct qedi_ctx *qedi = qedi_conn->qedi;
11098c2ecf20Sopenharmony_ci	struct qedi_cmd *qedi_cmd;
11108c2ecf20Sopenharmony_ci	struct qedi_endpoint *ep;
11118c2ecf20Sopenharmony_ci	s16 tid = 0;
11128c2ecf20Sopenharmony_ci	u16 sq_idx = 0;
11138c2ecf20Sopenharmony_ci	int rval = 0;
11148c2ecf20Sopenharmony_ci
11158c2ecf20Sopenharmony_ci	qedi_cmd = (struct qedi_cmd *)task->dd_data;
11168c2ecf20Sopenharmony_ci	logout_hdr = (struct iscsi_logout *)task->hdr;
11178c2ecf20Sopenharmony_ci	ep = qedi_conn->ep;
11188c2ecf20Sopenharmony_ci
11198c2ecf20Sopenharmony_ci	tid = qedi_get_task_idx(qedi);
11208c2ecf20Sopenharmony_ci	if (tid == -1)
11218c2ecf20Sopenharmony_ci		return -ENOMEM;
11228c2ecf20Sopenharmony_ci
11238c2ecf20Sopenharmony_ci	fw_task_ctx =
11248c2ecf20Sopenharmony_ci	     (struct e4_iscsi_task_context *)qedi_get_task_mem(&qedi->tasks,
11258c2ecf20Sopenharmony_ci							       tid);
11268c2ecf20Sopenharmony_ci	memset(fw_task_ctx, 0, sizeof(struct e4_iscsi_task_context));
11278c2ecf20Sopenharmony_ci
11288c2ecf20Sopenharmony_ci	qedi_cmd->task_id = tid;
11298c2ecf20Sopenharmony_ci
11308c2ecf20Sopenharmony_ci	memset(&task_params, 0, sizeof(task_params));
11318c2ecf20Sopenharmony_ci	memset(&logout_pdu_header, 0, sizeof(logout_pdu_header));
11328c2ecf20Sopenharmony_ci	memset(&tx_sgl_task_params, 0, sizeof(tx_sgl_task_params));
11338c2ecf20Sopenharmony_ci	memset(&rx_sgl_task_params, 0, sizeof(rx_sgl_task_params));
11348c2ecf20Sopenharmony_ci
11358c2ecf20Sopenharmony_ci	/* Update header info */
11368c2ecf20Sopenharmony_ci	logout_pdu_header.opcode = logout_hdr->opcode;
11378c2ecf20Sopenharmony_ci	logout_pdu_header.reason_code = 0x80 | logout_hdr->flags;
11388c2ecf20Sopenharmony_ci	qedi_update_itt_map(qedi, tid, task->itt, qedi_cmd);
11398c2ecf20Sopenharmony_ci	logout_pdu_header.itt = qedi_set_itt(tid, get_itt(task->itt));
11408c2ecf20Sopenharmony_ci	logout_pdu_header.exp_stat_sn = be32_to_cpu(logout_hdr->exp_statsn);
11418c2ecf20Sopenharmony_ci	logout_pdu_header.cmd_sn = be32_to_cpu(logout_hdr->cmdsn);
11428c2ecf20Sopenharmony_ci	logout_pdu_header.cid = qedi_conn->iscsi_conn_id;
11438c2ecf20Sopenharmony_ci
11448c2ecf20Sopenharmony_ci	/* Fill fw input params */
11458c2ecf20Sopenharmony_ci	task_params.context = fw_task_ctx;
11468c2ecf20Sopenharmony_ci	task_params.conn_icid = (u16)qedi_conn->iscsi_conn_id;
11478c2ecf20Sopenharmony_ci	task_params.itid = tid;
11488c2ecf20Sopenharmony_ci	task_params.cq_rss_number = 0;
11498c2ecf20Sopenharmony_ci	task_params.tx_io_size = 0;
11508c2ecf20Sopenharmony_ci	task_params.rx_io_size = 0;
11518c2ecf20Sopenharmony_ci
11528c2ecf20Sopenharmony_ci	sq_idx = qedi_get_wqe_idx(qedi_conn);
11538c2ecf20Sopenharmony_ci	task_params.sqe = &ep->sq[sq_idx];
11548c2ecf20Sopenharmony_ci	memset(task_params.sqe, 0, sizeof(struct iscsi_wqe));
11558c2ecf20Sopenharmony_ci
11568c2ecf20Sopenharmony_ci	rval = init_initiator_logout_request_task(&task_params,
11578c2ecf20Sopenharmony_ci						  &logout_pdu_header,
11588c2ecf20Sopenharmony_ci						  NULL, NULL);
11598c2ecf20Sopenharmony_ci	if (rval)
11608c2ecf20Sopenharmony_ci		return -1;
11618c2ecf20Sopenharmony_ci
11628c2ecf20Sopenharmony_ci	spin_lock(&qedi_conn->list_lock);
11638c2ecf20Sopenharmony_ci	list_add_tail(&qedi_cmd->io_cmd, &qedi_conn->active_cmd_list);
11648c2ecf20Sopenharmony_ci	qedi_cmd->io_cmd_in_list = true;
11658c2ecf20Sopenharmony_ci	qedi_conn->active_cmd_count++;
11668c2ecf20Sopenharmony_ci	spin_unlock(&qedi_conn->list_lock);
11678c2ecf20Sopenharmony_ci
11688c2ecf20Sopenharmony_ci	qedi_ring_doorbell(qedi_conn);
11698c2ecf20Sopenharmony_ci	return 0;
11708c2ecf20Sopenharmony_ci}
11718c2ecf20Sopenharmony_ci
11728c2ecf20Sopenharmony_ciint qedi_cleanup_all_io(struct qedi_ctx *qedi, struct qedi_conn *qedi_conn,
11738c2ecf20Sopenharmony_ci			struct iscsi_task *task, bool in_recovery)
11748c2ecf20Sopenharmony_ci{
11758c2ecf20Sopenharmony_ci	int rval;
11768c2ecf20Sopenharmony_ci	struct iscsi_task *ctask;
11778c2ecf20Sopenharmony_ci	struct qedi_cmd *cmd, *cmd_tmp;
11788c2ecf20Sopenharmony_ci	struct iscsi_tm *tmf_hdr;
11798c2ecf20Sopenharmony_ci	unsigned int lun = 0;
11808c2ecf20Sopenharmony_ci	bool lun_reset = false;
11818c2ecf20Sopenharmony_ci	struct iscsi_conn *conn = qedi_conn->cls_conn->dd_data;
11828c2ecf20Sopenharmony_ci	struct iscsi_session *session = conn->session;
11838c2ecf20Sopenharmony_ci
11848c2ecf20Sopenharmony_ci	/* From recovery, task is NULL or from tmf resp valid task */
11858c2ecf20Sopenharmony_ci	if (task) {
11868c2ecf20Sopenharmony_ci		tmf_hdr = (struct iscsi_tm *)task->hdr;
11878c2ecf20Sopenharmony_ci
11888c2ecf20Sopenharmony_ci		if ((tmf_hdr->flags & ISCSI_FLAG_TM_FUNC_MASK) ==
11898c2ecf20Sopenharmony_ci			ISCSI_TM_FUNC_LOGICAL_UNIT_RESET) {
11908c2ecf20Sopenharmony_ci			lun_reset = true;
11918c2ecf20Sopenharmony_ci			lun = scsilun_to_int(&tmf_hdr->lun);
11928c2ecf20Sopenharmony_ci		}
11938c2ecf20Sopenharmony_ci	}
11948c2ecf20Sopenharmony_ci
11958c2ecf20Sopenharmony_ci	qedi_conn->cmd_cleanup_req = 0;
11968c2ecf20Sopenharmony_ci	qedi_conn->cmd_cleanup_cmpl = 0;
11978c2ecf20Sopenharmony_ci
11988c2ecf20Sopenharmony_ci	QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_SCSI_TM,
11998c2ecf20Sopenharmony_ci		  "active_cmd_count=%d, cid=0x%x, in_recovery=%d, lun_reset=%d\n",
12008c2ecf20Sopenharmony_ci		  qedi_conn->active_cmd_count, qedi_conn->iscsi_conn_id,
12018c2ecf20Sopenharmony_ci		  in_recovery, lun_reset);
12028c2ecf20Sopenharmony_ci
12038c2ecf20Sopenharmony_ci	if (lun_reset)
12048c2ecf20Sopenharmony_ci		spin_lock_bh(&session->back_lock);
12058c2ecf20Sopenharmony_ci
12068c2ecf20Sopenharmony_ci	spin_lock(&qedi_conn->list_lock);
12078c2ecf20Sopenharmony_ci
12088c2ecf20Sopenharmony_ci	list_for_each_entry_safe(cmd, cmd_tmp, &qedi_conn->active_cmd_list,
12098c2ecf20Sopenharmony_ci				 io_cmd) {
12108c2ecf20Sopenharmony_ci		ctask = cmd->task;
12118c2ecf20Sopenharmony_ci		if (ctask == task)
12128c2ecf20Sopenharmony_ci			continue;
12138c2ecf20Sopenharmony_ci
12148c2ecf20Sopenharmony_ci		if (lun_reset) {
12158c2ecf20Sopenharmony_ci			if (cmd->scsi_cmd && cmd->scsi_cmd->device) {
12168c2ecf20Sopenharmony_ci				QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_SCSI_TM,
12178c2ecf20Sopenharmony_ci					  "tid=0x%x itt=0x%x scsi_cmd_ptr=%p device=%p task_state=%d cmd_state=0%x cid=0x%x\n",
12188c2ecf20Sopenharmony_ci					  cmd->task_id, get_itt(ctask->itt),
12198c2ecf20Sopenharmony_ci					  cmd->scsi_cmd, cmd->scsi_cmd->device,
12208c2ecf20Sopenharmony_ci					  ctask->state, cmd->state,
12218c2ecf20Sopenharmony_ci					  qedi_conn->iscsi_conn_id);
12228c2ecf20Sopenharmony_ci				if (cmd->scsi_cmd->device->lun != lun)
12238c2ecf20Sopenharmony_ci					continue;
12248c2ecf20Sopenharmony_ci			}
12258c2ecf20Sopenharmony_ci		}
12268c2ecf20Sopenharmony_ci		qedi_conn->cmd_cleanup_req++;
12278c2ecf20Sopenharmony_ci		qedi_iscsi_cleanup_task(ctask, true);
12288c2ecf20Sopenharmony_ci
12298c2ecf20Sopenharmony_ci		cmd->io_cmd_in_list = false;
12308c2ecf20Sopenharmony_ci		list_del_init(&cmd->io_cmd);
12318c2ecf20Sopenharmony_ci		qedi_conn->active_cmd_count--;
12328c2ecf20Sopenharmony_ci		QEDI_WARN(&qedi->dbg_ctx,
12338c2ecf20Sopenharmony_ci			  "Deleted active cmd list node io_cmd=%p, cid=0x%x\n",
12348c2ecf20Sopenharmony_ci			  &cmd->io_cmd, qedi_conn->iscsi_conn_id);
12358c2ecf20Sopenharmony_ci	}
12368c2ecf20Sopenharmony_ci
12378c2ecf20Sopenharmony_ci	spin_unlock(&qedi_conn->list_lock);
12388c2ecf20Sopenharmony_ci
12398c2ecf20Sopenharmony_ci	if (lun_reset)
12408c2ecf20Sopenharmony_ci		spin_unlock_bh(&session->back_lock);
12418c2ecf20Sopenharmony_ci
12428c2ecf20Sopenharmony_ci	QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_SCSI_TM,
12438c2ecf20Sopenharmony_ci		  "cmd_cleanup_req=%d, cid=0x%x\n",
12448c2ecf20Sopenharmony_ci		  qedi_conn->cmd_cleanup_req,
12458c2ecf20Sopenharmony_ci		  qedi_conn->iscsi_conn_id);
12468c2ecf20Sopenharmony_ci
12478c2ecf20Sopenharmony_ci	rval  = wait_event_interruptible_timeout(qedi_conn->wait_queue,
12488c2ecf20Sopenharmony_ci						 ((qedi_conn->cmd_cleanup_req ==
12498c2ecf20Sopenharmony_ci						 qedi_conn->cmd_cleanup_cmpl) ||
12508c2ecf20Sopenharmony_ci						 test_bit(QEDI_IN_RECOVERY,
12518c2ecf20Sopenharmony_ci							  &qedi->flags)),
12528c2ecf20Sopenharmony_ci						 5 * HZ);
12538c2ecf20Sopenharmony_ci	if (rval) {
12548c2ecf20Sopenharmony_ci		QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_SCSI_TM,
12558c2ecf20Sopenharmony_ci			  "i/o cmd_cleanup_req=%d, equal to cmd_cleanup_cmpl=%d, cid=0x%x\n",
12568c2ecf20Sopenharmony_ci			  qedi_conn->cmd_cleanup_req,
12578c2ecf20Sopenharmony_ci			  qedi_conn->cmd_cleanup_cmpl,
12588c2ecf20Sopenharmony_ci			  qedi_conn->iscsi_conn_id);
12598c2ecf20Sopenharmony_ci
12608c2ecf20Sopenharmony_ci		return 0;
12618c2ecf20Sopenharmony_ci	}
12628c2ecf20Sopenharmony_ci
12638c2ecf20Sopenharmony_ci	QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_SCSI_TM,
12648c2ecf20Sopenharmony_ci		  "i/o cmd_cleanup_req=%d, not equal to cmd_cleanup_cmpl=%d, cid=0x%x\n",
12658c2ecf20Sopenharmony_ci		  qedi_conn->cmd_cleanup_req,
12668c2ecf20Sopenharmony_ci		  qedi_conn->cmd_cleanup_cmpl,
12678c2ecf20Sopenharmony_ci		  qedi_conn->iscsi_conn_id);
12688c2ecf20Sopenharmony_ci
12698c2ecf20Sopenharmony_ci	iscsi_host_for_each_session(qedi->shost,
12708c2ecf20Sopenharmony_ci				    qedi_mark_device_missing);
12718c2ecf20Sopenharmony_ci	qedi_ops->common->drain(qedi->cdev);
12728c2ecf20Sopenharmony_ci
12738c2ecf20Sopenharmony_ci	/* Enable IOs for all other sessions except current.*/
12748c2ecf20Sopenharmony_ci	if (!wait_event_interruptible_timeout(qedi_conn->wait_queue,
12758c2ecf20Sopenharmony_ci					      (qedi_conn->cmd_cleanup_req ==
12768c2ecf20Sopenharmony_ci					       qedi_conn->cmd_cleanup_cmpl) ||
12778c2ecf20Sopenharmony_ci					       test_bit(QEDI_IN_RECOVERY,
12788c2ecf20Sopenharmony_ci							&qedi->flags),
12798c2ecf20Sopenharmony_ci					      5 * HZ)) {
12808c2ecf20Sopenharmony_ci		iscsi_host_for_each_session(qedi->shost,
12818c2ecf20Sopenharmony_ci					    qedi_mark_device_available);
12828c2ecf20Sopenharmony_ci		return -1;
12838c2ecf20Sopenharmony_ci	}
12848c2ecf20Sopenharmony_ci
12858c2ecf20Sopenharmony_ci	iscsi_host_for_each_session(qedi->shost,
12868c2ecf20Sopenharmony_ci				    qedi_mark_device_available);
12878c2ecf20Sopenharmony_ci
12888c2ecf20Sopenharmony_ci	return 0;
12898c2ecf20Sopenharmony_ci}
12908c2ecf20Sopenharmony_ci
12918c2ecf20Sopenharmony_civoid qedi_clearsq(struct qedi_ctx *qedi, struct qedi_conn *qedi_conn,
12928c2ecf20Sopenharmony_ci		  struct iscsi_task *task)
12938c2ecf20Sopenharmony_ci{
12948c2ecf20Sopenharmony_ci	struct qedi_endpoint *qedi_ep;
12958c2ecf20Sopenharmony_ci	int rval;
12968c2ecf20Sopenharmony_ci
12978c2ecf20Sopenharmony_ci	qedi_ep = qedi_conn->ep;
12988c2ecf20Sopenharmony_ci	qedi_conn->cmd_cleanup_req = 0;
12998c2ecf20Sopenharmony_ci	qedi_conn->cmd_cleanup_cmpl = 0;
13008c2ecf20Sopenharmony_ci
13018c2ecf20Sopenharmony_ci	if (!qedi_ep) {
13028c2ecf20Sopenharmony_ci		QEDI_WARN(&qedi->dbg_ctx,
13038c2ecf20Sopenharmony_ci			  "Cannot proceed, ep already disconnected, cid=0x%x\n",
13048c2ecf20Sopenharmony_ci			  qedi_conn->iscsi_conn_id);
13058c2ecf20Sopenharmony_ci		return;
13068c2ecf20Sopenharmony_ci	}
13078c2ecf20Sopenharmony_ci
13088c2ecf20Sopenharmony_ci	QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO,
13098c2ecf20Sopenharmony_ci		  "Clearing SQ for cid=0x%x, conn=%p, ep=%p\n",
13108c2ecf20Sopenharmony_ci		  qedi_conn->iscsi_conn_id, qedi_conn, qedi_ep);
13118c2ecf20Sopenharmony_ci
13128c2ecf20Sopenharmony_ci	qedi_ops->clear_sq(qedi->cdev, qedi_ep->handle);
13138c2ecf20Sopenharmony_ci
13148c2ecf20Sopenharmony_ci	rval = qedi_cleanup_all_io(qedi, qedi_conn, task, true);
13158c2ecf20Sopenharmony_ci	if (rval) {
13168c2ecf20Sopenharmony_ci		QEDI_ERR(&qedi->dbg_ctx,
13178c2ecf20Sopenharmony_ci			 "fatal error, need hard reset, cid=0x%x\n",
13188c2ecf20Sopenharmony_ci			 qedi_conn->iscsi_conn_id);
13198c2ecf20Sopenharmony_ci		WARN_ON(1);
13208c2ecf20Sopenharmony_ci	}
13218c2ecf20Sopenharmony_ci}
13228c2ecf20Sopenharmony_ci
13238c2ecf20Sopenharmony_cistatic int qedi_wait_for_cleanup_request(struct qedi_ctx *qedi,
13248c2ecf20Sopenharmony_ci					 struct qedi_conn *qedi_conn,
13258c2ecf20Sopenharmony_ci					 struct iscsi_task *task,
13268c2ecf20Sopenharmony_ci					 struct qedi_cmd *qedi_cmd,
13278c2ecf20Sopenharmony_ci					 struct qedi_work_map *list_work)
13288c2ecf20Sopenharmony_ci{
13298c2ecf20Sopenharmony_ci	struct qedi_cmd *cmd = (struct qedi_cmd *)task->dd_data;
13308c2ecf20Sopenharmony_ci	int wait;
13318c2ecf20Sopenharmony_ci
13328c2ecf20Sopenharmony_ci	wait  = wait_event_interruptible_timeout(qedi_conn->wait_queue,
13338c2ecf20Sopenharmony_ci						 ((qedi_cmd->state ==
13348c2ecf20Sopenharmony_ci						   CLEANUP_RECV) ||
13358c2ecf20Sopenharmony_ci						 ((qedi_cmd->type == TYPEIO) &&
13368c2ecf20Sopenharmony_ci						  (cmd->state ==
13378c2ecf20Sopenharmony_ci						   RESPONSE_RECEIVED))),
13388c2ecf20Sopenharmony_ci						 5 * HZ);
13398c2ecf20Sopenharmony_ci	if (!wait) {
13408c2ecf20Sopenharmony_ci		qedi_cmd->state = CLEANUP_WAIT_FAILED;
13418c2ecf20Sopenharmony_ci
13428c2ecf20Sopenharmony_ci		QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_SCSI_TM,
13438c2ecf20Sopenharmony_ci			  "Cleanup timedout tid=0x%x, issue connection recovery, cid=0x%x\n",
13448c2ecf20Sopenharmony_ci			  cmd->task_id, qedi_conn->iscsi_conn_id);
13458c2ecf20Sopenharmony_ci
13468c2ecf20Sopenharmony_ci		return -1;
13478c2ecf20Sopenharmony_ci	}
13488c2ecf20Sopenharmony_ci	return 0;
13498c2ecf20Sopenharmony_ci}
13508c2ecf20Sopenharmony_ci
13518c2ecf20Sopenharmony_cistatic void qedi_tmf_work(struct work_struct *work)
13528c2ecf20Sopenharmony_ci{
13538c2ecf20Sopenharmony_ci	struct qedi_cmd *qedi_cmd =
13548c2ecf20Sopenharmony_ci		container_of(work, struct qedi_cmd, tmf_work);
13558c2ecf20Sopenharmony_ci	struct qedi_conn *qedi_conn = qedi_cmd->conn;
13568c2ecf20Sopenharmony_ci	struct qedi_ctx *qedi = qedi_conn->qedi;
13578c2ecf20Sopenharmony_ci	struct iscsi_conn *conn = qedi_conn->cls_conn->dd_data;
13588c2ecf20Sopenharmony_ci	struct qedi_work_map *list_work = NULL;
13598c2ecf20Sopenharmony_ci	struct iscsi_task *mtask;
13608c2ecf20Sopenharmony_ci	struct qedi_cmd *cmd;
13618c2ecf20Sopenharmony_ci	struct iscsi_task *ctask;
13628c2ecf20Sopenharmony_ci	struct iscsi_tm *tmf_hdr;
13638c2ecf20Sopenharmony_ci	s16 rval = 0;
13648c2ecf20Sopenharmony_ci	s16 tid = 0;
13658c2ecf20Sopenharmony_ci
13668c2ecf20Sopenharmony_ci	mtask = qedi_cmd->task;
13678c2ecf20Sopenharmony_ci	tmf_hdr = (struct iscsi_tm *)mtask->hdr;
13688c2ecf20Sopenharmony_ci	set_bit(QEDI_CONN_FW_CLEANUP, &qedi_conn->flags);
13698c2ecf20Sopenharmony_ci
13708c2ecf20Sopenharmony_ci	ctask = iscsi_itt_to_task(conn, tmf_hdr->rtt);
13718c2ecf20Sopenharmony_ci	if (!ctask || !ctask->sc) {
13728c2ecf20Sopenharmony_ci		QEDI_ERR(&qedi->dbg_ctx, "Task already completed\n");
13738c2ecf20Sopenharmony_ci		goto abort_ret;
13748c2ecf20Sopenharmony_ci	}
13758c2ecf20Sopenharmony_ci
13768c2ecf20Sopenharmony_ci	cmd = (struct qedi_cmd *)ctask->dd_data;
13778c2ecf20Sopenharmony_ci	QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO,
13788c2ecf20Sopenharmony_ci		  "Abort tmf rtt=0x%x, cmd itt=0x%x, cmd tid=0x%x, cid=0x%x\n",
13798c2ecf20Sopenharmony_ci		  get_itt(tmf_hdr->rtt), get_itt(ctask->itt), cmd->task_id,
13808c2ecf20Sopenharmony_ci		  qedi_conn->iscsi_conn_id);
13818c2ecf20Sopenharmony_ci
13828c2ecf20Sopenharmony_ci	if (qedi_do_not_recover) {
13838c2ecf20Sopenharmony_ci		QEDI_ERR(&qedi->dbg_ctx, "DONT SEND CLEANUP/ABORT %d\n",
13848c2ecf20Sopenharmony_ci			 qedi_do_not_recover);
13858c2ecf20Sopenharmony_ci		goto abort_ret;
13868c2ecf20Sopenharmony_ci	}
13878c2ecf20Sopenharmony_ci
13888c2ecf20Sopenharmony_ci	list_work = kzalloc(sizeof(*list_work), GFP_ATOMIC);
13898c2ecf20Sopenharmony_ci	if (!list_work) {
13908c2ecf20Sopenharmony_ci		QEDI_ERR(&qedi->dbg_ctx, "Memory allocation failed\n");
13918c2ecf20Sopenharmony_ci		goto abort_ret;
13928c2ecf20Sopenharmony_ci	}
13938c2ecf20Sopenharmony_ci
13948c2ecf20Sopenharmony_ci	qedi_cmd->type = TYPEIO;
13958c2ecf20Sopenharmony_ci	list_work->qedi_cmd = qedi_cmd;
13968c2ecf20Sopenharmony_ci	list_work->rtid = cmd->task_id;
13978c2ecf20Sopenharmony_ci	list_work->state = QEDI_WORK_SCHEDULED;
13988c2ecf20Sopenharmony_ci	qedi_cmd->list_tmf_work = list_work;
13998c2ecf20Sopenharmony_ci
14008c2ecf20Sopenharmony_ci	QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_SCSI_TM,
14018c2ecf20Sopenharmony_ci		  "Queue tmf work=%p, list node=%p, cid=0x%x, tmf flags=0x%x\n",
14028c2ecf20Sopenharmony_ci		  list_work->ptr_tmf_work, list_work, qedi_conn->iscsi_conn_id,
14038c2ecf20Sopenharmony_ci		  tmf_hdr->flags);
14048c2ecf20Sopenharmony_ci
14058c2ecf20Sopenharmony_ci	spin_lock_bh(&qedi_conn->tmf_work_lock);
14068c2ecf20Sopenharmony_ci	list_add_tail(&list_work->list, &qedi_conn->tmf_work_list);
14078c2ecf20Sopenharmony_ci	spin_unlock_bh(&qedi_conn->tmf_work_lock);
14088c2ecf20Sopenharmony_ci
14098c2ecf20Sopenharmony_ci	qedi_iscsi_cleanup_task(ctask, false);
14108c2ecf20Sopenharmony_ci
14118c2ecf20Sopenharmony_ci	rval = qedi_wait_for_cleanup_request(qedi, qedi_conn, ctask, qedi_cmd,
14128c2ecf20Sopenharmony_ci					     list_work);
14138c2ecf20Sopenharmony_ci	if (rval == -1) {
14148c2ecf20Sopenharmony_ci		QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO,
14158c2ecf20Sopenharmony_ci			  "FW cleanup got escalated, cid=0x%x\n",
14168c2ecf20Sopenharmony_ci			  qedi_conn->iscsi_conn_id);
14178c2ecf20Sopenharmony_ci		goto ldel_exit;
14188c2ecf20Sopenharmony_ci	}
14198c2ecf20Sopenharmony_ci
14208c2ecf20Sopenharmony_ci	tid = qedi_get_task_idx(qedi);
14218c2ecf20Sopenharmony_ci	if (tid == -1) {
14228c2ecf20Sopenharmony_ci		QEDI_ERR(&qedi->dbg_ctx, "Invalid tid, cid=0x%x\n",
14238c2ecf20Sopenharmony_ci			 qedi_conn->iscsi_conn_id);
14248c2ecf20Sopenharmony_ci		goto ldel_exit;
14258c2ecf20Sopenharmony_ci	}
14268c2ecf20Sopenharmony_ci
14278c2ecf20Sopenharmony_ci	qedi_cmd->task_id = tid;
14288c2ecf20Sopenharmony_ci	qedi_send_iscsi_tmf(qedi_conn, qedi_cmd->task);
14298c2ecf20Sopenharmony_ci
14308c2ecf20Sopenharmony_ciabort_ret:
14318c2ecf20Sopenharmony_ci	clear_bit(QEDI_CONN_FW_CLEANUP, &qedi_conn->flags);
14328c2ecf20Sopenharmony_ci	return;
14338c2ecf20Sopenharmony_ci
14348c2ecf20Sopenharmony_cildel_exit:
14358c2ecf20Sopenharmony_ci	spin_lock_bh(&qedi_conn->tmf_work_lock);
14368c2ecf20Sopenharmony_ci	if (qedi_cmd->list_tmf_work) {
14378c2ecf20Sopenharmony_ci		list_del_init(&list_work->list);
14388c2ecf20Sopenharmony_ci		qedi_cmd->list_tmf_work = NULL;
14398c2ecf20Sopenharmony_ci		kfree(list_work);
14408c2ecf20Sopenharmony_ci	}
14418c2ecf20Sopenharmony_ci	spin_unlock_bh(&qedi_conn->tmf_work_lock);
14428c2ecf20Sopenharmony_ci
14438c2ecf20Sopenharmony_ci	spin_lock(&qedi_conn->list_lock);
14448c2ecf20Sopenharmony_ci	if (likely(cmd->io_cmd_in_list)) {
14458c2ecf20Sopenharmony_ci		cmd->io_cmd_in_list = false;
14468c2ecf20Sopenharmony_ci		list_del_init(&cmd->io_cmd);
14478c2ecf20Sopenharmony_ci		qedi_conn->active_cmd_count--;
14488c2ecf20Sopenharmony_ci	}
14498c2ecf20Sopenharmony_ci	spin_unlock(&qedi_conn->list_lock);
14508c2ecf20Sopenharmony_ci
14518c2ecf20Sopenharmony_ci	clear_bit(QEDI_CONN_FW_CLEANUP, &qedi_conn->flags);
14528c2ecf20Sopenharmony_ci}
14538c2ecf20Sopenharmony_ci
14548c2ecf20Sopenharmony_cistatic int qedi_send_iscsi_tmf(struct qedi_conn *qedi_conn,
14558c2ecf20Sopenharmony_ci			       struct iscsi_task *mtask)
14568c2ecf20Sopenharmony_ci{
14578c2ecf20Sopenharmony_ci	struct iscsi_tmf_request_hdr tmf_pdu_header;
14588c2ecf20Sopenharmony_ci	struct iscsi_task_params task_params;
14598c2ecf20Sopenharmony_ci	struct qedi_ctx *qedi = qedi_conn->qedi;
14608c2ecf20Sopenharmony_ci	struct e4_iscsi_task_context *fw_task_ctx;
14618c2ecf20Sopenharmony_ci	struct iscsi_conn *conn = qedi_conn->cls_conn->dd_data;
14628c2ecf20Sopenharmony_ci	struct iscsi_task *ctask;
14638c2ecf20Sopenharmony_ci	struct iscsi_tm *tmf_hdr;
14648c2ecf20Sopenharmony_ci	struct qedi_cmd *qedi_cmd;
14658c2ecf20Sopenharmony_ci	struct qedi_cmd *cmd;
14668c2ecf20Sopenharmony_ci	struct qedi_endpoint *ep;
14678c2ecf20Sopenharmony_ci	u32 scsi_lun[2];
14688c2ecf20Sopenharmony_ci	s16 tid = 0;
14698c2ecf20Sopenharmony_ci	u16 sq_idx = 0;
14708c2ecf20Sopenharmony_ci	int rval = 0;
14718c2ecf20Sopenharmony_ci
14728c2ecf20Sopenharmony_ci	tmf_hdr = (struct iscsi_tm *)mtask->hdr;
14738c2ecf20Sopenharmony_ci	qedi_cmd = (struct qedi_cmd *)mtask->dd_data;
14748c2ecf20Sopenharmony_ci	ep = qedi_conn->ep;
14758c2ecf20Sopenharmony_ci	if (!ep)
14768c2ecf20Sopenharmony_ci		return -ENODEV;
14778c2ecf20Sopenharmony_ci
14788c2ecf20Sopenharmony_ci	tid = qedi_get_task_idx(qedi);
14798c2ecf20Sopenharmony_ci	if (tid == -1)
14808c2ecf20Sopenharmony_ci		return -ENOMEM;
14818c2ecf20Sopenharmony_ci
14828c2ecf20Sopenharmony_ci	fw_task_ctx =
14838c2ecf20Sopenharmony_ci	     (struct e4_iscsi_task_context *)qedi_get_task_mem(&qedi->tasks,
14848c2ecf20Sopenharmony_ci							       tid);
14858c2ecf20Sopenharmony_ci	memset(fw_task_ctx, 0, sizeof(struct e4_iscsi_task_context));
14868c2ecf20Sopenharmony_ci
14878c2ecf20Sopenharmony_ci	qedi_cmd->task_id = tid;
14888c2ecf20Sopenharmony_ci
14898c2ecf20Sopenharmony_ci	memset(&task_params, 0, sizeof(task_params));
14908c2ecf20Sopenharmony_ci	memset(&tmf_pdu_header, 0, sizeof(tmf_pdu_header));
14918c2ecf20Sopenharmony_ci
14928c2ecf20Sopenharmony_ci	/* Update header info */
14938c2ecf20Sopenharmony_ci	qedi_update_itt_map(qedi, tid, mtask->itt, qedi_cmd);
14948c2ecf20Sopenharmony_ci	tmf_pdu_header.itt = qedi_set_itt(tid, get_itt(mtask->itt));
14958c2ecf20Sopenharmony_ci	tmf_pdu_header.cmd_sn = be32_to_cpu(tmf_hdr->cmdsn);
14968c2ecf20Sopenharmony_ci
14978c2ecf20Sopenharmony_ci	memcpy(scsi_lun, &tmf_hdr->lun, sizeof(struct scsi_lun));
14988c2ecf20Sopenharmony_ci	tmf_pdu_header.lun.lo = be32_to_cpu(scsi_lun[0]);
14998c2ecf20Sopenharmony_ci	tmf_pdu_header.lun.hi = be32_to_cpu(scsi_lun[1]);
15008c2ecf20Sopenharmony_ci
15018c2ecf20Sopenharmony_ci	if ((tmf_hdr->flags & ISCSI_FLAG_TM_FUNC_MASK) ==
15028c2ecf20Sopenharmony_ci	     ISCSI_TM_FUNC_ABORT_TASK) {
15038c2ecf20Sopenharmony_ci		ctask = iscsi_itt_to_task(conn, tmf_hdr->rtt);
15048c2ecf20Sopenharmony_ci		if (!ctask || !ctask->sc) {
15058c2ecf20Sopenharmony_ci			QEDI_ERR(&qedi->dbg_ctx,
15068c2ecf20Sopenharmony_ci				 "Could not get reference task\n");
15078c2ecf20Sopenharmony_ci			return 0;
15088c2ecf20Sopenharmony_ci		}
15098c2ecf20Sopenharmony_ci		cmd = (struct qedi_cmd *)ctask->dd_data;
15108c2ecf20Sopenharmony_ci		tmf_pdu_header.rtt =
15118c2ecf20Sopenharmony_ci				qedi_set_itt(cmd->task_id,
15128c2ecf20Sopenharmony_ci					     get_itt(tmf_hdr->rtt));
15138c2ecf20Sopenharmony_ci	} else {
15148c2ecf20Sopenharmony_ci		tmf_pdu_header.rtt = ISCSI_RESERVED_TAG;
15158c2ecf20Sopenharmony_ci	}
15168c2ecf20Sopenharmony_ci
15178c2ecf20Sopenharmony_ci	tmf_pdu_header.opcode = tmf_hdr->opcode;
15188c2ecf20Sopenharmony_ci	tmf_pdu_header.function = tmf_hdr->flags;
15198c2ecf20Sopenharmony_ci	tmf_pdu_header.hdr_second_dword = ntoh24(tmf_hdr->dlength);
15208c2ecf20Sopenharmony_ci	tmf_pdu_header.ref_cmd_sn = be32_to_cpu(tmf_hdr->refcmdsn);
15218c2ecf20Sopenharmony_ci
15228c2ecf20Sopenharmony_ci	/* Fill fw input params */
15238c2ecf20Sopenharmony_ci	task_params.context = fw_task_ctx;
15248c2ecf20Sopenharmony_ci	task_params.conn_icid = (u16)qedi_conn->iscsi_conn_id;
15258c2ecf20Sopenharmony_ci	task_params.itid = tid;
15268c2ecf20Sopenharmony_ci	task_params.cq_rss_number = 0;
15278c2ecf20Sopenharmony_ci	task_params.tx_io_size = 0;
15288c2ecf20Sopenharmony_ci	task_params.rx_io_size = 0;
15298c2ecf20Sopenharmony_ci
15308c2ecf20Sopenharmony_ci	sq_idx = qedi_get_wqe_idx(qedi_conn);
15318c2ecf20Sopenharmony_ci	task_params.sqe = &ep->sq[sq_idx];
15328c2ecf20Sopenharmony_ci
15338c2ecf20Sopenharmony_ci	memset(task_params.sqe, 0, sizeof(struct iscsi_wqe));
15348c2ecf20Sopenharmony_ci	rval = init_initiator_tmf_request_task(&task_params,
15358c2ecf20Sopenharmony_ci					       &tmf_pdu_header);
15368c2ecf20Sopenharmony_ci	if (rval)
15378c2ecf20Sopenharmony_ci		return -1;
15388c2ecf20Sopenharmony_ci
15398c2ecf20Sopenharmony_ci	spin_lock(&qedi_conn->list_lock);
15408c2ecf20Sopenharmony_ci	list_add_tail(&qedi_cmd->io_cmd, &qedi_conn->active_cmd_list);
15418c2ecf20Sopenharmony_ci	qedi_cmd->io_cmd_in_list = true;
15428c2ecf20Sopenharmony_ci	qedi_conn->active_cmd_count++;
15438c2ecf20Sopenharmony_ci	spin_unlock(&qedi_conn->list_lock);
15448c2ecf20Sopenharmony_ci
15458c2ecf20Sopenharmony_ci	qedi_ring_doorbell(qedi_conn);
15468c2ecf20Sopenharmony_ci	return 0;
15478c2ecf20Sopenharmony_ci}
15488c2ecf20Sopenharmony_ci
15498c2ecf20Sopenharmony_ciint qedi_iscsi_abort_work(struct qedi_conn *qedi_conn,
15508c2ecf20Sopenharmony_ci			  struct iscsi_task *mtask)
15518c2ecf20Sopenharmony_ci{
15528c2ecf20Sopenharmony_ci	struct qedi_ctx *qedi = qedi_conn->qedi;
15538c2ecf20Sopenharmony_ci	struct iscsi_tm *tmf_hdr;
15548c2ecf20Sopenharmony_ci	struct qedi_cmd *qedi_cmd = (struct qedi_cmd *)mtask->dd_data;
15558c2ecf20Sopenharmony_ci	s16 tid = 0;
15568c2ecf20Sopenharmony_ci
15578c2ecf20Sopenharmony_ci	tmf_hdr = (struct iscsi_tm *)mtask->hdr;
15588c2ecf20Sopenharmony_ci	qedi_cmd->task = mtask;
15598c2ecf20Sopenharmony_ci
15608c2ecf20Sopenharmony_ci	/* If abort task then schedule the work and return */
15618c2ecf20Sopenharmony_ci	if ((tmf_hdr->flags & ISCSI_FLAG_TM_FUNC_MASK) ==
15628c2ecf20Sopenharmony_ci	    ISCSI_TM_FUNC_ABORT_TASK) {
15638c2ecf20Sopenharmony_ci		qedi_cmd->state = CLEANUP_WAIT;
15648c2ecf20Sopenharmony_ci		INIT_WORK(&qedi_cmd->tmf_work, qedi_tmf_work);
15658c2ecf20Sopenharmony_ci		queue_work(qedi->tmf_thread, &qedi_cmd->tmf_work);
15668c2ecf20Sopenharmony_ci
15678c2ecf20Sopenharmony_ci	} else if (((tmf_hdr->flags & ISCSI_FLAG_TM_FUNC_MASK) ==
15688c2ecf20Sopenharmony_ci		    ISCSI_TM_FUNC_LOGICAL_UNIT_RESET) ||
15698c2ecf20Sopenharmony_ci		   ((tmf_hdr->flags & ISCSI_FLAG_TM_FUNC_MASK) ==
15708c2ecf20Sopenharmony_ci		    ISCSI_TM_FUNC_TARGET_WARM_RESET) ||
15718c2ecf20Sopenharmony_ci		   ((tmf_hdr->flags & ISCSI_FLAG_TM_FUNC_MASK) ==
15728c2ecf20Sopenharmony_ci		    ISCSI_TM_FUNC_TARGET_COLD_RESET)) {
15738c2ecf20Sopenharmony_ci		tid = qedi_get_task_idx(qedi);
15748c2ecf20Sopenharmony_ci		if (tid == -1) {
15758c2ecf20Sopenharmony_ci			QEDI_ERR(&qedi->dbg_ctx, "Invalid tid, cid=0x%x\n",
15768c2ecf20Sopenharmony_ci				 qedi_conn->iscsi_conn_id);
15778c2ecf20Sopenharmony_ci			return -1;
15788c2ecf20Sopenharmony_ci		}
15798c2ecf20Sopenharmony_ci		qedi_cmd->task_id = tid;
15808c2ecf20Sopenharmony_ci
15818c2ecf20Sopenharmony_ci		qedi_send_iscsi_tmf(qedi_conn, qedi_cmd->task);
15828c2ecf20Sopenharmony_ci
15838c2ecf20Sopenharmony_ci	} else {
15848c2ecf20Sopenharmony_ci		QEDI_ERR(&qedi->dbg_ctx, "Invalid tmf, cid=0x%x\n",
15858c2ecf20Sopenharmony_ci			 qedi_conn->iscsi_conn_id);
15868c2ecf20Sopenharmony_ci		return -1;
15878c2ecf20Sopenharmony_ci	}
15888c2ecf20Sopenharmony_ci
15898c2ecf20Sopenharmony_ci	return 0;
15908c2ecf20Sopenharmony_ci}
15918c2ecf20Sopenharmony_ci
15928c2ecf20Sopenharmony_ciint qedi_send_iscsi_text(struct qedi_conn *qedi_conn,
15938c2ecf20Sopenharmony_ci			 struct iscsi_task *task)
15948c2ecf20Sopenharmony_ci{
15958c2ecf20Sopenharmony_ci	struct iscsi_text_request_hdr text_request_pdu_header;
15968c2ecf20Sopenharmony_ci	struct scsi_sgl_task_params tx_sgl_task_params;
15978c2ecf20Sopenharmony_ci	struct scsi_sgl_task_params rx_sgl_task_params;
15988c2ecf20Sopenharmony_ci	struct iscsi_task_params task_params;
15998c2ecf20Sopenharmony_ci	struct e4_iscsi_task_context *fw_task_ctx;
16008c2ecf20Sopenharmony_ci	struct qedi_ctx *qedi = qedi_conn->qedi;
16018c2ecf20Sopenharmony_ci	struct iscsi_text *text_hdr;
16028c2ecf20Sopenharmony_ci	struct scsi_sge *req_sge = NULL;
16038c2ecf20Sopenharmony_ci	struct scsi_sge *resp_sge = NULL;
16048c2ecf20Sopenharmony_ci	struct qedi_cmd *qedi_cmd;
16058c2ecf20Sopenharmony_ci	struct qedi_endpoint *ep;
16068c2ecf20Sopenharmony_ci	s16 tid = 0;
16078c2ecf20Sopenharmony_ci	u16 sq_idx = 0;
16088c2ecf20Sopenharmony_ci	int rval = 0;
16098c2ecf20Sopenharmony_ci
16108c2ecf20Sopenharmony_ci	req_sge = (struct scsi_sge *)qedi_conn->gen_pdu.req_bd_tbl;
16118c2ecf20Sopenharmony_ci	resp_sge = (struct scsi_sge *)qedi_conn->gen_pdu.resp_bd_tbl;
16128c2ecf20Sopenharmony_ci	qedi_cmd = (struct qedi_cmd *)task->dd_data;
16138c2ecf20Sopenharmony_ci	text_hdr = (struct iscsi_text *)task->hdr;
16148c2ecf20Sopenharmony_ci	ep = qedi_conn->ep;
16158c2ecf20Sopenharmony_ci
16168c2ecf20Sopenharmony_ci	tid = qedi_get_task_idx(qedi);
16178c2ecf20Sopenharmony_ci	if (tid == -1)
16188c2ecf20Sopenharmony_ci		return -ENOMEM;
16198c2ecf20Sopenharmony_ci
16208c2ecf20Sopenharmony_ci	fw_task_ctx =
16218c2ecf20Sopenharmony_ci	     (struct e4_iscsi_task_context *)qedi_get_task_mem(&qedi->tasks,
16228c2ecf20Sopenharmony_ci							       tid);
16238c2ecf20Sopenharmony_ci	memset(fw_task_ctx, 0, sizeof(struct e4_iscsi_task_context));
16248c2ecf20Sopenharmony_ci
16258c2ecf20Sopenharmony_ci	qedi_cmd->task_id = tid;
16268c2ecf20Sopenharmony_ci
16278c2ecf20Sopenharmony_ci	memset(&task_params, 0, sizeof(task_params));
16288c2ecf20Sopenharmony_ci	memset(&text_request_pdu_header, 0, sizeof(text_request_pdu_header));
16298c2ecf20Sopenharmony_ci	memset(&tx_sgl_task_params, 0, sizeof(tx_sgl_task_params));
16308c2ecf20Sopenharmony_ci	memset(&rx_sgl_task_params, 0, sizeof(rx_sgl_task_params));
16318c2ecf20Sopenharmony_ci
16328c2ecf20Sopenharmony_ci	/* Update header info */
16338c2ecf20Sopenharmony_ci	text_request_pdu_header.opcode = text_hdr->opcode;
16348c2ecf20Sopenharmony_ci	text_request_pdu_header.flags_attr = text_hdr->flags;
16358c2ecf20Sopenharmony_ci
16368c2ecf20Sopenharmony_ci	qedi_update_itt_map(qedi, tid, task->itt, qedi_cmd);
16378c2ecf20Sopenharmony_ci	text_request_pdu_header.itt = qedi_set_itt(tid, get_itt(task->itt));
16388c2ecf20Sopenharmony_ci	text_request_pdu_header.ttt = text_hdr->ttt;
16398c2ecf20Sopenharmony_ci	text_request_pdu_header.cmd_sn = be32_to_cpu(text_hdr->cmdsn);
16408c2ecf20Sopenharmony_ci	text_request_pdu_header.exp_stat_sn = be32_to_cpu(text_hdr->exp_statsn);
16418c2ecf20Sopenharmony_ci	text_request_pdu_header.hdr_second_dword = ntoh24(text_hdr->dlength);
16428c2ecf20Sopenharmony_ci
16438c2ecf20Sopenharmony_ci	/* Fill tx AHS and rx buffer */
16448c2ecf20Sopenharmony_ci	tx_sgl_task_params.sgl =
16458c2ecf20Sopenharmony_ci			       (struct scsi_sge *)qedi_conn->gen_pdu.req_bd_tbl;
16468c2ecf20Sopenharmony_ci	tx_sgl_task_params.sgl_phys_addr.lo =
16478c2ecf20Sopenharmony_ci					 (u32)(qedi_conn->gen_pdu.req_dma_addr);
16488c2ecf20Sopenharmony_ci	tx_sgl_task_params.sgl_phys_addr.hi =
16498c2ecf20Sopenharmony_ci			      (u32)((u64)qedi_conn->gen_pdu.req_dma_addr >> 32);
16508c2ecf20Sopenharmony_ci	tx_sgl_task_params.total_buffer_size = req_sge->sge_len;
16518c2ecf20Sopenharmony_ci	tx_sgl_task_params.num_sges = 1;
16528c2ecf20Sopenharmony_ci
16538c2ecf20Sopenharmony_ci	rx_sgl_task_params.sgl =
16548c2ecf20Sopenharmony_ci			      (struct scsi_sge *)qedi_conn->gen_pdu.resp_bd_tbl;
16558c2ecf20Sopenharmony_ci	rx_sgl_task_params.sgl_phys_addr.lo =
16568c2ecf20Sopenharmony_ci					(u32)(qedi_conn->gen_pdu.resp_dma_addr);
16578c2ecf20Sopenharmony_ci	rx_sgl_task_params.sgl_phys_addr.hi =
16588c2ecf20Sopenharmony_ci			     (u32)((u64)qedi_conn->gen_pdu.resp_dma_addr >> 32);
16598c2ecf20Sopenharmony_ci	rx_sgl_task_params.total_buffer_size = resp_sge->sge_len;
16608c2ecf20Sopenharmony_ci	rx_sgl_task_params.num_sges = 1;
16618c2ecf20Sopenharmony_ci
16628c2ecf20Sopenharmony_ci	/* Fill fw input params */
16638c2ecf20Sopenharmony_ci	task_params.context = fw_task_ctx;
16648c2ecf20Sopenharmony_ci	task_params.conn_icid = (u16)qedi_conn->iscsi_conn_id;
16658c2ecf20Sopenharmony_ci	task_params.itid = tid;
16668c2ecf20Sopenharmony_ci	task_params.cq_rss_number = 0;
16678c2ecf20Sopenharmony_ci	task_params.tx_io_size = ntoh24(text_hdr->dlength);
16688c2ecf20Sopenharmony_ci	task_params.rx_io_size = resp_sge->sge_len;
16698c2ecf20Sopenharmony_ci
16708c2ecf20Sopenharmony_ci	sq_idx = qedi_get_wqe_idx(qedi_conn);
16718c2ecf20Sopenharmony_ci	task_params.sqe = &ep->sq[sq_idx];
16728c2ecf20Sopenharmony_ci
16738c2ecf20Sopenharmony_ci	memset(task_params.sqe, 0, sizeof(struct iscsi_wqe));
16748c2ecf20Sopenharmony_ci	rval = init_initiator_text_request_task(&task_params,
16758c2ecf20Sopenharmony_ci						&text_request_pdu_header,
16768c2ecf20Sopenharmony_ci						&tx_sgl_task_params,
16778c2ecf20Sopenharmony_ci						&rx_sgl_task_params);
16788c2ecf20Sopenharmony_ci	if (rval)
16798c2ecf20Sopenharmony_ci		return -1;
16808c2ecf20Sopenharmony_ci
16818c2ecf20Sopenharmony_ci	spin_lock(&qedi_conn->list_lock);
16828c2ecf20Sopenharmony_ci	list_add_tail(&qedi_cmd->io_cmd, &qedi_conn->active_cmd_list);
16838c2ecf20Sopenharmony_ci	qedi_cmd->io_cmd_in_list = true;
16848c2ecf20Sopenharmony_ci	qedi_conn->active_cmd_count++;
16858c2ecf20Sopenharmony_ci	spin_unlock(&qedi_conn->list_lock);
16868c2ecf20Sopenharmony_ci
16878c2ecf20Sopenharmony_ci	qedi_ring_doorbell(qedi_conn);
16888c2ecf20Sopenharmony_ci	return 0;
16898c2ecf20Sopenharmony_ci}
16908c2ecf20Sopenharmony_ci
16918c2ecf20Sopenharmony_ciint qedi_send_iscsi_nopout(struct qedi_conn *qedi_conn,
16928c2ecf20Sopenharmony_ci			   struct iscsi_task *task,
16938c2ecf20Sopenharmony_ci			   char *datap, int data_len, int unsol)
16948c2ecf20Sopenharmony_ci{
16958c2ecf20Sopenharmony_ci	struct iscsi_nop_out_hdr nop_out_pdu_header;
16968c2ecf20Sopenharmony_ci	struct scsi_sgl_task_params tx_sgl_task_params;
16978c2ecf20Sopenharmony_ci	struct scsi_sgl_task_params rx_sgl_task_params;
16988c2ecf20Sopenharmony_ci	struct iscsi_task_params task_params;
16998c2ecf20Sopenharmony_ci	struct qedi_ctx *qedi = qedi_conn->qedi;
17008c2ecf20Sopenharmony_ci	struct e4_iscsi_task_context *fw_task_ctx;
17018c2ecf20Sopenharmony_ci	struct iscsi_nopout *nopout_hdr;
17028c2ecf20Sopenharmony_ci	struct scsi_sge *resp_sge = NULL;
17038c2ecf20Sopenharmony_ci	struct qedi_cmd *qedi_cmd;
17048c2ecf20Sopenharmony_ci	struct qedi_endpoint *ep;
17058c2ecf20Sopenharmony_ci	u32 scsi_lun[2];
17068c2ecf20Sopenharmony_ci	s16 tid = 0;
17078c2ecf20Sopenharmony_ci	u16 sq_idx = 0;
17088c2ecf20Sopenharmony_ci	int rval = 0;
17098c2ecf20Sopenharmony_ci
17108c2ecf20Sopenharmony_ci	resp_sge = (struct scsi_sge *)qedi_conn->gen_pdu.resp_bd_tbl;
17118c2ecf20Sopenharmony_ci	qedi_cmd = (struct qedi_cmd *)task->dd_data;
17128c2ecf20Sopenharmony_ci	nopout_hdr = (struct iscsi_nopout *)task->hdr;
17138c2ecf20Sopenharmony_ci	ep = qedi_conn->ep;
17148c2ecf20Sopenharmony_ci
17158c2ecf20Sopenharmony_ci	tid = qedi_get_task_idx(qedi);
17168c2ecf20Sopenharmony_ci	if (tid == -1)
17178c2ecf20Sopenharmony_ci		return -ENOMEM;
17188c2ecf20Sopenharmony_ci
17198c2ecf20Sopenharmony_ci	fw_task_ctx =
17208c2ecf20Sopenharmony_ci	     (struct e4_iscsi_task_context *)qedi_get_task_mem(&qedi->tasks,
17218c2ecf20Sopenharmony_ci							       tid);
17228c2ecf20Sopenharmony_ci	memset(fw_task_ctx, 0, sizeof(struct e4_iscsi_task_context));
17238c2ecf20Sopenharmony_ci
17248c2ecf20Sopenharmony_ci	qedi_cmd->task_id = tid;
17258c2ecf20Sopenharmony_ci
17268c2ecf20Sopenharmony_ci	memset(&task_params, 0, sizeof(task_params));
17278c2ecf20Sopenharmony_ci	memset(&nop_out_pdu_header, 0, sizeof(nop_out_pdu_header));
17288c2ecf20Sopenharmony_ci	memset(&tx_sgl_task_params, 0, sizeof(tx_sgl_task_params));
17298c2ecf20Sopenharmony_ci	memset(&rx_sgl_task_params, 0, sizeof(rx_sgl_task_params));
17308c2ecf20Sopenharmony_ci
17318c2ecf20Sopenharmony_ci	/* Update header info */
17328c2ecf20Sopenharmony_ci	nop_out_pdu_header.opcode = nopout_hdr->opcode;
17338c2ecf20Sopenharmony_ci	SET_FIELD(nop_out_pdu_header.flags_attr, ISCSI_NOP_OUT_HDR_CONST1, 1);
17348c2ecf20Sopenharmony_ci	SET_FIELD(nop_out_pdu_header.flags_attr, ISCSI_NOP_OUT_HDR_RSRV, 0);
17358c2ecf20Sopenharmony_ci
17368c2ecf20Sopenharmony_ci	memcpy(scsi_lun, &nopout_hdr->lun, sizeof(struct scsi_lun));
17378c2ecf20Sopenharmony_ci	nop_out_pdu_header.lun.lo = be32_to_cpu(scsi_lun[0]);
17388c2ecf20Sopenharmony_ci	nop_out_pdu_header.lun.hi = be32_to_cpu(scsi_lun[1]);
17398c2ecf20Sopenharmony_ci	nop_out_pdu_header.cmd_sn = be32_to_cpu(nopout_hdr->cmdsn);
17408c2ecf20Sopenharmony_ci	nop_out_pdu_header.exp_stat_sn = be32_to_cpu(nopout_hdr->exp_statsn);
17418c2ecf20Sopenharmony_ci
17428c2ecf20Sopenharmony_ci	qedi_update_itt_map(qedi, tid, task->itt, qedi_cmd);
17438c2ecf20Sopenharmony_ci
17448c2ecf20Sopenharmony_ci	if (nopout_hdr->ttt != ISCSI_TTT_ALL_ONES) {
17458c2ecf20Sopenharmony_ci		nop_out_pdu_header.itt = be32_to_cpu(nopout_hdr->itt);
17468c2ecf20Sopenharmony_ci		nop_out_pdu_header.ttt = be32_to_cpu(nopout_hdr->ttt);
17478c2ecf20Sopenharmony_ci	} else {
17488c2ecf20Sopenharmony_ci		nop_out_pdu_header.itt = qedi_set_itt(tid, get_itt(task->itt));
17498c2ecf20Sopenharmony_ci		nop_out_pdu_header.ttt = ISCSI_TTT_ALL_ONES;
17508c2ecf20Sopenharmony_ci
17518c2ecf20Sopenharmony_ci		spin_lock(&qedi_conn->list_lock);
17528c2ecf20Sopenharmony_ci		list_add_tail(&qedi_cmd->io_cmd, &qedi_conn->active_cmd_list);
17538c2ecf20Sopenharmony_ci		qedi_cmd->io_cmd_in_list = true;
17548c2ecf20Sopenharmony_ci		qedi_conn->active_cmd_count++;
17558c2ecf20Sopenharmony_ci		spin_unlock(&qedi_conn->list_lock);
17568c2ecf20Sopenharmony_ci	}
17578c2ecf20Sopenharmony_ci
17588c2ecf20Sopenharmony_ci	/* Fill tx AHS and rx buffer */
17598c2ecf20Sopenharmony_ci	if (data_len) {
17608c2ecf20Sopenharmony_ci		tx_sgl_task_params.sgl =
17618c2ecf20Sopenharmony_ci			       (struct scsi_sge *)qedi_conn->gen_pdu.req_bd_tbl;
17628c2ecf20Sopenharmony_ci		tx_sgl_task_params.sgl_phys_addr.lo =
17638c2ecf20Sopenharmony_ci					 (u32)(qedi_conn->gen_pdu.req_dma_addr);
17648c2ecf20Sopenharmony_ci		tx_sgl_task_params.sgl_phys_addr.hi =
17658c2ecf20Sopenharmony_ci			      (u32)((u64)qedi_conn->gen_pdu.req_dma_addr >> 32);
17668c2ecf20Sopenharmony_ci		tx_sgl_task_params.total_buffer_size = data_len;
17678c2ecf20Sopenharmony_ci		tx_sgl_task_params.num_sges = 1;
17688c2ecf20Sopenharmony_ci
17698c2ecf20Sopenharmony_ci		rx_sgl_task_params.sgl =
17708c2ecf20Sopenharmony_ci			      (struct scsi_sge *)qedi_conn->gen_pdu.resp_bd_tbl;
17718c2ecf20Sopenharmony_ci		rx_sgl_task_params.sgl_phys_addr.lo =
17728c2ecf20Sopenharmony_ci					(u32)(qedi_conn->gen_pdu.resp_dma_addr);
17738c2ecf20Sopenharmony_ci		rx_sgl_task_params.sgl_phys_addr.hi =
17748c2ecf20Sopenharmony_ci			     (u32)((u64)qedi_conn->gen_pdu.resp_dma_addr >> 32);
17758c2ecf20Sopenharmony_ci		rx_sgl_task_params.total_buffer_size = resp_sge->sge_len;
17768c2ecf20Sopenharmony_ci		rx_sgl_task_params.num_sges = 1;
17778c2ecf20Sopenharmony_ci	}
17788c2ecf20Sopenharmony_ci
17798c2ecf20Sopenharmony_ci	/* Fill fw input params */
17808c2ecf20Sopenharmony_ci	task_params.context = fw_task_ctx;
17818c2ecf20Sopenharmony_ci	task_params.conn_icid = (u16)qedi_conn->iscsi_conn_id;
17828c2ecf20Sopenharmony_ci	task_params.itid = tid;
17838c2ecf20Sopenharmony_ci	task_params.cq_rss_number = 0;
17848c2ecf20Sopenharmony_ci	task_params.tx_io_size = data_len;
17858c2ecf20Sopenharmony_ci	task_params.rx_io_size = resp_sge->sge_len;
17868c2ecf20Sopenharmony_ci
17878c2ecf20Sopenharmony_ci	sq_idx = qedi_get_wqe_idx(qedi_conn);
17888c2ecf20Sopenharmony_ci	task_params.sqe = &ep->sq[sq_idx];
17898c2ecf20Sopenharmony_ci
17908c2ecf20Sopenharmony_ci	memset(task_params.sqe, 0, sizeof(struct iscsi_wqe));
17918c2ecf20Sopenharmony_ci	rval = init_initiator_nop_out_task(&task_params,
17928c2ecf20Sopenharmony_ci					   &nop_out_pdu_header,
17938c2ecf20Sopenharmony_ci					   &tx_sgl_task_params,
17948c2ecf20Sopenharmony_ci					   &rx_sgl_task_params);
17958c2ecf20Sopenharmony_ci	if (rval)
17968c2ecf20Sopenharmony_ci		return -1;
17978c2ecf20Sopenharmony_ci
17988c2ecf20Sopenharmony_ci	qedi_ring_doorbell(qedi_conn);
17998c2ecf20Sopenharmony_ci	return 0;
18008c2ecf20Sopenharmony_ci}
18018c2ecf20Sopenharmony_ci
18028c2ecf20Sopenharmony_cistatic int qedi_split_bd(struct qedi_cmd *cmd, u64 addr, int sg_len,
18038c2ecf20Sopenharmony_ci			 int bd_index)
18048c2ecf20Sopenharmony_ci{
18058c2ecf20Sopenharmony_ci	struct scsi_sge *bd = cmd->io_tbl.sge_tbl;
18068c2ecf20Sopenharmony_ci	int frag_size, sg_frags;
18078c2ecf20Sopenharmony_ci
18088c2ecf20Sopenharmony_ci	sg_frags = 0;
18098c2ecf20Sopenharmony_ci
18108c2ecf20Sopenharmony_ci	while (sg_len) {
18118c2ecf20Sopenharmony_ci		if (addr % QEDI_PAGE_SIZE)
18128c2ecf20Sopenharmony_ci			frag_size =
18138c2ecf20Sopenharmony_ci				   (QEDI_PAGE_SIZE - (addr % QEDI_PAGE_SIZE));
18148c2ecf20Sopenharmony_ci		else
18158c2ecf20Sopenharmony_ci			frag_size = (sg_len > QEDI_BD_SPLIT_SZ) ? 0 :
18168c2ecf20Sopenharmony_ci				    (sg_len % QEDI_BD_SPLIT_SZ);
18178c2ecf20Sopenharmony_ci
18188c2ecf20Sopenharmony_ci		if (frag_size == 0)
18198c2ecf20Sopenharmony_ci			frag_size = QEDI_BD_SPLIT_SZ;
18208c2ecf20Sopenharmony_ci
18218c2ecf20Sopenharmony_ci		bd[bd_index + sg_frags].sge_addr.lo = (addr & 0xffffffff);
18228c2ecf20Sopenharmony_ci		bd[bd_index + sg_frags].sge_addr.hi = (addr >> 32);
18238c2ecf20Sopenharmony_ci		bd[bd_index + sg_frags].sge_len = (u16)frag_size;
18248c2ecf20Sopenharmony_ci		QEDI_INFO(&cmd->conn->qedi->dbg_ctx, QEDI_LOG_IO,
18258c2ecf20Sopenharmony_ci			  "split sge %d: addr=%llx, len=%x",
18268c2ecf20Sopenharmony_ci			  (bd_index + sg_frags), addr, frag_size);
18278c2ecf20Sopenharmony_ci
18288c2ecf20Sopenharmony_ci		addr += (u64)frag_size;
18298c2ecf20Sopenharmony_ci		sg_frags++;
18308c2ecf20Sopenharmony_ci		sg_len -= frag_size;
18318c2ecf20Sopenharmony_ci	}
18328c2ecf20Sopenharmony_ci	return sg_frags;
18338c2ecf20Sopenharmony_ci}
18348c2ecf20Sopenharmony_ci
18358c2ecf20Sopenharmony_cistatic int qedi_map_scsi_sg(struct qedi_ctx *qedi, struct qedi_cmd *cmd)
18368c2ecf20Sopenharmony_ci{
18378c2ecf20Sopenharmony_ci	struct scsi_cmnd *sc = cmd->scsi_cmd;
18388c2ecf20Sopenharmony_ci	struct scsi_sge *bd = cmd->io_tbl.sge_tbl;
18398c2ecf20Sopenharmony_ci	struct scatterlist *sg;
18408c2ecf20Sopenharmony_ci	int byte_count = 0;
18418c2ecf20Sopenharmony_ci	int bd_count = 0;
18428c2ecf20Sopenharmony_ci	int sg_count;
18438c2ecf20Sopenharmony_ci	int sg_len;
18448c2ecf20Sopenharmony_ci	int sg_frags;
18458c2ecf20Sopenharmony_ci	u64 addr, end_addr;
18468c2ecf20Sopenharmony_ci	int i;
18478c2ecf20Sopenharmony_ci
18488c2ecf20Sopenharmony_ci	WARN_ON(scsi_sg_count(sc) > QEDI_ISCSI_MAX_BDS_PER_CMD);
18498c2ecf20Sopenharmony_ci
18508c2ecf20Sopenharmony_ci	sg_count = dma_map_sg(&qedi->pdev->dev, scsi_sglist(sc),
18518c2ecf20Sopenharmony_ci			      scsi_sg_count(sc), sc->sc_data_direction);
18528c2ecf20Sopenharmony_ci
18538c2ecf20Sopenharmony_ci	/*
18548c2ecf20Sopenharmony_ci	 * New condition to send single SGE as cached-SGL.
18558c2ecf20Sopenharmony_ci	 * Single SGE with length less than 64K.
18568c2ecf20Sopenharmony_ci	 */
18578c2ecf20Sopenharmony_ci	sg = scsi_sglist(sc);
18588c2ecf20Sopenharmony_ci	if ((sg_count == 1) && (sg_dma_len(sg) <= MAX_SGLEN_FOR_CACHESGL)) {
18598c2ecf20Sopenharmony_ci		sg_len = sg_dma_len(sg);
18608c2ecf20Sopenharmony_ci		addr = (u64)sg_dma_address(sg);
18618c2ecf20Sopenharmony_ci
18628c2ecf20Sopenharmony_ci		bd[bd_count].sge_addr.lo = (addr & 0xffffffff);
18638c2ecf20Sopenharmony_ci		bd[bd_count].sge_addr.hi = (addr >> 32);
18648c2ecf20Sopenharmony_ci		bd[bd_count].sge_len = (u16)sg_len;
18658c2ecf20Sopenharmony_ci
18668c2ecf20Sopenharmony_ci		QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_IO,
18678c2ecf20Sopenharmony_ci			  "single-cached-sgl: bd_count:%d addr=%llx, len=%x",
18688c2ecf20Sopenharmony_ci			  sg_count, addr, sg_len);
18698c2ecf20Sopenharmony_ci
18708c2ecf20Sopenharmony_ci		return ++bd_count;
18718c2ecf20Sopenharmony_ci	}
18728c2ecf20Sopenharmony_ci
18738c2ecf20Sopenharmony_ci	scsi_for_each_sg(sc, sg, sg_count, i) {
18748c2ecf20Sopenharmony_ci		sg_len = sg_dma_len(sg);
18758c2ecf20Sopenharmony_ci		addr = (u64)sg_dma_address(sg);
18768c2ecf20Sopenharmony_ci		end_addr = (addr + sg_len);
18778c2ecf20Sopenharmony_ci
18788c2ecf20Sopenharmony_ci		/*
18798c2ecf20Sopenharmony_ci		 * first sg elem in the 'list',
18808c2ecf20Sopenharmony_ci		 * check if end addr is page-aligned.
18818c2ecf20Sopenharmony_ci		 */
18828c2ecf20Sopenharmony_ci		if ((i == 0) && (sg_count > 1) && (end_addr % QEDI_PAGE_SIZE))
18838c2ecf20Sopenharmony_ci			cmd->use_slowpath = true;
18848c2ecf20Sopenharmony_ci
18858c2ecf20Sopenharmony_ci		/*
18868c2ecf20Sopenharmony_ci		 * last sg elem in the 'list',
18878c2ecf20Sopenharmony_ci		 * check if start addr is page-aligned.
18888c2ecf20Sopenharmony_ci		 */
18898c2ecf20Sopenharmony_ci		else if ((i == (sg_count - 1)) &&
18908c2ecf20Sopenharmony_ci			 (sg_count > 1) && (addr % QEDI_PAGE_SIZE))
18918c2ecf20Sopenharmony_ci			cmd->use_slowpath = true;
18928c2ecf20Sopenharmony_ci
18938c2ecf20Sopenharmony_ci		/*
18948c2ecf20Sopenharmony_ci		 * middle sg elements in list,
18958c2ecf20Sopenharmony_ci		 * check if start and end addr is page-aligned
18968c2ecf20Sopenharmony_ci		 */
18978c2ecf20Sopenharmony_ci		else if ((i != 0) && (i != (sg_count - 1)) &&
18988c2ecf20Sopenharmony_ci			 ((addr % QEDI_PAGE_SIZE) ||
18998c2ecf20Sopenharmony_ci			 (end_addr % QEDI_PAGE_SIZE)))
19008c2ecf20Sopenharmony_ci			cmd->use_slowpath = true;
19018c2ecf20Sopenharmony_ci
19028c2ecf20Sopenharmony_ci		QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_IO, "sg[%d] size=0x%x",
19038c2ecf20Sopenharmony_ci			  i, sg_len);
19048c2ecf20Sopenharmony_ci
19058c2ecf20Sopenharmony_ci		if (sg_len > QEDI_BD_SPLIT_SZ) {
19068c2ecf20Sopenharmony_ci			sg_frags = qedi_split_bd(cmd, addr, sg_len, bd_count);
19078c2ecf20Sopenharmony_ci		} else {
19088c2ecf20Sopenharmony_ci			sg_frags = 1;
19098c2ecf20Sopenharmony_ci			bd[bd_count].sge_addr.lo = addr & 0xffffffff;
19108c2ecf20Sopenharmony_ci			bd[bd_count].sge_addr.hi = addr >> 32;
19118c2ecf20Sopenharmony_ci			bd[bd_count].sge_len = sg_len;
19128c2ecf20Sopenharmony_ci		}
19138c2ecf20Sopenharmony_ci		byte_count += sg_len;
19148c2ecf20Sopenharmony_ci		bd_count += sg_frags;
19158c2ecf20Sopenharmony_ci	}
19168c2ecf20Sopenharmony_ci
19178c2ecf20Sopenharmony_ci	if (byte_count != scsi_bufflen(sc))
19188c2ecf20Sopenharmony_ci		QEDI_ERR(&qedi->dbg_ctx,
19198c2ecf20Sopenharmony_ci			 "byte_count = %d != scsi_bufflen = %d\n", byte_count,
19208c2ecf20Sopenharmony_ci			 scsi_bufflen(sc));
19218c2ecf20Sopenharmony_ci	else
19228c2ecf20Sopenharmony_ci		QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_IO, "byte_count = %d\n",
19238c2ecf20Sopenharmony_ci			  byte_count);
19248c2ecf20Sopenharmony_ci
19258c2ecf20Sopenharmony_ci	WARN_ON(byte_count != scsi_bufflen(sc));
19268c2ecf20Sopenharmony_ci
19278c2ecf20Sopenharmony_ci	return bd_count;
19288c2ecf20Sopenharmony_ci}
19298c2ecf20Sopenharmony_ci
19308c2ecf20Sopenharmony_cistatic void qedi_iscsi_map_sg_list(struct qedi_cmd *cmd)
19318c2ecf20Sopenharmony_ci{
19328c2ecf20Sopenharmony_ci	int bd_count;
19338c2ecf20Sopenharmony_ci	struct scsi_cmnd *sc = cmd->scsi_cmd;
19348c2ecf20Sopenharmony_ci
19358c2ecf20Sopenharmony_ci	if (scsi_sg_count(sc)) {
19368c2ecf20Sopenharmony_ci		bd_count  = qedi_map_scsi_sg(cmd->conn->qedi, cmd);
19378c2ecf20Sopenharmony_ci		if (bd_count == 0)
19388c2ecf20Sopenharmony_ci			return;
19398c2ecf20Sopenharmony_ci	} else {
19408c2ecf20Sopenharmony_ci		struct scsi_sge *bd = cmd->io_tbl.sge_tbl;
19418c2ecf20Sopenharmony_ci
19428c2ecf20Sopenharmony_ci		bd[0].sge_addr.lo = 0;
19438c2ecf20Sopenharmony_ci		bd[0].sge_addr.hi = 0;
19448c2ecf20Sopenharmony_ci		bd[0].sge_len = 0;
19458c2ecf20Sopenharmony_ci		bd_count = 0;
19468c2ecf20Sopenharmony_ci	}
19478c2ecf20Sopenharmony_ci	cmd->io_tbl.sge_valid = bd_count;
19488c2ecf20Sopenharmony_ci}
19498c2ecf20Sopenharmony_ci
19508c2ecf20Sopenharmony_cistatic void qedi_cpy_scsi_cdb(struct scsi_cmnd *sc, u32 *dstp)
19518c2ecf20Sopenharmony_ci{
19528c2ecf20Sopenharmony_ci	u32 dword;
19538c2ecf20Sopenharmony_ci	int lpcnt;
19548c2ecf20Sopenharmony_ci	u8 *srcp;
19558c2ecf20Sopenharmony_ci
19568c2ecf20Sopenharmony_ci	lpcnt = sc->cmd_len / sizeof(dword);
19578c2ecf20Sopenharmony_ci	srcp = (u8 *)sc->cmnd;
19588c2ecf20Sopenharmony_ci	while (lpcnt--) {
19598c2ecf20Sopenharmony_ci		memcpy(&dword, (const void *)srcp, 4);
19608c2ecf20Sopenharmony_ci		*dstp = cpu_to_be32(dword);
19618c2ecf20Sopenharmony_ci		srcp += 4;
19628c2ecf20Sopenharmony_ci		dstp++;
19638c2ecf20Sopenharmony_ci	}
19648c2ecf20Sopenharmony_ci	if (sc->cmd_len & 0x3) {
19658c2ecf20Sopenharmony_ci		dword = (u32)srcp[0] | ((u32)srcp[1] << 8);
19668c2ecf20Sopenharmony_ci		*dstp = cpu_to_be32(dword);
19678c2ecf20Sopenharmony_ci	}
19688c2ecf20Sopenharmony_ci}
19698c2ecf20Sopenharmony_ci
19708c2ecf20Sopenharmony_civoid qedi_trace_io(struct qedi_ctx *qedi, struct iscsi_task *task,
19718c2ecf20Sopenharmony_ci		   u16 tid, int8_t direction)
19728c2ecf20Sopenharmony_ci{
19738c2ecf20Sopenharmony_ci	struct qedi_io_log *io_log;
19748c2ecf20Sopenharmony_ci	struct iscsi_conn *conn = task->conn;
19758c2ecf20Sopenharmony_ci	struct qedi_conn *qedi_conn = conn->dd_data;
19768c2ecf20Sopenharmony_ci	struct scsi_cmnd *sc_cmd = task->sc;
19778c2ecf20Sopenharmony_ci	unsigned long flags;
19788c2ecf20Sopenharmony_ci
19798c2ecf20Sopenharmony_ci	spin_lock_irqsave(&qedi->io_trace_lock, flags);
19808c2ecf20Sopenharmony_ci
19818c2ecf20Sopenharmony_ci	io_log = &qedi->io_trace_buf[qedi->io_trace_idx];
19828c2ecf20Sopenharmony_ci	io_log->direction = direction;
19838c2ecf20Sopenharmony_ci	io_log->task_id = tid;
19848c2ecf20Sopenharmony_ci	io_log->cid = qedi_conn->iscsi_conn_id;
19858c2ecf20Sopenharmony_ci	io_log->lun = sc_cmd->device->lun;
19868c2ecf20Sopenharmony_ci	io_log->op = sc_cmd->cmnd[0];
19878c2ecf20Sopenharmony_ci	io_log->lba[0] = sc_cmd->cmnd[2];
19888c2ecf20Sopenharmony_ci	io_log->lba[1] = sc_cmd->cmnd[3];
19898c2ecf20Sopenharmony_ci	io_log->lba[2] = sc_cmd->cmnd[4];
19908c2ecf20Sopenharmony_ci	io_log->lba[3] = sc_cmd->cmnd[5];
19918c2ecf20Sopenharmony_ci	io_log->bufflen = scsi_bufflen(sc_cmd);
19928c2ecf20Sopenharmony_ci	io_log->sg_count = scsi_sg_count(sc_cmd);
19938c2ecf20Sopenharmony_ci	io_log->fast_sgs = qedi->fast_sgls;
19948c2ecf20Sopenharmony_ci	io_log->cached_sgs = qedi->cached_sgls;
19958c2ecf20Sopenharmony_ci	io_log->slow_sgs = qedi->slow_sgls;
19968c2ecf20Sopenharmony_ci	io_log->cached_sge = qedi->use_cached_sge;
19978c2ecf20Sopenharmony_ci	io_log->slow_sge = qedi->use_slow_sge;
19988c2ecf20Sopenharmony_ci	io_log->fast_sge = qedi->use_fast_sge;
19998c2ecf20Sopenharmony_ci	io_log->result = sc_cmd->result;
20008c2ecf20Sopenharmony_ci	io_log->jiffies = jiffies;
20018c2ecf20Sopenharmony_ci	io_log->blk_req_cpu = smp_processor_id();
20028c2ecf20Sopenharmony_ci
20038c2ecf20Sopenharmony_ci	if (direction == QEDI_IO_TRACE_REQ) {
20048c2ecf20Sopenharmony_ci		/* For requests we only care about the submission CPU */
20058c2ecf20Sopenharmony_ci		io_log->req_cpu = smp_processor_id() % qedi->num_queues;
20068c2ecf20Sopenharmony_ci		io_log->intr_cpu = 0;
20078c2ecf20Sopenharmony_ci		io_log->blk_rsp_cpu = 0;
20088c2ecf20Sopenharmony_ci	} else if (direction == QEDI_IO_TRACE_RSP) {
20098c2ecf20Sopenharmony_ci		io_log->req_cpu = smp_processor_id() % qedi->num_queues;
20108c2ecf20Sopenharmony_ci		io_log->intr_cpu = qedi->intr_cpu;
20118c2ecf20Sopenharmony_ci		io_log->blk_rsp_cpu = smp_processor_id();
20128c2ecf20Sopenharmony_ci	}
20138c2ecf20Sopenharmony_ci
20148c2ecf20Sopenharmony_ci	qedi->io_trace_idx++;
20158c2ecf20Sopenharmony_ci	if (qedi->io_trace_idx == QEDI_IO_TRACE_SIZE)
20168c2ecf20Sopenharmony_ci		qedi->io_trace_idx = 0;
20178c2ecf20Sopenharmony_ci
20188c2ecf20Sopenharmony_ci	qedi->use_cached_sge = false;
20198c2ecf20Sopenharmony_ci	qedi->use_slow_sge = false;
20208c2ecf20Sopenharmony_ci	qedi->use_fast_sge = false;
20218c2ecf20Sopenharmony_ci
20228c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&qedi->io_trace_lock, flags);
20238c2ecf20Sopenharmony_ci}
20248c2ecf20Sopenharmony_ci
20258c2ecf20Sopenharmony_ciint qedi_iscsi_send_ioreq(struct iscsi_task *task)
20268c2ecf20Sopenharmony_ci{
20278c2ecf20Sopenharmony_ci	struct iscsi_conn *conn = task->conn;
20288c2ecf20Sopenharmony_ci	struct iscsi_session *session = conn->session;
20298c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = iscsi_session_to_shost(session->cls_session);
20308c2ecf20Sopenharmony_ci	struct qedi_ctx *qedi = iscsi_host_priv(shost);
20318c2ecf20Sopenharmony_ci	struct qedi_conn *qedi_conn = conn->dd_data;
20328c2ecf20Sopenharmony_ci	struct qedi_cmd *cmd = task->dd_data;
20338c2ecf20Sopenharmony_ci	struct scsi_cmnd *sc = task->sc;
20348c2ecf20Sopenharmony_ci	struct iscsi_cmd_hdr cmd_pdu_header;
20358c2ecf20Sopenharmony_ci	struct scsi_sgl_task_params tx_sgl_task_params;
20368c2ecf20Sopenharmony_ci	struct scsi_sgl_task_params rx_sgl_task_params;
20378c2ecf20Sopenharmony_ci	struct scsi_sgl_task_params *prx_sgl = NULL;
20388c2ecf20Sopenharmony_ci	struct scsi_sgl_task_params *ptx_sgl = NULL;
20398c2ecf20Sopenharmony_ci	struct iscsi_task_params task_params;
20408c2ecf20Sopenharmony_ci	struct iscsi_conn_params conn_params;
20418c2ecf20Sopenharmony_ci	struct scsi_initiator_cmd_params cmd_params;
20428c2ecf20Sopenharmony_ci	struct e4_iscsi_task_context *fw_task_ctx;
20438c2ecf20Sopenharmony_ci	struct iscsi_cls_conn *cls_conn;
20448c2ecf20Sopenharmony_ci	struct iscsi_scsi_req *hdr = (struct iscsi_scsi_req *)task->hdr;
20458c2ecf20Sopenharmony_ci	enum iscsi_task_type task_type = MAX_ISCSI_TASK_TYPE;
20468c2ecf20Sopenharmony_ci	struct qedi_endpoint *ep;
20478c2ecf20Sopenharmony_ci	u32 scsi_lun[2];
20488c2ecf20Sopenharmony_ci	s16 tid = 0;
20498c2ecf20Sopenharmony_ci	u16 sq_idx = 0;
20508c2ecf20Sopenharmony_ci	u16 cq_idx;
20518c2ecf20Sopenharmony_ci	int rval = 0;
20528c2ecf20Sopenharmony_ci
20538c2ecf20Sopenharmony_ci	ep = qedi_conn->ep;
20548c2ecf20Sopenharmony_ci	cls_conn = qedi_conn->cls_conn;
20558c2ecf20Sopenharmony_ci	conn = cls_conn->dd_data;
20568c2ecf20Sopenharmony_ci
20578c2ecf20Sopenharmony_ci	qedi_iscsi_map_sg_list(cmd);
20588c2ecf20Sopenharmony_ci	int_to_scsilun(sc->device->lun, (struct scsi_lun *)scsi_lun);
20598c2ecf20Sopenharmony_ci
20608c2ecf20Sopenharmony_ci	tid = qedi_get_task_idx(qedi);
20618c2ecf20Sopenharmony_ci	if (tid == -1)
20628c2ecf20Sopenharmony_ci		return -ENOMEM;
20638c2ecf20Sopenharmony_ci
20648c2ecf20Sopenharmony_ci	fw_task_ctx =
20658c2ecf20Sopenharmony_ci	     (struct e4_iscsi_task_context *)qedi_get_task_mem(&qedi->tasks,
20668c2ecf20Sopenharmony_ci							       tid);
20678c2ecf20Sopenharmony_ci	memset(fw_task_ctx, 0, sizeof(struct e4_iscsi_task_context));
20688c2ecf20Sopenharmony_ci
20698c2ecf20Sopenharmony_ci	cmd->task_id = tid;
20708c2ecf20Sopenharmony_ci
20718c2ecf20Sopenharmony_ci	memset(&task_params, 0, sizeof(task_params));
20728c2ecf20Sopenharmony_ci	memset(&cmd_pdu_header, 0, sizeof(cmd_pdu_header));
20738c2ecf20Sopenharmony_ci	memset(&tx_sgl_task_params, 0, sizeof(tx_sgl_task_params));
20748c2ecf20Sopenharmony_ci	memset(&rx_sgl_task_params, 0, sizeof(rx_sgl_task_params));
20758c2ecf20Sopenharmony_ci	memset(&conn_params, 0, sizeof(conn_params));
20768c2ecf20Sopenharmony_ci	memset(&cmd_params, 0, sizeof(cmd_params));
20778c2ecf20Sopenharmony_ci
20788c2ecf20Sopenharmony_ci	cq_idx = smp_processor_id() % qedi->num_queues;
20798c2ecf20Sopenharmony_ci	/* Update header info */
20808c2ecf20Sopenharmony_ci	SET_FIELD(cmd_pdu_header.flags_attr, ISCSI_CMD_HDR_ATTR,
20818c2ecf20Sopenharmony_ci		  ISCSI_ATTR_SIMPLE);
20828c2ecf20Sopenharmony_ci	if (hdr->cdb[0] != TEST_UNIT_READY) {
20838c2ecf20Sopenharmony_ci		if (sc->sc_data_direction == DMA_TO_DEVICE) {
20848c2ecf20Sopenharmony_ci			SET_FIELD(cmd_pdu_header.flags_attr,
20858c2ecf20Sopenharmony_ci				  ISCSI_CMD_HDR_WRITE, 1);
20868c2ecf20Sopenharmony_ci			task_type = ISCSI_TASK_TYPE_INITIATOR_WRITE;
20878c2ecf20Sopenharmony_ci		} else {
20888c2ecf20Sopenharmony_ci			SET_FIELD(cmd_pdu_header.flags_attr,
20898c2ecf20Sopenharmony_ci				  ISCSI_CMD_HDR_READ, 1);
20908c2ecf20Sopenharmony_ci			task_type = ISCSI_TASK_TYPE_INITIATOR_READ;
20918c2ecf20Sopenharmony_ci		}
20928c2ecf20Sopenharmony_ci	}
20938c2ecf20Sopenharmony_ci
20948c2ecf20Sopenharmony_ci	cmd_pdu_header.lun.lo = be32_to_cpu(scsi_lun[0]);
20958c2ecf20Sopenharmony_ci	cmd_pdu_header.lun.hi = be32_to_cpu(scsi_lun[1]);
20968c2ecf20Sopenharmony_ci
20978c2ecf20Sopenharmony_ci	qedi_update_itt_map(qedi, tid, task->itt, cmd);
20988c2ecf20Sopenharmony_ci	cmd_pdu_header.itt = qedi_set_itt(tid, get_itt(task->itt));
20998c2ecf20Sopenharmony_ci	cmd_pdu_header.expected_transfer_length = cpu_to_be32(hdr->data_length);
21008c2ecf20Sopenharmony_ci	cmd_pdu_header.hdr_second_dword = ntoh24(hdr->dlength);
21018c2ecf20Sopenharmony_ci	cmd_pdu_header.cmd_sn = be32_to_cpu(hdr->cmdsn);
21028c2ecf20Sopenharmony_ci	cmd_pdu_header.hdr_first_byte = hdr->opcode;
21038c2ecf20Sopenharmony_ci	qedi_cpy_scsi_cdb(sc, (u32 *)cmd_pdu_header.cdb);
21048c2ecf20Sopenharmony_ci
21058c2ecf20Sopenharmony_ci	/* Fill tx AHS and rx buffer */
21068c2ecf20Sopenharmony_ci	if (task_type == ISCSI_TASK_TYPE_INITIATOR_WRITE) {
21078c2ecf20Sopenharmony_ci		tx_sgl_task_params.sgl = cmd->io_tbl.sge_tbl;
21088c2ecf20Sopenharmony_ci		tx_sgl_task_params.sgl_phys_addr.lo =
21098c2ecf20Sopenharmony_ci						 (u32)(cmd->io_tbl.sge_tbl_dma);
21108c2ecf20Sopenharmony_ci		tx_sgl_task_params.sgl_phys_addr.hi =
21118c2ecf20Sopenharmony_ci				      (u32)((u64)cmd->io_tbl.sge_tbl_dma >> 32);
21128c2ecf20Sopenharmony_ci		tx_sgl_task_params.total_buffer_size = scsi_bufflen(sc);
21138c2ecf20Sopenharmony_ci		tx_sgl_task_params.num_sges = cmd->io_tbl.sge_valid;
21148c2ecf20Sopenharmony_ci		if (cmd->use_slowpath)
21158c2ecf20Sopenharmony_ci			tx_sgl_task_params.small_mid_sge = true;
21168c2ecf20Sopenharmony_ci	} else if (task_type == ISCSI_TASK_TYPE_INITIATOR_READ) {
21178c2ecf20Sopenharmony_ci		rx_sgl_task_params.sgl = cmd->io_tbl.sge_tbl;
21188c2ecf20Sopenharmony_ci		rx_sgl_task_params.sgl_phys_addr.lo =
21198c2ecf20Sopenharmony_ci						 (u32)(cmd->io_tbl.sge_tbl_dma);
21208c2ecf20Sopenharmony_ci		rx_sgl_task_params.sgl_phys_addr.hi =
21218c2ecf20Sopenharmony_ci				      (u32)((u64)cmd->io_tbl.sge_tbl_dma >> 32);
21228c2ecf20Sopenharmony_ci		rx_sgl_task_params.total_buffer_size = scsi_bufflen(sc);
21238c2ecf20Sopenharmony_ci		rx_sgl_task_params.num_sges = cmd->io_tbl.sge_valid;
21248c2ecf20Sopenharmony_ci	}
21258c2ecf20Sopenharmony_ci
21268c2ecf20Sopenharmony_ci	/* Add conn param */
21278c2ecf20Sopenharmony_ci	conn_params.first_burst_length = conn->session->first_burst;
21288c2ecf20Sopenharmony_ci	conn_params.max_send_pdu_length = conn->max_xmit_dlength;
21298c2ecf20Sopenharmony_ci	conn_params.max_burst_length = conn->session->max_burst;
21308c2ecf20Sopenharmony_ci	if (conn->session->initial_r2t_en)
21318c2ecf20Sopenharmony_ci		conn_params.initial_r2t = true;
21328c2ecf20Sopenharmony_ci	if (conn->session->imm_data_en)
21338c2ecf20Sopenharmony_ci		conn_params.immediate_data = true;
21348c2ecf20Sopenharmony_ci
21358c2ecf20Sopenharmony_ci	/* Add cmd params */
21368c2ecf20Sopenharmony_ci	cmd_params.sense_data_buffer_phys_addr.lo = (u32)cmd->sense_buffer_dma;
21378c2ecf20Sopenharmony_ci	cmd_params.sense_data_buffer_phys_addr.hi =
21388c2ecf20Sopenharmony_ci					(u32)((u64)cmd->sense_buffer_dma >> 32);
21398c2ecf20Sopenharmony_ci	/* Fill fw input params */
21408c2ecf20Sopenharmony_ci	task_params.context = fw_task_ctx;
21418c2ecf20Sopenharmony_ci	task_params.conn_icid = (u16)qedi_conn->iscsi_conn_id;
21428c2ecf20Sopenharmony_ci	task_params.itid = tid;
21438c2ecf20Sopenharmony_ci	task_params.cq_rss_number = cq_idx;
21448c2ecf20Sopenharmony_ci	if (task_type == ISCSI_TASK_TYPE_INITIATOR_WRITE)
21458c2ecf20Sopenharmony_ci		task_params.tx_io_size = scsi_bufflen(sc);
21468c2ecf20Sopenharmony_ci	else if (task_type == ISCSI_TASK_TYPE_INITIATOR_READ)
21478c2ecf20Sopenharmony_ci		task_params.rx_io_size = scsi_bufflen(sc);
21488c2ecf20Sopenharmony_ci
21498c2ecf20Sopenharmony_ci	sq_idx = qedi_get_wqe_idx(qedi_conn);
21508c2ecf20Sopenharmony_ci	task_params.sqe = &ep->sq[sq_idx];
21518c2ecf20Sopenharmony_ci
21528c2ecf20Sopenharmony_ci	QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_IO,
21538c2ecf20Sopenharmony_ci		  "%s: %s-SGL: sg_len=0x%x num_sges=0x%x first-sge-lo=0x%x first-sge-hi=0x%x\n",
21548c2ecf20Sopenharmony_ci		  (task_type == ISCSI_TASK_TYPE_INITIATOR_WRITE) ?
21558c2ecf20Sopenharmony_ci		  "Write " : "Read ", (cmd->io_tbl.sge_valid == 1) ?
21568c2ecf20Sopenharmony_ci		  "Single" : (cmd->use_slowpath ? "SLOW" : "FAST"),
21578c2ecf20Sopenharmony_ci		  (u16)cmd->io_tbl.sge_valid, scsi_bufflen(sc),
21588c2ecf20Sopenharmony_ci		  (u32)(cmd->io_tbl.sge_tbl_dma),
21598c2ecf20Sopenharmony_ci		  (u32)((u64)cmd->io_tbl.sge_tbl_dma >> 32));
21608c2ecf20Sopenharmony_ci
21618c2ecf20Sopenharmony_ci	memset(task_params.sqe, 0, sizeof(struct iscsi_wqe));
21628c2ecf20Sopenharmony_ci
21638c2ecf20Sopenharmony_ci	if (task_params.tx_io_size != 0)
21648c2ecf20Sopenharmony_ci		ptx_sgl = &tx_sgl_task_params;
21658c2ecf20Sopenharmony_ci	if (task_params.rx_io_size != 0)
21668c2ecf20Sopenharmony_ci		prx_sgl = &rx_sgl_task_params;
21678c2ecf20Sopenharmony_ci
21688c2ecf20Sopenharmony_ci	rval = init_initiator_rw_iscsi_task(&task_params, &conn_params,
21698c2ecf20Sopenharmony_ci					    &cmd_params, &cmd_pdu_header,
21708c2ecf20Sopenharmony_ci					    ptx_sgl, prx_sgl,
21718c2ecf20Sopenharmony_ci					    NULL);
21728c2ecf20Sopenharmony_ci	if (rval)
21738c2ecf20Sopenharmony_ci		return -1;
21748c2ecf20Sopenharmony_ci
21758c2ecf20Sopenharmony_ci	spin_lock(&qedi_conn->list_lock);
21768c2ecf20Sopenharmony_ci	list_add_tail(&cmd->io_cmd, &qedi_conn->active_cmd_list);
21778c2ecf20Sopenharmony_ci	cmd->io_cmd_in_list = true;
21788c2ecf20Sopenharmony_ci	qedi_conn->active_cmd_count++;
21798c2ecf20Sopenharmony_ci	spin_unlock(&qedi_conn->list_lock);
21808c2ecf20Sopenharmony_ci
21818c2ecf20Sopenharmony_ci	qedi_ring_doorbell(qedi_conn);
21828c2ecf20Sopenharmony_ci	return 0;
21838c2ecf20Sopenharmony_ci}
21848c2ecf20Sopenharmony_ci
21858c2ecf20Sopenharmony_ciint qedi_iscsi_cleanup_task(struct iscsi_task *task, bool mark_cmd_node_deleted)
21868c2ecf20Sopenharmony_ci{
21878c2ecf20Sopenharmony_ci	struct iscsi_task_params task_params;
21888c2ecf20Sopenharmony_ci	struct qedi_endpoint *ep;
21898c2ecf20Sopenharmony_ci	struct iscsi_conn *conn = task->conn;
21908c2ecf20Sopenharmony_ci	struct qedi_conn *qedi_conn = conn->dd_data;
21918c2ecf20Sopenharmony_ci	struct qedi_cmd *cmd = task->dd_data;
21928c2ecf20Sopenharmony_ci	u16 sq_idx = 0;
21938c2ecf20Sopenharmony_ci	int rval = 0;
21948c2ecf20Sopenharmony_ci
21958c2ecf20Sopenharmony_ci	QEDI_INFO(&qedi_conn->qedi->dbg_ctx, QEDI_LOG_SCSI_TM,
21968c2ecf20Sopenharmony_ci		  "issue cleanup tid=0x%x itt=0x%x task_state=%d cmd_state=0%x cid=0x%x\n",
21978c2ecf20Sopenharmony_ci		  cmd->task_id, get_itt(task->itt), task->state,
21988c2ecf20Sopenharmony_ci		  cmd->state, qedi_conn->iscsi_conn_id);
21998c2ecf20Sopenharmony_ci
22008c2ecf20Sopenharmony_ci	memset(&task_params, 0, sizeof(task_params));
22018c2ecf20Sopenharmony_ci	ep = qedi_conn->ep;
22028c2ecf20Sopenharmony_ci
22038c2ecf20Sopenharmony_ci	sq_idx = qedi_get_wqe_idx(qedi_conn);
22048c2ecf20Sopenharmony_ci
22058c2ecf20Sopenharmony_ci	task_params.sqe = &ep->sq[sq_idx];
22068c2ecf20Sopenharmony_ci	memset(task_params.sqe, 0, sizeof(struct iscsi_wqe));
22078c2ecf20Sopenharmony_ci	task_params.itid = cmd->task_id;
22088c2ecf20Sopenharmony_ci
22098c2ecf20Sopenharmony_ci	rval = init_cleanup_task(&task_params);
22108c2ecf20Sopenharmony_ci	if (rval)
22118c2ecf20Sopenharmony_ci		return rval;
22128c2ecf20Sopenharmony_ci
22138c2ecf20Sopenharmony_ci	qedi_ring_doorbell(qedi_conn);
22148c2ecf20Sopenharmony_ci	return 0;
22158c2ecf20Sopenharmony_ci}
2216