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