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 <linux/etherdevice.h> 98c2ecf20Sopenharmony_ci#include <linux/if_ether.h> 108c2ecf20Sopenharmony_ci#include <linux/if_vlan.h> 118c2ecf20Sopenharmony_ci#include <scsi/scsi_tcq.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include "qedi.h" 148c2ecf20Sopenharmony_ci#include "qedi_iscsi.h" 158c2ecf20Sopenharmony_ci#include "qedi_gbl.h" 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ciint qedi_recover_all_conns(struct qedi_ctx *qedi) 188c2ecf20Sopenharmony_ci{ 198c2ecf20Sopenharmony_ci struct qedi_conn *qedi_conn; 208c2ecf20Sopenharmony_ci int i; 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci for (i = 0; i < qedi->max_active_conns; i++) { 238c2ecf20Sopenharmony_ci qedi_conn = qedi_get_conn_from_id(qedi, i); 248c2ecf20Sopenharmony_ci if (!qedi_conn) 258c2ecf20Sopenharmony_ci continue; 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci qedi_start_conn_recovery(qedi, qedi_conn); 288c2ecf20Sopenharmony_ci } 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci return SUCCESS; 318c2ecf20Sopenharmony_ci} 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistatic int qedi_eh_host_reset(struct scsi_cmnd *cmd) 348c2ecf20Sopenharmony_ci{ 358c2ecf20Sopenharmony_ci struct Scsi_Host *shost = cmd->device->host; 368c2ecf20Sopenharmony_ci struct qedi_ctx *qedi; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci qedi = iscsi_host_priv(shost); 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci return qedi_recover_all_conns(qedi); 418c2ecf20Sopenharmony_ci} 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistruct scsi_host_template qedi_host_template = { 448c2ecf20Sopenharmony_ci .module = THIS_MODULE, 458c2ecf20Sopenharmony_ci .name = "QLogic QEDI 25/40/100Gb iSCSI Initiator Driver", 468c2ecf20Sopenharmony_ci .proc_name = QEDI_MODULE_NAME, 478c2ecf20Sopenharmony_ci .queuecommand = iscsi_queuecommand, 488c2ecf20Sopenharmony_ci .eh_timed_out = iscsi_eh_cmd_timed_out, 498c2ecf20Sopenharmony_ci .eh_abort_handler = iscsi_eh_abort, 508c2ecf20Sopenharmony_ci .eh_device_reset_handler = iscsi_eh_device_reset, 518c2ecf20Sopenharmony_ci .eh_target_reset_handler = iscsi_eh_recover_target, 528c2ecf20Sopenharmony_ci .eh_host_reset_handler = qedi_eh_host_reset, 538c2ecf20Sopenharmony_ci .target_alloc = iscsi_target_alloc, 548c2ecf20Sopenharmony_ci .change_queue_depth = scsi_change_queue_depth, 558c2ecf20Sopenharmony_ci .can_queue = QEDI_MAX_ISCSI_TASK, 568c2ecf20Sopenharmony_ci .this_id = -1, 578c2ecf20Sopenharmony_ci .sg_tablesize = QEDI_ISCSI_MAX_BDS_PER_CMD, 588c2ecf20Sopenharmony_ci .max_sectors = 0xffff, 598c2ecf20Sopenharmony_ci .dma_boundary = QEDI_HW_DMA_BOUNDARY, 608c2ecf20Sopenharmony_ci .cmd_per_lun = 128, 618c2ecf20Sopenharmony_ci .shost_attrs = qedi_shost_attrs, 628c2ecf20Sopenharmony_ci}; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistatic void qedi_conn_free_login_resources(struct qedi_ctx *qedi, 658c2ecf20Sopenharmony_ci struct qedi_conn *qedi_conn) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci if (qedi_conn->gen_pdu.resp_bd_tbl) { 688c2ecf20Sopenharmony_ci dma_free_coherent(&qedi->pdev->dev, QEDI_PAGE_SIZE, 698c2ecf20Sopenharmony_ci qedi_conn->gen_pdu.resp_bd_tbl, 708c2ecf20Sopenharmony_ci qedi_conn->gen_pdu.resp_bd_dma); 718c2ecf20Sopenharmony_ci qedi_conn->gen_pdu.resp_bd_tbl = NULL; 728c2ecf20Sopenharmony_ci } 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci if (qedi_conn->gen_pdu.req_bd_tbl) { 758c2ecf20Sopenharmony_ci dma_free_coherent(&qedi->pdev->dev, QEDI_PAGE_SIZE, 768c2ecf20Sopenharmony_ci qedi_conn->gen_pdu.req_bd_tbl, 778c2ecf20Sopenharmony_ci qedi_conn->gen_pdu.req_bd_dma); 788c2ecf20Sopenharmony_ci qedi_conn->gen_pdu.req_bd_tbl = NULL; 798c2ecf20Sopenharmony_ci } 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci if (qedi_conn->gen_pdu.resp_buf) { 828c2ecf20Sopenharmony_ci dma_free_coherent(&qedi->pdev->dev, 838c2ecf20Sopenharmony_ci ISCSI_DEF_MAX_RECV_SEG_LEN, 848c2ecf20Sopenharmony_ci qedi_conn->gen_pdu.resp_buf, 858c2ecf20Sopenharmony_ci qedi_conn->gen_pdu.resp_dma_addr); 868c2ecf20Sopenharmony_ci qedi_conn->gen_pdu.resp_buf = NULL; 878c2ecf20Sopenharmony_ci } 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci if (qedi_conn->gen_pdu.req_buf) { 908c2ecf20Sopenharmony_ci dma_free_coherent(&qedi->pdev->dev, 918c2ecf20Sopenharmony_ci ISCSI_DEF_MAX_RECV_SEG_LEN, 928c2ecf20Sopenharmony_ci qedi_conn->gen_pdu.req_buf, 938c2ecf20Sopenharmony_ci qedi_conn->gen_pdu.req_dma_addr); 948c2ecf20Sopenharmony_ci qedi_conn->gen_pdu.req_buf = NULL; 958c2ecf20Sopenharmony_ci } 968c2ecf20Sopenharmony_ci} 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_cistatic int qedi_conn_alloc_login_resources(struct qedi_ctx *qedi, 998c2ecf20Sopenharmony_ci struct qedi_conn *qedi_conn) 1008c2ecf20Sopenharmony_ci{ 1018c2ecf20Sopenharmony_ci qedi_conn->gen_pdu.req_buf = 1028c2ecf20Sopenharmony_ci dma_alloc_coherent(&qedi->pdev->dev, 1038c2ecf20Sopenharmony_ci ISCSI_DEF_MAX_RECV_SEG_LEN, 1048c2ecf20Sopenharmony_ci &qedi_conn->gen_pdu.req_dma_addr, 1058c2ecf20Sopenharmony_ci GFP_KERNEL); 1068c2ecf20Sopenharmony_ci if (!qedi_conn->gen_pdu.req_buf) 1078c2ecf20Sopenharmony_ci goto login_req_buf_failure; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci qedi_conn->gen_pdu.req_buf_size = 0; 1108c2ecf20Sopenharmony_ci qedi_conn->gen_pdu.req_wr_ptr = qedi_conn->gen_pdu.req_buf; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci qedi_conn->gen_pdu.resp_buf = 1138c2ecf20Sopenharmony_ci dma_alloc_coherent(&qedi->pdev->dev, 1148c2ecf20Sopenharmony_ci ISCSI_DEF_MAX_RECV_SEG_LEN, 1158c2ecf20Sopenharmony_ci &qedi_conn->gen_pdu.resp_dma_addr, 1168c2ecf20Sopenharmony_ci GFP_KERNEL); 1178c2ecf20Sopenharmony_ci if (!qedi_conn->gen_pdu.resp_buf) 1188c2ecf20Sopenharmony_ci goto login_resp_buf_failure; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci qedi_conn->gen_pdu.resp_buf_size = ISCSI_DEF_MAX_RECV_SEG_LEN; 1218c2ecf20Sopenharmony_ci qedi_conn->gen_pdu.resp_wr_ptr = qedi_conn->gen_pdu.resp_buf; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci qedi_conn->gen_pdu.req_bd_tbl = 1248c2ecf20Sopenharmony_ci dma_alloc_coherent(&qedi->pdev->dev, QEDI_PAGE_SIZE, 1258c2ecf20Sopenharmony_ci &qedi_conn->gen_pdu.req_bd_dma, GFP_KERNEL); 1268c2ecf20Sopenharmony_ci if (!qedi_conn->gen_pdu.req_bd_tbl) 1278c2ecf20Sopenharmony_ci goto login_req_bd_tbl_failure; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci qedi_conn->gen_pdu.resp_bd_tbl = 1308c2ecf20Sopenharmony_ci dma_alloc_coherent(&qedi->pdev->dev, QEDI_PAGE_SIZE, 1318c2ecf20Sopenharmony_ci &qedi_conn->gen_pdu.resp_bd_dma, 1328c2ecf20Sopenharmony_ci GFP_KERNEL); 1338c2ecf20Sopenharmony_ci if (!qedi_conn->gen_pdu.resp_bd_tbl) 1348c2ecf20Sopenharmony_ci goto login_resp_bd_tbl_failure; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_SESS, 1378c2ecf20Sopenharmony_ci "Allocation successful, cid=0x%x\n", 1388c2ecf20Sopenharmony_ci qedi_conn->iscsi_conn_id); 1398c2ecf20Sopenharmony_ci return 0; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_cilogin_resp_bd_tbl_failure: 1428c2ecf20Sopenharmony_ci dma_free_coherent(&qedi->pdev->dev, QEDI_PAGE_SIZE, 1438c2ecf20Sopenharmony_ci qedi_conn->gen_pdu.req_bd_tbl, 1448c2ecf20Sopenharmony_ci qedi_conn->gen_pdu.req_bd_dma); 1458c2ecf20Sopenharmony_ci qedi_conn->gen_pdu.req_bd_tbl = NULL; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_cilogin_req_bd_tbl_failure: 1488c2ecf20Sopenharmony_ci dma_free_coherent(&qedi->pdev->dev, ISCSI_DEF_MAX_RECV_SEG_LEN, 1498c2ecf20Sopenharmony_ci qedi_conn->gen_pdu.resp_buf, 1508c2ecf20Sopenharmony_ci qedi_conn->gen_pdu.resp_dma_addr); 1518c2ecf20Sopenharmony_ci qedi_conn->gen_pdu.resp_buf = NULL; 1528c2ecf20Sopenharmony_cilogin_resp_buf_failure: 1538c2ecf20Sopenharmony_ci dma_free_coherent(&qedi->pdev->dev, ISCSI_DEF_MAX_RECV_SEG_LEN, 1548c2ecf20Sopenharmony_ci qedi_conn->gen_pdu.req_buf, 1558c2ecf20Sopenharmony_ci qedi_conn->gen_pdu.req_dma_addr); 1568c2ecf20Sopenharmony_ci qedi_conn->gen_pdu.req_buf = NULL; 1578c2ecf20Sopenharmony_cilogin_req_buf_failure: 1588c2ecf20Sopenharmony_ci iscsi_conn_printk(KERN_ERR, qedi_conn->cls_conn->dd_data, 1598c2ecf20Sopenharmony_ci "login resource alloc failed!!\n"); 1608c2ecf20Sopenharmony_ci return -ENOMEM; 1618c2ecf20Sopenharmony_ci} 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_cistatic void qedi_destroy_cmd_pool(struct qedi_ctx *qedi, 1648c2ecf20Sopenharmony_ci struct iscsi_session *session) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci int i; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci for (i = 0; i < session->cmds_max; i++) { 1698c2ecf20Sopenharmony_ci struct iscsi_task *task = session->cmds[i]; 1708c2ecf20Sopenharmony_ci struct qedi_cmd *cmd = task->dd_data; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci if (cmd->io_tbl.sge_tbl) 1738c2ecf20Sopenharmony_ci dma_free_coherent(&qedi->pdev->dev, 1748c2ecf20Sopenharmony_ci QEDI_ISCSI_MAX_BDS_PER_CMD * 1758c2ecf20Sopenharmony_ci sizeof(struct scsi_sge), 1768c2ecf20Sopenharmony_ci cmd->io_tbl.sge_tbl, 1778c2ecf20Sopenharmony_ci cmd->io_tbl.sge_tbl_dma); 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci if (cmd->sense_buffer) 1808c2ecf20Sopenharmony_ci dma_free_coherent(&qedi->pdev->dev, 1818c2ecf20Sopenharmony_ci SCSI_SENSE_BUFFERSIZE, 1828c2ecf20Sopenharmony_ci cmd->sense_buffer, 1838c2ecf20Sopenharmony_ci cmd->sense_buffer_dma); 1848c2ecf20Sopenharmony_ci } 1858c2ecf20Sopenharmony_ci} 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_cistatic int qedi_alloc_sget(struct qedi_ctx *qedi, struct iscsi_session *session, 1888c2ecf20Sopenharmony_ci struct qedi_cmd *cmd) 1898c2ecf20Sopenharmony_ci{ 1908c2ecf20Sopenharmony_ci struct qedi_io_bdt *io = &cmd->io_tbl; 1918c2ecf20Sopenharmony_ci struct scsi_sge *sge; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci io->sge_tbl = dma_alloc_coherent(&qedi->pdev->dev, 1948c2ecf20Sopenharmony_ci QEDI_ISCSI_MAX_BDS_PER_CMD * 1958c2ecf20Sopenharmony_ci sizeof(*sge), 1968c2ecf20Sopenharmony_ci &io->sge_tbl_dma, GFP_KERNEL); 1978c2ecf20Sopenharmony_ci if (!io->sge_tbl) { 1988c2ecf20Sopenharmony_ci iscsi_session_printk(KERN_ERR, session, 1998c2ecf20Sopenharmony_ci "Could not allocate BD table.\n"); 2008c2ecf20Sopenharmony_ci return -ENOMEM; 2018c2ecf20Sopenharmony_ci } 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci io->sge_valid = 0; 2048c2ecf20Sopenharmony_ci return 0; 2058c2ecf20Sopenharmony_ci} 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_cistatic int qedi_setup_cmd_pool(struct qedi_ctx *qedi, 2088c2ecf20Sopenharmony_ci struct iscsi_session *session) 2098c2ecf20Sopenharmony_ci{ 2108c2ecf20Sopenharmony_ci int i; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci for (i = 0; i < session->cmds_max; i++) { 2138c2ecf20Sopenharmony_ci struct iscsi_task *task = session->cmds[i]; 2148c2ecf20Sopenharmony_ci struct qedi_cmd *cmd = task->dd_data; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci task->hdr = &cmd->hdr; 2178c2ecf20Sopenharmony_ci task->hdr_max = sizeof(struct iscsi_hdr); 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci if (qedi_alloc_sget(qedi, session, cmd)) 2208c2ecf20Sopenharmony_ci goto free_sgets; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci cmd->sense_buffer = dma_alloc_coherent(&qedi->pdev->dev, 2238c2ecf20Sopenharmony_ci SCSI_SENSE_BUFFERSIZE, 2248c2ecf20Sopenharmony_ci &cmd->sense_buffer_dma, 2258c2ecf20Sopenharmony_ci GFP_KERNEL); 2268c2ecf20Sopenharmony_ci if (!cmd->sense_buffer) 2278c2ecf20Sopenharmony_ci goto free_sgets; 2288c2ecf20Sopenharmony_ci } 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci return 0; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_cifree_sgets: 2338c2ecf20Sopenharmony_ci qedi_destroy_cmd_pool(qedi, session); 2348c2ecf20Sopenharmony_ci return -ENOMEM; 2358c2ecf20Sopenharmony_ci} 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_cistatic struct iscsi_cls_session * 2388c2ecf20Sopenharmony_ciqedi_session_create(struct iscsi_endpoint *ep, u16 cmds_max, 2398c2ecf20Sopenharmony_ci u16 qdepth, uint32_t initial_cmdsn) 2408c2ecf20Sopenharmony_ci{ 2418c2ecf20Sopenharmony_ci struct Scsi_Host *shost; 2428c2ecf20Sopenharmony_ci struct iscsi_cls_session *cls_session; 2438c2ecf20Sopenharmony_ci struct qedi_ctx *qedi; 2448c2ecf20Sopenharmony_ci struct qedi_endpoint *qedi_ep; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci if (!ep) 2478c2ecf20Sopenharmony_ci return NULL; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci qedi_ep = ep->dd_data; 2508c2ecf20Sopenharmony_ci shost = qedi_ep->qedi->shost; 2518c2ecf20Sopenharmony_ci qedi = iscsi_host_priv(shost); 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci if (cmds_max > qedi->max_sqes) 2548c2ecf20Sopenharmony_ci cmds_max = qedi->max_sqes; 2558c2ecf20Sopenharmony_ci else if (cmds_max < QEDI_SQ_WQES_MIN) 2568c2ecf20Sopenharmony_ci cmds_max = QEDI_SQ_WQES_MIN; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci cls_session = iscsi_session_setup(&qedi_iscsi_transport, shost, 2598c2ecf20Sopenharmony_ci cmds_max, 0, sizeof(struct qedi_cmd), 2608c2ecf20Sopenharmony_ci initial_cmdsn, ISCSI_MAX_TARGET); 2618c2ecf20Sopenharmony_ci if (!cls_session) { 2628c2ecf20Sopenharmony_ci QEDI_ERR(&qedi->dbg_ctx, 2638c2ecf20Sopenharmony_ci "Failed to setup session for ep=%p\n", qedi_ep); 2648c2ecf20Sopenharmony_ci return NULL; 2658c2ecf20Sopenharmony_ci } 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci if (qedi_setup_cmd_pool(qedi, cls_session->dd_data)) { 2688c2ecf20Sopenharmony_ci QEDI_ERR(&qedi->dbg_ctx, 2698c2ecf20Sopenharmony_ci "Failed to setup cmd pool for ep=%p\n", qedi_ep); 2708c2ecf20Sopenharmony_ci goto session_teardown; 2718c2ecf20Sopenharmony_ci } 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci return cls_session; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_cisession_teardown: 2768c2ecf20Sopenharmony_ci iscsi_session_teardown(cls_session); 2778c2ecf20Sopenharmony_ci return NULL; 2788c2ecf20Sopenharmony_ci} 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_cistatic void qedi_session_destroy(struct iscsi_cls_session *cls_session) 2818c2ecf20Sopenharmony_ci{ 2828c2ecf20Sopenharmony_ci struct iscsi_session *session = cls_session->dd_data; 2838c2ecf20Sopenharmony_ci struct Scsi_Host *shost = iscsi_session_to_shost(cls_session); 2848c2ecf20Sopenharmony_ci struct qedi_ctx *qedi = iscsi_host_priv(shost); 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci qedi_destroy_cmd_pool(qedi, session); 2878c2ecf20Sopenharmony_ci iscsi_session_teardown(cls_session); 2888c2ecf20Sopenharmony_ci} 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_cistatic struct iscsi_cls_conn * 2918c2ecf20Sopenharmony_ciqedi_conn_create(struct iscsi_cls_session *cls_session, uint32_t cid) 2928c2ecf20Sopenharmony_ci{ 2938c2ecf20Sopenharmony_ci struct Scsi_Host *shost = iscsi_session_to_shost(cls_session); 2948c2ecf20Sopenharmony_ci struct qedi_ctx *qedi = iscsi_host_priv(shost); 2958c2ecf20Sopenharmony_ci struct iscsi_cls_conn *cls_conn; 2968c2ecf20Sopenharmony_ci struct qedi_conn *qedi_conn; 2978c2ecf20Sopenharmony_ci struct iscsi_conn *conn; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci cls_conn = iscsi_conn_setup(cls_session, sizeof(*qedi_conn), 3008c2ecf20Sopenharmony_ci cid); 3018c2ecf20Sopenharmony_ci if (!cls_conn) { 3028c2ecf20Sopenharmony_ci QEDI_ERR(&qedi->dbg_ctx, 3038c2ecf20Sopenharmony_ci "conn_new: iscsi conn setup failed, cid=0x%x, cls_sess=%p!\n", 3048c2ecf20Sopenharmony_ci cid, cls_session); 3058c2ecf20Sopenharmony_ci return NULL; 3068c2ecf20Sopenharmony_ci } 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci conn = cls_conn->dd_data; 3098c2ecf20Sopenharmony_ci qedi_conn = conn->dd_data; 3108c2ecf20Sopenharmony_ci qedi_conn->cls_conn = cls_conn; 3118c2ecf20Sopenharmony_ci qedi_conn->qedi = qedi; 3128c2ecf20Sopenharmony_ci qedi_conn->ep = NULL; 3138c2ecf20Sopenharmony_ci qedi_conn->active_cmd_count = 0; 3148c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&qedi_conn->active_cmd_list); 3158c2ecf20Sopenharmony_ci spin_lock_init(&qedi_conn->list_lock); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci if (qedi_conn_alloc_login_resources(qedi, qedi_conn)) { 3188c2ecf20Sopenharmony_ci iscsi_conn_printk(KERN_ALERT, conn, 3198c2ecf20Sopenharmony_ci "conn_new: login resc alloc failed, cid=0x%x, cls_sess=%p!!\n", 3208c2ecf20Sopenharmony_ci cid, cls_session); 3218c2ecf20Sopenharmony_ci goto free_conn; 3228c2ecf20Sopenharmony_ci } 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci return cls_conn; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_cifree_conn: 3278c2ecf20Sopenharmony_ci iscsi_conn_teardown(cls_conn); 3288c2ecf20Sopenharmony_ci return NULL; 3298c2ecf20Sopenharmony_ci} 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_civoid qedi_mark_device_missing(struct iscsi_cls_session *cls_session) 3328c2ecf20Sopenharmony_ci{ 3338c2ecf20Sopenharmony_ci struct iscsi_session *session = cls_session->dd_data; 3348c2ecf20Sopenharmony_ci struct qedi_conn *qedi_conn = session->leadconn->dd_data; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci spin_lock_bh(&session->frwd_lock); 3378c2ecf20Sopenharmony_ci set_bit(QEDI_BLOCK_IO, &qedi_conn->qedi->flags); 3388c2ecf20Sopenharmony_ci spin_unlock_bh(&session->frwd_lock); 3398c2ecf20Sopenharmony_ci} 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_civoid qedi_mark_device_available(struct iscsi_cls_session *cls_session) 3428c2ecf20Sopenharmony_ci{ 3438c2ecf20Sopenharmony_ci struct iscsi_session *session = cls_session->dd_data; 3448c2ecf20Sopenharmony_ci struct qedi_conn *qedi_conn = session->leadconn->dd_data; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci spin_lock_bh(&session->frwd_lock); 3478c2ecf20Sopenharmony_ci clear_bit(QEDI_BLOCK_IO, &qedi_conn->qedi->flags); 3488c2ecf20Sopenharmony_ci spin_unlock_bh(&session->frwd_lock); 3498c2ecf20Sopenharmony_ci} 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_cistatic int qedi_bind_conn_to_iscsi_cid(struct qedi_ctx *qedi, 3528c2ecf20Sopenharmony_ci struct qedi_conn *qedi_conn) 3538c2ecf20Sopenharmony_ci{ 3548c2ecf20Sopenharmony_ci u32 iscsi_cid = qedi_conn->iscsi_conn_id; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci if (qedi->cid_que.conn_cid_tbl[iscsi_cid]) { 3578c2ecf20Sopenharmony_ci iscsi_conn_printk(KERN_ALERT, qedi_conn->cls_conn->dd_data, 3588c2ecf20Sopenharmony_ci "conn bind - entry #%d not free\n", 3598c2ecf20Sopenharmony_ci iscsi_cid); 3608c2ecf20Sopenharmony_ci return -EBUSY; 3618c2ecf20Sopenharmony_ci } 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci qedi->cid_que.conn_cid_tbl[iscsi_cid] = qedi_conn; 3648c2ecf20Sopenharmony_ci return 0; 3658c2ecf20Sopenharmony_ci} 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_cistruct qedi_conn *qedi_get_conn_from_id(struct qedi_ctx *qedi, u32 iscsi_cid) 3688c2ecf20Sopenharmony_ci{ 3698c2ecf20Sopenharmony_ci if (!qedi->cid_que.conn_cid_tbl) { 3708c2ecf20Sopenharmony_ci QEDI_ERR(&qedi->dbg_ctx, "missing conn<->cid table\n"); 3718c2ecf20Sopenharmony_ci return NULL; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci } else if (iscsi_cid >= qedi->max_active_conns) { 3748c2ecf20Sopenharmony_ci QEDI_ERR(&qedi->dbg_ctx, "wrong cid #%d\n", iscsi_cid); 3758c2ecf20Sopenharmony_ci return NULL; 3768c2ecf20Sopenharmony_ci } 3778c2ecf20Sopenharmony_ci return qedi->cid_que.conn_cid_tbl[iscsi_cid]; 3788c2ecf20Sopenharmony_ci} 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_cistatic int qedi_conn_bind(struct iscsi_cls_session *cls_session, 3818c2ecf20Sopenharmony_ci struct iscsi_cls_conn *cls_conn, 3828c2ecf20Sopenharmony_ci u64 transport_fd, int is_leading) 3838c2ecf20Sopenharmony_ci{ 3848c2ecf20Sopenharmony_ci struct iscsi_conn *conn = cls_conn->dd_data; 3858c2ecf20Sopenharmony_ci struct qedi_conn *qedi_conn = conn->dd_data; 3868c2ecf20Sopenharmony_ci struct Scsi_Host *shost = iscsi_session_to_shost(cls_session); 3878c2ecf20Sopenharmony_ci struct qedi_ctx *qedi = iscsi_host_priv(shost); 3888c2ecf20Sopenharmony_ci struct qedi_endpoint *qedi_ep; 3898c2ecf20Sopenharmony_ci struct iscsi_endpoint *ep; 3908c2ecf20Sopenharmony_ci int rc = 0; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci ep = iscsi_lookup_endpoint(transport_fd); 3938c2ecf20Sopenharmony_ci if (!ep) 3948c2ecf20Sopenharmony_ci return -EINVAL; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci qedi_ep = ep->dd_data; 3978c2ecf20Sopenharmony_ci if ((qedi_ep->state == EP_STATE_TCP_FIN_RCVD) || 3988c2ecf20Sopenharmony_ci (qedi_ep->state == EP_STATE_TCP_RST_RCVD)) { 3998c2ecf20Sopenharmony_ci rc = -EINVAL; 4008c2ecf20Sopenharmony_ci goto put_ep; 4018c2ecf20Sopenharmony_ci } 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci if (iscsi_conn_bind(cls_session, cls_conn, is_leading)) { 4048c2ecf20Sopenharmony_ci rc = -EINVAL; 4058c2ecf20Sopenharmony_ci goto put_ep; 4068c2ecf20Sopenharmony_ci } 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci qedi_ep->conn = qedi_conn; 4108c2ecf20Sopenharmony_ci qedi_conn->ep = qedi_ep; 4118c2ecf20Sopenharmony_ci qedi_conn->iscsi_ep = ep; 4128c2ecf20Sopenharmony_ci qedi_conn->iscsi_conn_id = qedi_ep->iscsi_cid; 4138c2ecf20Sopenharmony_ci qedi_conn->fw_cid = qedi_ep->fw_cid; 4148c2ecf20Sopenharmony_ci qedi_conn->cmd_cleanup_req = 0; 4158c2ecf20Sopenharmony_ci qedi_conn->cmd_cleanup_cmpl = 0; 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci if (qedi_bind_conn_to_iscsi_cid(qedi, qedi_conn)) { 4188c2ecf20Sopenharmony_ci rc = -EINVAL; 4198c2ecf20Sopenharmony_ci goto put_ep; 4208c2ecf20Sopenharmony_ci } 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci spin_lock_init(&qedi_conn->tmf_work_lock); 4248c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&qedi_conn->tmf_work_list); 4258c2ecf20Sopenharmony_ci init_waitqueue_head(&qedi_conn->wait_queue); 4268c2ecf20Sopenharmony_ciput_ep: 4278c2ecf20Sopenharmony_ci iscsi_put_endpoint(ep); 4288c2ecf20Sopenharmony_ci return rc; 4298c2ecf20Sopenharmony_ci} 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_cistatic int qedi_iscsi_update_conn(struct qedi_ctx *qedi, 4328c2ecf20Sopenharmony_ci struct qedi_conn *qedi_conn) 4338c2ecf20Sopenharmony_ci{ 4348c2ecf20Sopenharmony_ci struct qed_iscsi_params_update *conn_info; 4358c2ecf20Sopenharmony_ci struct iscsi_cls_conn *cls_conn = qedi_conn->cls_conn; 4368c2ecf20Sopenharmony_ci struct iscsi_conn *conn = cls_conn->dd_data; 4378c2ecf20Sopenharmony_ci struct qedi_endpoint *qedi_ep; 4388c2ecf20Sopenharmony_ci int rval; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci qedi_ep = qedi_conn->ep; 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci conn_info = kzalloc(sizeof(*conn_info), GFP_KERNEL); 4438c2ecf20Sopenharmony_ci if (!conn_info) { 4448c2ecf20Sopenharmony_ci QEDI_ERR(&qedi->dbg_ctx, "memory alloc failed\n"); 4458c2ecf20Sopenharmony_ci return -ENOMEM; 4468c2ecf20Sopenharmony_ci } 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci conn_info->update_flag = 0; 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci if (conn->hdrdgst_en) 4518c2ecf20Sopenharmony_ci SET_FIELD(conn_info->update_flag, 4528c2ecf20Sopenharmony_ci ISCSI_CONN_UPDATE_RAMROD_PARAMS_HD_EN, true); 4538c2ecf20Sopenharmony_ci if (conn->datadgst_en) 4548c2ecf20Sopenharmony_ci SET_FIELD(conn_info->update_flag, 4558c2ecf20Sopenharmony_ci ISCSI_CONN_UPDATE_RAMROD_PARAMS_DD_EN, true); 4568c2ecf20Sopenharmony_ci if (conn->session->initial_r2t_en) 4578c2ecf20Sopenharmony_ci SET_FIELD(conn_info->update_flag, 4588c2ecf20Sopenharmony_ci ISCSI_CONN_UPDATE_RAMROD_PARAMS_INITIAL_R2T, 4598c2ecf20Sopenharmony_ci true); 4608c2ecf20Sopenharmony_ci if (conn->session->imm_data_en) 4618c2ecf20Sopenharmony_ci SET_FIELD(conn_info->update_flag, 4628c2ecf20Sopenharmony_ci ISCSI_CONN_UPDATE_RAMROD_PARAMS_IMMEDIATE_DATA, 4638c2ecf20Sopenharmony_ci true); 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci conn_info->max_seq_size = conn->session->max_burst; 4668c2ecf20Sopenharmony_ci conn_info->max_recv_pdu_length = conn->max_recv_dlength; 4678c2ecf20Sopenharmony_ci conn_info->max_send_pdu_length = conn->max_xmit_dlength; 4688c2ecf20Sopenharmony_ci conn_info->first_seq_length = conn->session->first_burst; 4698c2ecf20Sopenharmony_ci conn_info->exp_stat_sn = conn->exp_statsn; 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci rval = qedi_ops->update_conn(qedi->cdev, qedi_ep->handle, 4728c2ecf20Sopenharmony_ci conn_info); 4738c2ecf20Sopenharmony_ci if (rval) { 4748c2ecf20Sopenharmony_ci rval = -ENXIO; 4758c2ecf20Sopenharmony_ci QEDI_ERR(&qedi->dbg_ctx, "Could not update connection\n"); 4768c2ecf20Sopenharmony_ci } 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci kfree(conn_info); 4798c2ecf20Sopenharmony_ci return rval; 4808c2ecf20Sopenharmony_ci} 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_cistatic u16 qedi_calc_mss(u16 pmtu, u8 is_ipv6, u8 tcp_ts_en, u8 vlan_en) 4838c2ecf20Sopenharmony_ci{ 4848c2ecf20Sopenharmony_ci u16 mss = 0; 4858c2ecf20Sopenharmony_ci u16 hdrs = TCP_HDR_LEN; 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci if (is_ipv6) 4888c2ecf20Sopenharmony_ci hdrs += IPV6_HDR_LEN; 4898c2ecf20Sopenharmony_ci else 4908c2ecf20Sopenharmony_ci hdrs += IPV4_HDR_LEN; 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci mss = pmtu - hdrs; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci if (!mss) 4958c2ecf20Sopenharmony_ci mss = DEF_MSS; 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci return mss; 4988c2ecf20Sopenharmony_ci} 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_cistatic int qedi_iscsi_offload_conn(struct qedi_endpoint *qedi_ep) 5018c2ecf20Sopenharmony_ci{ 5028c2ecf20Sopenharmony_ci struct qedi_ctx *qedi = qedi_ep->qedi; 5038c2ecf20Sopenharmony_ci struct qed_iscsi_params_offload *conn_info; 5048c2ecf20Sopenharmony_ci int rval; 5058c2ecf20Sopenharmony_ci int i; 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci conn_info = kzalloc(sizeof(*conn_info), GFP_KERNEL); 5088c2ecf20Sopenharmony_ci if (!conn_info) { 5098c2ecf20Sopenharmony_ci QEDI_ERR(&qedi->dbg_ctx, 5108c2ecf20Sopenharmony_ci "Failed to allocate memory ep=%p\n", qedi_ep); 5118c2ecf20Sopenharmony_ci return -ENOMEM; 5128c2ecf20Sopenharmony_ci } 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci ether_addr_copy(conn_info->src.mac, qedi_ep->src_mac); 5158c2ecf20Sopenharmony_ci ether_addr_copy(conn_info->dst.mac, qedi_ep->dst_mac); 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci conn_info->src.ip[0] = ntohl(qedi_ep->src_addr[0]); 5188c2ecf20Sopenharmony_ci conn_info->dst.ip[0] = ntohl(qedi_ep->dst_addr[0]); 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci if (qedi_ep->ip_type == TCP_IPV4) { 5218c2ecf20Sopenharmony_ci conn_info->ip_version = 0; 5228c2ecf20Sopenharmony_ci QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN, 5238c2ecf20Sopenharmony_ci "After ntohl: src_addr=%pI4, dst_addr=%pI4\n", 5248c2ecf20Sopenharmony_ci qedi_ep->src_addr, qedi_ep->dst_addr); 5258c2ecf20Sopenharmony_ci } else { 5268c2ecf20Sopenharmony_ci for (i = 1; i < 4; i++) { 5278c2ecf20Sopenharmony_ci conn_info->src.ip[i] = ntohl(qedi_ep->src_addr[i]); 5288c2ecf20Sopenharmony_ci conn_info->dst.ip[i] = ntohl(qedi_ep->dst_addr[i]); 5298c2ecf20Sopenharmony_ci } 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci conn_info->ip_version = 1; 5328c2ecf20Sopenharmony_ci QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN, 5338c2ecf20Sopenharmony_ci "After ntohl: src_addr=%pI6, dst_addr=%pI6\n", 5348c2ecf20Sopenharmony_ci qedi_ep->src_addr, qedi_ep->dst_addr); 5358c2ecf20Sopenharmony_ci } 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci conn_info->src.port = qedi_ep->src_port; 5388c2ecf20Sopenharmony_ci conn_info->dst.port = qedi_ep->dst_port; 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci conn_info->layer_code = ISCSI_SLOW_PATH_LAYER_CODE; 5418c2ecf20Sopenharmony_ci conn_info->sq_pbl_addr = qedi_ep->sq_pbl_dma; 5428c2ecf20Sopenharmony_ci conn_info->vlan_id = qedi_ep->vlan_id; 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci SET_FIELD(conn_info->tcp_flags, TCP_OFFLOAD_PARAMS_TS_EN, 1); 5458c2ecf20Sopenharmony_ci SET_FIELD(conn_info->tcp_flags, TCP_OFFLOAD_PARAMS_DA_EN, 1); 5468c2ecf20Sopenharmony_ci SET_FIELD(conn_info->tcp_flags, TCP_OFFLOAD_PARAMS_DA_CNT_EN, 1); 5478c2ecf20Sopenharmony_ci SET_FIELD(conn_info->tcp_flags, TCP_OFFLOAD_PARAMS_KA_EN, 1); 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci conn_info->default_cq = (qedi_ep->fw_cid % qedi->num_queues); 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci conn_info->ka_max_probe_cnt = DEF_KA_MAX_PROBE_COUNT; 5528c2ecf20Sopenharmony_ci conn_info->dup_ack_theshold = 3; 5538c2ecf20Sopenharmony_ci conn_info->rcv_wnd = 65535; 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci conn_info->ss_thresh = 65535; 5568c2ecf20Sopenharmony_ci conn_info->srtt = 300; 5578c2ecf20Sopenharmony_ci conn_info->rtt_var = 150; 5588c2ecf20Sopenharmony_ci conn_info->flow_label = 0; 5598c2ecf20Sopenharmony_ci conn_info->ka_timeout = DEF_KA_TIMEOUT; 5608c2ecf20Sopenharmony_ci conn_info->ka_interval = DEF_KA_INTERVAL; 5618c2ecf20Sopenharmony_ci conn_info->max_rt_time = DEF_MAX_RT_TIME; 5628c2ecf20Sopenharmony_ci conn_info->ttl = DEF_TTL; 5638c2ecf20Sopenharmony_ci conn_info->tos_or_tc = DEF_TOS; 5648c2ecf20Sopenharmony_ci conn_info->remote_port = qedi_ep->dst_port; 5658c2ecf20Sopenharmony_ci conn_info->local_port = qedi_ep->src_port; 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci conn_info->mss = qedi_calc_mss(qedi_ep->pmtu, 5688c2ecf20Sopenharmony_ci (qedi_ep->ip_type == TCP_IPV6), 5698c2ecf20Sopenharmony_ci 1, (qedi_ep->vlan_id != 0)); 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci conn_info->cwnd = DEF_MAX_CWND * conn_info->mss; 5728c2ecf20Sopenharmony_ci conn_info->rcv_wnd_scale = 4; 5738c2ecf20Sopenharmony_ci conn_info->da_timeout_value = 200; 5748c2ecf20Sopenharmony_ci conn_info->ack_frequency = 2; 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, 5778c2ecf20Sopenharmony_ci "Default cq index [%d], mss [%d]\n", 5788c2ecf20Sopenharmony_ci conn_info->default_cq, conn_info->mss); 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci rval = qedi_ops->offload_conn(qedi->cdev, qedi_ep->handle, conn_info); 5818c2ecf20Sopenharmony_ci if (rval) 5828c2ecf20Sopenharmony_ci QEDI_ERR(&qedi->dbg_ctx, "offload_conn returned %d, ep=%p\n", 5838c2ecf20Sopenharmony_ci rval, qedi_ep); 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci kfree(conn_info); 5868c2ecf20Sopenharmony_ci return rval; 5878c2ecf20Sopenharmony_ci} 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_cistatic int qedi_conn_start(struct iscsi_cls_conn *cls_conn) 5908c2ecf20Sopenharmony_ci{ 5918c2ecf20Sopenharmony_ci struct iscsi_conn *conn = cls_conn->dd_data; 5928c2ecf20Sopenharmony_ci struct qedi_conn *qedi_conn = conn->dd_data; 5938c2ecf20Sopenharmony_ci struct qedi_ctx *qedi; 5948c2ecf20Sopenharmony_ci int rval; 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci qedi = qedi_conn->qedi; 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci rval = qedi_iscsi_update_conn(qedi, qedi_conn); 5998c2ecf20Sopenharmony_ci if (rval) { 6008c2ecf20Sopenharmony_ci iscsi_conn_printk(KERN_ALERT, conn, 6018c2ecf20Sopenharmony_ci "conn_start: FW offload conn failed.\n"); 6028c2ecf20Sopenharmony_ci rval = -EINVAL; 6038c2ecf20Sopenharmony_ci goto start_err; 6048c2ecf20Sopenharmony_ci } 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci clear_bit(QEDI_CONN_FW_CLEANUP, &qedi_conn->flags); 6078c2ecf20Sopenharmony_ci qedi_conn->abrt_conn = 0; 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci rval = iscsi_conn_start(cls_conn); 6108c2ecf20Sopenharmony_ci if (rval) { 6118c2ecf20Sopenharmony_ci iscsi_conn_printk(KERN_ALERT, conn, 6128c2ecf20Sopenharmony_ci "iscsi_conn_start: FW offload conn failed!!\n"); 6138c2ecf20Sopenharmony_ci } 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_cistart_err: 6168c2ecf20Sopenharmony_ci return rval; 6178c2ecf20Sopenharmony_ci} 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_cistatic void qedi_conn_destroy(struct iscsi_cls_conn *cls_conn) 6208c2ecf20Sopenharmony_ci{ 6218c2ecf20Sopenharmony_ci struct iscsi_conn *conn = cls_conn->dd_data; 6228c2ecf20Sopenharmony_ci struct qedi_conn *qedi_conn = conn->dd_data; 6238c2ecf20Sopenharmony_ci struct Scsi_Host *shost; 6248c2ecf20Sopenharmony_ci struct qedi_ctx *qedi; 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci shost = iscsi_session_to_shost(iscsi_conn_to_session(cls_conn)); 6278c2ecf20Sopenharmony_ci qedi = iscsi_host_priv(shost); 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci qedi_conn_free_login_resources(qedi, qedi_conn); 6308c2ecf20Sopenharmony_ci iscsi_conn_teardown(cls_conn); 6318c2ecf20Sopenharmony_ci} 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_cistatic int qedi_ep_get_param(struct iscsi_endpoint *ep, 6348c2ecf20Sopenharmony_ci enum iscsi_param param, char *buf) 6358c2ecf20Sopenharmony_ci{ 6368c2ecf20Sopenharmony_ci struct qedi_endpoint *qedi_ep = ep->dd_data; 6378c2ecf20Sopenharmony_ci int len; 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci if (!qedi_ep) 6408c2ecf20Sopenharmony_ci return -ENOTCONN; 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci switch (param) { 6438c2ecf20Sopenharmony_ci case ISCSI_PARAM_CONN_PORT: 6448c2ecf20Sopenharmony_ci len = sprintf(buf, "%hu\n", qedi_ep->dst_port); 6458c2ecf20Sopenharmony_ci break; 6468c2ecf20Sopenharmony_ci case ISCSI_PARAM_CONN_ADDRESS: 6478c2ecf20Sopenharmony_ci if (qedi_ep->ip_type == TCP_IPV4) 6488c2ecf20Sopenharmony_ci len = sprintf(buf, "%pI4\n", qedi_ep->dst_addr); 6498c2ecf20Sopenharmony_ci else 6508c2ecf20Sopenharmony_ci len = sprintf(buf, "%pI6\n", qedi_ep->dst_addr); 6518c2ecf20Sopenharmony_ci break; 6528c2ecf20Sopenharmony_ci default: 6538c2ecf20Sopenharmony_ci return -ENOTCONN; 6548c2ecf20Sopenharmony_ci } 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci return len; 6578c2ecf20Sopenharmony_ci} 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_cistatic int qedi_host_get_param(struct Scsi_Host *shost, 6608c2ecf20Sopenharmony_ci enum iscsi_host_param param, char *buf) 6618c2ecf20Sopenharmony_ci{ 6628c2ecf20Sopenharmony_ci struct qedi_ctx *qedi; 6638c2ecf20Sopenharmony_ci int len; 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci qedi = iscsi_host_priv(shost); 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci switch (param) { 6688c2ecf20Sopenharmony_ci case ISCSI_HOST_PARAM_HWADDRESS: 6698c2ecf20Sopenharmony_ci len = sysfs_format_mac(buf, qedi->mac, 6); 6708c2ecf20Sopenharmony_ci break; 6718c2ecf20Sopenharmony_ci case ISCSI_HOST_PARAM_NETDEV_NAME: 6728c2ecf20Sopenharmony_ci len = sprintf(buf, "host%d\n", shost->host_no); 6738c2ecf20Sopenharmony_ci break; 6748c2ecf20Sopenharmony_ci case ISCSI_HOST_PARAM_IPADDRESS: 6758c2ecf20Sopenharmony_ci if (qedi->ip_type == TCP_IPV4) 6768c2ecf20Sopenharmony_ci len = sprintf(buf, "%pI4\n", qedi->src_ip); 6778c2ecf20Sopenharmony_ci else 6788c2ecf20Sopenharmony_ci len = sprintf(buf, "%pI6\n", qedi->src_ip); 6798c2ecf20Sopenharmony_ci break; 6808c2ecf20Sopenharmony_ci default: 6818c2ecf20Sopenharmony_ci return iscsi_host_get_param(shost, param, buf); 6828c2ecf20Sopenharmony_ci } 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci return len; 6858c2ecf20Sopenharmony_ci} 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_cistatic void qedi_conn_get_stats(struct iscsi_cls_conn *cls_conn, 6888c2ecf20Sopenharmony_ci struct iscsi_stats *stats) 6898c2ecf20Sopenharmony_ci{ 6908c2ecf20Sopenharmony_ci struct iscsi_conn *conn = cls_conn->dd_data; 6918c2ecf20Sopenharmony_ci struct qed_iscsi_stats iscsi_stats; 6928c2ecf20Sopenharmony_ci struct Scsi_Host *shost; 6938c2ecf20Sopenharmony_ci struct qedi_ctx *qedi; 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci shost = iscsi_session_to_shost(iscsi_conn_to_session(cls_conn)); 6968c2ecf20Sopenharmony_ci qedi = iscsi_host_priv(shost); 6978c2ecf20Sopenharmony_ci qedi_ops->get_stats(qedi->cdev, &iscsi_stats); 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci conn->txdata_octets = iscsi_stats.iscsi_tx_bytes_cnt; 7008c2ecf20Sopenharmony_ci conn->rxdata_octets = iscsi_stats.iscsi_rx_bytes_cnt; 7018c2ecf20Sopenharmony_ci conn->dataout_pdus_cnt = (uint32_t)iscsi_stats.iscsi_tx_data_pdu_cnt; 7028c2ecf20Sopenharmony_ci conn->datain_pdus_cnt = (uint32_t)iscsi_stats.iscsi_rx_data_pdu_cnt; 7038c2ecf20Sopenharmony_ci conn->r2t_pdus_cnt = (uint32_t)iscsi_stats.iscsi_rx_r2t_pdu_cnt; 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci stats->txdata_octets = conn->txdata_octets; 7068c2ecf20Sopenharmony_ci stats->rxdata_octets = conn->rxdata_octets; 7078c2ecf20Sopenharmony_ci stats->scsicmd_pdus = conn->scsicmd_pdus_cnt; 7088c2ecf20Sopenharmony_ci stats->dataout_pdus = conn->dataout_pdus_cnt; 7098c2ecf20Sopenharmony_ci stats->scsirsp_pdus = conn->scsirsp_pdus_cnt; 7108c2ecf20Sopenharmony_ci stats->datain_pdus = conn->datain_pdus_cnt; 7118c2ecf20Sopenharmony_ci stats->r2t_pdus = conn->r2t_pdus_cnt; 7128c2ecf20Sopenharmony_ci stats->tmfcmd_pdus = conn->tmfcmd_pdus_cnt; 7138c2ecf20Sopenharmony_ci stats->tmfrsp_pdus = conn->tmfrsp_pdus_cnt; 7148c2ecf20Sopenharmony_ci stats->digest_err = 0; 7158c2ecf20Sopenharmony_ci stats->timeout_err = 0; 7168c2ecf20Sopenharmony_ci strcpy(stats->custom[0].desc, "eh_abort_cnt"); 7178c2ecf20Sopenharmony_ci stats->custom[0].value = conn->eh_abort_cnt; 7188c2ecf20Sopenharmony_ci stats->custom_length = 1; 7198c2ecf20Sopenharmony_ci} 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_cistatic void qedi_iscsi_prep_generic_pdu_bd(struct qedi_conn *qedi_conn) 7228c2ecf20Sopenharmony_ci{ 7238c2ecf20Sopenharmony_ci struct scsi_sge *bd_tbl; 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci bd_tbl = (struct scsi_sge *)qedi_conn->gen_pdu.req_bd_tbl; 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci bd_tbl->sge_addr.hi = 7288c2ecf20Sopenharmony_ci (u32)((u64)qedi_conn->gen_pdu.req_dma_addr >> 32); 7298c2ecf20Sopenharmony_ci bd_tbl->sge_addr.lo = (u32)qedi_conn->gen_pdu.req_dma_addr; 7308c2ecf20Sopenharmony_ci bd_tbl->sge_len = qedi_conn->gen_pdu.req_wr_ptr - 7318c2ecf20Sopenharmony_ci qedi_conn->gen_pdu.req_buf; 7328c2ecf20Sopenharmony_ci bd_tbl = (struct scsi_sge *)qedi_conn->gen_pdu.resp_bd_tbl; 7338c2ecf20Sopenharmony_ci bd_tbl->sge_addr.hi = 7348c2ecf20Sopenharmony_ci (u32)((u64)qedi_conn->gen_pdu.resp_dma_addr >> 32); 7358c2ecf20Sopenharmony_ci bd_tbl->sge_addr.lo = (u32)qedi_conn->gen_pdu.resp_dma_addr; 7368c2ecf20Sopenharmony_ci bd_tbl->sge_len = ISCSI_DEF_MAX_RECV_SEG_LEN; 7378c2ecf20Sopenharmony_ci} 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_cistatic int qedi_iscsi_send_generic_request(struct iscsi_task *task) 7408c2ecf20Sopenharmony_ci{ 7418c2ecf20Sopenharmony_ci struct qedi_cmd *cmd = task->dd_data; 7428c2ecf20Sopenharmony_ci struct qedi_conn *qedi_conn = cmd->conn; 7438c2ecf20Sopenharmony_ci char *buf; 7448c2ecf20Sopenharmony_ci int data_len; 7458c2ecf20Sopenharmony_ci int rc = 0; 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci qedi_iscsi_prep_generic_pdu_bd(qedi_conn); 7488c2ecf20Sopenharmony_ci switch (task->hdr->opcode & ISCSI_OPCODE_MASK) { 7498c2ecf20Sopenharmony_ci case ISCSI_OP_LOGIN: 7508c2ecf20Sopenharmony_ci qedi_send_iscsi_login(qedi_conn, task); 7518c2ecf20Sopenharmony_ci break; 7528c2ecf20Sopenharmony_ci case ISCSI_OP_NOOP_OUT: 7538c2ecf20Sopenharmony_ci data_len = qedi_conn->gen_pdu.req_buf_size; 7548c2ecf20Sopenharmony_ci buf = qedi_conn->gen_pdu.req_buf; 7558c2ecf20Sopenharmony_ci if (data_len) 7568c2ecf20Sopenharmony_ci rc = qedi_send_iscsi_nopout(qedi_conn, task, 7578c2ecf20Sopenharmony_ci buf, data_len, 1); 7588c2ecf20Sopenharmony_ci else 7598c2ecf20Sopenharmony_ci rc = qedi_send_iscsi_nopout(qedi_conn, task, 7608c2ecf20Sopenharmony_ci NULL, 0, 1); 7618c2ecf20Sopenharmony_ci break; 7628c2ecf20Sopenharmony_ci case ISCSI_OP_LOGOUT: 7638c2ecf20Sopenharmony_ci rc = qedi_send_iscsi_logout(qedi_conn, task); 7648c2ecf20Sopenharmony_ci break; 7658c2ecf20Sopenharmony_ci case ISCSI_OP_SCSI_TMFUNC: 7668c2ecf20Sopenharmony_ci rc = qedi_iscsi_abort_work(qedi_conn, task); 7678c2ecf20Sopenharmony_ci break; 7688c2ecf20Sopenharmony_ci case ISCSI_OP_TEXT: 7698c2ecf20Sopenharmony_ci rc = qedi_send_iscsi_text(qedi_conn, task); 7708c2ecf20Sopenharmony_ci break; 7718c2ecf20Sopenharmony_ci default: 7728c2ecf20Sopenharmony_ci iscsi_conn_printk(KERN_ALERT, qedi_conn->cls_conn->dd_data, 7738c2ecf20Sopenharmony_ci "unsupported op 0x%x\n", task->hdr->opcode); 7748c2ecf20Sopenharmony_ci } 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci return rc; 7778c2ecf20Sopenharmony_ci} 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_cistatic int qedi_mtask_xmit(struct iscsi_conn *conn, struct iscsi_task *task) 7808c2ecf20Sopenharmony_ci{ 7818c2ecf20Sopenharmony_ci struct qedi_conn *qedi_conn = conn->dd_data; 7828c2ecf20Sopenharmony_ci struct qedi_cmd *cmd = task->dd_data; 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci memset(qedi_conn->gen_pdu.req_buf, 0, ISCSI_DEF_MAX_RECV_SEG_LEN); 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci qedi_conn->gen_pdu.req_buf_size = task->data_count; 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci if (task->data_count) { 7898c2ecf20Sopenharmony_ci memcpy(qedi_conn->gen_pdu.req_buf, task->data, 7908c2ecf20Sopenharmony_ci task->data_count); 7918c2ecf20Sopenharmony_ci qedi_conn->gen_pdu.req_wr_ptr = 7928c2ecf20Sopenharmony_ci qedi_conn->gen_pdu.req_buf + task->data_count; 7938c2ecf20Sopenharmony_ci } 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci cmd->conn = conn->dd_data; 7968c2ecf20Sopenharmony_ci return qedi_iscsi_send_generic_request(task); 7978c2ecf20Sopenharmony_ci} 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_cistatic int qedi_task_xmit(struct iscsi_task *task) 8008c2ecf20Sopenharmony_ci{ 8018c2ecf20Sopenharmony_ci struct iscsi_conn *conn = task->conn; 8028c2ecf20Sopenharmony_ci struct qedi_conn *qedi_conn = conn->dd_data; 8038c2ecf20Sopenharmony_ci struct qedi_cmd *cmd = task->dd_data; 8048c2ecf20Sopenharmony_ci struct scsi_cmnd *sc = task->sc; 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci /* Clear now so in cleanup_task we know it didn't make it */ 8078c2ecf20Sopenharmony_ci cmd->scsi_cmd = NULL; 8088c2ecf20Sopenharmony_ci cmd->task_id = U16_MAX; 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci if (test_bit(QEDI_IN_SHUTDOWN, &qedi_conn->qedi->flags)) 8118c2ecf20Sopenharmony_ci return -ENODEV; 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_ci if (test_bit(QEDI_BLOCK_IO, &qedi_conn->qedi->flags)) 8148c2ecf20Sopenharmony_ci return -EACCES; 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci cmd->state = 0; 8178c2ecf20Sopenharmony_ci cmd->task = NULL; 8188c2ecf20Sopenharmony_ci cmd->use_slowpath = false; 8198c2ecf20Sopenharmony_ci cmd->conn = qedi_conn; 8208c2ecf20Sopenharmony_ci cmd->task = task; 8218c2ecf20Sopenharmony_ci cmd->io_cmd_in_list = false; 8228c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&cmd->io_cmd); 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci if (!sc) 8258c2ecf20Sopenharmony_ci return qedi_mtask_xmit(conn, task); 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci cmd->scsi_cmd = sc; 8288c2ecf20Sopenharmony_ci return qedi_iscsi_send_ioreq(task); 8298c2ecf20Sopenharmony_ci} 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_cistatic void qedi_offload_work(struct work_struct *work) 8328c2ecf20Sopenharmony_ci{ 8338c2ecf20Sopenharmony_ci struct qedi_endpoint *qedi_ep = 8348c2ecf20Sopenharmony_ci container_of(work, struct qedi_endpoint, offload_work); 8358c2ecf20Sopenharmony_ci struct qedi_ctx *qedi; 8368c2ecf20Sopenharmony_ci int wait_delay = 5 * HZ; 8378c2ecf20Sopenharmony_ci int ret; 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci qedi = qedi_ep->qedi; 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci ret = qedi_iscsi_offload_conn(qedi_ep); 8428c2ecf20Sopenharmony_ci if (ret) { 8438c2ecf20Sopenharmony_ci QEDI_ERR(&qedi->dbg_ctx, 8448c2ecf20Sopenharmony_ci "offload error: iscsi_cid=%u, qedi_ep=%p, ret=%d\n", 8458c2ecf20Sopenharmony_ci qedi_ep->iscsi_cid, qedi_ep, ret); 8468c2ecf20Sopenharmony_ci qedi_ep->state = EP_STATE_OFLDCONN_FAILED; 8478c2ecf20Sopenharmony_ci return; 8488c2ecf20Sopenharmony_ci } 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci ret = wait_event_interruptible_timeout(qedi_ep->tcp_ofld_wait, 8518c2ecf20Sopenharmony_ci (qedi_ep->state == 8528c2ecf20Sopenharmony_ci EP_STATE_OFLDCONN_COMPL), 8538c2ecf20Sopenharmony_ci wait_delay); 8548c2ecf20Sopenharmony_ci if (ret <= 0 || qedi_ep->state != EP_STATE_OFLDCONN_COMPL) { 8558c2ecf20Sopenharmony_ci qedi_ep->state = EP_STATE_OFLDCONN_FAILED; 8568c2ecf20Sopenharmony_ci QEDI_ERR(&qedi->dbg_ctx, 8578c2ecf20Sopenharmony_ci "Offload conn TIMEOUT iscsi_cid=%u, qedi_ep=%p\n", 8588c2ecf20Sopenharmony_ci qedi_ep->iscsi_cid, qedi_ep); 8598c2ecf20Sopenharmony_ci } 8608c2ecf20Sopenharmony_ci} 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_cistatic struct iscsi_endpoint * 8638c2ecf20Sopenharmony_ciqedi_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr, 8648c2ecf20Sopenharmony_ci int non_blocking) 8658c2ecf20Sopenharmony_ci{ 8668c2ecf20Sopenharmony_ci struct qedi_ctx *qedi; 8678c2ecf20Sopenharmony_ci struct iscsi_endpoint *ep; 8688c2ecf20Sopenharmony_ci struct qedi_endpoint *qedi_ep; 8698c2ecf20Sopenharmony_ci struct sockaddr_in *addr; 8708c2ecf20Sopenharmony_ci struct sockaddr_in6 *addr6; 8718c2ecf20Sopenharmony_ci struct iscsi_path path_req; 8728c2ecf20Sopenharmony_ci u32 msg_type = ISCSI_KEVENT_IF_DOWN; 8738c2ecf20Sopenharmony_ci u32 iscsi_cid = QEDI_CID_RESERVED; 8748c2ecf20Sopenharmony_ci u16 len = 0; 8758c2ecf20Sopenharmony_ci char *buf = NULL; 8768c2ecf20Sopenharmony_ci int ret, tmp; 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci if (!shost) { 8798c2ecf20Sopenharmony_ci ret = -ENXIO; 8808c2ecf20Sopenharmony_ci QEDI_ERR(NULL, "shost is NULL\n"); 8818c2ecf20Sopenharmony_ci return ERR_PTR(ret); 8828c2ecf20Sopenharmony_ci } 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci if (qedi_do_not_recover) { 8858c2ecf20Sopenharmony_ci ret = -ENOMEM; 8868c2ecf20Sopenharmony_ci return ERR_PTR(ret); 8878c2ecf20Sopenharmony_ci } 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci qedi = iscsi_host_priv(shost); 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci if (test_bit(QEDI_IN_OFFLINE, &qedi->flags) || 8928c2ecf20Sopenharmony_ci test_bit(QEDI_IN_RECOVERY, &qedi->flags)) { 8938c2ecf20Sopenharmony_ci ret = -ENOMEM; 8948c2ecf20Sopenharmony_ci return ERR_PTR(ret); 8958c2ecf20Sopenharmony_ci } 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci if (atomic_read(&qedi->link_state) != QEDI_LINK_UP) { 8988c2ecf20Sopenharmony_ci QEDI_WARN(&qedi->dbg_ctx, "qedi link down\n"); 8998c2ecf20Sopenharmony_ci return ERR_PTR(-ENXIO); 9008c2ecf20Sopenharmony_ci } 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci ep = iscsi_create_endpoint(sizeof(struct qedi_endpoint)); 9038c2ecf20Sopenharmony_ci if (!ep) { 9048c2ecf20Sopenharmony_ci QEDI_ERR(&qedi->dbg_ctx, "endpoint create fail\n"); 9058c2ecf20Sopenharmony_ci ret = -ENOMEM; 9068c2ecf20Sopenharmony_ci return ERR_PTR(ret); 9078c2ecf20Sopenharmony_ci } 9088c2ecf20Sopenharmony_ci qedi_ep = ep->dd_data; 9098c2ecf20Sopenharmony_ci memset(qedi_ep, 0, sizeof(struct qedi_endpoint)); 9108c2ecf20Sopenharmony_ci INIT_WORK(&qedi_ep->offload_work, qedi_offload_work); 9118c2ecf20Sopenharmony_ci qedi_ep->state = EP_STATE_IDLE; 9128c2ecf20Sopenharmony_ci qedi_ep->iscsi_cid = (u32)-1; 9138c2ecf20Sopenharmony_ci qedi_ep->qedi = qedi; 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci if (dst_addr->sa_family == AF_INET) { 9168c2ecf20Sopenharmony_ci addr = (struct sockaddr_in *)dst_addr; 9178c2ecf20Sopenharmony_ci memcpy(qedi_ep->dst_addr, &addr->sin_addr.s_addr, 9188c2ecf20Sopenharmony_ci sizeof(struct in_addr)); 9198c2ecf20Sopenharmony_ci qedi_ep->dst_port = ntohs(addr->sin_port); 9208c2ecf20Sopenharmony_ci qedi_ep->ip_type = TCP_IPV4; 9218c2ecf20Sopenharmony_ci QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN, 9228c2ecf20Sopenharmony_ci "dst_addr=%pI4, dst_port=%u\n", 9238c2ecf20Sopenharmony_ci qedi_ep->dst_addr, qedi_ep->dst_port); 9248c2ecf20Sopenharmony_ci } else if (dst_addr->sa_family == AF_INET6) { 9258c2ecf20Sopenharmony_ci addr6 = (struct sockaddr_in6 *)dst_addr; 9268c2ecf20Sopenharmony_ci memcpy(qedi_ep->dst_addr, &addr6->sin6_addr, 9278c2ecf20Sopenharmony_ci sizeof(struct in6_addr)); 9288c2ecf20Sopenharmony_ci qedi_ep->dst_port = ntohs(addr6->sin6_port); 9298c2ecf20Sopenharmony_ci qedi_ep->ip_type = TCP_IPV6; 9308c2ecf20Sopenharmony_ci QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN, 9318c2ecf20Sopenharmony_ci "dst_addr=%pI6, dst_port=%u\n", 9328c2ecf20Sopenharmony_ci qedi_ep->dst_addr, qedi_ep->dst_port); 9338c2ecf20Sopenharmony_ci } else { 9348c2ecf20Sopenharmony_ci QEDI_ERR(&qedi->dbg_ctx, "Invalid endpoint\n"); 9358c2ecf20Sopenharmony_ci } 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci ret = qedi_alloc_sq(qedi, qedi_ep); 9388c2ecf20Sopenharmony_ci if (ret) 9398c2ecf20Sopenharmony_ci goto ep_conn_exit; 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci ret = qedi_ops->acquire_conn(qedi->cdev, &qedi_ep->handle, 9428c2ecf20Sopenharmony_ci &qedi_ep->fw_cid, &qedi_ep->p_doorbell); 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci if (ret) { 9458c2ecf20Sopenharmony_ci QEDI_ERR(&qedi->dbg_ctx, "Could not acquire connection\n"); 9468c2ecf20Sopenharmony_ci ret = -ENXIO; 9478c2ecf20Sopenharmony_ci goto ep_free_sq; 9488c2ecf20Sopenharmony_ci } 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci iscsi_cid = qedi_ep->handle; 9518c2ecf20Sopenharmony_ci qedi_ep->iscsi_cid = iscsi_cid; 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci init_waitqueue_head(&qedi_ep->ofld_wait); 9548c2ecf20Sopenharmony_ci init_waitqueue_head(&qedi_ep->tcp_ofld_wait); 9558c2ecf20Sopenharmony_ci qedi_ep->state = EP_STATE_OFLDCONN_START; 9568c2ecf20Sopenharmony_ci qedi->ep_tbl[iscsi_cid] = qedi_ep; 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci buf = (char *)&path_req; 9598c2ecf20Sopenharmony_ci len = sizeof(path_req); 9608c2ecf20Sopenharmony_ci memset(&path_req, 0, len); 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci msg_type = ISCSI_KEVENT_PATH_REQ; 9638c2ecf20Sopenharmony_ci path_req.handle = (u64)qedi_ep->iscsi_cid; 9648c2ecf20Sopenharmony_ci path_req.pmtu = qedi->ll2_mtu; 9658c2ecf20Sopenharmony_ci qedi_ep->pmtu = qedi->ll2_mtu; 9668c2ecf20Sopenharmony_ci if (qedi_ep->ip_type == TCP_IPV4) { 9678c2ecf20Sopenharmony_ci memcpy(&path_req.dst.v4_addr, &qedi_ep->dst_addr, 9688c2ecf20Sopenharmony_ci sizeof(struct in_addr)); 9698c2ecf20Sopenharmony_ci path_req.ip_addr_len = 4; 9708c2ecf20Sopenharmony_ci } else { 9718c2ecf20Sopenharmony_ci memcpy(&path_req.dst.v6_addr, &qedi_ep->dst_addr, 9728c2ecf20Sopenharmony_ci sizeof(struct in6_addr)); 9738c2ecf20Sopenharmony_ci path_req.ip_addr_len = 16; 9748c2ecf20Sopenharmony_ci } 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci ret = iscsi_offload_mesg(shost, &qedi_iscsi_transport, msg_type, buf, 9778c2ecf20Sopenharmony_ci len); 9788c2ecf20Sopenharmony_ci if (ret) { 9798c2ecf20Sopenharmony_ci QEDI_ERR(&qedi->dbg_ctx, 9808c2ecf20Sopenharmony_ci "iscsi_offload_mesg() failed for cid=0x%x ret=%d\n", 9818c2ecf20Sopenharmony_ci iscsi_cid, ret); 9828c2ecf20Sopenharmony_ci goto ep_rel_conn; 9838c2ecf20Sopenharmony_ci } 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci atomic_inc(&qedi->num_offloads); 9868c2ecf20Sopenharmony_ci return ep; 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ciep_rel_conn: 9898c2ecf20Sopenharmony_ci qedi->ep_tbl[iscsi_cid] = NULL; 9908c2ecf20Sopenharmony_ci tmp = qedi_ops->release_conn(qedi->cdev, qedi_ep->handle); 9918c2ecf20Sopenharmony_ci if (tmp) 9928c2ecf20Sopenharmony_ci QEDI_WARN(&qedi->dbg_ctx, "release_conn returned %d\n", 9938c2ecf20Sopenharmony_ci tmp); 9948c2ecf20Sopenharmony_ciep_free_sq: 9958c2ecf20Sopenharmony_ci qedi_free_sq(qedi, qedi_ep); 9968c2ecf20Sopenharmony_ciep_conn_exit: 9978c2ecf20Sopenharmony_ci iscsi_destroy_endpoint(ep); 9988c2ecf20Sopenharmony_ci return ERR_PTR(ret); 9998c2ecf20Sopenharmony_ci} 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_cistatic int qedi_ep_poll(struct iscsi_endpoint *ep, int timeout_ms) 10028c2ecf20Sopenharmony_ci{ 10038c2ecf20Sopenharmony_ci struct qedi_endpoint *qedi_ep; 10048c2ecf20Sopenharmony_ci int ret = 0; 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci if (qedi_do_not_recover) 10078c2ecf20Sopenharmony_ci return 1; 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci qedi_ep = ep->dd_data; 10108c2ecf20Sopenharmony_ci if (qedi_ep->state == EP_STATE_IDLE || 10118c2ecf20Sopenharmony_ci qedi_ep->state == EP_STATE_OFLDCONN_NONE || 10128c2ecf20Sopenharmony_ci qedi_ep->state == EP_STATE_OFLDCONN_FAILED) 10138c2ecf20Sopenharmony_ci return -1; 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_ci if (qedi_ep->state == EP_STATE_OFLDCONN_COMPL) 10168c2ecf20Sopenharmony_ci ret = 1; 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ci ret = wait_event_interruptible_timeout(qedi_ep->ofld_wait, 10198c2ecf20Sopenharmony_ci QEDI_OFLD_WAIT_STATE(qedi_ep), 10208c2ecf20Sopenharmony_ci msecs_to_jiffies(timeout_ms)); 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_ci if (qedi_ep->state == EP_STATE_OFLDCONN_FAILED) 10238c2ecf20Sopenharmony_ci ret = -1; 10248c2ecf20Sopenharmony_ci 10258c2ecf20Sopenharmony_ci if (ret > 0) 10268c2ecf20Sopenharmony_ci return 1; 10278c2ecf20Sopenharmony_ci else if (!ret) 10288c2ecf20Sopenharmony_ci return 0; 10298c2ecf20Sopenharmony_ci else 10308c2ecf20Sopenharmony_ci return ret; 10318c2ecf20Sopenharmony_ci} 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_cistatic void qedi_cleanup_active_cmd_list(struct qedi_conn *qedi_conn) 10348c2ecf20Sopenharmony_ci{ 10358c2ecf20Sopenharmony_ci struct qedi_cmd *cmd, *cmd_tmp; 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci spin_lock(&qedi_conn->list_lock); 10388c2ecf20Sopenharmony_ci list_for_each_entry_safe(cmd, cmd_tmp, &qedi_conn->active_cmd_list, 10398c2ecf20Sopenharmony_ci io_cmd) { 10408c2ecf20Sopenharmony_ci list_del_init(&cmd->io_cmd); 10418c2ecf20Sopenharmony_ci qedi_conn->active_cmd_count--; 10428c2ecf20Sopenharmony_ci } 10438c2ecf20Sopenharmony_ci spin_unlock(&qedi_conn->list_lock); 10448c2ecf20Sopenharmony_ci} 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_cistatic void qedi_ep_disconnect(struct iscsi_endpoint *ep) 10478c2ecf20Sopenharmony_ci{ 10488c2ecf20Sopenharmony_ci struct qedi_endpoint *qedi_ep; 10498c2ecf20Sopenharmony_ci struct qedi_conn *qedi_conn = NULL; 10508c2ecf20Sopenharmony_ci struct iscsi_conn *conn = NULL; 10518c2ecf20Sopenharmony_ci struct qedi_ctx *qedi; 10528c2ecf20Sopenharmony_ci int ret = 0; 10538c2ecf20Sopenharmony_ci int wait_delay; 10548c2ecf20Sopenharmony_ci int abrt_conn = 0; 10558c2ecf20Sopenharmony_ci int count = 10; 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_ci wait_delay = 60 * HZ + DEF_MAX_RT_TIME; 10588c2ecf20Sopenharmony_ci qedi_ep = ep->dd_data; 10598c2ecf20Sopenharmony_ci qedi = qedi_ep->qedi; 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_ci flush_work(&qedi_ep->offload_work); 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci if (qedi_ep->state == EP_STATE_OFLDCONN_START) 10648c2ecf20Sopenharmony_ci goto ep_exit_recover; 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci if (qedi_ep->conn) { 10678c2ecf20Sopenharmony_ci qedi_conn = qedi_ep->conn; 10688c2ecf20Sopenharmony_ci conn = qedi_conn->cls_conn->dd_data; 10698c2ecf20Sopenharmony_ci iscsi_suspend_queue(conn); 10708c2ecf20Sopenharmony_ci abrt_conn = qedi_conn->abrt_conn; 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci while (count--) { 10738c2ecf20Sopenharmony_ci if (!test_bit(QEDI_CONN_FW_CLEANUP, 10748c2ecf20Sopenharmony_ci &qedi_conn->flags)) { 10758c2ecf20Sopenharmony_ci break; 10768c2ecf20Sopenharmony_ci } 10778c2ecf20Sopenharmony_ci msleep(1000); 10788c2ecf20Sopenharmony_ci } 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_ci if (test_bit(QEDI_IN_RECOVERY, &qedi->flags)) { 10818c2ecf20Sopenharmony_ci if (qedi_do_not_recover) { 10828c2ecf20Sopenharmony_ci QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, 10838c2ecf20Sopenharmony_ci "Do not recover cid=0x%x\n", 10848c2ecf20Sopenharmony_ci qedi_ep->iscsi_cid); 10858c2ecf20Sopenharmony_ci goto ep_exit_recover; 10868c2ecf20Sopenharmony_ci } 10878c2ecf20Sopenharmony_ci QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, 10888c2ecf20Sopenharmony_ci "Reset recovery cid=0x%x, qedi_ep=%p, state=0x%x\n", 10898c2ecf20Sopenharmony_ci qedi_ep->iscsi_cid, qedi_ep, qedi_ep->state); 10908c2ecf20Sopenharmony_ci qedi_cleanup_active_cmd_list(qedi_conn); 10918c2ecf20Sopenharmony_ci goto ep_release_conn; 10928c2ecf20Sopenharmony_ci } 10938c2ecf20Sopenharmony_ci } 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ci if (qedi_do_not_recover) 10968c2ecf20Sopenharmony_ci goto ep_exit_recover; 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci switch (qedi_ep->state) { 10998c2ecf20Sopenharmony_ci case EP_STATE_OFLDCONN_START: 11008c2ecf20Sopenharmony_ci case EP_STATE_OFLDCONN_NONE: 11018c2ecf20Sopenharmony_ci goto ep_release_conn; 11028c2ecf20Sopenharmony_ci case EP_STATE_OFLDCONN_FAILED: 11038c2ecf20Sopenharmony_ci break; 11048c2ecf20Sopenharmony_ci case EP_STATE_OFLDCONN_COMPL: 11058c2ecf20Sopenharmony_ci if (unlikely(!qedi_conn)) 11068c2ecf20Sopenharmony_ci break; 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, 11098c2ecf20Sopenharmony_ci "Active cmd count=%d, abrt_conn=%d, ep state=0x%x, cid=0x%x, qedi_conn=%p\n", 11108c2ecf20Sopenharmony_ci qedi_conn->active_cmd_count, abrt_conn, 11118c2ecf20Sopenharmony_ci qedi_ep->state, 11128c2ecf20Sopenharmony_ci qedi_ep->iscsi_cid, 11138c2ecf20Sopenharmony_ci qedi_ep->conn 11148c2ecf20Sopenharmony_ci ); 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci if (!qedi_conn->active_cmd_count) 11178c2ecf20Sopenharmony_ci abrt_conn = 0; 11188c2ecf20Sopenharmony_ci else 11198c2ecf20Sopenharmony_ci abrt_conn = 1; 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci if (abrt_conn) 11228c2ecf20Sopenharmony_ci qedi_clearsq(qedi, qedi_conn, NULL); 11238c2ecf20Sopenharmony_ci break; 11248c2ecf20Sopenharmony_ci default: 11258c2ecf20Sopenharmony_ci break; 11268c2ecf20Sopenharmony_ci } 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_ci if (!abrt_conn) 11298c2ecf20Sopenharmony_ci wait_delay += qedi->pf_params.iscsi_pf_params.two_msl_timer; 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci qedi_ep->state = EP_STATE_DISCONN_START; 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_ci if (test_bit(QEDI_IN_SHUTDOWN, &qedi->flags) || 11348c2ecf20Sopenharmony_ci test_bit(QEDI_IN_RECOVERY, &qedi->flags)) 11358c2ecf20Sopenharmony_ci goto ep_release_conn; 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_ci ret = qedi_ops->destroy_conn(qedi->cdev, qedi_ep->handle, abrt_conn); 11388c2ecf20Sopenharmony_ci if (ret) { 11398c2ecf20Sopenharmony_ci QEDI_WARN(&qedi->dbg_ctx, 11408c2ecf20Sopenharmony_ci "destroy_conn failed returned %d\n", ret); 11418c2ecf20Sopenharmony_ci } else { 11428c2ecf20Sopenharmony_ci ret = wait_event_interruptible_timeout( 11438c2ecf20Sopenharmony_ci qedi_ep->tcp_ofld_wait, 11448c2ecf20Sopenharmony_ci (qedi_ep->state != 11458c2ecf20Sopenharmony_ci EP_STATE_DISCONN_START), 11468c2ecf20Sopenharmony_ci wait_delay); 11478c2ecf20Sopenharmony_ci if ((ret <= 0) || (qedi_ep->state == EP_STATE_DISCONN_START)) { 11488c2ecf20Sopenharmony_ci QEDI_WARN(&qedi->dbg_ctx, 11498c2ecf20Sopenharmony_ci "Destroy conn timedout or interrupted, ret=%d, delay=%d, cid=0x%x\n", 11508c2ecf20Sopenharmony_ci ret, wait_delay, qedi_ep->iscsi_cid); 11518c2ecf20Sopenharmony_ci } 11528c2ecf20Sopenharmony_ci } 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_ciep_release_conn: 11558c2ecf20Sopenharmony_ci ret = qedi_ops->release_conn(qedi->cdev, qedi_ep->handle); 11568c2ecf20Sopenharmony_ci if (ret) 11578c2ecf20Sopenharmony_ci QEDI_WARN(&qedi->dbg_ctx, 11588c2ecf20Sopenharmony_ci "release_conn returned %d, cid=0x%x\n", 11598c2ecf20Sopenharmony_ci ret, qedi_ep->iscsi_cid); 11608c2ecf20Sopenharmony_ciep_exit_recover: 11618c2ecf20Sopenharmony_ci qedi_ep->state = EP_STATE_IDLE; 11628c2ecf20Sopenharmony_ci qedi->ep_tbl[qedi_ep->iscsi_cid] = NULL; 11638c2ecf20Sopenharmony_ci qedi->cid_que.conn_cid_tbl[qedi_ep->iscsi_cid] = NULL; 11648c2ecf20Sopenharmony_ci qedi_free_id(&qedi->lcl_port_tbl, qedi_ep->src_port); 11658c2ecf20Sopenharmony_ci qedi_free_sq(qedi, qedi_ep); 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci if (qedi_conn) 11688c2ecf20Sopenharmony_ci qedi_conn->ep = NULL; 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci qedi_ep->conn = NULL; 11718c2ecf20Sopenharmony_ci qedi_ep->qedi = NULL; 11728c2ecf20Sopenharmony_ci atomic_dec(&qedi->num_offloads); 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_ci iscsi_destroy_endpoint(ep); 11758c2ecf20Sopenharmony_ci} 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_cistatic int qedi_data_avail(struct qedi_ctx *qedi, u16 vlanid) 11788c2ecf20Sopenharmony_ci{ 11798c2ecf20Sopenharmony_ci struct qed_dev *cdev = qedi->cdev; 11808c2ecf20Sopenharmony_ci struct qedi_uio_dev *udev; 11818c2ecf20Sopenharmony_ci struct qedi_uio_ctrl *uctrl; 11828c2ecf20Sopenharmony_ci struct sk_buff *skb; 11838c2ecf20Sopenharmony_ci u32 len; 11848c2ecf20Sopenharmony_ci int rc = 0; 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_ci udev = qedi->udev; 11878c2ecf20Sopenharmony_ci if (!udev) { 11888c2ecf20Sopenharmony_ci QEDI_ERR(&qedi->dbg_ctx, "udev is NULL.\n"); 11898c2ecf20Sopenharmony_ci return -EINVAL; 11908c2ecf20Sopenharmony_ci } 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_ci uctrl = (struct qedi_uio_ctrl *)udev->uctrl; 11938c2ecf20Sopenharmony_ci if (!uctrl) { 11948c2ecf20Sopenharmony_ci QEDI_ERR(&qedi->dbg_ctx, "uctlr is NULL.\n"); 11958c2ecf20Sopenharmony_ci return -EINVAL; 11968c2ecf20Sopenharmony_ci } 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ci len = uctrl->host_tx_pkt_len; 11998c2ecf20Sopenharmony_ci if (!len) { 12008c2ecf20Sopenharmony_ci QEDI_ERR(&qedi->dbg_ctx, "Invalid len %u\n", len); 12018c2ecf20Sopenharmony_ci return -EINVAL; 12028c2ecf20Sopenharmony_ci } 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci skb = alloc_skb(len, GFP_ATOMIC); 12058c2ecf20Sopenharmony_ci if (!skb) { 12068c2ecf20Sopenharmony_ci QEDI_ERR(&qedi->dbg_ctx, "alloc_skb failed\n"); 12078c2ecf20Sopenharmony_ci return -EINVAL; 12088c2ecf20Sopenharmony_ci } 12098c2ecf20Sopenharmony_ci 12108c2ecf20Sopenharmony_ci skb_put(skb, len); 12118c2ecf20Sopenharmony_ci memcpy(skb->data, udev->tx_pkt, len); 12128c2ecf20Sopenharmony_ci skb->ip_summed = CHECKSUM_NONE; 12138c2ecf20Sopenharmony_ci 12148c2ecf20Sopenharmony_ci if (vlanid) 12158c2ecf20Sopenharmony_ci __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlanid); 12168c2ecf20Sopenharmony_ci 12178c2ecf20Sopenharmony_ci rc = qedi_ops->ll2->start_xmit(cdev, skb, 0); 12188c2ecf20Sopenharmony_ci if (rc) { 12198c2ecf20Sopenharmony_ci QEDI_ERR(&qedi->dbg_ctx, "ll2 start_xmit returned %d\n", 12208c2ecf20Sopenharmony_ci rc); 12218c2ecf20Sopenharmony_ci kfree_skb(skb); 12228c2ecf20Sopenharmony_ci } 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_ci uctrl->host_tx_pkt_len = 0; 12258c2ecf20Sopenharmony_ci uctrl->hw_tx_cons++; 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_ci return rc; 12288c2ecf20Sopenharmony_ci} 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_cistatic int qedi_set_path(struct Scsi_Host *shost, struct iscsi_path *path_data) 12318c2ecf20Sopenharmony_ci{ 12328c2ecf20Sopenharmony_ci struct qedi_ctx *qedi; 12338c2ecf20Sopenharmony_ci struct qedi_endpoint *qedi_ep; 12348c2ecf20Sopenharmony_ci int ret = 0; 12358c2ecf20Sopenharmony_ci u32 iscsi_cid; 12368c2ecf20Sopenharmony_ci u16 port_id = 0; 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_ci if (!shost) { 12398c2ecf20Sopenharmony_ci ret = -ENXIO; 12408c2ecf20Sopenharmony_ci QEDI_ERR(NULL, "shost is NULL\n"); 12418c2ecf20Sopenharmony_ci return ret; 12428c2ecf20Sopenharmony_ci } 12438c2ecf20Sopenharmony_ci 12448c2ecf20Sopenharmony_ci if (strcmp(shost->hostt->proc_name, "qedi")) { 12458c2ecf20Sopenharmony_ci ret = -ENXIO; 12468c2ecf20Sopenharmony_ci QEDI_ERR(NULL, "shost %s is invalid\n", 12478c2ecf20Sopenharmony_ci shost->hostt->proc_name); 12488c2ecf20Sopenharmony_ci return ret; 12498c2ecf20Sopenharmony_ci } 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_ci qedi = iscsi_host_priv(shost); 12528c2ecf20Sopenharmony_ci if (path_data->handle == QEDI_PATH_HANDLE) { 12538c2ecf20Sopenharmony_ci ret = qedi_data_avail(qedi, path_data->vlan_id); 12548c2ecf20Sopenharmony_ci goto set_path_exit; 12558c2ecf20Sopenharmony_ci } 12568c2ecf20Sopenharmony_ci 12578c2ecf20Sopenharmony_ci iscsi_cid = (u32)path_data->handle; 12588c2ecf20Sopenharmony_ci if (iscsi_cid >= qedi->max_active_conns) { 12598c2ecf20Sopenharmony_ci ret = -EINVAL; 12608c2ecf20Sopenharmony_ci goto set_path_exit; 12618c2ecf20Sopenharmony_ci } 12628c2ecf20Sopenharmony_ci qedi_ep = qedi->ep_tbl[iscsi_cid]; 12638c2ecf20Sopenharmony_ci QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, 12648c2ecf20Sopenharmony_ci "iscsi_cid=0x%x, qedi_ep=%p\n", iscsi_cid, qedi_ep); 12658c2ecf20Sopenharmony_ci if (!qedi_ep) { 12668c2ecf20Sopenharmony_ci ret = -EINVAL; 12678c2ecf20Sopenharmony_ci goto set_path_exit; 12688c2ecf20Sopenharmony_ci } 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_ci if (!is_valid_ether_addr(&path_data->mac_addr[0])) { 12718c2ecf20Sopenharmony_ci QEDI_NOTICE(&qedi->dbg_ctx, "dst mac NOT VALID\n"); 12728c2ecf20Sopenharmony_ci qedi_ep->state = EP_STATE_OFLDCONN_NONE; 12738c2ecf20Sopenharmony_ci ret = -EIO; 12748c2ecf20Sopenharmony_ci goto set_path_exit; 12758c2ecf20Sopenharmony_ci } 12768c2ecf20Sopenharmony_ci 12778c2ecf20Sopenharmony_ci ether_addr_copy(&qedi_ep->src_mac[0], &qedi->mac[0]); 12788c2ecf20Sopenharmony_ci ether_addr_copy(&qedi_ep->dst_mac[0], &path_data->mac_addr[0]); 12798c2ecf20Sopenharmony_ci 12808c2ecf20Sopenharmony_ci qedi_ep->vlan_id = path_data->vlan_id; 12818c2ecf20Sopenharmony_ci if (path_data->pmtu < DEF_PATH_MTU) { 12828c2ecf20Sopenharmony_ci qedi_ep->pmtu = qedi->ll2_mtu; 12838c2ecf20Sopenharmony_ci QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, 12848c2ecf20Sopenharmony_ci "MTU cannot be %u, using default MTU %u\n", 12858c2ecf20Sopenharmony_ci path_data->pmtu, qedi_ep->pmtu); 12868c2ecf20Sopenharmony_ci } 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_ci if (path_data->pmtu != qedi->ll2_mtu) { 12898c2ecf20Sopenharmony_ci if (path_data->pmtu > JUMBO_MTU) { 12908c2ecf20Sopenharmony_ci ret = -EINVAL; 12918c2ecf20Sopenharmony_ci QEDI_ERR(NULL, "Invalid MTU %u\n", path_data->pmtu); 12928c2ecf20Sopenharmony_ci goto set_path_exit; 12938c2ecf20Sopenharmony_ci } 12948c2ecf20Sopenharmony_ci 12958c2ecf20Sopenharmony_ci qedi_reset_host_mtu(qedi, path_data->pmtu); 12968c2ecf20Sopenharmony_ci qedi_ep->pmtu = qedi->ll2_mtu; 12978c2ecf20Sopenharmony_ci } 12988c2ecf20Sopenharmony_ci 12998c2ecf20Sopenharmony_ci port_id = qedi_ep->src_port; 13008c2ecf20Sopenharmony_ci if (port_id >= QEDI_LOCAL_PORT_MIN && 13018c2ecf20Sopenharmony_ci port_id < QEDI_LOCAL_PORT_MAX) { 13028c2ecf20Sopenharmony_ci if (qedi_alloc_id(&qedi->lcl_port_tbl, port_id)) 13038c2ecf20Sopenharmony_ci port_id = 0; 13048c2ecf20Sopenharmony_ci } else { 13058c2ecf20Sopenharmony_ci port_id = 0; 13068c2ecf20Sopenharmony_ci } 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_ci if (!port_id) { 13098c2ecf20Sopenharmony_ci port_id = qedi_alloc_new_id(&qedi->lcl_port_tbl); 13108c2ecf20Sopenharmony_ci if (port_id == QEDI_LOCAL_PORT_INVALID) { 13118c2ecf20Sopenharmony_ci QEDI_ERR(&qedi->dbg_ctx, 13128c2ecf20Sopenharmony_ci "Failed to allocate port id for iscsi_cid=0x%x\n", 13138c2ecf20Sopenharmony_ci iscsi_cid); 13148c2ecf20Sopenharmony_ci ret = -ENOMEM; 13158c2ecf20Sopenharmony_ci goto set_path_exit; 13168c2ecf20Sopenharmony_ci } 13178c2ecf20Sopenharmony_ci } 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_ci qedi_ep->src_port = port_id; 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_ci if (qedi_ep->ip_type == TCP_IPV4) { 13228c2ecf20Sopenharmony_ci memcpy(&qedi_ep->src_addr[0], &path_data->src.v4_addr, 13238c2ecf20Sopenharmony_ci sizeof(struct in_addr)); 13248c2ecf20Sopenharmony_ci memcpy(&qedi->src_ip[0], &path_data->src.v4_addr, 13258c2ecf20Sopenharmony_ci sizeof(struct in_addr)); 13268c2ecf20Sopenharmony_ci qedi->ip_type = TCP_IPV4; 13278c2ecf20Sopenharmony_ci 13288c2ecf20Sopenharmony_ci QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN, 13298c2ecf20Sopenharmony_ci "src addr:port=%pI4:%u, dst addr:port=%pI4:%u\n", 13308c2ecf20Sopenharmony_ci qedi_ep->src_addr, qedi_ep->src_port, 13318c2ecf20Sopenharmony_ci qedi_ep->dst_addr, qedi_ep->dst_port); 13328c2ecf20Sopenharmony_ci } else { 13338c2ecf20Sopenharmony_ci memcpy(&qedi_ep->src_addr[0], &path_data->src.v6_addr, 13348c2ecf20Sopenharmony_ci sizeof(struct in6_addr)); 13358c2ecf20Sopenharmony_ci memcpy(&qedi->src_ip[0], &path_data->src.v6_addr, 13368c2ecf20Sopenharmony_ci sizeof(struct in6_addr)); 13378c2ecf20Sopenharmony_ci qedi->ip_type = TCP_IPV6; 13388c2ecf20Sopenharmony_ci 13398c2ecf20Sopenharmony_ci QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN, 13408c2ecf20Sopenharmony_ci "src addr:port=%pI6:%u, dst addr:port=%pI6:%u\n", 13418c2ecf20Sopenharmony_ci qedi_ep->src_addr, qedi_ep->src_port, 13428c2ecf20Sopenharmony_ci qedi_ep->dst_addr, qedi_ep->dst_port); 13438c2ecf20Sopenharmony_ci } 13448c2ecf20Sopenharmony_ci 13458c2ecf20Sopenharmony_ci queue_work(qedi->offload_thread, &qedi_ep->offload_work); 13468c2ecf20Sopenharmony_ci 13478c2ecf20Sopenharmony_ci ret = 0; 13488c2ecf20Sopenharmony_ci 13498c2ecf20Sopenharmony_ciset_path_exit: 13508c2ecf20Sopenharmony_ci return ret; 13518c2ecf20Sopenharmony_ci} 13528c2ecf20Sopenharmony_ci 13538c2ecf20Sopenharmony_cistatic umode_t qedi_attr_is_visible(int param_type, int param) 13548c2ecf20Sopenharmony_ci{ 13558c2ecf20Sopenharmony_ci switch (param_type) { 13568c2ecf20Sopenharmony_ci case ISCSI_HOST_PARAM: 13578c2ecf20Sopenharmony_ci switch (param) { 13588c2ecf20Sopenharmony_ci case ISCSI_HOST_PARAM_NETDEV_NAME: 13598c2ecf20Sopenharmony_ci case ISCSI_HOST_PARAM_HWADDRESS: 13608c2ecf20Sopenharmony_ci case ISCSI_HOST_PARAM_IPADDRESS: 13618c2ecf20Sopenharmony_ci return 0444; 13628c2ecf20Sopenharmony_ci default: 13638c2ecf20Sopenharmony_ci return 0; 13648c2ecf20Sopenharmony_ci } 13658c2ecf20Sopenharmony_ci case ISCSI_PARAM: 13668c2ecf20Sopenharmony_ci switch (param) { 13678c2ecf20Sopenharmony_ci case ISCSI_PARAM_MAX_RECV_DLENGTH: 13688c2ecf20Sopenharmony_ci case ISCSI_PARAM_MAX_XMIT_DLENGTH: 13698c2ecf20Sopenharmony_ci case ISCSI_PARAM_HDRDGST_EN: 13708c2ecf20Sopenharmony_ci case ISCSI_PARAM_DATADGST_EN: 13718c2ecf20Sopenharmony_ci case ISCSI_PARAM_CONN_ADDRESS: 13728c2ecf20Sopenharmony_ci case ISCSI_PARAM_CONN_PORT: 13738c2ecf20Sopenharmony_ci case ISCSI_PARAM_EXP_STATSN: 13748c2ecf20Sopenharmony_ci case ISCSI_PARAM_PERSISTENT_ADDRESS: 13758c2ecf20Sopenharmony_ci case ISCSI_PARAM_PERSISTENT_PORT: 13768c2ecf20Sopenharmony_ci case ISCSI_PARAM_PING_TMO: 13778c2ecf20Sopenharmony_ci case ISCSI_PARAM_RECV_TMO: 13788c2ecf20Sopenharmony_ci case ISCSI_PARAM_INITIAL_R2T_EN: 13798c2ecf20Sopenharmony_ci case ISCSI_PARAM_MAX_R2T: 13808c2ecf20Sopenharmony_ci case ISCSI_PARAM_IMM_DATA_EN: 13818c2ecf20Sopenharmony_ci case ISCSI_PARAM_FIRST_BURST: 13828c2ecf20Sopenharmony_ci case ISCSI_PARAM_MAX_BURST: 13838c2ecf20Sopenharmony_ci case ISCSI_PARAM_PDU_INORDER_EN: 13848c2ecf20Sopenharmony_ci case ISCSI_PARAM_DATASEQ_INORDER_EN: 13858c2ecf20Sopenharmony_ci case ISCSI_PARAM_ERL: 13868c2ecf20Sopenharmony_ci case ISCSI_PARAM_TARGET_NAME: 13878c2ecf20Sopenharmony_ci case ISCSI_PARAM_TPGT: 13888c2ecf20Sopenharmony_ci case ISCSI_PARAM_USERNAME: 13898c2ecf20Sopenharmony_ci case ISCSI_PARAM_PASSWORD: 13908c2ecf20Sopenharmony_ci case ISCSI_PARAM_USERNAME_IN: 13918c2ecf20Sopenharmony_ci case ISCSI_PARAM_PASSWORD_IN: 13928c2ecf20Sopenharmony_ci case ISCSI_PARAM_FAST_ABORT: 13938c2ecf20Sopenharmony_ci case ISCSI_PARAM_ABORT_TMO: 13948c2ecf20Sopenharmony_ci case ISCSI_PARAM_LU_RESET_TMO: 13958c2ecf20Sopenharmony_ci case ISCSI_PARAM_TGT_RESET_TMO: 13968c2ecf20Sopenharmony_ci case ISCSI_PARAM_IFACE_NAME: 13978c2ecf20Sopenharmony_ci case ISCSI_PARAM_INITIATOR_NAME: 13988c2ecf20Sopenharmony_ci case ISCSI_PARAM_BOOT_ROOT: 13998c2ecf20Sopenharmony_ci case ISCSI_PARAM_BOOT_NIC: 14008c2ecf20Sopenharmony_ci case ISCSI_PARAM_BOOT_TARGET: 14018c2ecf20Sopenharmony_ci return 0444; 14028c2ecf20Sopenharmony_ci default: 14038c2ecf20Sopenharmony_ci return 0; 14048c2ecf20Sopenharmony_ci } 14058c2ecf20Sopenharmony_ci } 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_ci return 0; 14088c2ecf20Sopenharmony_ci} 14098c2ecf20Sopenharmony_ci 14108c2ecf20Sopenharmony_cistatic void qedi_cleanup_task(struct iscsi_task *task) 14118c2ecf20Sopenharmony_ci{ 14128c2ecf20Sopenharmony_ci struct qedi_cmd *cmd; 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_ci if (task->state == ISCSI_TASK_PENDING) { 14158c2ecf20Sopenharmony_ci QEDI_INFO(NULL, QEDI_LOG_IO, "Returning ref_cnt=%d\n", 14168c2ecf20Sopenharmony_ci refcount_read(&task->refcount)); 14178c2ecf20Sopenharmony_ci return; 14188c2ecf20Sopenharmony_ci } 14198c2ecf20Sopenharmony_ci 14208c2ecf20Sopenharmony_ci if (task->sc) 14218c2ecf20Sopenharmony_ci qedi_iscsi_unmap_sg_list(task->dd_data); 14228c2ecf20Sopenharmony_ci 14238c2ecf20Sopenharmony_ci cmd = task->dd_data; 14248c2ecf20Sopenharmony_ci if (cmd->task_id != U16_MAX) 14258c2ecf20Sopenharmony_ci qedi_clear_task_idx(iscsi_host_priv(task->conn->session->host), 14268c2ecf20Sopenharmony_ci cmd->task_id); 14278c2ecf20Sopenharmony_ci 14288c2ecf20Sopenharmony_ci cmd->task_id = U16_MAX; 14298c2ecf20Sopenharmony_ci cmd->scsi_cmd = NULL; 14308c2ecf20Sopenharmony_ci} 14318c2ecf20Sopenharmony_ci 14328c2ecf20Sopenharmony_cistruct iscsi_transport qedi_iscsi_transport = { 14338c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 14348c2ecf20Sopenharmony_ci .name = QEDI_MODULE_NAME, 14358c2ecf20Sopenharmony_ci .caps = CAP_RECOVERY_L0 | CAP_HDRDGST | CAP_MULTI_R2T | CAP_DATADGST | 14368c2ecf20Sopenharmony_ci CAP_DATA_PATH_OFFLOAD | CAP_TEXT_NEGO, 14378c2ecf20Sopenharmony_ci .create_session = qedi_session_create, 14388c2ecf20Sopenharmony_ci .destroy_session = qedi_session_destroy, 14398c2ecf20Sopenharmony_ci .create_conn = qedi_conn_create, 14408c2ecf20Sopenharmony_ci .bind_conn = qedi_conn_bind, 14418c2ecf20Sopenharmony_ci .unbind_conn = iscsi_conn_unbind, 14428c2ecf20Sopenharmony_ci .start_conn = qedi_conn_start, 14438c2ecf20Sopenharmony_ci .stop_conn = iscsi_conn_stop, 14448c2ecf20Sopenharmony_ci .destroy_conn = qedi_conn_destroy, 14458c2ecf20Sopenharmony_ci .set_param = iscsi_set_param, 14468c2ecf20Sopenharmony_ci .get_ep_param = qedi_ep_get_param, 14478c2ecf20Sopenharmony_ci .get_conn_param = iscsi_conn_get_param, 14488c2ecf20Sopenharmony_ci .get_session_param = iscsi_session_get_param, 14498c2ecf20Sopenharmony_ci .get_host_param = qedi_host_get_param, 14508c2ecf20Sopenharmony_ci .send_pdu = iscsi_conn_send_pdu, 14518c2ecf20Sopenharmony_ci .get_stats = qedi_conn_get_stats, 14528c2ecf20Sopenharmony_ci .xmit_task = qedi_task_xmit, 14538c2ecf20Sopenharmony_ci .cleanup_task = qedi_cleanup_task, 14548c2ecf20Sopenharmony_ci .session_recovery_timedout = iscsi_session_recovery_timedout, 14558c2ecf20Sopenharmony_ci .ep_connect = qedi_ep_connect, 14568c2ecf20Sopenharmony_ci .ep_poll = qedi_ep_poll, 14578c2ecf20Sopenharmony_ci .ep_disconnect = qedi_ep_disconnect, 14588c2ecf20Sopenharmony_ci .set_path = qedi_set_path, 14598c2ecf20Sopenharmony_ci .attr_is_visible = qedi_attr_is_visible, 14608c2ecf20Sopenharmony_ci}; 14618c2ecf20Sopenharmony_ci 14628c2ecf20Sopenharmony_civoid qedi_start_conn_recovery(struct qedi_ctx *qedi, 14638c2ecf20Sopenharmony_ci struct qedi_conn *qedi_conn) 14648c2ecf20Sopenharmony_ci{ 14658c2ecf20Sopenharmony_ci struct iscsi_cls_session *cls_sess; 14668c2ecf20Sopenharmony_ci struct iscsi_cls_conn *cls_conn; 14678c2ecf20Sopenharmony_ci struct iscsi_conn *conn; 14688c2ecf20Sopenharmony_ci 14698c2ecf20Sopenharmony_ci cls_conn = qedi_conn->cls_conn; 14708c2ecf20Sopenharmony_ci conn = cls_conn->dd_data; 14718c2ecf20Sopenharmony_ci cls_sess = iscsi_conn_to_session(cls_conn); 14728c2ecf20Sopenharmony_ci 14738c2ecf20Sopenharmony_ci if (iscsi_is_session_online(cls_sess)) { 14748c2ecf20Sopenharmony_ci qedi_conn->abrt_conn = 1; 14758c2ecf20Sopenharmony_ci QEDI_ERR(&qedi->dbg_ctx, 14768c2ecf20Sopenharmony_ci "Failing connection, state=0x%x, cid=0x%x\n", 14778c2ecf20Sopenharmony_ci conn->session->state, qedi_conn->iscsi_conn_id); 14788c2ecf20Sopenharmony_ci iscsi_conn_failure(qedi_conn->cls_conn->dd_data, 14798c2ecf20Sopenharmony_ci ISCSI_ERR_CONN_FAILED); 14808c2ecf20Sopenharmony_ci } 14818c2ecf20Sopenharmony_ci} 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_cistatic const struct { 14848c2ecf20Sopenharmony_ci enum iscsi_error_types error_code; 14858c2ecf20Sopenharmony_ci char *err_string; 14868c2ecf20Sopenharmony_ci} qedi_iscsi_error[] = { 14878c2ecf20Sopenharmony_ci { ISCSI_STATUS_NONE, 14888c2ecf20Sopenharmony_ci "tcp_error none" 14898c2ecf20Sopenharmony_ci }, 14908c2ecf20Sopenharmony_ci { ISCSI_CONN_ERROR_TASK_CID_MISMATCH, 14918c2ecf20Sopenharmony_ci "task cid mismatch" 14928c2ecf20Sopenharmony_ci }, 14938c2ecf20Sopenharmony_ci { ISCSI_CONN_ERROR_TASK_NOT_VALID, 14948c2ecf20Sopenharmony_ci "invalid task" 14958c2ecf20Sopenharmony_ci }, 14968c2ecf20Sopenharmony_ci { ISCSI_CONN_ERROR_RQ_RING_IS_FULL, 14978c2ecf20Sopenharmony_ci "rq ring full" 14988c2ecf20Sopenharmony_ci }, 14998c2ecf20Sopenharmony_ci { ISCSI_CONN_ERROR_CMDQ_RING_IS_FULL, 15008c2ecf20Sopenharmony_ci "cmdq ring full" 15018c2ecf20Sopenharmony_ci }, 15028c2ecf20Sopenharmony_ci { ISCSI_CONN_ERROR_HQE_CACHING_FAILED, 15038c2ecf20Sopenharmony_ci "sge caching failed" 15048c2ecf20Sopenharmony_ci }, 15058c2ecf20Sopenharmony_ci { ISCSI_CONN_ERROR_HEADER_DIGEST_ERROR, 15068c2ecf20Sopenharmony_ci "hdr digest error" 15078c2ecf20Sopenharmony_ci }, 15088c2ecf20Sopenharmony_ci { ISCSI_CONN_ERROR_LOCAL_COMPLETION_ERROR, 15098c2ecf20Sopenharmony_ci "local cmpl error" 15108c2ecf20Sopenharmony_ci }, 15118c2ecf20Sopenharmony_ci { ISCSI_CONN_ERROR_DATA_OVERRUN, 15128c2ecf20Sopenharmony_ci "invalid task" 15138c2ecf20Sopenharmony_ci }, 15148c2ecf20Sopenharmony_ci { ISCSI_CONN_ERROR_OUT_OF_SGES_ERROR, 15158c2ecf20Sopenharmony_ci "out of sge error" 15168c2ecf20Sopenharmony_ci }, 15178c2ecf20Sopenharmony_ci { ISCSI_CONN_ERROR_TCP_IP_FRAGMENT_ERROR, 15188c2ecf20Sopenharmony_ci "tcp ip fragment error" 15198c2ecf20Sopenharmony_ci }, 15208c2ecf20Sopenharmony_ci { ISCSI_CONN_ERROR_PROTOCOL_ERR_AHS_LEN, 15218c2ecf20Sopenharmony_ci "AHS len protocol error" 15228c2ecf20Sopenharmony_ci }, 15238c2ecf20Sopenharmony_ci { ISCSI_CONN_ERROR_PROTOCOL_ERR_ITT_OUT_OF_RANGE, 15248c2ecf20Sopenharmony_ci "itt out of range error" 15258c2ecf20Sopenharmony_ci }, 15268c2ecf20Sopenharmony_ci { ISCSI_CONN_ERROR_PROTOCOL_ERR_DATA_SEG_LEN_EXCEEDS_PDU_SIZE, 15278c2ecf20Sopenharmony_ci "data seg more than pdu size" 15288c2ecf20Sopenharmony_ci }, 15298c2ecf20Sopenharmony_ci { ISCSI_CONN_ERROR_PROTOCOL_ERR_INVALID_OPCODE, 15308c2ecf20Sopenharmony_ci "invalid opcode" 15318c2ecf20Sopenharmony_ci }, 15328c2ecf20Sopenharmony_ci { ISCSI_CONN_ERROR_PROTOCOL_ERR_INVALID_OPCODE_BEFORE_UPDATE, 15338c2ecf20Sopenharmony_ci "invalid opcode before update" 15348c2ecf20Sopenharmony_ci }, 15358c2ecf20Sopenharmony_ci { ISCSI_CONN_ERROR_UNVALID_NOPIN_DSL, 15368c2ecf20Sopenharmony_ci "unexpected opcode" 15378c2ecf20Sopenharmony_ci }, 15388c2ecf20Sopenharmony_ci { ISCSI_CONN_ERROR_PROTOCOL_ERR_R2T_CARRIES_NO_DATA, 15398c2ecf20Sopenharmony_ci "r2t carries no data" 15408c2ecf20Sopenharmony_ci }, 15418c2ecf20Sopenharmony_ci { ISCSI_CONN_ERROR_PROTOCOL_ERR_DATA_SN, 15428c2ecf20Sopenharmony_ci "data sn error" 15438c2ecf20Sopenharmony_ci }, 15448c2ecf20Sopenharmony_ci { ISCSI_CONN_ERROR_PROTOCOL_ERR_DATA_IN_TTT, 15458c2ecf20Sopenharmony_ci "data TTT error" 15468c2ecf20Sopenharmony_ci }, 15478c2ecf20Sopenharmony_ci { ISCSI_CONN_ERROR_PROTOCOL_ERR_R2T_TTT, 15488c2ecf20Sopenharmony_ci "r2t TTT error" 15498c2ecf20Sopenharmony_ci }, 15508c2ecf20Sopenharmony_ci { ISCSI_CONN_ERROR_PROTOCOL_ERR_R2T_BUFFER_OFFSET, 15518c2ecf20Sopenharmony_ci "buffer offset error" 15528c2ecf20Sopenharmony_ci }, 15538c2ecf20Sopenharmony_ci { ISCSI_CONN_ERROR_PROTOCOL_ERR_BUFFER_OFFSET_OOO, 15548c2ecf20Sopenharmony_ci "buffer offset ooo" 15558c2ecf20Sopenharmony_ci }, 15568c2ecf20Sopenharmony_ci { ISCSI_CONN_ERROR_PROTOCOL_ERR_R2T_SN, 15578c2ecf20Sopenharmony_ci "data seg len 0" 15588c2ecf20Sopenharmony_ci }, 15598c2ecf20Sopenharmony_ci { ISCSI_CONN_ERROR_PROTOCOL_ERR_DESIRED_DATA_TRNS_LEN_0, 15608c2ecf20Sopenharmony_ci "data xer len error" 15618c2ecf20Sopenharmony_ci }, 15628c2ecf20Sopenharmony_ci { ISCSI_CONN_ERROR_PROTOCOL_ERR_DESIRED_DATA_TRNS_LEN_1, 15638c2ecf20Sopenharmony_ci "data xer len1 error" 15648c2ecf20Sopenharmony_ci }, 15658c2ecf20Sopenharmony_ci { ISCSI_CONN_ERROR_PROTOCOL_ERR_DESIRED_DATA_TRNS_LEN_2, 15668c2ecf20Sopenharmony_ci "data xer len2 error" 15678c2ecf20Sopenharmony_ci }, 15688c2ecf20Sopenharmony_ci { ISCSI_CONN_ERROR_PROTOCOL_ERR_LUN, 15698c2ecf20Sopenharmony_ci "protocol lun error" 15708c2ecf20Sopenharmony_ci }, 15718c2ecf20Sopenharmony_ci { ISCSI_CONN_ERROR_PROTOCOL_ERR_F_BIT_ZERO, 15728c2ecf20Sopenharmony_ci "f bit zero error" 15738c2ecf20Sopenharmony_ci }, 15748c2ecf20Sopenharmony_ci { ISCSI_CONN_ERROR_PROTOCOL_ERR_EXP_STAT_SN, 15758c2ecf20Sopenharmony_ci "exp stat sn error" 15768c2ecf20Sopenharmony_ci }, 15778c2ecf20Sopenharmony_ci { ISCSI_CONN_ERROR_PROTOCOL_ERR_DSL_NOT_ZERO, 15788c2ecf20Sopenharmony_ci "dsl not zero error" 15798c2ecf20Sopenharmony_ci }, 15808c2ecf20Sopenharmony_ci { ISCSI_CONN_ERROR_PROTOCOL_ERR_INVALID_DSL, 15818c2ecf20Sopenharmony_ci "invalid dsl" 15828c2ecf20Sopenharmony_ci }, 15838c2ecf20Sopenharmony_ci { ISCSI_CONN_ERROR_PROTOCOL_ERR_DATA_SEG_LEN_TOO_BIG, 15848c2ecf20Sopenharmony_ci "data seg len too big" 15858c2ecf20Sopenharmony_ci }, 15868c2ecf20Sopenharmony_ci { ISCSI_CONN_ERROR_PROTOCOL_ERR_OUTSTANDING_R2T_COUNT, 15878c2ecf20Sopenharmony_ci "outstanding r2t count error" 15888c2ecf20Sopenharmony_ci }, 15898c2ecf20Sopenharmony_ci { ISCSI_CONN_ERROR_SENSE_DATA_LENGTH, 15908c2ecf20Sopenharmony_ci "sense datalen error" 15918c2ecf20Sopenharmony_ci }, 15928c2ecf20Sopenharmony_ci}; 15938c2ecf20Sopenharmony_ci 15948c2ecf20Sopenharmony_cistatic char *qedi_get_iscsi_error(enum iscsi_error_types err_code) 15958c2ecf20Sopenharmony_ci{ 15968c2ecf20Sopenharmony_ci int i; 15978c2ecf20Sopenharmony_ci char *msg = NULL; 15988c2ecf20Sopenharmony_ci 15998c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(qedi_iscsi_error); i++) { 16008c2ecf20Sopenharmony_ci if (qedi_iscsi_error[i].error_code == err_code) { 16018c2ecf20Sopenharmony_ci msg = qedi_iscsi_error[i].err_string; 16028c2ecf20Sopenharmony_ci break; 16038c2ecf20Sopenharmony_ci } 16048c2ecf20Sopenharmony_ci } 16058c2ecf20Sopenharmony_ci return msg; 16068c2ecf20Sopenharmony_ci} 16078c2ecf20Sopenharmony_ci 16088c2ecf20Sopenharmony_civoid qedi_process_iscsi_error(struct qedi_endpoint *ep, 16098c2ecf20Sopenharmony_ci struct iscsi_eqe_data *data) 16108c2ecf20Sopenharmony_ci{ 16118c2ecf20Sopenharmony_ci struct qedi_conn *qedi_conn; 16128c2ecf20Sopenharmony_ci struct qedi_ctx *qedi; 16138c2ecf20Sopenharmony_ci char warn_notice[] = "iscsi_warning"; 16148c2ecf20Sopenharmony_ci char error_notice[] = "iscsi_error"; 16158c2ecf20Sopenharmony_ci char unknown_msg[] = "Unknown error"; 16168c2ecf20Sopenharmony_ci char *message; 16178c2ecf20Sopenharmony_ci int need_recovery = 0; 16188c2ecf20Sopenharmony_ci u32 err_mask = 0; 16198c2ecf20Sopenharmony_ci char *msg; 16208c2ecf20Sopenharmony_ci 16218c2ecf20Sopenharmony_ci if (!ep) 16228c2ecf20Sopenharmony_ci return; 16238c2ecf20Sopenharmony_ci 16248c2ecf20Sopenharmony_ci qedi_conn = ep->conn; 16258c2ecf20Sopenharmony_ci if (!qedi_conn) 16268c2ecf20Sopenharmony_ci return; 16278c2ecf20Sopenharmony_ci 16288c2ecf20Sopenharmony_ci qedi = ep->qedi; 16298c2ecf20Sopenharmony_ci 16308c2ecf20Sopenharmony_ci QEDI_ERR(&qedi->dbg_ctx, "async event iscsi error:0x%x\n", 16318c2ecf20Sopenharmony_ci data->error_code); 16328c2ecf20Sopenharmony_ci 16338c2ecf20Sopenharmony_ci if (err_mask) { 16348c2ecf20Sopenharmony_ci need_recovery = 0; 16358c2ecf20Sopenharmony_ci message = warn_notice; 16368c2ecf20Sopenharmony_ci } else { 16378c2ecf20Sopenharmony_ci need_recovery = 1; 16388c2ecf20Sopenharmony_ci message = error_notice; 16398c2ecf20Sopenharmony_ci } 16408c2ecf20Sopenharmony_ci 16418c2ecf20Sopenharmony_ci msg = qedi_get_iscsi_error(data->error_code); 16428c2ecf20Sopenharmony_ci if (!msg) { 16438c2ecf20Sopenharmony_ci need_recovery = 0; 16448c2ecf20Sopenharmony_ci msg = unknown_msg; 16458c2ecf20Sopenharmony_ci } 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci iscsi_conn_printk(KERN_ALERT, 16488c2ecf20Sopenharmony_ci qedi_conn->cls_conn->dd_data, 16498c2ecf20Sopenharmony_ci "qedi: %s - %s\n", message, msg); 16508c2ecf20Sopenharmony_ci 16518c2ecf20Sopenharmony_ci if (need_recovery) 16528c2ecf20Sopenharmony_ci qedi_start_conn_recovery(qedi_conn->qedi, qedi_conn); 16538c2ecf20Sopenharmony_ci} 16548c2ecf20Sopenharmony_ci 16558c2ecf20Sopenharmony_civoid qedi_clear_session_ctx(struct iscsi_cls_session *cls_sess) 16568c2ecf20Sopenharmony_ci{ 16578c2ecf20Sopenharmony_ci struct iscsi_session *session = cls_sess->dd_data; 16588c2ecf20Sopenharmony_ci struct iscsi_conn *conn = session->leadconn; 16598c2ecf20Sopenharmony_ci struct qedi_conn *qedi_conn = conn->dd_data; 16608c2ecf20Sopenharmony_ci 16618c2ecf20Sopenharmony_ci if (iscsi_is_session_online(cls_sess)) 16628c2ecf20Sopenharmony_ci qedi_ep_disconnect(qedi_conn->iscsi_ep); 16638c2ecf20Sopenharmony_ci 16648c2ecf20Sopenharmony_ci qedi_conn_destroy(qedi_conn->cls_conn); 16658c2ecf20Sopenharmony_ci 16668c2ecf20Sopenharmony_ci qedi_session_destroy(cls_sess); 16678c2ecf20Sopenharmony_ci} 16688c2ecf20Sopenharmony_ci 16698c2ecf20Sopenharmony_civoid qedi_process_tcp_error(struct qedi_endpoint *ep, 16708c2ecf20Sopenharmony_ci struct iscsi_eqe_data *data) 16718c2ecf20Sopenharmony_ci{ 16728c2ecf20Sopenharmony_ci struct qedi_conn *qedi_conn; 16738c2ecf20Sopenharmony_ci 16748c2ecf20Sopenharmony_ci if (!ep) 16758c2ecf20Sopenharmony_ci return; 16768c2ecf20Sopenharmony_ci 16778c2ecf20Sopenharmony_ci qedi_conn = ep->conn; 16788c2ecf20Sopenharmony_ci if (!qedi_conn) 16798c2ecf20Sopenharmony_ci return; 16808c2ecf20Sopenharmony_ci 16818c2ecf20Sopenharmony_ci QEDI_ERR(&ep->qedi->dbg_ctx, "async event TCP error:0x%x\n", 16828c2ecf20Sopenharmony_ci data->error_code); 16838c2ecf20Sopenharmony_ci 16848c2ecf20Sopenharmony_ci qedi_start_conn_recovery(qedi_conn->qedi, qedi_conn); 16858c2ecf20Sopenharmony_ci} 1686