18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * QLogic FCoE Offload Driver 48c2ecf20Sopenharmony_ci * Copyright (c) 2016-2018 Cavium Inc. 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 78c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 88c2ecf20Sopenharmony_ci#include "qedf.h" 98c2ecf20Sopenharmony_ci#include <scsi/scsi_tcq.h> 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_civoid qedf_cmd_timer_set(struct qedf_ctx *qedf, struct qedf_ioreq *io_req, 128c2ecf20Sopenharmony_ci unsigned int timer_msec) 138c2ecf20Sopenharmony_ci{ 148c2ecf20Sopenharmony_ci queue_delayed_work(qedf->timer_work_queue, &io_req->timeout_work, 158c2ecf20Sopenharmony_ci msecs_to_jiffies(timer_msec)); 168c2ecf20Sopenharmony_ci} 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_cistatic void qedf_cmd_timeout(struct work_struct *work) 198c2ecf20Sopenharmony_ci{ 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci struct qedf_ioreq *io_req = 228c2ecf20Sopenharmony_ci container_of(work, struct qedf_ioreq, timeout_work.work); 238c2ecf20Sopenharmony_ci struct qedf_ctx *qedf; 248c2ecf20Sopenharmony_ci struct qedf_rport *fcport; 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci if (io_req == NULL) { 278c2ecf20Sopenharmony_ci QEDF_INFO(NULL, QEDF_LOG_IO, "io_req is NULL.\n"); 288c2ecf20Sopenharmony_ci return; 298c2ecf20Sopenharmony_ci } 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci fcport = io_req->fcport; 328c2ecf20Sopenharmony_ci if (io_req->fcport == NULL) { 338c2ecf20Sopenharmony_ci QEDF_INFO(NULL, QEDF_LOG_IO, "fcport is NULL.\n"); 348c2ecf20Sopenharmony_ci return; 358c2ecf20Sopenharmony_ci } 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci qedf = fcport->qedf; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci switch (io_req->cmd_type) { 408c2ecf20Sopenharmony_ci case QEDF_ABTS: 418c2ecf20Sopenharmony_ci if (qedf == NULL) { 428c2ecf20Sopenharmony_ci QEDF_INFO(NULL, QEDF_LOG_IO, 438c2ecf20Sopenharmony_ci "qedf is NULL for ABTS xid=0x%x.\n", 448c2ecf20Sopenharmony_ci io_req->xid); 458c2ecf20Sopenharmony_ci return; 468c2ecf20Sopenharmony_ci } 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci QEDF_ERR((&qedf->dbg_ctx), "ABTS timeout, xid=0x%x.\n", 498c2ecf20Sopenharmony_ci io_req->xid); 508c2ecf20Sopenharmony_ci /* Cleanup timed out ABTS */ 518c2ecf20Sopenharmony_ci qedf_initiate_cleanup(io_req, true); 528c2ecf20Sopenharmony_ci complete(&io_req->abts_done); 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci /* 558c2ecf20Sopenharmony_ci * Need to call kref_put for reference taken when initiate_abts 568c2ecf20Sopenharmony_ci * was called since abts_compl won't be called now that we've 578c2ecf20Sopenharmony_ci * cleaned up the task. 588c2ecf20Sopenharmony_ci */ 598c2ecf20Sopenharmony_ci kref_put(&io_req->refcount, qedf_release_cmd); 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci /* Clear in abort bit now that we're done with the command */ 628c2ecf20Sopenharmony_ci clear_bit(QEDF_CMD_IN_ABORT, &io_req->flags); 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci /* 658c2ecf20Sopenharmony_ci * Now that the original I/O and the ABTS are complete see 668c2ecf20Sopenharmony_ci * if we need to reconnect to the target. 678c2ecf20Sopenharmony_ci */ 688c2ecf20Sopenharmony_ci qedf_restart_rport(fcport); 698c2ecf20Sopenharmony_ci break; 708c2ecf20Sopenharmony_ci case QEDF_ELS: 718c2ecf20Sopenharmony_ci if (!qedf) { 728c2ecf20Sopenharmony_ci QEDF_INFO(NULL, QEDF_LOG_IO, 738c2ecf20Sopenharmony_ci "qedf is NULL for ELS xid=0x%x.\n", 748c2ecf20Sopenharmony_ci io_req->xid); 758c2ecf20Sopenharmony_ci return; 768c2ecf20Sopenharmony_ci } 778c2ecf20Sopenharmony_ci /* ELS request no longer outstanding since it timed out */ 788c2ecf20Sopenharmony_ci clear_bit(QEDF_CMD_OUTSTANDING, &io_req->flags); 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci kref_get(&io_req->refcount); 818c2ecf20Sopenharmony_ci /* 828c2ecf20Sopenharmony_ci * Don't attempt to clean an ELS timeout as any subseqeunt 838c2ecf20Sopenharmony_ci * ABTS or cleanup requests just hang. For now just free 848c2ecf20Sopenharmony_ci * the resources of the original I/O and the RRQ 858c2ecf20Sopenharmony_ci */ 868c2ecf20Sopenharmony_ci QEDF_ERR(&(qedf->dbg_ctx), "ELS timeout, xid=0x%x.\n", 878c2ecf20Sopenharmony_ci io_req->xid); 888c2ecf20Sopenharmony_ci qedf_initiate_cleanup(io_req, true); 898c2ecf20Sopenharmony_ci io_req->event = QEDF_IOREQ_EV_ELS_TMO; 908c2ecf20Sopenharmony_ci /* Call callback function to complete command */ 918c2ecf20Sopenharmony_ci if (io_req->cb_func && io_req->cb_arg) { 928c2ecf20Sopenharmony_ci io_req->cb_func(io_req->cb_arg); 938c2ecf20Sopenharmony_ci io_req->cb_arg = NULL; 948c2ecf20Sopenharmony_ci } 958c2ecf20Sopenharmony_ci kref_put(&io_req->refcount, qedf_release_cmd); 968c2ecf20Sopenharmony_ci break; 978c2ecf20Sopenharmony_ci case QEDF_SEQ_CLEANUP: 988c2ecf20Sopenharmony_ci QEDF_ERR(&(qedf->dbg_ctx), "Sequence cleanup timeout, " 998c2ecf20Sopenharmony_ci "xid=0x%x.\n", io_req->xid); 1008c2ecf20Sopenharmony_ci qedf_initiate_cleanup(io_req, true); 1018c2ecf20Sopenharmony_ci io_req->event = QEDF_IOREQ_EV_ELS_TMO; 1028c2ecf20Sopenharmony_ci qedf_process_seq_cleanup_compl(qedf, NULL, io_req); 1038c2ecf20Sopenharmony_ci break; 1048c2ecf20Sopenharmony_ci default: 1058c2ecf20Sopenharmony_ci QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, 1068c2ecf20Sopenharmony_ci "Hit default case, xid=0x%x.\n", io_req->xid); 1078c2ecf20Sopenharmony_ci break; 1088c2ecf20Sopenharmony_ci } 1098c2ecf20Sopenharmony_ci} 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_civoid qedf_cmd_mgr_free(struct qedf_cmd_mgr *cmgr) 1128c2ecf20Sopenharmony_ci{ 1138c2ecf20Sopenharmony_ci struct io_bdt *bdt_info; 1148c2ecf20Sopenharmony_ci struct qedf_ctx *qedf = cmgr->qedf; 1158c2ecf20Sopenharmony_ci size_t bd_tbl_sz; 1168c2ecf20Sopenharmony_ci u16 min_xid = 0; 1178c2ecf20Sopenharmony_ci u16 max_xid = (FCOE_PARAMS_NUM_TASKS - 1); 1188c2ecf20Sopenharmony_ci int num_ios; 1198c2ecf20Sopenharmony_ci int i; 1208c2ecf20Sopenharmony_ci struct qedf_ioreq *io_req; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci num_ios = max_xid - min_xid + 1; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci /* Free fcoe_bdt_ctx structures */ 1258c2ecf20Sopenharmony_ci if (!cmgr->io_bdt_pool) { 1268c2ecf20Sopenharmony_ci QEDF_ERR(&qedf->dbg_ctx, "io_bdt_pool is NULL.\n"); 1278c2ecf20Sopenharmony_ci goto free_cmd_pool; 1288c2ecf20Sopenharmony_ci } 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci bd_tbl_sz = QEDF_MAX_BDS_PER_CMD * sizeof(struct scsi_sge); 1318c2ecf20Sopenharmony_ci for (i = 0; i < num_ios; i++) { 1328c2ecf20Sopenharmony_ci bdt_info = cmgr->io_bdt_pool[i]; 1338c2ecf20Sopenharmony_ci if (bdt_info->bd_tbl) { 1348c2ecf20Sopenharmony_ci dma_free_coherent(&qedf->pdev->dev, bd_tbl_sz, 1358c2ecf20Sopenharmony_ci bdt_info->bd_tbl, bdt_info->bd_tbl_dma); 1368c2ecf20Sopenharmony_ci bdt_info->bd_tbl = NULL; 1378c2ecf20Sopenharmony_ci } 1388c2ecf20Sopenharmony_ci } 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci /* Destroy io_bdt pool */ 1418c2ecf20Sopenharmony_ci for (i = 0; i < num_ios; i++) { 1428c2ecf20Sopenharmony_ci kfree(cmgr->io_bdt_pool[i]); 1438c2ecf20Sopenharmony_ci cmgr->io_bdt_pool[i] = NULL; 1448c2ecf20Sopenharmony_ci } 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci kfree(cmgr->io_bdt_pool); 1478c2ecf20Sopenharmony_ci cmgr->io_bdt_pool = NULL; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_cifree_cmd_pool: 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci for (i = 0; i < num_ios; i++) { 1528c2ecf20Sopenharmony_ci io_req = &cmgr->cmds[i]; 1538c2ecf20Sopenharmony_ci kfree(io_req->sgl_task_params); 1548c2ecf20Sopenharmony_ci kfree(io_req->task_params); 1558c2ecf20Sopenharmony_ci /* Make sure we free per command sense buffer */ 1568c2ecf20Sopenharmony_ci if (io_req->sense_buffer) 1578c2ecf20Sopenharmony_ci dma_free_coherent(&qedf->pdev->dev, 1588c2ecf20Sopenharmony_ci QEDF_SCSI_SENSE_BUFFERSIZE, io_req->sense_buffer, 1598c2ecf20Sopenharmony_ci io_req->sense_buffer_dma); 1608c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&io_req->rrq_work); 1618c2ecf20Sopenharmony_ci } 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci /* Free command manager itself */ 1648c2ecf20Sopenharmony_ci vfree(cmgr); 1658c2ecf20Sopenharmony_ci} 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_cistatic void qedf_handle_rrq(struct work_struct *work) 1688c2ecf20Sopenharmony_ci{ 1698c2ecf20Sopenharmony_ci struct qedf_ioreq *io_req = 1708c2ecf20Sopenharmony_ci container_of(work, struct qedf_ioreq, rrq_work.work); 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci atomic_set(&io_req->state, QEDFC_CMD_ST_RRQ_ACTIVE); 1738c2ecf20Sopenharmony_ci qedf_send_rrq(io_req); 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci} 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_cistruct qedf_cmd_mgr *qedf_cmd_mgr_alloc(struct qedf_ctx *qedf) 1788c2ecf20Sopenharmony_ci{ 1798c2ecf20Sopenharmony_ci struct qedf_cmd_mgr *cmgr; 1808c2ecf20Sopenharmony_ci struct io_bdt *bdt_info; 1818c2ecf20Sopenharmony_ci struct qedf_ioreq *io_req; 1828c2ecf20Sopenharmony_ci u16 xid; 1838c2ecf20Sopenharmony_ci int i; 1848c2ecf20Sopenharmony_ci int num_ios; 1858c2ecf20Sopenharmony_ci u16 min_xid = 0; 1868c2ecf20Sopenharmony_ci u16 max_xid = (FCOE_PARAMS_NUM_TASKS - 1); 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci /* Make sure num_queues is already set before calling this function */ 1898c2ecf20Sopenharmony_ci if (!qedf->num_queues) { 1908c2ecf20Sopenharmony_ci QEDF_ERR(&(qedf->dbg_ctx), "num_queues is not set.\n"); 1918c2ecf20Sopenharmony_ci return NULL; 1928c2ecf20Sopenharmony_ci } 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci if (max_xid <= min_xid || max_xid == FC_XID_UNKNOWN) { 1958c2ecf20Sopenharmony_ci QEDF_WARN(&(qedf->dbg_ctx), "Invalid min_xid 0x%x and " 1968c2ecf20Sopenharmony_ci "max_xid 0x%x.\n", min_xid, max_xid); 1978c2ecf20Sopenharmony_ci return NULL; 1988c2ecf20Sopenharmony_ci } 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_DISC, "min xid 0x%x, max xid " 2018c2ecf20Sopenharmony_ci "0x%x.\n", min_xid, max_xid); 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci num_ios = max_xid - min_xid + 1; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci cmgr = vzalloc(sizeof(struct qedf_cmd_mgr)); 2068c2ecf20Sopenharmony_ci if (!cmgr) { 2078c2ecf20Sopenharmony_ci QEDF_WARN(&(qedf->dbg_ctx), "Failed to alloc cmd mgr.\n"); 2088c2ecf20Sopenharmony_ci return NULL; 2098c2ecf20Sopenharmony_ci } 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci cmgr->qedf = qedf; 2128c2ecf20Sopenharmony_ci spin_lock_init(&cmgr->lock); 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci /* 2158c2ecf20Sopenharmony_ci * Initialize I/O request fields. 2168c2ecf20Sopenharmony_ci */ 2178c2ecf20Sopenharmony_ci xid = 0; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci for (i = 0; i < num_ios; i++) { 2208c2ecf20Sopenharmony_ci io_req = &cmgr->cmds[i]; 2218c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&io_req->timeout_work, qedf_cmd_timeout); 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci io_req->xid = xid++; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&io_req->rrq_work, qedf_handle_rrq); 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci /* Allocate DMA memory to hold sense buffer */ 2288c2ecf20Sopenharmony_ci io_req->sense_buffer = dma_alloc_coherent(&qedf->pdev->dev, 2298c2ecf20Sopenharmony_ci QEDF_SCSI_SENSE_BUFFERSIZE, &io_req->sense_buffer_dma, 2308c2ecf20Sopenharmony_ci GFP_KERNEL); 2318c2ecf20Sopenharmony_ci if (!io_req->sense_buffer) { 2328c2ecf20Sopenharmony_ci QEDF_ERR(&qedf->dbg_ctx, 2338c2ecf20Sopenharmony_ci "Failed to alloc sense buffer.\n"); 2348c2ecf20Sopenharmony_ci goto mem_err; 2358c2ecf20Sopenharmony_ci } 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci /* Allocate task parameters to pass to f/w init funcions */ 2388c2ecf20Sopenharmony_ci io_req->task_params = kzalloc(sizeof(*io_req->task_params), 2398c2ecf20Sopenharmony_ci GFP_KERNEL); 2408c2ecf20Sopenharmony_ci if (!io_req->task_params) { 2418c2ecf20Sopenharmony_ci QEDF_ERR(&(qedf->dbg_ctx), 2428c2ecf20Sopenharmony_ci "Failed to allocate task_params for xid=0x%x\n", 2438c2ecf20Sopenharmony_ci i); 2448c2ecf20Sopenharmony_ci goto mem_err; 2458c2ecf20Sopenharmony_ci } 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci /* 2488c2ecf20Sopenharmony_ci * Allocate scatter/gather list info to pass to f/w init 2498c2ecf20Sopenharmony_ci * functions. 2508c2ecf20Sopenharmony_ci */ 2518c2ecf20Sopenharmony_ci io_req->sgl_task_params = kzalloc( 2528c2ecf20Sopenharmony_ci sizeof(struct scsi_sgl_task_params), GFP_KERNEL); 2538c2ecf20Sopenharmony_ci if (!io_req->sgl_task_params) { 2548c2ecf20Sopenharmony_ci QEDF_ERR(&(qedf->dbg_ctx), 2558c2ecf20Sopenharmony_ci "Failed to allocate sgl_task_params for xid=0x%x\n", 2568c2ecf20Sopenharmony_ci i); 2578c2ecf20Sopenharmony_ci goto mem_err; 2588c2ecf20Sopenharmony_ci } 2598c2ecf20Sopenharmony_ci } 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci /* Allocate pool of io_bdts - one for each qedf_ioreq */ 2628c2ecf20Sopenharmony_ci cmgr->io_bdt_pool = kmalloc_array(num_ios, sizeof(struct io_bdt *), 2638c2ecf20Sopenharmony_ci GFP_KERNEL); 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci if (!cmgr->io_bdt_pool) { 2668c2ecf20Sopenharmony_ci QEDF_WARN(&(qedf->dbg_ctx), "Failed to alloc io_bdt_pool.\n"); 2678c2ecf20Sopenharmony_ci goto mem_err; 2688c2ecf20Sopenharmony_ci } 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci for (i = 0; i < num_ios; i++) { 2718c2ecf20Sopenharmony_ci cmgr->io_bdt_pool[i] = kmalloc(sizeof(struct io_bdt), 2728c2ecf20Sopenharmony_ci GFP_KERNEL); 2738c2ecf20Sopenharmony_ci if (!cmgr->io_bdt_pool[i]) { 2748c2ecf20Sopenharmony_ci QEDF_WARN(&(qedf->dbg_ctx), 2758c2ecf20Sopenharmony_ci "Failed to alloc io_bdt_pool[%d].\n", i); 2768c2ecf20Sopenharmony_ci goto mem_err; 2778c2ecf20Sopenharmony_ci } 2788c2ecf20Sopenharmony_ci } 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci for (i = 0; i < num_ios; i++) { 2818c2ecf20Sopenharmony_ci bdt_info = cmgr->io_bdt_pool[i]; 2828c2ecf20Sopenharmony_ci bdt_info->bd_tbl = dma_alloc_coherent(&qedf->pdev->dev, 2838c2ecf20Sopenharmony_ci QEDF_MAX_BDS_PER_CMD * sizeof(struct scsi_sge), 2848c2ecf20Sopenharmony_ci &bdt_info->bd_tbl_dma, GFP_KERNEL); 2858c2ecf20Sopenharmony_ci if (!bdt_info->bd_tbl) { 2868c2ecf20Sopenharmony_ci QEDF_WARN(&(qedf->dbg_ctx), 2878c2ecf20Sopenharmony_ci "Failed to alloc bdt_tbl[%d].\n", i); 2888c2ecf20Sopenharmony_ci goto mem_err; 2898c2ecf20Sopenharmony_ci } 2908c2ecf20Sopenharmony_ci } 2918c2ecf20Sopenharmony_ci atomic_set(&cmgr->free_list_cnt, num_ios); 2928c2ecf20Sopenharmony_ci QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_IO, 2938c2ecf20Sopenharmony_ci "cmgr->free_list_cnt=%d.\n", 2948c2ecf20Sopenharmony_ci atomic_read(&cmgr->free_list_cnt)); 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci return cmgr; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_cimem_err: 2998c2ecf20Sopenharmony_ci qedf_cmd_mgr_free(cmgr); 3008c2ecf20Sopenharmony_ci return NULL; 3018c2ecf20Sopenharmony_ci} 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_cistruct qedf_ioreq *qedf_alloc_cmd(struct qedf_rport *fcport, u8 cmd_type) 3048c2ecf20Sopenharmony_ci{ 3058c2ecf20Sopenharmony_ci struct qedf_ctx *qedf = fcport->qedf; 3068c2ecf20Sopenharmony_ci struct qedf_cmd_mgr *cmd_mgr = qedf->cmd_mgr; 3078c2ecf20Sopenharmony_ci struct qedf_ioreq *io_req = NULL; 3088c2ecf20Sopenharmony_ci struct io_bdt *bd_tbl; 3098c2ecf20Sopenharmony_ci u16 xid; 3108c2ecf20Sopenharmony_ci uint32_t free_sqes; 3118c2ecf20Sopenharmony_ci int i; 3128c2ecf20Sopenharmony_ci unsigned long flags; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci free_sqes = atomic_read(&fcport->free_sqes); 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci if (!free_sqes) { 3178c2ecf20Sopenharmony_ci QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_IO, 3188c2ecf20Sopenharmony_ci "Returning NULL, free_sqes=%d.\n ", 3198c2ecf20Sopenharmony_ci free_sqes); 3208c2ecf20Sopenharmony_ci goto out_failed; 3218c2ecf20Sopenharmony_ci } 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci /* Limit the number of outstanding R/W tasks */ 3248c2ecf20Sopenharmony_ci if ((atomic_read(&fcport->num_active_ios) >= 3258c2ecf20Sopenharmony_ci NUM_RW_TASKS_PER_CONNECTION)) { 3268c2ecf20Sopenharmony_ci QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_IO, 3278c2ecf20Sopenharmony_ci "Returning NULL, num_active_ios=%d.\n", 3288c2ecf20Sopenharmony_ci atomic_read(&fcport->num_active_ios)); 3298c2ecf20Sopenharmony_ci goto out_failed; 3308c2ecf20Sopenharmony_ci } 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci /* Limit global TIDs certain tasks */ 3338c2ecf20Sopenharmony_ci if (atomic_read(&cmd_mgr->free_list_cnt) <= GBL_RSVD_TASKS) { 3348c2ecf20Sopenharmony_ci QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_IO, 3358c2ecf20Sopenharmony_ci "Returning NULL, free_list_cnt=%d.\n", 3368c2ecf20Sopenharmony_ci atomic_read(&cmd_mgr->free_list_cnt)); 3378c2ecf20Sopenharmony_ci goto out_failed; 3388c2ecf20Sopenharmony_ci } 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci spin_lock_irqsave(&cmd_mgr->lock, flags); 3418c2ecf20Sopenharmony_ci for (i = 0; i < FCOE_PARAMS_NUM_TASKS; i++) { 3428c2ecf20Sopenharmony_ci io_req = &cmd_mgr->cmds[cmd_mgr->idx]; 3438c2ecf20Sopenharmony_ci cmd_mgr->idx++; 3448c2ecf20Sopenharmony_ci if (cmd_mgr->idx == FCOE_PARAMS_NUM_TASKS) 3458c2ecf20Sopenharmony_ci cmd_mgr->idx = 0; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci /* Check to make sure command was previously freed */ 3488c2ecf20Sopenharmony_ci if (!io_req->alloc) 3498c2ecf20Sopenharmony_ci break; 3508c2ecf20Sopenharmony_ci } 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci if (i == FCOE_PARAMS_NUM_TASKS) { 3538c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&cmd_mgr->lock, flags); 3548c2ecf20Sopenharmony_ci goto out_failed; 3558c2ecf20Sopenharmony_ci } 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci if (test_bit(QEDF_CMD_DIRTY, &io_req->flags)) 3588c2ecf20Sopenharmony_ci QEDF_ERR(&qedf->dbg_ctx, 3598c2ecf20Sopenharmony_ci "io_req found to be dirty ox_id = 0x%x.\n", 3608c2ecf20Sopenharmony_ci io_req->xid); 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci /* Clear any flags now that we've reallocated the xid */ 3638c2ecf20Sopenharmony_ci io_req->flags = 0; 3648c2ecf20Sopenharmony_ci io_req->alloc = 1; 3658c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&cmd_mgr->lock, flags); 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci atomic_inc(&fcport->num_active_ios); 3688c2ecf20Sopenharmony_ci atomic_dec(&fcport->free_sqes); 3698c2ecf20Sopenharmony_ci xid = io_req->xid; 3708c2ecf20Sopenharmony_ci atomic_dec(&cmd_mgr->free_list_cnt); 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci io_req->cmd_mgr = cmd_mgr; 3738c2ecf20Sopenharmony_ci io_req->fcport = fcport; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci /* Clear any stale sc_cmd back pointer */ 3768c2ecf20Sopenharmony_ci io_req->sc_cmd = NULL; 3778c2ecf20Sopenharmony_ci io_req->lun = -1; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci /* Hold the io_req against deletion */ 3808c2ecf20Sopenharmony_ci kref_init(&io_req->refcount); /* ID: 001 */ 3818c2ecf20Sopenharmony_ci atomic_set(&io_req->state, QEDFC_CMD_ST_IO_ACTIVE); 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci /* Bind io_bdt for this io_req */ 3848c2ecf20Sopenharmony_ci /* Have a static link between io_req and io_bdt_pool */ 3858c2ecf20Sopenharmony_ci bd_tbl = io_req->bd_tbl = cmd_mgr->io_bdt_pool[xid]; 3868c2ecf20Sopenharmony_ci if (bd_tbl == NULL) { 3878c2ecf20Sopenharmony_ci QEDF_ERR(&(qedf->dbg_ctx), "bd_tbl is NULL, xid=%x.\n", xid); 3888c2ecf20Sopenharmony_ci kref_put(&io_req->refcount, qedf_release_cmd); 3898c2ecf20Sopenharmony_ci goto out_failed; 3908c2ecf20Sopenharmony_ci } 3918c2ecf20Sopenharmony_ci bd_tbl->io_req = io_req; 3928c2ecf20Sopenharmony_ci io_req->cmd_type = cmd_type; 3938c2ecf20Sopenharmony_ci io_req->tm_flags = 0; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci /* Reset sequence offset data */ 3968c2ecf20Sopenharmony_ci io_req->rx_buf_off = 0; 3978c2ecf20Sopenharmony_ci io_req->tx_buf_off = 0; 3988c2ecf20Sopenharmony_ci io_req->rx_id = 0xffff; /* No OX_ID */ 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci return io_req; 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ciout_failed: 4038c2ecf20Sopenharmony_ci /* Record failure for stats and return NULL to caller */ 4048c2ecf20Sopenharmony_ci qedf->alloc_failures++; 4058c2ecf20Sopenharmony_ci return NULL; 4068c2ecf20Sopenharmony_ci} 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_cistatic void qedf_free_mp_resc(struct qedf_ioreq *io_req) 4098c2ecf20Sopenharmony_ci{ 4108c2ecf20Sopenharmony_ci struct qedf_mp_req *mp_req = &(io_req->mp_req); 4118c2ecf20Sopenharmony_ci struct qedf_ctx *qedf = io_req->fcport->qedf; 4128c2ecf20Sopenharmony_ci uint64_t sz = sizeof(struct scsi_sge); 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci /* clear tm flags */ 4158c2ecf20Sopenharmony_ci if (mp_req->mp_req_bd) { 4168c2ecf20Sopenharmony_ci dma_free_coherent(&qedf->pdev->dev, sz, 4178c2ecf20Sopenharmony_ci mp_req->mp_req_bd, mp_req->mp_req_bd_dma); 4188c2ecf20Sopenharmony_ci mp_req->mp_req_bd = NULL; 4198c2ecf20Sopenharmony_ci } 4208c2ecf20Sopenharmony_ci if (mp_req->mp_resp_bd) { 4218c2ecf20Sopenharmony_ci dma_free_coherent(&qedf->pdev->dev, sz, 4228c2ecf20Sopenharmony_ci mp_req->mp_resp_bd, mp_req->mp_resp_bd_dma); 4238c2ecf20Sopenharmony_ci mp_req->mp_resp_bd = NULL; 4248c2ecf20Sopenharmony_ci } 4258c2ecf20Sopenharmony_ci if (mp_req->req_buf) { 4268c2ecf20Sopenharmony_ci dma_free_coherent(&qedf->pdev->dev, QEDF_PAGE_SIZE, 4278c2ecf20Sopenharmony_ci mp_req->req_buf, mp_req->req_buf_dma); 4288c2ecf20Sopenharmony_ci mp_req->req_buf = NULL; 4298c2ecf20Sopenharmony_ci } 4308c2ecf20Sopenharmony_ci if (mp_req->resp_buf) { 4318c2ecf20Sopenharmony_ci dma_free_coherent(&qedf->pdev->dev, QEDF_PAGE_SIZE, 4328c2ecf20Sopenharmony_ci mp_req->resp_buf, mp_req->resp_buf_dma); 4338c2ecf20Sopenharmony_ci mp_req->resp_buf = NULL; 4348c2ecf20Sopenharmony_ci } 4358c2ecf20Sopenharmony_ci} 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_civoid qedf_release_cmd(struct kref *ref) 4388c2ecf20Sopenharmony_ci{ 4398c2ecf20Sopenharmony_ci struct qedf_ioreq *io_req = 4408c2ecf20Sopenharmony_ci container_of(ref, struct qedf_ioreq, refcount); 4418c2ecf20Sopenharmony_ci struct qedf_cmd_mgr *cmd_mgr = io_req->cmd_mgr; 4428c2ecf20Sopenharmony_ci struct qedf_rport *fcport = io_req->fcport; 4438c2ecf20Sopenharmony_ci unsigned long flags; 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci if (io_req->cmd_type == QEDF_SCSI_CMD) { 4468c2ecf20Sopenharmony_ci QEDF_WARN(&fcport->qedf->dbg_ctx, 4478c2ecf20Sopenharmony_ci "Cmd released called without scsi_done called, io_req %p xid=0x%x.\n", 4488c2ecf20Sopenharmony_ci io_req, io_req->xid); 4498c2ecf20Sopenharmony_ci WARN_ON(io_req->sc_cmd); 4508c2ecf20Sopenharmony_ci } 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci if (io_req->cmd_type == QEDF_ELS || 4538c2ecf20Sopenharmony_ci io_req->cmd_type == QEDF_TASK_MGMT_CMD) 4548c2ecf20Sopenharmony_ci qedf_free_mp_resc(io_req); 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci atomic_inc(&cmd_mgr->free_list_cnt); 4578c2ecf20Sopenharmony_ci atomic_dec(&fcport->num_active_ios); 4588c2ecf20Sopenharmony_ci atomic_set(&io_req->state, QEDF_CMD_ST_INACTIVE); 4598c2ecf20Sopenharmony_ci if (atomic_read(&fcport->num_active_ios) < 0) { 4608c2ecf20Sopenharmony_ci QEDF_WARN(&(fcport->qedf->dbg_ctx), "active_ios < 0.\n"); 4618c2ecf20Sopenharmony_ci WARN_ON(1); 4628c2ecf20Sopenharmony_ci } 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci /* Increment task retry identifier now that the request is released */ 4658c2ecf20Sopenharmony_ci io_req->task_retry_identifier++; 4668c2ecf20Sopenharmony_ci io_req->fcport = NULL; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci clear_bit(QEDF_CMD_DIRTY, &io_req->flags); 4698c2ecf20Sopenharmony_ci io_req->cpu = 0; 4708c2ecf20Sopenharmony_ci spin_lock_irqsave(&cmd_mgr->lock, flags); 4718c2ecf20Sopenharmony_ci io_req->fcport = NULL; 4728c2ecf20Sopenharmony_ci io_req->alloc = 0; 4738c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&cmd_mgr->lock, flags); 4748c2ecf20Sopenharmony_ci} 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_cistatic int qedf_map_sg(struct qedf_ioreq *io_req) 4778c2ecf20Sopenharmony_ci{ 4788c2ecf20Sopenharmony_ci struct scsi_cmnd *sc = io_req->sc_cmd; 4798c2ecf20Sopenharmony_ci struct Scsi_Host *host = sc->device->host; 4808c2ecf20Sopenharmony_ci struct fc_lport *lport = shost_priv(host); 4818c2ecf20Sopenharmony_ci struct qedf_ctx *qedf = lport_priv(lport); 4828c2ecf20Sopenharmony_ci struct scsi_sge *bd = io_req->bd_tbl->bd_tbl; 4838c2ecf20Sopenharmony_ci struct scatterlist *sg; 4848c2ecf20Sopenharmony_ci int byte_count = 0; 4858c2ecf20Sopenharmony_ci int sg_count = 0; 4868c2ecf20Sopenharmony_ci int bd_count = 0; 4878c2ecf20Sopenharmony_ci u32 sg_len; 4888c2ecf20Sopenharmony_ci u64 addr; 4898c2ecf20Sopenharmony_ci int i = 0; 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci sg_count = dma_map_sg(&qedf->pdev->dev, scsi_sglist(sc), 4928c2ecf20Sopenharmony_ci scsi_sg_count(sc), sc->sc_data_direction); 4938c2ecf20Sopenharmony_ci sg = scsi_sglist(sc); 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci io_req->sge_type = QEDF_IOREQ_UNKNOWN_SGE; 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci if (sg_count <= 8 || io_req->io_req_flags == QEDF_READ) 4988c2ecf20Sopenharmony_ci io_req->sge_type = QEDF_IOREQ_FAST_SGE; 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci scsi_for_each_sg(sc, sg, sg_count, i) { 5018c2ecf20Sopenharmony_ci sg_len = (u32)sg_dma_len(sg); 5028c2ecf20Sopenharmony_ci addr = (u64)sg_dma_address(sg); 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci /* 5058c2ecf20Sopenharmony_ci * Intermediate s/g element so check if start address 5068c2ecf20Sopenharmony_ci * is page aligned. Only required for writes and only if the 5078c2ecf20Sopenharmony_ci * number of scatter/gather elements is 8 or more. 5088c2ecf20Sopenharmony_ci */ 5098c2ecf20Sopenharmony_ci if (io_req->sge_type == QEDF_IOREQ_UNKNOWN_SGE && (i) && 5108c2ecf20Sopenharmony_ci (i != (sg_count - 1)) && sg_len < QEDF_PAGE_SIZE) 5118c2ecf20Sopenharmony_ci io_req->sge_type = QEDF_IOREQ_SLOW_SGE; 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci bd[bd_count].sge_addr.lo = cpu_to_le32(U64_LO(addr)); 5148c2ecf20Sopenharmony_ci bd[bd_count].sge_addr.hi = cpu_to_le32(U64_HI(addr)); 5158c2ecf20Sopenharmony_ci bd[bd_count].sge_len = cpu_to_le32(sg_len); 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci bd_count++; 5188c2ecf20Sopenharmony_ci byte_count += sg_len; 5198c2ecf20Sopenharmony_ci } 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci /* To catch a case where FAST and SLOW nothing is set, set FAST */ 5228c2ecf20Sopenharmony_ci if (io_req->sge_type == QEDF_IOREQ_UNKNOWN_SGE) 5238c2ecf20Sopenharmony_ci io_req->sge_type = QEDF_IOREQ_FAST_SGE; 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci if (byte_count != scsi_bufflen(sc)) 5268c2ecf20Sopenharmony_ci QEDF_ERR(&(qedf->dbg_ctx), "byte_count = %d != " 5278c2ecf20Sopenharmony_ci "scsi_bufflen = %d, task_id = 0x%x.\n", byte_count, 5288c2ecf20Sopenharmony_ci scsi_bufflen(sc), io_req->xid); 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci return bd_count; 5318c2ecf20Sopenharmony_ci} 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_cistatic int qedf_build_bd_list_from_sg(struct qedf_ioreq *io_req) 5348c2ecf20Sopenharmony_ci{ 5358c2ecf20Sopenharmony_ci struct scsi_cmnd *sc = io_req->sc_cmd; 5368c2ecf20Sopenharmony_ci struct scsi_sge *bd = io_req->bd_tbl->bd_tbl; 5378c2ecf20Sopenharmony_ci int bd_count; 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci if (scsi_sg_count(sc)) { 5408c2ecf20Sopenharmony_ci bd_count = qedf_map_sg(io_req); 5418c2ecf20Sopenharmony_ci if (bd_count == 0) 5428c2ecf20Sopenharmony_ci return -ENOMEM; 5438c2ecf20Sopenharmony_ci } else { 5448c2ecf20Sopenharmony_ci bd_count = 0; 5458c2ecf20Sopenharmony_ci bd[0].sge_addr.lo = bd[0].sge_addr.hi = 0; 5468c2ecf20Sopenharmony_ci bd[0].sge_len = 0; 5478c2ecf20Sopenharmony_ci } 5488c2ecf20Sopenharmony_ci io_req->bd_tbl->bd_valid = bd_count; 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci return 0; 5518c2ecf20Sopenharmony_ci} 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_cistatic void qedf_build_fcp_cmnd(struct qedf_ioreq *io_req, 5548c2ecf20Sopenharmony_ci struct fcp_cmnd *fcp_cmnd) 5558c2ecf20Sopenharmony_ci{ 5568c2ecf20Sopenharmony_ci struct scsi_cmnd *sc_cmd = io_req->sc_cmd; 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci /* fcp_cmnd is 32 bytes */ 5598c2ecf20Sopenharmony_ci memset(fcp_cmnd, 0, FCP_CMND_LEN); 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci /* 8 bytes: SCSI LUN info */ 5628c2ecf20Sopenharmony_ci int_to_scsilun(sc_cmd->device->lun, 5638c2ecf20Sopenharmony_ci (struct scsi_lun *)&fcp_cmnd->fc_lun); 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci /* 4 bytes: flag info */ 5668c2ecf20Sopenharmony_ci fcp_cmnd->fc_pri_ta = 0; 5678c2ecf20Sopenharmony_ci fcp_cmnd->fc_tm_flags = io_req->tm_flags; 5688c2ecf20Sopenharmony_ci fcp_cmnd->fc_flags = io_req->io_req_flags; 5698c2ecf20Sopenharmony_ci fcp_cmnd->fc_cmdref = 0; 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci /* Populate data direction */ 5728c2ecf20Sopenharmony_ci if (io_req->cmd_type == QEDF_TASK_MGMT_CMD) { 5738c2ecf20Sopenharmony_ci fcp_cmnd->fc_flags |= FCP_CFL_RDDATA; 5748c2ecf20Sopenharmony_ci } else { 5758c2ecf20Sopenharmony_ci if (sc_cmd->sc_data_direction == DMA_TO_DEVICE) 5768c2ecf20Sopenharmony_ci fcp_cmnd->fc_flags |= FCP_CFL_WRDATA; 5778c2ecf20Sopenharmony_ci else if (sc_cmd->sc_data_direction == DMA_FROM_DEVICE) 5788c2ecf20Sopenharmony_ci fcp_cmnd->fc_flags |= FCP_CFL_RDDATA; 5798c2ecf20Sopenharmony_ci } 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci fcp_cmnd->fc_pri_ta = FCP_PTA_SIMPLE; 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci /* 16 bytes: CDB information */ 5848c2ecf20Sopenharmony_ci if (io_req->cmd_type != QEDF_TASK_MGMT_CMD) 5858c2ecf20Sopenharmony_ci memcpy(fcp_cmnd->fc_cdb, sc_cmd->cmnd, sc_cmd->cmd_len); 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci /* 4 bytes: FCP data length */ 5888c2ecf20Sopenharmony_ci fcp_cmnd->fc_dl = htonl(io_req->data_xfer_len); 5898c2ecf20Sopenharmony_ci} 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_cistatic void qedf_init_task(struct qedf_rport *fcport, struct fc_lport *lport, 5928c2ecf20Sopenharmony_ci struct qedf_ioreq *io_req, struct e4_fcoe_task_context *task_ctx, 5938c2ecf20Sopenharmony_ci struct fcoe_wqe *sqe) 5948c2ecf20Sopenharmony_ci{ 5958c2ecf20Sopenharmony_ci enum fcoe_task_type task_type; 5968c2ecf20Sopenharmony_ci struct scsi_cmnd *sc_cmd = io_req->sc_cmd; 5978c2ecf20Sopenharmony_ci struct io_bdt *bd_tbl = io_req->bd_tbl; 5988c2ecf20Sopenharmony_ci u8 fcp_cmnd[32]; 5998c2ecf20Sopenharmony_ci u32 tmp_fcp_cmnd[8]; 6008c2ecf20Sopenharmony_ci int bd_count = 0; 6018c2ecf20Sopenharmony_ci struct qedf_ctx *qedf = fcport->qedf; 6028c2ecf20Sopenharmony_ci uint16_t cq_idx = smp_processor_id() % qedf->num_queues; 6038c2ecf20Sopenharmony_ci struct regpair sense_data_buffer_phys_addr; 6048c2ecf20Sopenharmony_ci u32 tx_io_size = 0; 6058c2ecf20Sopenharmony_ci u32 rx_io_size = 0; 6068c2ecf20Sopenharmony_ci int i, cnt; 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci /* Note init_initiator_rw_fcoe_task memsets the task context */ 6098c2ecf20Sopenharmony_ci io_req->task = task_ctx; 6108c2ecf20Sopenharmony_ci memset(task_ctx, 0, sizeof(struct e4_fcoe_task_context)); 6118c2ecf20Sopenharmony_ci memset(io_req->task_params, 0, sizeof(struct fcoe_task_params)); 6128c2ecf20Sopenharmony_ci memset(io_req->sgl_task_params, 0, sizeof(struct scsi_sgl_task_params)); 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci /* Set task type bassed on DMA directio of command */ 6158c2ecf20Sopenharmony_ci if (io_req->cmd_type == QEDF_TASK_MGMT_CMD) { 6168c2ecf20Sopenharmony_ci task_type = FCOE_TASK_TYPE_READ_INITIATOR; 6178c2ecf20Sopenharmony_ci } else { 6188c2ecf20Sopenharmony_ci if (sc_cmd->sc_data_direction == DMA_TO_DEVICE) { 6198c2ecf20Sopenharmony_ci task_type = FCOE_TASK_TYPE_WRITE_INITIATOR; 6208c2ecf20Sopenharmony_ci tx_io_size = io_req->data_xfer_len; 6218c2ecf20Sopenharmony_ci } else { 6228c2ecf20Sopenharmony_ci task_type = FCOE_TASK_TYPE_READ_INITIATOR; 6238c2ecf20Sopenharmony_ci rx_io_size = io_req->data_xfer_len; 6248c2ecf20Sopenharmony_ci } 6258c2ecf20Sopenharmony_ci } 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci /* Setup the fields for fcoe_task_params */ 6288c2ecf20Sopenharmony_ci io_req->task_params->context = task_ctx; 6298c2ecf20Sopenharmony_ci io_req->task_params->sqe = sqe; 6308c2ecf20Sopenharmony_ci io_req->task_params->task_type = task_type; 6318c2ecf20Sopenharmony_ci io_req->task_params->tx_io_size = tx_io_size; 6328c2ecf20Sopenharmony_ci io_req->task_params->rx_io_size = rx_io_size; 6338c2ecf20Sopenharmony_ci io_req->task_params->conn_cid = fcport->fw_cid; 6348c2ecf20Sopenharmony_ci io_req->task_params->itid = io_req->xid; 6358c2ecf20Sopenharmony_ci io_req->task_params->cq_rss_number = cq_idx; 6368c2ecf20Sopenharmony_ci io_req->task_params->is_tape_device = fcport->dev_type; 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci /* Fill in information for scatter/gather list */ 6398c2ecf20Sopenharmony_ci if (io_req->cmd_type != QEDF_TASK_MGMT_CMD) { 6408c2ecf20Sopenharmony_ci bd_count = bd_tbl->bd_valid; 6418c2ecf20Sopenharmony_ci io_req->sgl_task_params->sgl = bd_tbl->bd_tbl; 6428c2ecf20Sopenharmony_ci io_req->sgl_task_params->sgl_phys_addr.lo = 6438c2ecf20Sopenharmony_ci U64_LO(bd_tbl->bd_tbl_dma); 6448c2ecf20Sopenharmony_ci io_req->sgl_task_params->sgl_phys_addr.hi = 6458c2ecf20Sopenharmony_ci U64_HI(bd_tbl->bd_tbl_dma); 6468c2ecf20Sopenharmony_ci io_req->sgl_task_params->num_sges = bd_count; 6478c2ecf20Sopenharmony_ci io_req->sgl_task_params->total_buffer_size = 6488c2ecf20Sopenharmony_ci scsi_bufflen(io_req->sc_cmd); 6498c2ecf20Sopenharmony_ci if (io_req->sge_type == QEDF_IOREQ_SLOW_SGE) 6508c2ecf20Sopenharmony_ci io_req->sgl_task_params->small_mid_sge = 1; 6518c2ecf20Sopenharmony_ci else 6528c2ecf20Sopenharmony_ci io_req->sgl_task_params->small_mid_sge = 0; 6538c2ecf20Sopenharmony_ci } 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci /* Fill in physical address of sense buffer */ 6568c2ecf20Sopenharmony_ci sense_data_buffer_phys_addr.lo = U64_LO(io_req->sense_buffer_dma); 6578c2ecf20Sopenharmony_ci sense_data_buffer_phys_addr.hi = U64_HI(io_req->sense_buffer_dma); 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci /* fill FCP_CMND IU */ 6608c2ecf20Sopenharmony_ci qedf_build_fcp_cmnd(io_req, (struct fcp_cmnd *)tmp_fcp_cmnd); 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci /* Swap fcp_cmnd since FC is big endian */ 6638c2ecf20Sopenharmony_ci cnt = sizeof(struct fcp_cmnd) / sizeof(u32); 6648c2ecf20Sopenharmony_ci for (i = 0; i < cnt; i++) { 6658c2ecf20Sopenharmony_ci tmp_fcp_cmnd[i] = cpu_to_be32(tmp_fcp_cmnd[i]); 6668c2ecf20Sopenharmony_ci } 6678c2ecf20Sopenharmony_ci memcpy(fcp_cmnd, tmp_fcp_cmnd, sizeof(struct fcp_cmnd)); 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci init_initiator_rw_fcoe_task(io_req->task_params, 6708c2ecf20Sopenharmony_ci io_req->sgl_task_params, 6718c2ecf20Sopenharmony_ci sense_data_buffer_phys_addr, 6728c2ecf20Sopenharmony_ci io_req->task_retry_identifier, fcp_cmnd); 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci /* Increment SGL type counters */ 6758c2ecf20Sopenharmony_ci if (io_req->sge_type == QEDF_IOREQ_SLOW_SGE) 6768c2ecf20Sopenharmony_ci qedf->slow_sge_ios++; 6778c2ecf20Sopenharmony_ci else 6788c2ecf20Sopenharmony_ci qedf->fast_sge_ios++; 6798c2ecf20Sopenharmony_ci} 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_civoid qedf_init_mp_task(struct qedf_ioreq *io_req, 6828c2ecf20Sopenharmony_ci struct e4_fcoe_task_context *task_ctx, struct fcoe_wqe *sqe) 6838c2ecf20Sopenharmony_ci{ 6848c2ecf20Sopenharmony_ci struct qedf_mp_req *mp_req = &(io_req->mp_req); 6858c2ecf20Sopenharmony_ci struct qedf_rport *fcport = io_req->fcport; 6868c2ecf20Sopenharmony_ci struct qedf_ctx *qedf = io_req->fcport->qedf; 6878c2ecf20Sopenharmony_ci struct fc_frame_header *fc_hdr; 6888c2ecf20Sopenharmony_ci struct fcoe_tx_mid_path_params task_fc_hdr; 6898c2ecf20Sopenharmony_ci struct scsi_sgl_task_params tx_sgl_task_params; 6908c2ecf20Sopenharmony_ci struct scsi_sgl_task_params rx_sgl_task_params; 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_DISC, 6938c2ecf20Sopenharmony_ci "Initializing MP task for cmd_type=%d\n", 6948c2ecf20Sopenharmony_ci io_req->cmd_type); 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci qedf->control_requests++; 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci memset(&tx_sgl_task_params, 0, sizeof(struct scsi_sgl_task_params)); 6998c2ecf20Sopenharmony_ci memset(&rx_sgl_task_params, 0, sizeof(struct scsi_sgl_task_params)); 7008c2ecf20Sopenharmony_ci memset(task_ctx, 0, sizeof(struct e4_fcoe_task_context)); 7018c2ecf20Sopenharmony_ci memset(&task_fc_hdr, 0, sizeof(struct fcoe_tx_mid_path_params)); 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci /* Setup the task from io_req for easy reference */ 7048c2ecf20Sopenharmony_ci io_req->task = task_ctx; 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci /* Setup the fields for fcoe_task_params */ 7078c2ecf20Sopenharmony_ci io_req->task_params->context = task_ctx; 7088c2ecf20Sopenharmony_ci io_req->task_params->sqe = sqe; 7098c2ecf20Sopenharmony_ci io_req->task_params->task_type = FCOE_TASK_TYPE_MIDPATH; 7108c2ecf20Sopenharmony_ci io_req->task_params->tx_io_size = io_req->data_xfer_len; 7118c2ecf20Sopenharmony_ci /* rx_io_size tells the f/w how large a response buffer we have */ 7128c2ecf20Sopenharmony_ci io_req->task_params->rx_io_size = PAGE_SIZE; 7138c2ecf20Sopenharmony_ci io_req->task_params->conn_cid = fcport->fw_cid; 7148c2ecf20Sopenharmony_ci io_req->task_params->itid = io_req->xid; 7158c2ecf20Sopenharmony_ci /* Return middle path commands on CQ 0 */ 7168c2ecf20Sopenharmony_ci io_req->task_params->cq_rss_number = 0; 7178c2ecf20Sopenharmony_ci io_req->task_params->is_tape_device = fcport->dev_type; 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci fc_hdr = &(mp_req->req_fc_hdr); 7208c2ecf20Sopenharmony_ci /* Set OX_ID and RX_ID based on driver task id */ 7218c2ecf20Sopenharmony_ci fc_hdr->fh_ox_id = io_req->xid; 7228c2ecf20Sopenharmony_ci fc_hdr->fh_rx_id = htons(0xffff); 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci /* Set up FC header information */ 7258c2ecf20Sopenharmony_ci task_fc_hdr.parameter = fc_hdr->fh_parm_offset; 7268c2ecf20Sopenharmony_ci task_fc_hdr.r_ctl = fc_hdr->fh_r_ctl; 7278c2ecf20Sopenharmony_ci task_fc_hdr.type = fc_hdr->fh_type; 7288c2ecf20Sopenharmony_ci task_fc_hdr.cs_ctl = fc_hdr->fh_cs_ctl; 7298c2ecf20Sopenharmony_ci task_fc_hdr.df_ctl = fc_hdr->fh_df_ctl; 7308c2ecf20Sopenharmony_ci task_fc_hdr.rx_id = fc_hdr->fh_rx_id; 7318c2ecf20Sopenharmony_ci task_fc_hdr.ox_id = fc_hdr->fh_ox_id; 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci /* Set up s/g list parameters for request buffer */ 7348c2ecf20Sopenharmony_ci tx_sgl_task_params.sgl = mp_req->mp_req_bd; 7358c2ecf20Sopenharmony_ci tx_sgl_task_params.sgl_phys_addr.lo = U64_LO(mp_req->mp_req_bd_dma); 7368c2ecf20Sopenharmony_ci tx_sgl_task_params.sgl_phys_addr.hi = U64_HI(mp_req->mp_req_bd_dma); 7378c2ecf20Sopenharmony_ci tx_sgl_task_params.num_sges = 1; 7388c2ecf20Sopenharmony_ci /* Set PAGE_SIZE for now since sg element is that size ??? */ 7398c2ecf20Sopenharmony_ci tx_sgl_task_params.total_buffer_size = io_req->data_xfer_len; 7408c2ecf20Sopenharmony_ci tx_sgl_task_params.small_mid_sge = 0; 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci /* Set up s/g list parameters for request buffer */ 7438c2ecf20Sopenharmony_ci rx_sgl_task_params.sgl = mp_req->mp_resp_bd; 7448c2ecf20Sopenharmony_ci rx_sgl_task_params.sgl_phys_addr.lo = U64_LO(mp_req->mp_resp_bd_dma); 7458c2ecf20Sopenharmony_ci rx_sgl_task_params.sgl_phys_addr.hi = U64_HI(mp_req->mp_resp_bd_dma); 7468c2ecf20Sopenharmony_ci rx_sgl_task_params.num_sges = 1; 7478c2ecf20Sopenharmony_ci /* Set PAGE_SIZE for now since sg element is that size ??? */ 7488c2ecf20Sopenharmony_ci rx_sgl_task_params.total_buffer_size = PAGE_SIZE; 7498c2ecf20Sopenharmony_ci rx_sgl_task_params.small_mid_sge = 0; 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci /* 7538c2ecf20Sopenharmony_ci * Last arg is 0 as previous code did not set that we wanted the 7548c2ecf20Sopenharmony_ci * fc header information. 7558c2ecf20Sopenharmony_ci */ 7568c2ecf20Sopenharmony_ci init_initiator_midpath_unsolicited_fcoe_task(io_req->task_params, 7578c2ecf20Sopenharmony_ci &task_fc_hdr, 7588c2ecf20Sopenharmony_ci &tx_sgl_task_params, 7598c2ecf20Sopenharmony_ci &rx_sgl_task_params, 0); 7608c2ecf20Sopenharmony_ci} 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci/* Presumed that fcport->rport_lock is held */ 7638c2ecf20Sopenharmony_ciu16 qedf_get_sqe_idx(struct qedf_rport *fcport) 7648c2ecf20Sopenharmony_ci{ 7658c2ecf20Sopenharmony_ci uint16_t total_sqe = (fcport->sq_mem_size)/(sizeof(struct fcoe_wqe)); 7668c2ecf20Sopenharmony_ci u16 rval; 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci rval = fcport->sq_prod_idx; 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci /* Adjust ring index */ 7718c2ecf20Sopenharmony_ci fcport->sq_prod_idx++; 7728c2ecf20Sopenharmony_ci fcport->fw_sq_prod_idx++; 7738c2ecf20Sopenharmony_ci if (fcport->sq_prod_idx == total_sqe) 7748c2ecf20Sopenharmony_ci fcport->sq_prod_idx = 0; 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci return rval; 7778c2ecf20Sopenharmony_ci} 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_civoid qedf_ring_doorbell(struct qedf_rport *fcport) 7808c2ecf20Sopenharmony_ci{ 7818c2ecf20Sopenharmony_ci struct fcoe_db_data dbell = { 0 }; 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci dbell.agg_flags = 0; 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci dbell.params |= DB_DEST_XCM << FCOE_DB_DATA_DEST_SHIFT; 7868c2ecf20Sopenharmony_ci dbell.params |= DB_AGG_CMD_SET << FCOE_DB_DATA_AGG_CMD_SHIFT; 7878c2ecf20Sopenharmony_ci dbell.params |= DQ_XCM_FCOE_SQ_PROD_CMD << 7888c2ecf20Sopenharmony_ci FCOE_DB_DATA_AGG_VAL_SEL_SHIFT; 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci dbell.sq_prod = fcport->fw_sq_prod_idx; 7918c2ecf20Sopenharmony_ci /* wmb makes sure that the BDs data is updated before updating the 7928c2ecf20Sopenharmony_ci * producer, otherwise FW may read old data from the BDs. 7938c2ecf20Sopenharmony_ci */ 7948c2ecf20Sopenharmony_ci wmb(); 7958c2ecf20Sopenharmony_ci barrier(); 7968c2ecf20Sopenharmony_ci writel(*(u32 *)&dbell, fcport->p_doorbell); 7978c2ecf20Sopenharmony_ci /* 7988c2ecf20Sopenharmony_ci * Fence required to flush the write combined buffer, since another 7998c2ecf20Sopenharmony_ci * CPU may write to the same doorbell address and data may be lost 8008c2ecf20Sopenharmony_ci * due to relaxed order nature of write combined bar. 8018c2ecf20Sopenharmony_ci */ 8028c2ecf20Sopenharmony_ci wmb(); 8038c2ecf20Sopenharmony_ci} 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_cistatic void qedf_trace_io(struct qedf_rport *fcport, struct qedf_ioreq *io_req, 8068c2ecf20Sopenharmony_ci int8_t direction) 8078c2ecf20Sopenharmony_ci{ 8088c2ecf20Sopenharmony_ci struct qedf_ctx *qedf = fcport->qedf; 8098c2ecf20Sopenharmony_ci struct qedf_io_log *io_log; 8108c2ecf20Sopenharmony_ci struct scsi_cmnd *sc_cmd = io_req->sc_cmd; 8118c2ecf20Sopenharmony_ci unsigned long flags; 8128c2ecf20Sopenharmony_ci uint8_t op; 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci spin_lock_irqsave(&qedf->io_trace_lock, flags); 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci io_log = &qedf->io_trace_buf[qedf->io_trace_idx]; 8178c2ecf20Sopenharmony_ci io_log->direction = direction; 8188c2ecf20Sopenharmony_ci io_log->task_id = io_req->xid; 8198c2ecf20Sopenharmony_ci io_log->port_id = fcport->rdata->ids.port_id; 8208c2ecf20Sopenharmony_ci io_log->lun = sc_cmd->device->lun; 8218c2ecf20Sopenharmony_ci io_log->op = op = sc_cmd->cmnd[0]; 8228c2ecf20Sopenharmony_ci io_log->lba[0] = sc_cmd->cmnd[2]; 8238c2ecf20Sopenharmony_ci io_log->lba[1] = sc_cmd->cmnd[3]; 8248c2ecf20Sopenharmony_ci io_log->lba[2] = sc_cmd->cmnd[4]; 8258c2ecf20Sopenharmony_ci io_log->lba[3] = sc_cmd->cmnd[5]; 8268c2ecf20Sopenharmony_ci io_log->bufflen = scsi_bufflen(sc_cmd); 8278c2ecf20Sopenharmony_ci io_log->sg_count = scsi_sg_count(sc_cmd); 8288c2ecf20Sopenharmony_ci io_log->result = sc_cmd->result; 8298c2ecf20Sopenharmony_ci io_log->jiffies = jiffies; 8308c2ecf20Sopenharmony_ci io_log->refcount = kref_read(&io_req->refcount); 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci if (direction == QEDF_IO_TRACE_REQ) { 8338c2ecf20Sopenharmony_ci /* For requests we only care abot the submission CPU */ 8348c2ecf20Sopenharmony_ci io_log->req_cpu = io_req->cpu; 8358c2ecf20Sopenharmony_ci io_log->int_cpu = 0; 8368c2ecf20Sopenharmony_ci io_log->rsp_cpu = 0; 8378c2ecf20Sopenharmony_ci } else if (direction == QEDF_IO_TRACE_RSP) { 8388c2ecf20Sopenharmony_ci io_log->req_cpu = io_req->cpu; 8398c2ecf20Sopenharmony_ci io_log->int_cpu = io_req->int_cpu; 8408c2ecf20Sopenharmony_ci io_log->rsp_cpu = smp_processor_id(); 8418c2ecf20Sopenharmony_ci } 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci io_log->sge_type = io_req->sge_type; 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_ci qedf->io_trace_idx++; 8468c2ecf20Sopenharmony_ci if (qedf->io_trace_idx == QEDF_IO_TRACE_SIZE) 8478c2ecf20Sopenharmony_ci qedf->io_trace_idx = 0; 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&qedf->io_trace_lock, flags); 8508c2ecf20Sopenharmony_ci} 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ciint qedf_post_io_req(struct qedf_rport *fcport, struct qedf_ioreq *io_req) 8538c2ecf20Sopenharmony_ci{ 8548c2ecf20Sopenharmony_ci struct scsi_cmnd *sc_cmd = io_req->sc_cmd; 8558c2ecf20Sopenharmony_ci struct Scsi_Host *host = sc_cmd->device->host; 8568c2ecf20Sopenharmony_ci struct fc_lport *lport = shost_priv(host); 8578c2ecf20Sopenharmony_ci struct qedf_ctx *qedf = lport_priv(lport); 8588c2ecf20Sopenharmony_ci struct e4_fcoe_task_context *task_ctx; 8598c2ecf20Sopenharmony_ci u16 xid; 8608c2ecf20Sopenharmony_ci struct fcoe_wqe *sqe; 8618c2ecf20Sopenharmony_ci u16 sqe_idx; 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci /* Initialize rest of io_req fileds */ 8648c2ecf20Sopenharmony_ci io_req->data_xfer_len = scsi_bufflen(sc_cmd); 8658c2ecf20Sopenharmony_ci sc_cmd->SCp.ptr = (char *)io_req; 8668c2ecf20Sopenharmony_ci io_req->sge_type = QEDF_IOREQ_FAST_SGE; /* Assume fast SGL by default */ 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci /* Record which cpu this request is associated with */ 8698c2ecf20Sopenharmony_ci io_req->cpu = smp_processor_id(); 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci if (sc_cmd->sc_data_direction == DMA_FROM_DEVICE) { 8728c2ecf20Sopenharmony_ci io_req->io_req_flags = QEDF_READ; 8738c2ecf20Sopenharmony_ci qedf->input_requests++; 8748c2ecf20Sopenharmony_ci } else if (sc_cmd->sc_data_direction == DMA_TO_DEVICE) { 8758c2ecf20Sopenharmony_ci io_req->io_req_flags = QEDF_WRITE; 8768c2ecf20Sopenharmony_ci qedf->output_requests++; 8778c2ecf20Sopenharmony_ci } else { 8788c2ecf20Sopenharmony_ci io_req->io_req_flags = 0; 8798c2ecf20Sopenharmony_ci qedf->control_requests++; 8808c2ecf20Sopenharmony_ci } 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci xid = io_req->xid; 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci /* Build buffer descriptor list for firmware from sg list */ 8858c2ecf20Sopenharmony_ci if (qedf_build_bd_list_from_sg(io_req)) { 8868c2ecf20Sopenharmony_ci QEDF_ERR(&(qedf->dbg_ctx), "BD list creation failed.\n"); 8878c2ecf20Sopenharmony_ci /* Release cmd will release io_req, but sc_cmd is assigned */ 8888c2ecf20Sopenharmony_ci io_req->sc_cmd = NULL; 8898c2ecf20Sopenharmony_ci kref_put(&io_req->refcount, qedf_release_cmd); 8908c2ecf20Sopenharmony_ci return -EAGAIN; 8918c2ecf20Sopenharmony_ci } 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci if (!test_bit(QEDF_RPORT_SESSION_READY, &fcport->flags) || 8948c2ecf20Sopenharmony_ci test_bit(QEDF_RPORT_UPLOADING_CONNECTION, &fcport->flags)) { 8958c2ecf20Sopenharmony_ci QEDF_ERR(&(qedf->dbg_ctx), "Session not offloaded yet.\n"); 8968c2ecf20Sopenharmony_ci /* Release cmd will release io_req, but sc_cmd is assigned */ 8978c2ecf20Sopenharmony_ci io_req->sc_cmd = NULL; 8988c2ecf20Sopenharmony_ci kref_put(&io_req->refcount, qedf_release_cmd); 8998c2ecf20Sopenharmony_ci return -EINVAL; 9008c2ecf20Sopenharmony_ci } 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci /* Record LUN number for later use if we neeed them */ 9038c2ecf20Sopenharmony_ci io_req->lun = (int)sc_cmd->device->lun; 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci /* Obtain free SQE */ 9068c2ecf20Sopenharmony_ci sqe_idx = qedf_get_sqe_idx(fcport); 9078c2ecf20Sopenharmony_ci sqe = &fcport->sq[sqe_idx]; 9088c2ecf20Sopenharmony_ci memset(sqe, 0, sizeof(struct fcoe_wqe)); 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci /* Get the task context */ 9118c2ecf20Sopenharmony_ci task_ctx = qedf_get_task_mem(&qedf->tasks, xid); 9128c2ecf20Sopenharmony_ci if (!task_ctx) { 9138c2ecf20Sopenharmony_ci QEDF_WARN(&(qedf->dbg_ctx), "task_ctx is NULL, xid=%d.\n", 9148c2ecf20Sopenharmony_ci xid); 9158c2ecf20Sopenharmony_ci /* Release cmd will release io_req, but sc_cmd is assigned */ 9168c2ecf20Sopenharmony_ci io_req->sc_cmd = NULL; 9178c2ecf20Sopenharmony_ci kref_put(&io_req->refcount, qedf_release_cmd); 9188c2ecf20Sopenharmony_ci return -EINVAL; 9198c2ecf20Sopenharmony_ci } 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci qedf_init_task(fcport, lport, io_req, task_ctx, sqe); 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci /* Ring doorbell */ 9248c2ecf20Sopenharmony_ci qedf_ring_doorbell(fcport); 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci /* Set that command is with the firmware now */ 9278c2ecf20Sopenharmony_ci set_bit(QEDF_CMD_OUTSTANDING, &io_req->flags); 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_ci if (qedf_io_tracing && io_req->sc_cmd) 9308c2ecf20Sopenharmony_ci qedf_trace_io(fcport, io_req, QEDF_IO_TRACE_REQ); 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci return false; 9338c2ecf20Sopenharmony_ci} 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ciint 9368c2ecf20Sopenharmony_ciqedf_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc_cmd) 9378c2ecf20Sopenharmony_ci{ 9388c2ecf20Sopenharmony_ci struct fc_lport *lport = shost_priv(host); 9398c2ecf20Sopenharmony_ci struct qedf_ctx *qedf = lport_priv(lport); 9408c2ecf20Sopenharmony_ci struct fc_rport *rport = starget_to_rport(scsi_target(sc_cmd->device)); 9418c2ecf20Sopenharmony_ci struct fc_rport_libfc_priv *rp = rport->dd_data; 9428c2ecf20Sopenharmony_ci struct qedf_rport *fcport; 9438c2ecf20Sopenharmony_ci struct qedf_ioreq *io_req; 9448c2ecf20Sopenharmony_ci int rc = 0; 9458c2ecf20Sopenharmony_ci int rval; 9468c2ecf20Sopenharmony_ci unsigned long flags = 0; 9478c2ecf20Sopenharmony_ci int num_sgs = 0; 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci num_sgs = scsi_sg_count(sc_cmd); 9508c2ecf20Sopenharmony_ci if (scsi_sg_count(sc_cmd) > QEDF_MAX_BDS_PER_CMD) { 9518c2ecf20Sopenharmony_ci QEDF_ERR(&qedf->dbg_ctx, 9528c2ecf20Sopenharmony_ci "Number of SG elements %d exceeds what hardware limitation of %d.\n", 9538c2ecf20Sopenharmony_ci num_sgs, QEDF_MAX_BDS_PER_CMD); 9548c2ecf20Sopenharmony_ci sc_cmd->result = DID_ERROR; 9558c2ecf20Sopenharmony_ci sc_cmd->scsi_done(sc_cmd); 9568c2ecf20Sopenharmony_ci return 0; 9578c2ecf20Sopenharmony_ci } 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci if (test_bit(QEDF_UNLOADING, &qedf->flags) || 9608c2ecf20Sopenharmony_ci test_bit(QEDF_DBG_STOP_IO, &qedf->flags)) { 9618c2ecf20Sopenharmony_ci QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, 9628c2ecf20Sopenharmony_ci "Returning DNC as unloading or stop io, flags 0x%lx.\n", 9638c2ecf20Sopenharmony_ci qedf->flags); 9648c2ecf20Sopenharmony_ci sc_cmd->result = DID_NO_CONNECT << 16; 9658c2ecf20Sopenharmony_ci sc_cmd->scsi_done(sc_cmd); 9668c2ecf20Sopenharmony_ci return 0; 9678c2ecf20Sopenharmony_ci } 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci if (!qedf->pdev->msix_enabled) { 9708c2ecf20Sopenharmony_ci QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_IO, 9718c2ecf20Sopenharmony_ci "Completing sc_cmd=%p DID_NO_CONNECT as MSI-X is not enabled.\n", 9728c2ecf20Sopenharmony_ci sc_cmd); 9738c2ecf20Sopenharmony_ci sc_cmd->result = DID_NO_CONNECT << 16; 9748c2ecf20Sopenharmony_ci sc_cmd->scsi_done(sc_cmd); 9758c2ecf20Sopenharmony_ci return 0; 9768c2ecf20Sopenharmony_ci } 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci rval = fc_remote_port_chkready(rport); 9798c2ecf20Sopenharmony_ci if (rval) { 9808c2ecf20Sopenharmony_ci QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, 9818c2ecf20Sopenharmony_ci "fc_remote_port_chkready failed=0x%x for port_id=0x%06x.\n", 9828c2ecf20Sopenharmony_ci rval, rport->port_id); 9838c2ecf20Sopenharmony_ci sc_cmd->result = rval; 9848c2ecf20Sopenharmony_ci sc_cmd->scsi_done(sc_cmd); 9858c2ecf20Sopenharmony_ci return 0; 9868c2ecf20Sopenharmony_ci } 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ci /* Retry command if we are doing a qed drain operation */ 9898c2ecf20Sopenharmony_ci if (test_bit(QEDF_DRAIN_ACTIVE, &qedf->flags)) { 9908c2ecf20Sopenharmony_ci QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, "Drain active.\n"); 9918c2ecf20Sopenharmony_ci rc = SCSI_MLQUEUE_HOST_BUSY; 9928c2ecf20Sopenharmony_ci goto exit_qcmd; 9938c2ecf20Sopenharmony_ci } 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci if (lport->state != LPORT_ST_READY || 9968c2ecf20Sopenharmony_ci atomic_read(&qedf->link_state) != QEDF_LINK_UP) { 9978c2ecf20Sopenharmony_ci QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, "Link down.\n"); 9988c2ecf20Sopenharmony_ci rc = SCSI_MLQUEUE_HOST_BUSY; 9998c2ecf20Sopenharmony_ci goto exit_qcmd; 10008c2ecf20Sopenharmony_ci } 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci /* rport and tgt are allocated together, so tgt should be non-NULL */ 10038c2ecf20Sopenharmony_ci fcport = (struct qedf_rport *)&rp[1]; 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci if (!test_bit(QEDF_RPORT_SESSION_READY, &fcport->flags) || 10068c2ecf20Sopenharmony_ci test_bit(QEDF_RPORT_UPLOADING_CONNECTION, &fcport->flags)) { 10078c2ecf20Sopenharmony_ci /* 10088c2ecf20Sopenharmony_ci * Session is not offloaded yet. Let SCSI-ml retry 10098c2ecf20Sopenharmony_ci * the command. 10108c2ecf20Sopenharmony_ci */ 10118c2ecf20Sopenharmony_ci rc = SCSI_MLQUEUE_TARGET_BUSY; 10128c2ecf20Sopenharmony_ci goto exit_qcmd; 10138c2ecf20Sopenharmony_ci } 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_ci atomic_inc(&fcport->ios_to_queue); 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci if (fcport->retry_delay_timestamp) { 10188c2ecf20Sopenharmony_ci /* Take fcport->rport_lock for resetting the delay_timestamp */ 10198c2ecf20Sopenharmony_ci spin_lock_irqsave(&fcport->rport_lock, flags); 10208c2ecf20Sopenharmony_ci if (time_after(jiffies, fcport->retry_delay_timestamp)) { 10218c2ecf20Sopenharmony_ci fcport->retry_delay_timestamp = 0; 10228c2ecf20Sopenharmony_ci } else { 10238c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&fcport->rport_lock, flags); 10248c2ecf20Sopenharmony_ci /* If retry_delay timer is active, flow off the ML */ 10258c2ecf20Sopenharmony_ci rc = SCSI_MLQUEUE_TARGET_BUSY; 10268c2ecf20Sopenharmony_ci atomic_dec(&fcport->ios_to_queue); 10278c2ecf20Sopenharmony_ci goto exit_qcmd; 10288c2ecf20Sopenharmony_ci } 10298c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&fcport->rport_lock, flags); 10308c2ecf20Sopenharmony_ci } 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_ci io_req = qedf_alloc_cmd(fcport, QEDF_SCSI_CMD); 10338c2ecf20Sopenharmony_ci if (!io_req) { 10348c2ecf20Sopenharmony_ci rc = SCSI_MLQUEUE_HOST_BUSY; 10358c2ecf20Sopenharmony_ci atomic_dec(&fcport->ios_to_queue); 10368c2ecf20Sopenharmony_ci goto exit_qcmd; 10378c2ecf20Sopenharmony_ci } 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ci io_req->sc_cmd = sc_cmd; 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci /* Take fcport->rport_lock for posting to fcport send queue */ 10428c2ecf20Sopenharmony_ci spin_lock_irqsave(&fcport->rport_lock, flags); 10438c2ecf20Sopenharmony_ci if (qedf_post_io_req(fcport, io_req)) { 10448c2ecf20Sopenharmony_ci QEDF_WARN(&(qedf->dbg_ctx), "Unable to post io_req\n"); 10458c2ecf20Sopenharmony_ci /* Return SQE to pool */ 10468c2ecf20Sopenharmony_ci atomic_inc(&fcport->free_sqes); 10478c2ecf20Sopenharmony_ci rc = SCSI_MLQUEUE_HOST_BUSY; 10488c2ecf20Sopenharmony_ci } 10498c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&fcport->rport_lock, flags); 10508c2ecf20Sopenharmony_ci atomic_dec(&fcport->ios_to_queue); 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ciexit_qcmd: 10538c2ecf20Sopenharmony_ci return rc; 10548c2ecf20Sopenharmony_ci} 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_cistatic void qedf_parse_fcp_rsp(struct qedf_ioreq *io_req, 10578c2ecf20Sopenharmony_ci struct fcoe_cqe_rsp_info *fcp_rsp) 10588c2ecf20Sopenharmony_ci{ 10598c2ecf20Sopenharmony_ci struct scsi_cmnd *sc_cmd = io_req->sc_cmd; 10608c2ecf20Sopenharmony_ci struct qedf_ctx *qedf = io_req->fcport->qedf; 10618c2ecf20Sopenharmony_ci u8 rsp_flags = fcp_rsp->rsp_flags.flags; 10628c2ecf20Sopenharmony_ci int fcp_sns_len = 0; 10638c2ecf20Sopenharmony_ci int fcp_rsp_len = 0; 10648c2ecf20Sopenharmony_ci uint8_t *rsp_info, *sense_data; 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci io_req->fcp_status = FC_GOOD; 10678c2ecf20Sopenharmony_ci io_req->fcp_resid = 0; 10688c2ecf20Sopenharmony_ci if (rsp_flags & (FCOE_FCP_RSP_FLAGS_FCP_RESID_OVER | 10698c2ecf20Sopenharmony_ci FCOE_FCP_RSP_FLAGS_FCP_RESID_UNDER)) 10708c2ecf20Sopenharmony_ci io_req->fcp_resid = fcp_rsp->fcp_resid; 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci io_req->scsi_comp_flags = rsp_flags; 10738c2ecf20Sopenharmony_ci CMD_SCSI_STATUS(sc_cmd) = io_req->cdb_status = 10748c2ecf20Sopenharmony_ci fcp_rsp->scsi_status_code; 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_ci if (rsp_flags & 10778c2ecf20Sopenharmony_ci FCOE_FCP_RSP_FLAGS_FCP_RSP_LEN_VALID) 10788c2ecf20Sopenharmony_ci fcp_rsp_len = fcp_rsp->fcp_rsp_len; 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_ci if (rsp_flags & 10818c2ecf20Sopenharmony_ci FCOE_FCP_RSP_FLAGS_FCP_SNS_LEN_VALID) 10828c2ecf20Sopenharmony_ci fcp_sns_len = fcp_rsp->fcp_sns_len; 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_ci io_req->fcp_rsp_len = fcp_rsp_len; 10858c2ecf20Sopenharmony_ci io_req->fcp_sns_len = fcp_sns_len; 10868c2ecf20Sopenharmony_ci rsp_info = sense_data = io_req->sense_buffer; 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_ci /* fetch fcp_rsp_code */ 10898c2ecf20Sopenharmony_ci if ((fcp_rsp_len == 4) || (fcp_rsp_len == 8)) { 10908c2ecf20Sopenharmony_ci /* Only for task management function */ 10918c2ecf20Sopenharmony_ci io_req->fcp_rsp_code = rsp_info[3]; 10928c2ecf20Sopenharmony_ci QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_IO, 10938c2ecf20Sopenharmony_ci "fcp_rsp_code = %d\n", io_req->fcp_rsp_code); 10948c2ecf20Sopenharmony_ci /* Adjust sense-data location. */ 10958c2ecf20Sopenharmony_ci sense_data += fcp_rsp_len; 10968c2ecf20Sopenharmony_ci } 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci if (fcp_sns_len > SCSI_SENSE_BUFFERSIZE) { 10998c2ecf20Sopenharmony_ci QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_IO, 11008c2ecf20Sopenharmony_ci "Truncating sense buffer\n"); 11018c2ecf20Sopenharmony_ci fcp_sns_len = SCSI_SENSE_BUFFERSIZE; 11028c2ecf20Sopenharmony_ci } 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_ci /* The sense buffer can be NULL for TMF commands */ 11058c2ecf20Sopenharmony_ci if (sc_cmd->sense_buffer) { 11068c2ecf20Sopenharmony_ci memset(sc_cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); 11078c2ecf20Sopenharmony_ci if (fcp_sns_len) 11088c2ecf20Sopenharmony_ci memcpy(sc_cmd->sense_buffer, sense_data, 11098c2ecf20Sopenharmony_ci fcp_sns_len); 11108c2ecf20Sopenharmony_ci } 11118c2ecf20Sopenharmony_ci} 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_cistatic void qedf_unmap_sg_list(struct qedf_ctx *qedf, struct qedf_ioreq *io_req) 11148c2ecf20Sopenharmony_ci{ 11158c2ecf20Sopenharmony_ci struct scsi_cmnd *sc = io_req->sc_cmd; 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_ci if (io_req->bd_tbl->bd_valid && sc && scsi_sg_count(sc)) { 11188c2ecf20Sopenharmony_ci dma_unmap_sg(&qedf->pdev->dev, scsi_sglist(sc), 11198c2ecf20Sopenharmony_ci scsi_sg_count(sc), sc->sc_data_direction); 11208c2ecf20Sopenharmony_ci io_req->bd_tbl->bd_valid = 0; 11218c2ecf20Sopenharmony_ci } 11228c2ecf20Sopenharmony_ci} 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_civoid qedf_scsi_completion(struct qedf_ctx *qedf, struct fcoe_cqe *cqe, 11258c2ecf20Sopenharmony_ci struct qedf_ioreq *io_req) 11268c2ecf20Sopenharmony_ci{ 11278c2ecf20Sopenharmony_ci struct scsi_cmnd *sc_cmd; 11288c2ecf20Sopenharmony_ci struct fcoe_cqe_rsp_info *fcp_rsp; 11298c2ecf20Sopenharmony_ci struct qedf_rport *fcport; 11308c2ecf20Sopenharmony_ci int refcount; 11318c2ecf20Sopenharmony_ci u16 scope, qualifier = 0; 11328c2ecf20Sopenharmony_ci u8 fw_residual_flag = 0; 11338c2ecf20Sopenharmony_ci unsigned long flags = 0; 11348c2ecf20Sopenharmony_ci u16 chk_scope = 0; 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci if (!io_req) 11378c2ecf20Sopenharmony_ci return; 11388c2ecf20Sopenharmony_ci if (!cqe) 11398c2ecf20Sopenharmony_ci return; 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_ci if (!test_bit(QEDF_CMD_OUTSTANDING, &io_req->flags) || 11428c2ecf20Sopenharmony_ci test_bit(QEDF_CMD_IN_CLEANUP, &io_req->flags) || 11438c2ecf20Sopenharmony_ci test_bit(QEDF_CMD_IN_ABORT, &io_req->flags)) { 11448c2ecf20Sopenharmony_ci QEDF_ERR(&qedf->dbg_ctx, 11458c2ecf20Sopenharmony_ci "io_req xid=0x%x already in cleanup or abort processing or already completed.\n", 11468c2ecf20Sopenharmony_ci io_req->xid); 11478c2ecf20Sopenharmony_ci return; 11488c2ecf20Sopenharmony_ci } 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_ci sc_cmd = io_req->sc_cmd; 11518c2ecf20Sopenharmony_ci fcp_rsp = &cqe->cqe_info.rsp_info; 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_ci if (!sc_cmd) { 11548c2ecf20Sopenharmony_ci QEDF_WARN(&(qedf->dbg_ctx), "sc_cmd is NULL!\n"); 11558c2ecf20Sopenharmony_ci return; 11568c2ecf20Sopenharmony_ci } 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_ci if (!sc_cmd->SCp.ptr) { 11598c2ecf20Sopenharmony_ci QEDF_WARN(&(qedf->dbg_ctx), "SCp.ptr is NULL, returned in " 11608c2ecf20Sopenharmony_ci "another context.\n"); 11618c2ecf20Sopenharmony_ci return; 11628c2ecf20Sopenharmony_ci } 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_ci if (!sc_cmd->device) { 11658c2ecf20Sopenharmony_ci QEDF_ERR(&qedf->dbg_ctx, 11668c2ecf20Sopenharmony_ci "Device for sc_cmd %p is NULL.\n", sc_cmd); 11678c2ecf20Sopenharmony_ci return; 11688c2ecf20Sopenharmony_ci } 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci if (!sc_cmd->request) { 11718c2ecf20Sopenharmony_ci QEDF_WARN(&(qedf->dbg_ctx), "sc_cmd->request is NULL, " 11728c2ecf20Sopenharmony_ci "sc_cmd=%p.\n", sc_cmd); 11738c2ecf20Sopenharmony_ci return; 11748c2ecf20Sopenharmony_ci } 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_ci if (!sc_cmd->request->q) { 11778c2ecf20Sopenharmony_ci QEDF_WARN(&(qedf->dbg_ctx), "request->q is NULL so request " 11788c2ecf20Sopenharmony_ci "is not valid, sc_cmd=%p.\n", sc_cmd); 11798c2ecf20Sopenharmony_ci return; 11808c2ecf20Sopenharmony_ci } 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_ci fcport = io_req->fcport; 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_ci /* 11858c2ecf20Sopenharmony_ci * When flush is active, let the cmds be completed from the cleanup 11868c2ecf20Sopenharmony_ci * context 11878c2ecf20Sopenharmony_ci */ 11888c2ecf20Sopenharmony_ci if (test_bit(QEDF_RPORT_IN_TARGET_RESET, &fcport->flags) || 11898c2ecf20Sopenharmony_ci (test_bit(QEDF_RPORT_IN_LUN_RESET, &fcport->flags) && 11908c2ecf20Sopenharmony_ci sc_cmd->device->lun == (u64)fcport->lun_reset_lun)) { 11918c2ecf20Sopenharmony_ci QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, 11928c2ecf20Sopenharmony_ci "Dropping good completion xid=0x%x as fcport is flushing", 11938c2ecf20Sopenharmony_ci io_req->xid); 11948c2ecf20Sopenharmony_ci return; 11958c2ecf20Sopenharmony_ci } 11968c2ecf20Sopenharmony_ci 11978c2ecf20Sopenharmony_ci qedf_parse_fcp_rsp(io_req, fcp_rsp); 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_ci qedf_unmap_sg_list(qedf, io_req); 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_ci /* Check for FCP transport error */ 12028c2ecf20Sopenharmony_ci if (io_req->fcp_rsp_len > 3 && io_req->fcp_rsp_code) { 12038c2ecf20Sopenharmony_ci QEDF_ERR(&(qedf->dbg_ctx), 12048c2ecf20Sopenharmony_ci "FCP I/O protocol failure xid=0x%x fcp_rsp_len=%d " 12058c2ecf20Sopenharmony_ci "fcp_rsp_code=%d.\n", io_req->xid, io_req->fcp_rsp_len, 12068c2ecf20Sopenharmony_ci io_req->fcp_rsp_code); 12078c2ecf20Sopenharmony_ci sc_cmd->result = DID_BUS_BUSY << 16; 12088c2ecf20Sopenharmony_ci goto out; 12098c2ecf20Sopenharmony_ci } 12108c2ecf20Sopenharmony_ci 12118c2ecf20Sopenharmony_ci fw_residual_flag = GET_FIELD(cqe->cqe_info.rsp_info.fw_error_flags, 12128c2ecf20Sopenharmony_ci FCOE_CQE_RSP_INFO_FW_UNDERRUN); 12138c2ecf20Sopenharmony_ci if (fw_residual_flag) { 12148c2ecf20Sopenharmony_ci QEDF_ERR(&qedf->dbg_ctx, 12158c2ecf20Sopenharmony_ci "Firmware detected underrun: xid=0x%x fcp_rsp.flags=0x%02x fcp_resid=%d fw_residual=0x%x lba=%02x%02x%02x%02x.\n", 12168c2ecf20Sopenharmony_ci io_req->xid, fcp_rsp->rsp_flags.flags, 12178c2ecf20Sopenharmony_ci io_req->fcp_resid, 12188c2ecf20Sopenharmony_ci cqe->cqe_info.rsp_info.fw_residual, sc_cmd->cmnd[2], 12198c2ecf20Sopenharmony_ci sc_cmd->cmnd[3], sc_cmd->cmnd[4], sc_cmd->cmnd[5]); 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ci if (io_req->cdb_status == 0) 12228c2ecf20Sopenharmony_ci sc_cmd->result = (DID_ERROR << 16) | io_req->cdb_status; 12238c2ecf20Sopenharmony_ci else 12248c2ecf20Sopenharmony_ci sc_cmd->result = (DID_OK << 16) | io_req->cdb_status; 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_ci /* 12278c2ecf20Sopenharmony_ci * Set resid to the whole buffer length so we won't try to resue 12288c2ecf20Sopenharmony_ci * any previously data. 12298c2ecf20Sopenharmony_ci */ 12308c2ecf20Sopenharmony_ci scsi_set_resid(sc_cmd, scsi_bufflen(sc_cmd)); 12318c2ecf20Sopenharmony_ci goto out; 12328c2ecf20Sopenharmony_ci } 12338c2ecf20Sopenharmony_ci 12348c2ecf20Sopenharmony_ci switch (io_req->fcp_status) { 12358c2ecf20Sopenharmony_ci case FC_GOOD: 12368c2ecf20Sopenharmony_ci if (io_req->cdb_status == 0) { 12378c2ecf20Sopenharmony_ci /* Good I/O completion */ 12388c2ecf20Sopenharmony_ci sc_cmd->result = DID_OK << 16; 12398c2ecf20Sopenharmony_ci } else { 12408c2ecf20Sopenharmony_ci refcount = kref_read(&io_req->refcount); 12418c2ecf20Sopenharmony_ci QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_IO, 12428c2ecf20Sopenharmony_ci "%d:0:%d:%lld xid=0x%0x op=0x%02x " 12438c2ecf20Sopenharmony_ci "lba=%02x%02x%02x%02x cdb_status=%d " 12448c2ecf20Sopenharmony_ci "fcp_resid=0x%x refcount=%d.\n", 12458c2ecf20Sopenharmony_ci qedf->lport->host->host_no, sc_cmd->device->id, 12468c2ecf20Sopenharmony_ci sc_cmd->device->lun, io_req->xid, 12478c2ecf20Sopenharmony_ci sc_cmd->cmnd[0], sc_cmd->cmnd[2], sc_cmd->cmnd[3], 12488c2ecf20Sopenharmony_ci sc_cmd->cmnd[4], sc_cmd->cmnd[5], 12498c2ecf20Sopenharmony_ci io_req->cdb_status, io_req->fcp_resid, 12508c2ecf20Sopenharmony_ci refcount); 12518c2ecf20Sopenharmony_ci sc_cmd->result = (DID_OK << 16) | io_req->cdb_status; 12528c2ecf20Sopenharmony_ci 12538c2ecf20Sopenharmony_ci if (io_req->cdb_status == SAM_STAT_TASK_SET_FULL || 12548c2ecf20Sopenharmony_ci io_req->cdb_status == SAM_STAT_BUSY) { 12558c2ecf20Sopenharmony_ci /* 12568c2ecf20Sopenharmony_ci * Check whether we need to set retry_delay at 12578c2ecf20Sopenharmony_ci * all based on retry_delay module parameter 12588c2ecf20Sopenharmony_ci * and the status qualifier. 12598c2ecf20Sopenharmony_ci */ 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ci /* Upper 2 bits */ 12628c2ecf20Sopenharmony_ci scope = fcp_rsp->retry_delay_timer & 0xC000; 12638c2ecf20Sopenharmony_ci /* Lower 14 bits */ 12648c2ecf20Sopenharmony_ci qualifier = fcp_rsp->retry_delay_timer & 0x3FFF; 12658c2ecf20Sopenharmony_ci 12668c2ecf20Sopenharmony_ci if (qedf_retry_delay) 12678c2ecf20Sopenharmony_ci chk_scope = 1; 12688c2ecf20Sopenharmony_ci /* Record stats */ 12698c2ecf20Sopenharmony_ci if (io_req->cdb_status == 12708c2ecf20Sopenharmony_ci SAM_STAT_TASK_SET_FULL) 12718c2ecf20Sopenharmony_ci qedf->task_set_fulls++; 12728c2ecf20Sopenharmony_ci else 12738c2ecf20Sopenharmony_ci qedf->busy++; 12748c2ecf20Sopenharmony_ci } 12758c2ecf20Sopenharmony_ci } 12768c2ecf20Sopenharmony_ci if (io_req->fcp_resid) 12778c2ecf20Sopenharmony_ci scsi_set_resid(sc_cmd, io_req->fcp_resid); 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_ci if (chk_scope == 1) { 12808c2ecf20Sopenharmony_ci if ((scope == 1 || scope == 2) && 12818c2ecf20Sopenharmony_ci (qualifier > 0 && qualifier <= 0x3FEF)) { 12828c2ecf20Sopenharmony_ci /* Check we don't go over the max */ 12838c2ecf20Sopenharmony_ci if (qualifier > QEDF_RETRY_DELAY_MAX) { 12848c2ecf20Sopenharmony_ci qualifier = QEDF_RETRY_DELAY_MAX; 12858c2ecf20Sopenharmony_ci QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, 12868c2ecf20Sopenharmony_ci "qualifier = %d\n", 12878c2ecf20Sopenharmony_ci (fcp_rsp->retry_delay_timer & 12888c2ecf20Sopenharmony_ci 0x3FFF)); 12898c2ecf20Sopenharmony_ci } 12908c2ecf20Sopenharmony_ci QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, 12918c2ecf20Sopenharmony_ci "Scope = %d and qualifier = %d", 12928c2ecf20Sopenharmony_ci scope, qualifier); 12938c2ecf20Sopenharmony_ci /* Take fcport->rport_lock to 12948c2ecf20Sopenharmony_ci * update the retry_delay_timestamp 12958c2ecf20Sopenharmony_ci */ 12968c2ecf20Sopenharmony_ci spin_lock_irqsave(&fcport->rport_lock, flags); 12978c2ecf20Sopenharmony_ci fcport->retry_delay_timestamp = 12988c2ecf20Sopenharmony_ci jiffies + (qualifier * HZ / 10); 12998c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&fcport->rport_lock, 13008c2ecf20Sopenharmony_ci flags); 13018c2ecf20Sopenharmony_ci 13028c2ecf20Sopenharmony_ci } else { 13038c2ecf20Sopenharmony_ci QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, 13048c2ecf20Sopenharmony_ci "combination of scope = %d and qualifier = %d is not handled in qedf.\n", 13058c2ecf20Sopenharmony_ci scope, qualifier); 13068c2ecf20Sopenharmony_ci } 13078c2ecf20Sopenharmony_ci } 13088c2ecf20Sopenharmony_ci break; 13098c2ecf20Sopenharmony_ci default: 13108c2ecf20Sopenharmony_ci QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_IO, "fcp_status=%d.\n", 13118c2ecf20Sopenharmony_ci io_req->fcp_status); 13128c2ecf20Sopenharmony_ci break; 13138c2ecf20Sopenharmony_ci } 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_ciout: 13168c2ecf20Sopenharmony_ci if (qedf_io_tracing) 13178c2ecf20Sopenharmony_ci qedf_trace_io(fcport, io_req, QEDF_IO_TRACE_RSP); 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_ci /* 13208c2ecf20Sopenharmony_ci * We wait till the end of the function to clear the 13218c2ecf20Sopenharmony_ci * outstanding bit in case we need to send an abort 13228c2ecf20Sopenharmony_ci */ 13238c2ecf20Sopenharmony_ci clear_bit(QEDF_CMD_OUTSTANDING, &io_req->flags); 13248c2ecf20Sopenharmony_ci 13258c2ecf20Sopenharmony_ci io_req->sc_cmd = NULL; 13268c2ecf20Sopenharmony_ci sc_cmd->SCp.ptr = NULL; 13278c2ecf20Sopenharmony_ci sc_cmd->scsi_done(sc_cmd); 13288c2ecf20Sopenharmony_ci kref_put(&io_req->refcount, qedf_release_cmd); 13298c2ecf20Sopenharmony_ci} 13308c2ecf20Sopenharmony_ci 13318c2ecf20Sopenharmony_ci/* Return a SCSI command in some other context besides a normal completion */ 13328c2ecf20Sopenharmony_civoid qedf_scsi_done(struct qedf_ctx *qedf, struct qedf_ioreq *io_req, 13338c2ecf20Sopenharmony_ci int result) 13348c2ecf20Sopenharmony_ci{ 13358c2ecf20Sopenharmony_ci struct scsi_cmnd *sc_cmd; 13368c2ecf20Sopenharmony_ci int refcount; 13378c2ecf20Sopenharmony_ci 13388c2ecf20Sopenharmony_ci if (!io_req) { 13398c2ecf20Sopenharmony_ci QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, "io_req is NULL\n"); 13408c2ecf20Sopenharmony_ci return; 13418c2ecf20Sopenharmony_ci } 13428c2ecf20Sopenharmony_ci 13438c2ecf20Sopenharmony_ci if (test_and_set_bit(QEDF_CMD_ERR_SCSI_DONE, &io_req->flags)) { 13448c2ecf20Sopenharmony_ci QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, 13458c2ecf20Sopenharmony_ci "io_req:%p scsi_done handling already done\n", 13468c2ecf20Sopenharmony_ci io_req); 13478c2ecf20Sopenharmony_ci return; 13488c2ecf20Sopenharmony_ci } 13498c2ecf20Sopenharmony_ci 13508c2ecf20Sopenharmony_ci /* 13518c2ecf20Sopenharmony_ci * We will be done with this command after this call so clear the 13528c2ecf20Sopenharmony_ci * outstanding bit. 13538c2ecf20Sopenharmony_ci */ 13548c2ecf20Sopenharmony_ci clear_bit(QEDF_CMD_OUTSTANDING, &io_req->flags); 13558c2ecf20Sopenharmony_ci 13568c2ecf20Sopenharmony_ci sc_cmd = io_req->sc_cmd; 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_ci if (!sc_cmd) { 13598c2ecf20Sopenharmony_ci QEDF_WARN(&(qedf->dbg_ctx), "sc_cmd is NULL!\n"); 13608c2ecf20Sopenharmony_ci return; 13618c2ecf20Sopenharmony_ci } 13628c2ecf20Sopenharmony_ci 13638c2ecf20Sopenharmony_ci if (!virt_addr_valid(sc_cmd)) { 13648c2ecf20Sopenharmony_ci QEDF_ERR(&qedf->dbg_ctx, "sc_cmd=%p is not valid.", sc_cmd); 13658c2ecf20Sopenharmony_ci goto bad_scsi_ptr; 13668c2ecf20Sopenharmony_ci } 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_ci if (!sc_cmd->SCp.ptr) { 13698c2ecf20Sopenharmony_ci QEDF_WARN(&(qedf->dbg_ctx), "SCp.ptr is NULL, returned in " 13708c2ecf20Sopenharmony_ci "another context.\n"); 13718c2ecf20Sopenharmony_ci return; 13728c2ecf20Sopenharmony_ci } 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_ci if (!sc_cmd->device) { 13758c2ecf20Sopenharmony_ci QEDF_ERR(&qedf->dbg_ctx, "Device for sc_cmd %p is NULL.\n", 13768c2ecf20Sopenharmony_ci sc_cmd); 13778c2ecf20Sopenharmony_ci goto bad_scsi_ptr; 13788c2ecf20Sopenharmony_ci } 13798c2ecf20Sopenharmony_ci 13808c2ecf20Sopenharmony_ci if (!virt_addr_valid(sc_cmd->device)) { 13818c2ecf20Sopenharmony_ci QEDF_ERR(&qedf->dbg_ctx, 13828c2ecf20Sopenharmony_ci "Device pointer for sc_cmd %p is bad.\n", sc_cmd); 13838c2ecf20Sopenharmony_ci goto bad_scsi_ptr; 13848c2ecf20Sopenharmony_ci } 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_ci if (!sc_cmd->sense_buffer) { 13878c2ecf20Sopenharmony_ci QEDF_ERR(&qedf->dbg_ctx, 13888c2ecf20Sopenharmony_ci "sc_cmd->sense_buffer for sc_cmd %p is NULL.\n", 13898c2ecf20Sopenharmony_ci sc_cmd); 13908c2ecf20Sopenharmony_ci goto bad_scsi_ptr; 13918c2ecf20Sopenharmony_ci } 13928c2ecf20Sopenharmony_ci 13938c2ecf20Sopenharmony_ci if (!virt_addr_valid(sc_cmd->sense_buffer)) { 13948c2ecf20Sopenharmony_ci QEDF_ERR(&qedf->dbg_ctx, 13958c2ecf20Sopenharmony_ci "sc_cmd->sense_buffer for sc_cmd %p is bad.\n", 13968c2ecf20Sopenharmony_ci sc_cmd); 13978c2ecf20Sopenharmony_ci goto bad_scsi_ptr; 13988c2ecf20Sopenharmony_ci } 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_ci if (!sc_cmd->scsi_done) { 14018c2ecf20Sopenharmony_ci QEDF_ERR(&qedf->dbg_ctx, 14028c2ecf20Sopenharmony_ci "sc_cmd->scsi_done for sc_cmd %p is NULL.\n", 14038c2ecf20Sopenharmony_ci sc_cmd); 14048c2ecf20Sopenharmony_ci goto bad_scsi_ptr; 14058c2ecf20Sopenharmony_ci } 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_ci qedf_unmap_sg_list(qedf, io_req); 14088c2ecf20Sopenharmony_ci 14098c2ecf20Sopenharmony_ci sc_cmd->result = result << 16; 14108c2ecf20Sopenharmony_ci refcount = kref_read(&io_req->refcount); 14118c2ecf20Sopenharmony_ci QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_IO, "%d:0:%d:%lld: Completing " 14128c2ecf20Sopenharmony_ci "sc_cmd=%p result=0x%08x op=0x%02x lba=0x%02x%02x%02x%02x, " 14138c2ecf20Sopenharmony_ci "allowed=%d retries=%d refcount=%d.\n", 14148c2ecf20Sopenharmony_ci qedf->lport->host->host_no, sc_cmd->device->id, 14158c2ecf20Sopenharmony_ci sc_cmd->device->lun, sc_cmd, sc_cmd->result, sc_cmd->cmnd[0], 14168c2ecf20Sopenharmony_ci sc_cmd->cmnd[2], sc_cmd->cmnd[3], sc_cmd->cmnd[4], 14178c2ecf20Sopenharmony_ci sc_cmd->cmnd[5], sc_cmd->allowed, sc_cmd->retries, 14188c2ecf20Sopenharmony_ci refcount); 14198c2ecf20Sopenharmony_ci 14208c2ecf20Sopenharmony_ci /* 14218c2ecf20Sopenharmony_ci * Set resid to the whole buffer length so we won't try to resue any 14228c2ecf20Sopenharmony_ci * previously read data 14238c2ecf20Sopenharmony_ci */ 14248c2ecf20Sopenharmony_ci scsi_set_resid(sc_cmd, scsi_bufflen(sc_cmd)); 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ci if (qedf_io_tracing) 14278c2ecf20Sopenharmony_ci qedf_trace_io(io_req->fcport, io_req, QEDF_IO_TRACE_RSP); 14288c2ecf20Sopenharmony_ci 14298c2ecf20Sopenharmony_ci io_req->sc_cmd = NULL; 14308c2ecf20Sopenharmony_ci sc_cmd->SCp.ptr = NULL; 14318c2ecf20Sopenharmony_ci sc_cmd->scsi_done(sc_cmd); 14328c2ecf20Sopenharmony_ci kref_put(&io_req->refcount, qedf_release_cmd); 14338c2ecf20Sopenharmony_ci return; 14348c2ecf20Sopenharmony_ci 14358c2ecf20Sopenharmony_cibad_scsi_ptr: 14368c2ecf20Sopenharmony_ci /* 14378c2ecf20Sopenharmony_ci * Clear the io_req->sc_cmd backpointer so we don't try to process 14388c2ecf20Sopenharmony_ci * this again 14398c2ecf20Sopenharmony_ci */ 14408c2ecf20Sopenharmony_ci io_req->sc_cmd = NULL; 14418c2ecf20Sopenharmony_ci kref_put(&io_req->refcount, qedf_release_cmd); /* ID: 001 */ 14428c2ecf20Sopenharmony_ci} 14438c2ecf20Sopenharmony_ci 14448c2ecf20Sopenharmony_ci/* 14458c2ecf20Sopenharmony_ci * Handle warning type CQE completions. This is mainly used for REC timer 14468c2ecf20Sopenharmony_ci * popping. 14478c2ecf20Sopenharmony_ci */ 14488c2ecf20Sopenharmony_civoid qedf_process_warning_compl(struct qedf_ctx *qedf, struct fcoe_cqe *cqe, 14498c2ecf20Sopenharmony_ci struct qedf_ioreq *io_req) 14508c2ecf20Sopenharmony_ci{ 14518c2ecf20Sopenharmony_ci int rval, i; 14528c2ecf20Sopenharmony_ci struct qedf_rport *fcport = io_req->fcport; 14538c2ecf20Sopenharmony_ci u64 err_warn_bit_map; 14548c2ecf20Sopenharmony_ci u8 err_warn = 0xff; 14558c2ecf20Sopenharmony_ci 14568c2ecf20Sopenharmony_ci if (!cqe) { 14578c2ecf20Sopenharmony_ci QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, 14588c2ecf20Sopenharmony_ci "cqe is NULL for io_req %p xid=0x%x\n", 14598c2ecf20Sopenharmony_ci io_req, io_req->xid); 14608c2ecf20Sopenharmony_ci return; 14618c2ecf20Sopenharmony_ci } 14628c2ecf20Sopenharmony_ci 14638c2ecf20Sopenharmony_ci QEDF_ERR(&(io_req->fcport->qedf->dbg_ctx), "Warning CQE, " 14648c2ecf20Sopenharmony_ci "xid=0x%x\n", io_req->xid); 14658c2ecf20Sopenharmony_ci QEDF_ERR(&(io_req->fcport->qedf->dbg_ctx), 14668c2ecf20Sopenharmony_ci "err_warn_bitmap=%08x:%08x\n", 14678c2ecf20Sopenharmony_ci le32_to_cpu(cqe->cqe_info.err_info.err_warn_bitmap_hi), 14688c2ecf20Sopenharmony_ci le32_to_cpu(cqe->cqe_info.err_info.err_warn_bitmap_lo)); 14698c2ecf20Sopenharmony_ci QEDF_ERR(&(io_req->fcport->qedf->dbg_ctx), "tx_buff_off=%08x, " 14708c2ecf20Sopenharmony_ci "rx_buff_off=%08x, rx_id=%04x\n", 14718c2ecf20Sopenharmony_ci le32_to_cpu(cqe->cqe_info.err_info.tx_buf_off), 14728c2ecf20Sopenharmony_ci le32_to_cpu(cqe->cqe_info.err_info.rx_buf_off), 14738c2ecf20Sopenharmony_ci le32_to_cpu(cqe->cqe_info.err_info.rx_id)); 14748c2ecf20Sopenharmony_ci 14758c2ecf20Sopenharmony_ci /* Normalize the error bitmap value to an just an unsigned int */ 14768c2ecf20Sopenharmony_ci err_warn_bit_map = (u64) 14778c2ecf20Sopenharmony_ci ((u64)cqe->cqe_info.err_info.err_warn_bitmap_hi << 32) | 14788c2ecf20Sopenharmony_ci (u64)cqe->cqe_info.err_info.err_warn_bitmap_lo; 14798c2ecf20Sopenharmony_ci for (i = 0; i < 64; i++) { 14808c2ecf20Sopenharmony_ci if (err_warn_bit_map & (u64)((u64)1 << i)) { 14818c2ecf20Sopenharmony_ci err_warn = i; 14828c2ecf20Sopenharmony_ci break; 14838c2ecf20Sopenharmony_ci } 14848c2ecf20Sopenharmony_ci } 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_ci /* Check if REC TOV expired if this is a tape device */ 14878c2ecf20Sopenharmony_ci if (fcport->dev_type == QEDF_RPORT_TYPE_TAPE) { 14888c2ecf20Sopenharmony_ci if (err_warn == 14898c2ecf20Sopenharmony_ci FCOE_WARNING_CODE_REC_TOV_TIMER_EXPIRATION) { 14908c2ecf20Sopenharmony_ci QEDF_ERR(&(qedf->dbg_ctx), "REC timer expired.\n"); 14918c2ecf20Sopenharmony_ci if (!test_bit(QEDF_CMD_SRR_SENT, &io_req->flags)) { 14928c2ecf20Sopenharmony_ci io_req->rx_buf_off = 14938c2ecf20Sopenharmony_ci cqe->cqe_info.err_info.rx_buf_off; 14948c2ecf20Sopenharmony_ci io_req->tx_buf_off = 14958c2ecf20Sopenharmony_ci cqe->cqe_info.err_info.tx_buf_off; 14968c2ecf20Sopenharmony_ci io_req->rx_id = cqe->cqe_info.err_info.rx_id; 14978c2ecf20Sopenharmony_ci rval = qedf_send_rec(io_req); 14988c2ecf20Sopenharmony_ci /* 14998c2ecf20Sopenharmony_ci * We only want to abort the io_req if we 15008c2ecf20Sopenharmony_ci * can't queue the REC command as we want to 15018c2ecf20Sopenharmony_ci * keep the exchange open for recovery. 15028c2ecf20Sopenharmony_ci */ 15038c2ecf20Sopenharmony_ci if (rval) 15048c2ecf20Sopenharmony_ci goto send_abort; 15058c2ecf20Sopenharmony_ci } 15068c2ecf20Sopenharmony_ci return; 15078c2ecf20Sopenharmony_ci } 15088c2ecf20Sopenharmony_ci } 15098c2ecf20Sopenharmony_ci 15108c2ecf20Sopenharmony_cisend_abort: 15118c2ecf20Sopenharmony_ci init_completion(&io_req->abts_done); 15128c2ecf20Sopenharmony_ci rval = qedf_initiate_abts(io_req, true); 15138c2ecf20Sopenharmony_ci if (rval) 15148c2ecf20Sopenharmony_ci QEDF_ERR(&(qedf->dbg_ctx), "Failed to queue ABTS.\n"); 15158c2ecf20Sopenharmony_ci} 15168c2ecf20Sopenharmony_ci 15178c2ecf20Sopenharmony_ci/* Cleanup a command when we receive an error detection completion */ 15188c2ecf20Sopenharmony_civoid qedf_process_error_detect(struct qedf_ctx *qedf, struct fcoe_cqe *cqe, 15198c2ecf20Sopenharmony_ci struct qedf_ioreq *io_req) 15208c2ecf20Sopenharmony_ci{ 15218c2ecf20Sopenharmony_ci int rval; 15228c2ecf20Sopenharmony_ci 15238c2ecf20Sopenharmony_ci if (io_req == NULL) { 15248c2ecf20Sopenharmony_ci QEDF_INFO(NULL, QEDF_LOG_IO, "io_req is NULL.\n"); 15258c2ecf20Sopenharmony_ci return; 15268c2ecf20Sopenharmony_ci } 15278c2ecf20Sopenharmony_ci 15288c2ecf20Sopenharmony_ci if (io_req->fcport == NULL) { 15298c2ecf20Sopenharmony_ci QEDF_INFO(NULL, QEDF_LOG_IO, "fcport is NULL.\n"); 15308c2ecf20Sopenharmony_ci return; 15318c2ecf20Sopenharmony_ci } 15328c2ecf20Sopenharmony_ci 15338c2ecf20Sopenharmony_ci if (!cqe) { 15348c2ecf20Sopenharmony_ci QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, 15358c2ecf20Sopenharmony_ci "cqe is NULL for io_req %p\n", io_req); 15368c2ecf20Sopenharmony_ci return; 15378c2ecf20Sopenharmony_ci } 15388c2ecf20Sopenharmony_ci 15398c2ecf20Sopenharmony_ci QEDF_ERR(&(io_req->fcport->qedf->dbg_ctx), "Error detection CQE, " 15408c2ecf20Sopenharmony_ci "xid=0x%x\n", io_req->xid); 15418c2ecf20Sopenharmony_ci QEDF_ERR(&(io_req->fcport->qedf->dbg_ctx), 15428c2ecf20Sopenharmony_ci "err_warn_bitmap=%08x:%08x\n", 15438c2ecf20Sopenharmony_ci le32_to_cpu(cqe->cqe_info.err_info.err_warn_bitmap_hi), 15448c2ecf20Sopenharmony_ci le32_to_cpu(cqe->cqe_info.err_info.err_warn_bitmap_lo)); 15458c2ecf20Sopenharmony_ci QEDF_ERR(&(io_req->fcport->qedf->dbg_ctx), "tx_buff_off=%08x, " 15468c2ecf20Sopenharmony_ci "rx_buff_off=%08x, rx_id=%04x\n", 15478c2ecf20Sopenharmony_ci le32_to_cpu(cqe->cqe_info.err_info.tx_buf_off), 15488c2ecf20Sopenharmony_ci le32_to_cpu(cqe->cqe_info.err_info.rx_buf_off), 15498c2ecf20Sopenharmony_ci le32_to_cpu(cqe->cqe_info.err_info.rx_id)); 15508c2ecf20Sopenharmony_ci 15518c2ecf20Sopenharmony_ci /* When flush is active, let the cmds be flushed out from the cleanup context */ 15528c2ecf20Sopenharmony_ci if (test_bit(QEDF_RPORT_IN_TARGET_RESET, &io_req->fcport->flags) || 15538c2ecf20Sopenharmony_ci (test_bit(QEDF_RPORT_IN_LUN_RESET, &io_req->fcport->flags) && 15548c2ecf20Sopenharmony_ci io_req->sc_cmd->device->lun == (u64)io_req->fcport->lun_reset_lun)) { 15558c2ecf20Sopenharmony_ci QEDF_ERR(&qedf->dbg_ctx, 15568c2ecf20Sopenharmony_ci "Dropping EQE for xid=0x%x as fcport is flushing", 15578c2ecf20Sopenharmony_ci io_req->xid); 15588c2ecf20Sopenharmony_ci return; 15598c2ecf20Sopenharmony_ci } 15608c2ecf20Sopenharmony_ci 15618c2ecf20Sopenharmony_ci if (qedf->stop_io_on_error) { 15628c2ecf20Sopenharmony_ci qedf_stop_all_io(qedf); 15638c2ecf20Sopenharmony_ci return; 15648c2ecf20Sopenharmony_ci } 15658c2ecf20Sopenharmony_ci 15668c2ecf20Sopenharmony_ci init_completion(&io_req->abts_done); 15678c2ecf20Sopenharmony_ci rval = qedf_initiate_abts(io_req, true); 15688c2ecf20Sopenharmony_ci if (rval) 15698c2ecf20Sopenharmony_ci QEDF_ERR(&(qedf->dbg_ctx), "Failed to queue ABTS.\n"); 15708c2ecf20Sopenharmony_ci} 15718c2ecf20Sopenharmony_ci 15728c2ecf20Sopenharmony_cistatic void qedf_flush_els_req(struct qedf_ctx *qedf, 15738c2ecf20Sopenharmony_ci struct qedf_ioreq *els_req) 15748c2ecf20Sopenharmony_ci{ 15758c2ecf20Sopenharmony_ci QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_IO, 15768c2ecf20Sopenharmony_ci "Flushing ELS request xid=0x%x refcount=%d.\n", els_req->xid, 15778c2ecf20Sopenharmony_ci kref_read(&els_req->refcount)); 15788c2ecf20Sopenharmony_ci 15798c2ecf20Sopenharmony_ci /* 15808c2ecf20Sopenharmony_ci * Need to distinguish this from a timeout when calling the 15818c2ecf20Sopenharmony_ci * els_req->cb_func. 15828c2ecf20Sopenharmony_ci */ 15838c2ecf20Sopenharmony_ci els_req->event = QEDF_IOREQ_EV_ELS_FLUSH; 15848c2ecf20Sopenharmony_ci 15858c2ecf20Sopenharmony_ci clear_bit(QEDF_CMD_OUTSTANDING, &els_req->flags); 15868c2ecf20Sopenharmony_ci 15878c2ecf20Sopenharmony_ci /* Cancel the timer */ 15888c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&els_req->timeout_work); 15898c2ecf20Sopenharmony_ci 15908c2ecf20Sopenharmony_ci /* Call callback function to complete command */ 15918c2ecf20Sopenharmony_ci if (els_req->cb_func && els_req->cb_arg) { 15928c2ecf20Sopenharmony_ci els_req->cb_func(els_req->cb_arg); 15938c2ecf20Sopenharmony_ci els_req->cb_arg = NULL; 15948c2ecf20Sopenharmony_ci } 15958c2ecf20Sopenharmony_ci 15968c2ecf20Sopenharmony_ci /* Release kref for original initiate_els */ 15978c2ecf20Sopenharmony_ci kref_put(&els_req->refcount, qedf_release_cmd); 15988c2ecf20Sopenharmony_ci} 15998c2ecf20Sopenharmony_ci 16008c2ecf20Sopenharmony_ci/* A value of -1 for lun is a wild card that means flush all 16018c2ecf20Sopenharmony_ci * active SCSI I/Os for the target. 16028c2ecf20Sopenharmony_ci */ 16038c2ecf20Sopenharmony_civoid qedf_flush_active_ios(struct qedf_rport *fcport, int lun) 16048c2ecf20Sopenharmony_ci{ 16058c2ecf20Sopenharmony_ci struct qedf_ioreq *io_req; 16068c2ecf20Sopenharmony_ci struct qedf_ctx *qedf; 16078c2ecf20Sopenharmony_ci struct qedf_cmd_mgr *cmd_mgr; 16088c2ecf20Sopenharmony_ci int i, rc; 16098c2ecf20Sopenharmony_ci unsigned long flags; 16108c2ecf20Sopenharmony_ci int flush_cnt = 0; 16118c2ecf20Sopenharmony_ci int wait_cnt = 100; 16128c2ecf20Sopenharmony_ci int refcount = 0; 16138c2ecf20Sopenharmony_ci 16148c2ecf20Sopenharmony_ci if (!fcport) { 16158c2ecf20Sopenharmony_ci QEDF_ERR(NULL, "fcport is NULL\n"); 16168c2ecf20Sopenharmony_ci return; 16178c2ecf20Sopenharmony_ci } 16188c2ecf20Sopenharmony_ci 16198c2ecf20Sopenharmony_ci /* Check that fcport is still offloaded */ 16208c2ecf20Sopenharmony_ci if (!test_bit(QEDF_RPORT_SESSION_READY, &fcport->flags)) { 16218c2ecf20Sopenharmony_ci QEDF_ERR(NULL, "fcport is no longer offloaded.\n"); 16228c2ecf20Sopenharmony_ci return; 16238c2ecf20Sopenharmony_ci } 16248c2ecf20Sopenharmony_ci 16258c2ecf20Sopenharmony_ci qedf = fcport->qedf; 16268c2ecf20Sopenharmony_ci 16278c2ecf20Sopenharmony_ci if (!qedf) { 16288c2ecf20Sopenharmony_ci QEDF_ERR(NULL, "qedf is NULL.\n"); 16298c2ecf20Sopenharmony_ci return; 16308c2ecf20Sopenharmony_ci } 16318c2ecf20Sopenharmony_ci 16328c2ecf20Sopenharmony_ci /* Only wait for all commands to be queued in the Upload context */ 16338c2ecf20Sopenharmony_ci if (test_bit(QEDF_RPORT_UPLOADING_CONNECTION, &fcport->flags) && 16348c2ecf20Sopenharmony_ci (lun == -1)) { 16358c2ecf20Sopenharmony_ci while (atomic_read(&fcport->ios_to_queue)) { 16368c2ecf20Sopenharmony_ci QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, 16378c2ecf20Sopenharmony_ci "Waiting for %d I/Os to be queued\n", 16388c2ecf20Sopenharmony_ci atomic_read(&fcport->ios_to_queue)); 16398c2ecf20Sopenharmony_ci if (wait_cnt == 0) { 16408c2ecf20Sopenharmony_ci QEDF_ERR(NULL, 16418c2ecf20Sopenharmony_ci "%d IOs request could not be queued\n", 16428c2ecf20Sopenharmony_ci atomic_read(&fcport->ios_to_queue)); 16438c2ecf20Sopenharmony_ci } 16448c2ecf20Sopenharmony_ci msleep(20); 16458c2ecf20Sopenharmony_ci wait_cnt--; 16468c2ecf20Sopenharmony_ci } 16478c2ecf20Sopenharmony_ci } 16488c2ecf20Sopenharmony_ci 16498c2ecf20Sopenharmony_ci cmd_mgr = qedf->cmd_mgr; 16508c2ecf20Sopenharmony_ci 16518c2ecf20Sopenharmony_ci QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, 16528c2ecf20Sopenharmony_ci "Flush active i/o's num=0x%x fcport=0x%p port_id=0x%06x scsi_id=%d.\n", 16538c2ecf20Sopenharmony_ci atomic_read(&fcport->num_active_ios), fcport, 16548c2ecf20Sopenharmony_ci fcport->rdata->ids.port_id, fcport->rport->scsi_target_id); 16558c2ecf20Sopenharmony_ci QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, "Locking flush mutex.\n"); 16568c2ecf20Sopenharmony_ci 16578c2ecf20Sopenharmony_ci mutex_lock(&qedf->flush_mutex); 16588c2ecf20Sopenharmony_ci if (lun == -1) { 16598c2ecf20Sopenharmony_ci set_bit(QEDF_RPORT_IN_TARGET_RESET, &fcport->flags); 16608c2ecf20Sopenharmony_ci } else { 16618c2ecf20Sopenharmony_ci set_bit(QEDF_RPORT_IN_LUN_RESET, &fcport->flags); 16628c2ecf20Sopenharmony_ci fcport->lun_reset_lun = lun; 16638c2ecf20Sopenharmony_ci } 16648c2ecf20Sopenharmony_ci 16658c2ecf20Sopenharmony_ci for (i = 0; i < FCOE_PARAMS_NUM_TASKS; i++) { 16668c2ecf20Sopenharmony_ci io_req = &cmd_mgr->cmds[i]; 16678c2ecf20Sopenharmony_ci 16688c2ecf20Sopenharmony_ci if (!io_req) 16698c2ecf20Sopenharmony_ci continue; 16708c2ecf20Sopenharmony_ci if (!io_req->fcport) 16718c2ecf20Sopenharmony_ci continue; 16728c2ecf20Sopenharmony_ci 16738c2ecf20Sopenharmony_ci spin_lock_irqsave(&cmd_mgr->lock, flags); 16748c2ecf20Sopenharmony_ci 16758c2ecf20Sopenharmony_ci if (io_req->alloc) { 16768c2ecf20Sopenharmony_ci if (!test_bit(QEDF_CMD_OUTSTANDING, &io_req->flags)) { 16778c2ecf20Sopenharmony_ci if (io_req->cmd_type == QEDF_SCSI_CMD) 16788c2ecf20Sopenharmony_ci QEDF_ERR(&qedf->dbg_ctx, 16798c2ecf20Sopenharmony_ci "Allocated but not queued, xid=0x%x\n", 16808c2ecf20Sopenharmony_ci io_req->xid); 16818c2ecf20Sopenharmony_ci } 16828c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&cmd_mgr->lock, flags); 16838c2ecf20Sopenharmony_ci } else { 16848c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&cmd_mgr->lock, flags); 16858c2ecf20Sopenharmony_ci continue; 16868c2ecf20Sopenharmony_ci } 16878c2ecf20Sopenharmony_ci 16888c2ecf20Sopenharmony_ci if (io_req->fcport != fcport) 16898c2ecf20Sopenharmony_ci continue; 16908c2ecf20Sopenharmony_ci 16918c2ecf20Sopenharmony_ci /* In case of ABTS, CMD_OUTSTANDING is cleared on ABTS response, 16928c2ecf20Sopenharmony_ci * but RRQ is still pending. 16938c2ecf20Sopenharmony_ci * Workaround: Within qedf_send_rrq, we check if the fcport is 16948c2ecf20Sopenharmony_ci * NULL, and we drop the ref on the io_req to clean it up. 16958c2ecf20Sopenharmony_ci */ 16968c2ecf20Sopenharmony_ci if (!test_bit(QEDF_CMD_OUTSTANDING, &io_req->flags)) { 16978c2ecf20Sopenharmony_ci refcount = kref_read(&io_req->refcount); 16988c2ecf20Sopenharmony_ci QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, 16998c2ecf20Sopenharmony_ci "Not outstanding, xid=0x%x, cmd_type=%d refcount=%d.\n", 17008c2ecf20Sopenharmony_ci io_req->xid, io_req->cmd_type, refcount); 17018c2ecf20Sopenharmony_ci /* If RRQ work has been queue, try to cancel it and 17028c2ecf20Sopenharmony_ci * free the io_req 17038c2ecf20Sopenharmony_ci */ 17048c2ecf20Sopenharmony_ci if (atomic_read(&io_req->state) == 17058c2ecf20Sopenharmony_ci QEDFC_CMD_ST_RRQ_WAIT) { 17068c2ecf20Sopenharmony_ci if (cancel_delayed_work_sync 17078c2ecf20Sopenharmony_ci (&io_req->rrq_work)) { 17088c2ecf20Sopenharmony_ci QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, 17098c2ecf20Sopenharmony_ci "Putting reference for pending RRQ work xid=0x%x.\n", 17108c2ecf20Sopenharmony_ci io_req->xid); 17118c2ecf20Sopenharmony_ci /* ID: 003 */ 17128c2ecf20Sopenharmony_ci kref_put(&io_req->refcount, 17138c2ecf20Sopenharmony_ci qedf_release_cmd); 17148c2ecf20Sopenharmony_ci } 17158c2ecf20Sopenharmony_ci } 17168c2ecf20Sopenharmony_ci continue; 17178c2ecf20Sopenharmony_ci } 17188c2ecf20Sopenharmony_ci 17198c2ecf20Sopenharmony_ci /* Only consider flushing ELS during target reset */ 17208c2ecf20Sopenharmony_ci if (io_req->cmd_type == QEDF_ELS && 17218c2ecf20Sopenharmony_ci lun == -1) { 17228c2ecf20Sopenharmony_ci rc = kref_get_unless_zero(&io_req->refcount); 17238c2ecf20Sopenharmony_ci if (!rc) { 17248c2ecf20Sopenharmony_ci QEDF_ERR(&(qedf->dbg_ctx), 17258c2ecf20Sopenharmony_ci "Could not get kref for ELS io_req=0x%p xid=0x%x.\n", 17268c2ecf20Sopenharmony_ci io_req, io_req->xid); 17278c2ecf20Sopenharmony_ci continue; 17288c2ecf20Sopenharmony_ci } 17298c2ecf20Sopenharmony_ci qedf_initiate_cleanup(io_req, false); 17308c2ecf20Sopenharmony_ci flush_cnt++; 17318c2ecf20Sopenharmony_ci qedf_flush_els_req(qedf, io_req); 17328c2ecf20Sopenharmony_ci 17338c2ecf20Sopenharmony_ci /* 17348c2ecf20Sopenharmony_ci * Release the kref and go back to the top of the 17358c2ecf20Sopenharmony_ci * loop. 17368c2ecf20Sopenharmony_ci */ 17378c2ecf20Sopenharmony_ci goto free_cmd; 17388c2ecf20Sopenharmony_ci } 17398c2ecf20Sopenharmony_ci 17408c2ecf20Sopenharmony_ci if (io_req->cmd_type == QEDF_ABTS) { 17418c2ecf20Sopenharmony_ci /* ID: 004 */ 17428c2ecf20Sopenharmony_ci rc = kref_get_unless_zero(&io_req->refcount); 17438c2ecf20Sopenharmony_ci if (!rc) { 17448c2ecf20Sopenharmony_ci QEDF_ERR(&(qedf->dbg_ctx), 17458c2ecf20Sopenharmony_ci "Could not get kref for abort io_req=0x%p xid=0x%x.\n", 17468c2ecf20Sopenharmony_ci io_req, io_req->xid); 17478c2ecf20Sopenharmony_ci continue; 17488c2ecf20Sopenharmony_ci } 17498c2ecf20Sopenharmony_ci if (lun != -1 && io_req->lun != lun) 17508c2ecf20Sopenharmony_ci goto free_cmd; 17518c2ecf20Sopenharmony_ci 17528c2ecf20Sopenharmony_ci QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, 17538c2ecf20Sopenharmony_ci "Flushing abort xid=0x%x.\n", io_req->xid); 17548c2ecf20Sopenharmony_ci 17558c2ecf20Sopenharmony_ci if (cancel_delayed_work_sync(&io_req->rrq_work)) { 17568c2ecf20Sopenharmony_ci QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, 17578c2ecf20Sopenharmony_ci "Putting ref for cancelled RRQ work xid=0x%x.\n", 17588c2ecf20Sopenharmony_ci io_req->xid); 17598c2ecf20Sopenharmony_ci kref_put(&io_req->refcount, qedf_release_cmd); 17608c2ecf20Sopenharmony_ci } 17618c2ecf20Sopenharmony_ci 17628c2ecf20Sopenharmony_ci if (cancel_delayed_work_sync(&io_req->timeout_work)) { 17638c2ecf20Sopenharmony_ci QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, 17648c2ecf20Sopenharmony_ci "Putting ref for cancelled tmo work xid=0x%x.\n", 17658c2ecf20Sopenharmony_ci io_req->xid); 17668c2ecf20Sopenharmony_ci qedf_initiate_cleanup(io_req, true); 17678c2ecf20Sopenharmony_ci /* Notify eh_abort handler that ABTS is 17688c2ecf20Sopenharmony_ci * complete 17698c2ecf20Sopenharmony_ci */ 17708c2ecf20Sopenharmony_ci complete(&io_req->abts_done); 17718c2ecf20Sopenharmony_ci clear_bit(QEDF_CMD_IN_ABORT, &io_req->flags); 17728c2ecf20Sopenharmony_ci /* ID: 002 */ 17738c2ecf20Sopenharmony_ci kref_put(&io_req->refcount, qedf_release_cmd); 17748c2ecf20Sopenharmony_ci } 17758c2ecf20Sopenharmony_ci flush_cnt++; 17768c2ecf20Sopenharmony_ci goto free_cmd; 17778c2ecf20Sopenharmony_ci } 17788c2ecf20Sopenharmony_ci 17798c2ecf20Sopenharmony_ci if (!io_req->sc_cmd) 17808c2ecf20Sopenharmony_ci continue; 17818c2ecf20Sopenharmony_ci if (!io_req->sc_cmd->device) { 17828c2ecf20Sopenharmony_ci QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, 17838c2ecf20Sopenharmony_ci "Device backpointer NULL for sc_cmd=%p.\n", 17848c2ecf20Sopenharmony_ci io_req->sc_cmd); 17858c2ecf20Sopenharmony_ci /* Put reference for non-existent scsi_cmnd */ 17868c2ecf20Sopenharmony_ci io_req->sc_cmd = NULL; 17878c2ecf20Sopenharmony_ci qedf_initiate_cleanup(io_req, false); 17888c2ecf20Sopenharmony_ci kref_put(&io_req->refcount, qedf_release_cmd); 17898c2ecf20Sopenharmony_ci continue; 17908c2ecf20Sopenharmony_ci } 17918c2ecf20Sopenharmony_ci if (lun > -1) { 17928c2ecf20Sopenharmony_ci if (io_req->lun != lun) 17938c2ecf20Sopenharmony_ci continue; 17948c2ecf20Sopenharmony_ci } 17958c2ecf20Sopenharmony_ci 17968c2ecf20Sopenharmony_ci /* 17978c2ecf20Sopenharmony_ci * Use kref_get_unless_zero in the unlikely case the command 17988c2ecf20Sopenharmony_ci * we're about to flush was completed in the normal SCSI path 17998c2ecf20Sopenharmony_ci */ 18008c2ecf20Sopenharmony_ci rc = kref_get_unless_zero(&io_req->refcount); 18018c2ecf20Sopenharmony_ci if (!rc) { 18028c2ecf20Sopenharmony_ci QEDF_ERR(&(qedf->dbg_ctx), "Could not get kref for " 18038c2ecf20Sopenharmony_ci "io_req=0x%p xid=0x%x\n", io_req, io_req->xid); 18048c2ecf20Sopenharmony_ci continue; 18058c2ecf20Sopenharmony_ci } 18068c2ecf20Sopenharmony_ci 18078c2ecf20Sopenharmony_ci QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_IO, 18088c2ecf20Sopenharmony_ci "Cleanup xid=0x%x.\n", io_req->xid); 18098c2ecf20Sopenharmony_ci flush_cnt++; 18108c2ecf20Sopenharmony_ci 18118c2ecf20Sopenharmony_ci /* Cleanup task and return I/O mid-layer */ 18128c2ecf20Sopenharmony_ci qedf_initiate_cleanup(io_req, true); 18138c2ecf20Sopenharmony_ci 18148c2ecf20Sopenharmony_cifree_cmd: 18158c2ecf20Sopenharmony_ci kref_put(&io_req->refcount, qedf_release_cmd); /* ID: 004 */ 18168c2ecf20Sopenharmony_ci } 18178c2ecf20Sopenharmony_ci 18188c2ecf20Sopenharmony_ci wait_cnt = 60; 18198c2ecf20Sopenharmony_ci QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, 18208c2ecf20Sopenharmony_ci "Flushed 0x%x I/Os, active=0x%x.\n", 18218c2ecf20Sopenharmony_ci flush_cnt, atomic_read(&fcport->num_active_ios)); 18228c2ecf20Sopenharmony_ci /* Only wait for all commands to complete in the Upload context */ 18238c2ecf20Sopenharmony_ci if (test_bit(QEDF_RPORT_UPLOADING_CONNECTION, &fcport->flags) && 18248c2ecf20Sopenharmony_ci (lun == -1)) { 18258c2ecf20Sopenharmony_ci while (atomic_read(&fcport->num_active_ios)) { 18268c2ecf20Sopenharmony_ci QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, 18278c2ecf20Sopenharmony_ci "Flushed 0x%x I/Os, active=0x%x cnt=%d.\n", 18288c2ecf20Sopenharmony_ci flush_cnt, 18298c2ecf20Sopenharmony_ci atomic_read(&fcport->num_active_ios), 18308c2ecf20Sopenharmony_ci wait_cnt); 18318c2ecf20Sopenharmony_ci if (wait_cnt == 0) { 18328c2ecf20Sopenharmony_ci QEDF_ERR(&qedf->dbg_ctx, 18338c2ecf20Sopenharmony_ci "Flushed %d I/Os, active=%d.\n", 18348c2ecf20Sopenharmony_ci flush_cnt, 18358c2ecf20Sopenharmony_ci atomic_read(&fcport->num_active_ios)); 18368c2ecf20Sopenharmony_ci for (i = 0; i < FCOE_PARAMS_NUM_TASKS; i++) { 18378c2ecf20Sopenharmony_ci io_req = &cmd_mgr->cmds[i]; 18388c2ecf20Sopenharmony_ci if (io_req->fcport && 18398c2ecf20Sopenharmony_ci io_req->fcport == fcport) { 18408c2ecf20Sopenharmony_ci refcount = 18418c2ecf20Sopenharmony_ci kref_read(&io_req->refcount); 18428c2ecf20Sopenharmony_ci set_bit(QEDF_CMD_DIRTY, 18438c2ecf20Sopenharmony_ci &io_req->flags); 18448c2ecf20Sopenharmony_ci QEDF_ERR(&qedf->dbg_ctx, 18458c2ecf20Sopenharmony_ci "Outstanding io_req =%p xid=0x%x flags=0x%lx, sc_cmd=%p refcount=%d cmd_type=%d.\n", 18468c2ecf20Sopenharmony_ci io_req, io_req->xid, 18478c2ecf20Sopenharmony_ci io_req->flags, 18488c2ecf20Sopenharmony_ci io_req->sc_cmd, 18498c2ecf20Sopenharmony_ci refcount, 18508c2ecf20Sopenharmony_ci io_req->cmd_type); 18518c2ecf20Sopenharmony_ci } 18528c2ecf20Sopenharmony_ci } 18538c2ecf20Sopenharmony_ci WARN_ON(1); 18548c2ecf20Sopenharmony_ci break; 18558c2ecf20Sopenharmony_ci } 18568c2ecf20Sopenharmony_ci msleep(500); 18578c2ecf20Sopenharmony_ci wait_cnt--; 18588c2ecf20Sopenharmony_ci } 18598c2ecf20Sopenharmony_ci } 18608c2ecf20Sopenharmony_ci 18618c2ecf20Sopenharmony_ci clear_bit(QEDF_RPORT_IN_LUN_RESET, &fcport->flags); 18628c2ecf20Sopenharmony_ci clear_bit(QEDF_RPORT_IN_TARGET_RESET, &fcport->flags); 18638c2ecf20Sopenharmony_ci QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, "Unlocking flush mutex.\n"); 18648c2ecf20Sopenharmony_ci mutex_unlock(&qedf->flush_mutex); 18658c2ecf20Sopenharmony_ci} 18668c2ecf20Sopenharmony_ci 18678c2ecf20Sopenharmony_ci/* 18688c2ecf20Sopenharmony_ci * Initiate a ABTS middle path command. Note that we don't have to initialize 18698c2ecf20Sopenharmony_ci * the task context for an ABTS task. 18708c2ecf20Sopenharmony_ci */ 18718c2ecf20Sopenharmony_ciint qedf_initiate_abts(struct qedf_ioreq *io_req, bool return_scsi_cmd_on_abts) 18728c2ecf20Sopenharmony_ci{ 18738c2ecf20Sopenharmony_ci struct fc_lport *lport; 18748c2ecf20Sopenharmony_ci struct qedf_rport *fcport = io_req->fcport; 18758c2ecf20Sopenharmony_ci struct fc_rport_priv *rdata; 18768c2ecf20Sopenharmony_ci struct qedf_ctx *qedf; 18778c2ecf20Sopenharmony_ci u16 xid; 18788c2ecf20Sopenharmony_ci int rc = 0; 18798c2ecf20Sopenharmony_ci unsigned long flags; 18808c2ecf20Sopenharmony_ci struct fcoe_wqe *sqe; 18818c2ecf20Sopenharmony_ci u16 sqe_idx; 18828c2ecf20Sopenharmony_ci int refcount = 0; 18838c2ecf20Sopenharmony_ci 18848c2ecf20Sopenharmony_ci /* Sanity check qedf_rport before dereferencing any pointers */ 18858c2ecf20Sopenharmony_ci if (!test_bit(QEDF_RPORT_SESSION_READY, &fcport->flags)) { 18868c2ecf20Sopenharmony_ci QEDF_ERR(NULL, "tgt not offloaded\n"); 18878c2ecf20Sopenharmony_ci rc = 1; 18888c2ecf20Sopenharmony_ci goto out; 18898c2ecf20Sopenharmony_ci } 18908c2ecf20Sopenharmony_ci 18918c2ecf20Sopenharmony_ci qedf = fcport->qedf; 18928c2ecf20Sopenharmony_ci rdata = fcport->rdata; 18938c2ecf20Sopenharmony_ci 18948c2ecf20Sopenharmony_ci if (!rdata || !kref_get_unless_zero(&rdata->kref)) { 18958c2ecf20Sopenharmony_ci QEDF_ERR(&qedf->dbg_ctx, "stale rport\n"); 18968c2ecf20Sopenharmony_ci rc = 1; 18978c2ecf20Sopenharmony_ci goto out; 18988c2ecf20Sopenharmony_ci } 18998c2ecf20Sopenharmony_ci 19008c2ecf20Sopenharmony_ci lport = qedf->lport; 19018c2ecf20Sopenharmony_ci 19028c2ecf20Sopenharmony_ci if (lport->state != LPORT_ST_READY || !(lport->link_up)) { 19038c2ecf20Sopenharmony_ci QEDF_ERR(&(qedf->dbg_ctx), "link is not ready\n"); 19048c2ecf20Sopenharmony_ci rc = 1; 19058c2ecf20Sopenharmony_ci goto drop_rdata_kref; 19068c2ecf20Sopenharmony_ci } 19078c2ecf20Sopenharmony_ci 19088c2ecf20Sopenharmony_ci if (atomic_read(&qedf->link_down_tmo_valid) > 0) { 19098c2ecf20Sopenharmony_ci QEDF_ERR(&(qedf->dbg_ctx), "link_down_tmo active.\n"); 19108c2ecf20Sopenharmony_ci rc = 1; 19118c2ecf20Sopenharmony_ci goto drop_rdata_kref; 19128c2ecf20Sopenharmony_ci } 19138c2ecf20Sopenharmony_ci 19148c2ecf20Sopenharmony_ci /* Ensure room on SQ */ 19158c2ecf20Sopenharmony_ci if (!atomic_read(&fcport->free_sqes)) { 19168c2ecf20Sopenharmony_ci QEDF_ERR(&(qedf->dbg_ctx), "No SQ entries available\n"); 19178c2ecf20Sopenharmony_ci rc = 1; 19188c2ecf20Sopenharmony_ci goto drop_rdata_kref; 19198c2ecf20Sopenharmony_ci } 19208c2ecf20Sopenharmony_ci 19218c2ecf20Sopenharmony_ci if (test_bit(QEDF_RPORT_UPLOADING_CONNECTION, &fcport->flags)) { 19228c2ecf20Sopenharmony_ci QEDF_ERR(&qedf->dbg_ctx, "fcport is uploading.\n"); 19238c2ecf20Sopenharmony_ci rc = 1; 19248c2ecf20Sopenharmony_ci goto drop_rdata_kref; 19258c2ecf20Sopenharmony_ci } 19268c2ecf20Sopenharmony_ci 19278c2ecf20Sopenharmony_ci spin_lock_irqsave(&fcport->rport_lock, flags); 19288c2ecf20Sopenharmony_ci if (!test_bit(QEDF_CMD_OUTSTANDING, &io_req->flags) || 19298c2ecf20Sopenharmony_ci test_bit(QEDF_CMD_IN_CLEANUP, &io_req->flags) || 19308c2ecf20Sopenharmony_ci test_bit(QEDF_CMD_IN_ABORT, &io_req->flags)) { 19318c2ecf20Sopenharmony_ci QEDF_ERR(&qedf->dbg_ctx, 19328c2ecf20Sopenharmony_ci "io_req xid=0x%x sc_cmd=%p already in cleanup or abort processing or already completed.\n", 19338c2ecf20Sopenharmony_ci io_req->xid, io_req->sc_cmd); 19348c2ecf20Sopenharmony_ci rc = 1; 19358c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&fcport->rport_lock, flags); 19368c2ecf20Sopenharmony_ci goto drop_rdata_kref; 19378c2ecf20Sopenharmony_ci } 19388c2ecf20Sopenharmony_ci 19398c2ecf20Sopenharmony_ci /* Set the command type to abort */ 19408c2ecf20Sopenharmony_ci io_req->cmd_type = QEDF_ABTS; 19418c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&fcport->rport_lock, flags); 19428c2ecf20Sopenharmony_ci 19438c2ecf20Sopenharmony_ci kref_get(&io_req->refcount); 19448c2ecf20Sopenharmony_ci 19458c2ecf20Sopenharmony_ci xid = io_req->xid; 19468c2ecf20Sopenharmony_ci qedf->control_requests++; 19478c2ecf20Sopenharmony_ci qedf->packet_aborts++; 19488c2ecf20Sopenharmony_ci 19498c2ecf20Sopenharmony_ci io_req->return_scsi_cmd_on_abts = return_scsi_cmd_on_abts; 19508c2ecf20Sopenharmony_ci 19518c2ecf20Sopenharmony_ci set_bit(QEDF_CMD_IN_ABORT, &io_req->flags); 19528c2ecf20Sopenharmony_ci refcount = kref_read(&io_req->refcount); 19538c2ecf20Sopenharmony_ci QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_SCSI_TM, 19548c2ecf20Sopenharmony_ci "ABTS io_req xid = 0x%x refcount=%d\n", 19558c2ecf20Sopenharmony_ci xid, refcount); 19568c2ecf20Sopenharmony_ci 19578c2ecf20Sopenharmony_ci qedf_cmd_timer_set(qedf, io_req, QEDF_ABORT_TIMEOUT); 19588c2ecf20Sopenharmony_ci 19598c2ecf20Sopenharmony_ci spin_lock_irqsave(&fcport->rport_lock, flags); 19608c2ecf20Sopenharmony_ci 19618c2ecf20Sopenharmony_ci sqe_idx = qedf_get_sqe_idx(fcport); 19628c2ecf20Sopenharmony_ci sqe = &fcport->sq[sqe_idx]; 19638c2ecf20Sopenharmony_ci memset(sqe, 0, sizeof(struct fcoe_wqe)); 19648c2ecf20Sopenharmony_ci io_req->task_params->sqe = sqe; 19658c2ecf20Sopenharmony_ci 19668c2ecf20Sopenharmony_ci init_initiator_abort_fcoe_task(io_req->task_params); 19678c2ecf20Sopenharmony_ci qedf_ring_doorbell(fcport); 19688c2ecf20Sopenharmony_ci 19698c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&fcport->rport_lock, flags); 19708c2ecf20Sopenharmony_ci 19718c2ecf20Sopenharmony_cidrop_rdata_kref: 19728c2ecf20Sopenharmony_ci kref_put(&rdata->kref, fc_rport_destroy); 19738c2ecf20Sopenharmony_ciout: 19748c2ecf20Sopenharmony_ci return rc; 19758c2ecf20Sopenharmony_ci} 19768c2ecf20Sopenharmony_ci 19778c2ecf20Sopenharmony_civoid qedf_process_abts_compl(struct qedf_ctx *qedf, struct fcoe_cqe *cqe, 19788c2ecf20Sopenharmony_ci struct qedf_ioreq *io_req) 19798c2ecf20Sopenharmony_ci{ 19808c2ecf20Sopenharmony_ci uint32_t r_ctl; 19818c2ecf20Sopenharmony_ci int rc; 19828c2ecf20Sopenharmony_ci struct qedf_rport *fcport = io_req->fcport; 19838c2ecf20Sopenharmony_ci 19848c2ecf20Sopenharmony_ci QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_SCSI_TM, "Entered with xid = " 19858c2ecf20Sopenharmony_ci "0x%x cmd_type = %d\n", io_req->xid, io_req->cmd_type); 19868c2ecf20Sopenharmony_ci 19878c2ecf20Sopenharmony_ci r_ctl = cqe->cqe_info.abts_info.r_ctl; 19888c2ecf20Sopenharmony_ci 19898c2ecf20Sopenharmony_ci /* This was added at a point when we were scheduling abts_compl & 19908c2ecf20Sopenharmony_ci * cleanup_compl on different CPUs and there was a possibility of 19918c2ecf20Sopenharmony_ci * the io_req to be freed from the other context before we got here. 19928c2ecf20Sopenharmony_ci */ 19938c2ecf20Sopenharmony_ci if (!fcport) { 19948c2ecf20Sopenharmony_ci QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, 19958c2ecf20Sopenharmony_ci "Dropping ABTS completion xid=0x%x as fcport is NULL", 19968c2ecf20Sopenharmony_ci io_req->xid); 19978c2ecf20Sopenharmony_ci return; 19988c2ecf20Sopenharmony_ci } 19998c2ecf20Sopenharmony_ci 20008c2ecf20Sopenharmony_ci /* 20018c2ecf20Sopenharmony_ci * When flush is active, let the cmds be completed from the cleanup 20028c2ecf20Sopenharmony_ci * context 20038c2ecf20Sopenharmony_ci */ 20048c2ecf20Sopenharmony_ci if (test_bit(QEDF_RPORT_IN_TARGET_RESET, &fcport->flags) || 20058c2ecf20Sopenharmony_ci test_bit(QEDF_RPORT_IN_LUN_RESET, &fcport->flags)) { 20068c2ecf20Sopenharmony_ci QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, 20078c2ecf20Sopenharmony_ci "Dropping ABTS completion xid=0x%x as fcport is flushing", 20088c2ecf20Sopenharmony_ci io_req->xid); 20098c2ecf20Sopenharmony_ci return; 20108c2ecf20Sopenharmony_ci } 20118c2ecf20Sopenharmony_ci 20128c2ecf20Sopenharmony_ci if (!cancel_delayed_work(&io_req->timeout_work)) { 20138c2ecf20Sopenharmony_ci QEDF_ERR(&qedf->dbg_ctx, 20148c2ecf20Sopenharmony_ci "Wasn't able to cancel abts timeout work.\n"); 20158c2ecf20Sopenharmony_ci } 20168c2ecf20Sopenharmony_ci 20178c2ecf20Sopenharmony_ci switch (r_ctl) { 20188c2ecf20Sopenharmony_ci case FC_RCTL_BA_ACC: 20198c2ecf20Sopenharmony_ci QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_SCSI_TM, 20208c2ecf20Sopenharmony_ci "ABTS response - ACC Send RRQ after R_A_TOV\n"); 20218c2ecf20Sopenharmony_ci io_req->event = QEDF_IOREQ_EV_ABORT_SUCCESS; 20228c2ecf20Sopenharmony_ci rc = kref_get_unless_zero(&io_req->refcount); /* ID: 003 */ 20238c2ecf20Sopenharmony_ci if (!rc) { 20248c2ecf20Sopenharmony_ci QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_SCSI_TM, 20258c2ecf20Sopenharmony_ci "kref is already zero so ABTS was already completed or flushed xid=0x%x.\n", 20268c2ecf20Sopenharmony_ci io_req->xid); 20278c2ecf20Sopenharmony_ci return; 20288c2ecf20Sopenharmony_ci } 20298c2ecf20Sopenharmony_ci /* 20308c2ecf20Sopenharmony_ci * Dont release this cmd yet. It will be relesed 20318c2ecf20Sopenharmony_ci * after we get RRQ response 20328c2ecf20Sopenharmony_ci */ 20338c2ecf20Sopenharmony_ci queue_delayed_work(qedf->dpc_wq, &io_req->rrq_work, 20348c2ecf20Sopenharmony_ci msecs_to_jiffies(qedf->lport->r_a_tov)); 20358c2ecf20Sopenharmony_ci atomic_set(&io_req->state, QEDFC_CMD_ST_RRQ_WAIT); 20368c2ecf20Sopenharmony_ci break; 20378c2ecf20Sopenharmony_ci /* For error cases let the cleanup return the command */ 20388c2ecf20Sopenharmony_ci case FC_RCTL_BA_RJT: 20398c2ecf20Sopenharmony_ci QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_SCSI_TM, 20408c2ecf20Sopenharmony_ci "ABTS response - RJT\n"); 20418c2ecf20Sopenharmony_ci io_req->event = QEDF_IOREQ_EV_ABORT_FAILED; 20428c2ecf20Sopenharmony_ci break; 20438c2ecf20Sopenharmony_ci default: 20448c2ecf20Sopenharmony_ci QEDF_ERR(&(qedf->dbg_ctx), "Unknown ABTS response\n"); 20458c2ecf20Sopenharmony_ci break; 20468c2ecf20Sopenharmony_ci } 20478c2ecf20Sopenharmony_ci 20488c2ecf20Sopenharmony_ci clear_bit(QEDF_CMD_IN_ABORT, &io_req->flags); 20498c2ecf20Sopenharmony_ci 20508c2ecf20Sopenharmony_ci if (io_req->sc_cmd) { 20518c2ecf20Sopenharmony_ci if (!io_req->return_scsi_cmd_on_abts) 20528c2ecf20Sopenharmony_ci QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_SCSI_TM, 20538c2ecf20Sopenharmony_ci "Not call scsi_done for xid=0x%x.\n", 20548c2ecf20Sopenharmony_ci io_req->xid); 20558c2ecf20Sopenharmony_ci if (io_req->return_scsi_cmd_on_abts) 20568c2ecf20Sopenharmony_ci qedf_scsi_done(qedf, io_req, DID_ERROR); 20578c2ecf20Sopenharmony_ci } 20588c2ecf20Sopenharmony_ci 20598c2ecf20Sopenharmony_ci /* Notify eh_abort handler that ABTS is complete */ 20608c2ecf20Sopenharmony_ci complete(&io_req->abts_done); 20618c2ecf20Sopenharmony_ci 20628c2ecf20Sopenharmony_ci kref_put(&io_req->refcount, qedf_release_cmd); 20638c2ecf20Sopenharmony_ci} 20648c2ecf20Sopenharmony_ci 20658c2ecf20Sopenharmony_ciint qedf_init_mp_req(struct qedf_ioreq *io_req) 20668c2ecf20Sopenharmony_ci{ 20678c2ecf20Sopenharmony_ci struct qedf_mp_req *mp_req; 20688c2ecf20Sopenharmony_ci struct scsi_sge *mp_req_bd; 20698c2ecf20Sopenharmony_ci struct scsi_sge *mp_resp_bd; 20708c2ecf20Sopenharmony_ci struct qedf_ctx *qedf = io_req->fcport->qedf; 20718c2ecf20Sopenharmony_ci dma_addr_t addr; 20728c2ecf20Sopenharmony_ci uint64_t sz; 20738c2ecf20Sopenharmony_ci 20748c2ecf20Sopenharmony_ci QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_MP_REQ, "Entered.\n"); 20758c2ecf20Sopenharmony_ci 20768c2ecf20Sopenharmony_ci mp_req = (struct qedf_mp_req *)&(io_req->mp_req); 20778c2ecf20Sopenharmony_ci memset(mp_req, 0, sizeof(struct qedf_mp_req)); 20788c2ecf20Sopenharmony_ci 20798c2ecf20Sopenharmony_ci if (io_req->cmd_type != QEDF_ELS) { 20808c2ecf20Sopenharmony_ci mp_req->req_len = sizeof(struct fcp_cmnd); 20818c2ecf20Sopenharmony_ci io_req->data_xfer_len = mp_req->req_len; 20828c2ecf20Sopenharmony_ci } else 20838c2ecf20Sopenharmony_ci mp_req->req_len = io_req->data_xfer_len; 20848c2ecf20Sopenharmony_ci 20858c2ecf20Sopenharmony_ci mp_req->req_buf = dma_alloc_coherent(&qedf->pdev->dev, QEDF_PAGE_SIZE, 20868c2ecf20Sopenharmony_ci &mp_req->req_buf_dma, GFP_KERNEL); 20878c2ecf20Sopenharmony_ci if (!mp_req->req_buf) { 20888c2ecf20Sopenharmony_ci QEDF_ERR(&(qedf->dbg_ctx), "Unable to alloc MP req buffer\n"); 20898c2ecf20Sopenharmony_ci qedf_free_mp_resc(io_req); 20908c2ecf20Sopenharmony_ci return -ENOMEM; 20918c2ecf20Sopenharmony_ci } 20928c2ecf20Sopenharmony_ci 20938c2ecf20Sopenharmony_ci mp_req->resp_buf = dma_alloc_coherent(&qedf->pdev->dev, 20948c2ecf20Sopenharmony_ci QEDF_PAGE_SIZE, &mp_req->resp_buf_dma, GFP_KERNEL); 20958c2ecf20Sopenharmony_ci if (!mp_req->resp_buf) { 20968c2ecf20Sopenharmony_ci QEDF_ERR(&(qedf->dbg_ctx), "Unable to alloc TM resp " 20978c2ecf20Sopenharmony_ci "buffer\n"); 20988c2ecf20Sopenharmony_ci qedf_free_mp_resc(io_req); 20998c2ecf20Sopenharmony_ci return -ENOMEM; 21008c2ecf20Sopenharmony_ci } 21018c2ecf20Sopenharmony_ci 21028c2ecf20Sopenharmony_ci /* Allocate and map mp_req_bd and mp_resp_bd */ 21038c2ecf20Sopenharmony_ci sz = sizeof(struct scsi_sge); 21048c2ecf20Sopenharmony_ci mp_req->mp_req_bd = dma_alloc_coherent(&qedf->pdev->dev, sz, 21058c2ecf20Sopenharmony_ci &mp_req->mp_req_bd_dma, GFP_KERNEL); 21068c2ecf20Sopenharmony_ci if (!mp_req->mp_req_bd) { 21078c2ecf20Sopenharmony_ci QEDF_ERR(&(qedf->dbg_ctx), "Unable to alloc MP req bd\n"); 21088c2ecf20Sopenharmony_ci qedf_free_mp_resc(io_req); 21098c2ecf20Sopenharmony_ci return -ENOMEM; 21108c2ecf20Sopenharmony_ci } 21118c2ecf20Sopenharmony_ci 21128c2ecf20Sopenharmony_ci mp_req->mp_resp_bd = dma_alloc_coherent(&qedf->pdev->dev, sz, 21138c2ecf20Sopenharmony_ci &mp_req->mp_resp_bd_dma, GFP_KERNEL); 21148c2ecf20Sopenharmony_ci if (!mp_req->mp_resp_bd) { 21158c2ecf20Sopenharmony_ci QEDF_ERR(&(qedf->dbg_ctx), "Unable to alloc MP resp bd\n"); 21168c2ecf20Sopenharmony_ci qedf_free_mp_resc(io_req); 21178c2ecf20Sopenharmony_ci return -ENOMEM; 21188c2ecf20Sopenharmony_ci } 21198c2ecf20Sopenharmony_ci 21208c2ecf20Sopenharmony_ci /* Fill bd table */ 21218c2ecf20Sopenharmony_ci addr = mp_req->req_buf_dma; 21228c2ecf20Sopenharmony_ci mp_req_bd = mp_req->mp_req_bd; 21238c2ecf20Sopenharmony_ci mp_req_bd->sge_addr.lo = U64_LO(addr); 21248c2ecf20Sopenharmony_ci mp_req_bd->sge_addr.hi = U64_HI(addr); 21258c2ecf20Sopenharmony_ci mp_req_bd->sge_len = QEDF_PAGE_SIZE; 21268c2ecf20Sopenharmony_ci 21278c2ecf20Sopenharmony_ci /* 21288c2ecf20Sopenharmony_ci * MP buffer is either a task mgmt command or an ELS. 21298c2ecf20Sopenharmony_ci * So the assumption is that it consumes a single bd 21308c2ecf20Sopenharmony_ci * entry in the bd table 21318c2ecf20Sopenharmony_ci */ 21328c2ecf20Sopenharmony_ci mp_resp_bd = mp_req->mp_resp_bd; 21338c2ecf20Sopenharmony_ci addr = mp_req->resp_buf_dma; 21348c2ecf20Sopenharmony_ci mp_resp_bd->sge_addr.lo = U64_LO(addr); 21358c2ecf20Sopenharmony_ci mp_resp_bd->sge_addr.hi = U64_HI(addr); 21368c2ecf20Sopenharmony_ci mp_resp_bd->sge_len = QEDF_PAGE_SIZE; 21378c2ecf20Sopenharmony_ci 21388c2ecf20Sopenharmony_ci return 0; 21398c2ecf20Sopenharmony_ci} 21408c2ecf20Sopenharmony_ci 21418c2ecf20Sopenharmony_ci/* 21428c2ecf20Sopenharmony_ci * Last ditch effort to clear the port if it's stuck. Used only after a 21438c2ecf20Sopenharmony_ci * cleanup task times out. 21448c2ecf20Sopenharmony_ci */ 21458c2ecf20Sopenharmony_cistatic void qedf_drain_request(struct qedf_ctx *qedf) 21468c2ecf20Sopenharmony_ci{ 21478c2ecf20Sopenharmony_ci if (test_bit(QEDF_DRAIN_ACTIVE, &qedf->flags)) { 21488c2ecf20Sopenharmony_ci QEDF_ERR(&(qedf->dbg_ctx), "MCP drain already active.\n"); 21498c2ecf20Sopenharmony_ci return; 21508c2ecf20Sopenharmony_ci } 21518c2ecf20Sopenharmony_ci 21528c2ecf20Sopenharmony_ci /* Set bit to return all queuecommand requests as busy */ 21538c2ecf20Sopenharmony_ci set_bit(QEDF_DRAIN_ACTIVE, &qedf->flags); 21548c2ecf20Sopenharmony_ci 21558c2ecf20Sopenharmony_ci /* Call qed drain request for function. Should be synchronous */ 21568c2ecf20Sopenharmony_ci qed_ops->common->drain(qedf->cdev); 21578c2ecf20Sopenharmony_ci 21588c2ecf20Sopenharmony_ci /* Settle time for CQEs to be returned */ 21598c2ecf20Sopenharmony_ci msleep(100); 21608c2ecf20Sopenharmony_ci 21618c2ecf20Sopenharmony_ci /* Unplug and continue */ 21628c2ecf20Sopenharmony_ci clear_bit(QEDF_DRAIN_ACTIVE, &qedf->flags); 21638c2ecf20Sopenharmony_ci} 21648c2ecf20Sopenharmony_ci 21658c2ecf20Sopenharmony_ci/* 21668c2ecf20Sopenharmony_ci * Returns SUCCESS if the cleanup task does not timeout, otherwise return 21678c2ecf20Sopenharmony_ci * FAILURE. 21688c2ecf20Sopenharmony_ci */ 21698c2ecf20Sopenharmony_ciint qedf_initiate_cleanup(struct qedf_ioreq *io_req, 21708c2ecf20Sopenharmony_ci bool return_scsi_cmd_on_abts) 21718c2ecf20Sopenharmony_ci{ 21728c2ecf20Sopenharmony_ci struct qedf_rport *fcport; 21738c2ecf20Sopenharmony_ci struct qedf_ctx *qedf; 21748c2ecf20Sopenharmony_ci int tmo = 0; 21758c2ecf20Sopenharmony_ci int rc = SUCCESS; 21768c2ecf20Sopenharmony_ci unsigned long flags; 21778c2ecf20Sopenharmony_ci struct fcoe_wqe *sqe; 21788c2ecf20Sopenharmony_ci u16 sqe_idx; 21798c2ecf20Sopenharmony_ci int refcount = 0; 21808c2ecf20Sopenharmony_ci 21818c2ecf20Sopenharmony_ci fcport = io_req->fcport; 21828c2ecf20Sopenharmony_ci if (!fcport) { 21838c2ecf20Sopenharmony_ci QEDF_ERR(NULL, "fcport is NULL.\n"); 21848c2ecf20Sopenharmony_ci return SUCCESS; 21858c2ecf20Sopenharmony_ci } 21868c2ecf20Sopenharmony_ci 21878c2ecf20Sopenharmony_ci /* Sanity check qedf_rport before dereferencing any pointers */ 21888c2ecf20Sopenharmony_ci if (!test_bit(QEDF_RPORT_SESSION_READY, &fcport->flags)) { 21898c2ecf20Sopenharmony_ci QEDF_ERR(NULL, "tgt not offloaded\n"); 21908c2ecf20Sopenharmony_ci return SUCCESS; 21918c2ecf20Sopenharmony_ci } 21928c2ecf20Sopenharmony_ci 21938c2ecf20Sopenharmony_ci qedf = fcport->qedf; 21948c2ecf20Sopenharmony_ci if (!qedf) { 21958c2ecf20Sopenharmony_ci QEDF_ERR(NULL, "qedf is NULL.\n"); 21968c2ecf20Sopenharmony_ci return SUCCESS; 21978c2ecf20Sopenharmony_ci } 21988c2ecf20Sopenharmony_ci 21998c2ecf20Sopenharmony_ci if (io_req->cmd_type == QEDF_ELS) { 22008c2ecf20Sopenharmony_ci goto process_els; 22018c2ecf20Sopenharmony_ci } 22028c2ecf20Sopenharmony_ci 22038c2ecf20Sopenharmony_ci if (!test_bit(QEDF_CMD_OUTSTANDING, &io_req->flags) || 22048c2ecf20Sopenharmony_ci test_and_set_bit(QEDF_CMD_IN_CLEANUP, &io_req->flags)) { 22058c2ecf20Sopenharmony_ci QEDF_ERR(&(qedf->dbg_ctx), "io_req xid=0x%x already in " 22068c2ecf20Sopenharmony_ci "cleanup processing or already completed.\n", 22078c2ecf20Sopenharmony_ci io_req->xid); 22088c2ecf20Sopenharmony_ci return SUCCESS; 22098c2ecf20Sopenharmony_ci } 22108c2ecf20Sopenharmony_ci set_bit(QEDF_CMD_IN_CLEANUP, &io_req->flags); 22118c2ecf20Sopenharmony_ci 22128c2ecf20Sopenharmony_ciprocess_els: 22138c2ecf20Sopenharmony_ci /* Ensure room on SQ */ 22148c2ecf20Sopenharmony_ci if (!atomic_read(&fcport->free_sqes)) { 22158c2ecf20Sopenharmony_ci QEDF_ERR(&(qedf->dbg_ctx), "No SQ entries available\n"); 22168c2ecf20Sopenharmony_ci /* Need to make sure we clear the flag since it was set */ 22178c2ecf20Sopenharmony_ci clear_bit(QEDF_CMD_IN_CLEANUP, &io_req->flags); 22188c2ecf20Sopenharmony_ci return FAILED; 22198c2ecf20Sopenharmony_ci } 22208c2ecf20Sopenharmony_ci 22218c2ecf20Sopenharmony_ci if (io_req->cmd_type == QEDF_CLEANUP) { 22228c2ecf20Sopenharmony_ci QEDF_ERR(&qedf->dbg_ctx, 22238c2ecf20Sopenharmony_ci "io_req=0x%x is already a cleanup command cmd_type=%d.\n", 22248c2ecf20Sopenharmony_ci io_req->xid, io_req->cmd_type); 22258c2ecf20Sopenharmony_ci clear_bit(QEDF_CMD_IN_CLEANUP, &io_req->flags); 22268c2ecf20Sopenharmony_ci return SUCCESS; 22278c2ecf20Sopenharmony_ci } 22288c2ecf20Sopenharmony_ci 22298c2ecf20Sopenharmony_ci refcount = kref_read(&io_req->refcount); 22308c2ecf20Sopenharmony_ci 22318c2ecf20Sopenharmony_ci QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, 22328c2ecf20Sopenharmony_ci "Entered xid=0x%x sc_cmd=%p cmd_type=%d flags=0x%lx refcount=%d fcport=%p port_id=0x%06x\n", 22338c2ecf20Sopenharmony_ci io_req->xid, io_req->sc_cmd, io_req->cmd_type, io_req->flags, 22348c2ecf20Sopenharmony_ci refcount, fcport, fcport->rdata->ids.port_id); 22358c2ecf20Sopenharmony_ci 22368c2ecf20Sopenharmony_ci /* Cleanup cmds re-use the same TID as the original I/O */ 22378c2ecf20Sopenharmony_ci spin_lock_irqsave(&fcport->rport_lock, flags); 22388c2ecf20Sopenharmony_ci io_req->cmd_type = QEDF_CLEANUP; 22398c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&fcport->rport_lock, flags); 22408c2ecf20Sopenharmony_ci io_req->return_scsi_cmd_on_abts = return_scsi_cmd_on_abts; 22418c2ecf20Sopenharmony_ci 22428c2ecf20Sopenharmony_ci init_completion(&io_req->cleanup_done); 22438c2ecf20Sopenharmony_ci 22448c2ecf20Sopenharmony_ci spin_lock_irqsave(&fcport->rport_lock, flags); 22458c2ecf20Sopenharmony_ci 22468c2ecf20Sopenharmony_ci sqe_idx = qedf_get_sqe_idx(fcport); 22478c2ecf20Sopenharmony_ci sqe = &fcport->sq[sqe_idx]; 22488c2ecf20Sopenharmony_ci memset(sqe, 0, sizeof(struct fcoe_wqe)); 22498c2ecf20Sopenharmony_ci io_req->task_params->sqe = sqe; 22508c2ecf20Sopenharmony_ci 22518c2ecf20Sopenharmony_ci init_initiator_cleanup_fcoe_task(io_req->task_params); 22528c2ecf20Sopenharmony_ci qedf_ring_doorbell(fcport); 22538c2ecf20Sopenharmony_ci 22548c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&fcport->rport_lock, flags); 22558c2ecf20Sopenharmony_ci 22568c2ecf20Sopenharmony_ci tmo = wait_for_completion_timeout(&io_req->cleanup_done, 22578c2ecf20Sopenharmony_ci QEDF_CLEANUP_TIMEOUT * HZ); 22588c2ecf20Sopenharmony_ci 22598c2ecf20Sopenharmony_ci if (!tmo) { 22608c2ecf20Sopenharmony_ci rc = FAILED; 22618c2ecf20Sopenharmony_ci /* Timeout case */ 22628c2ecf20Sopenharmony_ci QEDF_ERR(&(qedf->dbg_ctx), "Cleanup command timeout, " 22638c2ecf20Sopenharmony_ci "xid=%x.\n", io_req->xid); 22648c2ecf20Sopenharmony_ci clear_bit(QEDF_CMD_IN_CLEANUP, &io_req->flags); 22658c2ecf20Sopenharmony_ci /* Issue a drain request if cleanup task times out */ 22668c2ecf20Sopenharmony_ci QEDF_ERR(&(qedf->dbg_ctx), "Issuing MCP drain request.\n"); 22678c2ecf20Sopenharmony_ci qedf_drain_request(qedf); 22688c2ecf20Sopenharmony_ci } 22698c2ecf20Sopenharmony_ci 22708c2ecf20Sopenharmony_ci /* If it TASK MGMT handle it, reference will be decreased 22718c2ecf20Sopenharmony_ci * in qedf_execute_tmf 22728c2ecf20Sopenharmony_ci */ 22738c2ecf20Sopenharmony_ci if (io_req->tm_flags == FCP_TMF_LUN_RESET || 22748c2ecf20Sopenharmony_ci io_req->tm_flags == FCP_TMF_TGT_RESET) { 22758c2ecf20Sopenharmony_ci clear_bit(QEDF_CMD_OUTSTANDING, &io_req->flags); 22768c2ecf20Sopenharmony_ci io_req->sc_cmd = NULL; 22778c2ecf20Sopenharmony_ci kref_put(&io_req->refcount, qedf_release_cmd); 22788c2ecf20Sopenharmony_ci complete(&io_req->tm_done); 22798c2ecf20Sopenharmony_ci } 22808c2ecf20Sopenharmony_ci 22818c2ecf20Sopenharmony_ci if (io_req->sc_cmd) { 22828c2ecf20Sopenharmony_ci if (!io_req->return_scsi_cmd_on_abts) 22838c2ecf20Sopenharmony_ci QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_SCSI_TM, 22848c2ecf20Sopenharmony_ci "Not call scsi_done for xid=0x%x.\n", 22858c2ecf20Sopenharmony_ci io_req->xid); 22868c2ecf20Sopenharmony_ci if (io_req->return_scsi_cmd_on_abts) 22878c2ecf20Sopenharmony_ci qedf_scsi_done(qedf, io_req, DID_ERROR); 22888c2ecf20Sopenharmony_ci } 22898c2ecf20Sopenharmony_ci 22908c2ecf20Sopenharmony_ci if (rc == SUCCESS) 22918c2ecf20Sopenharmony_ci io_req->event = QEDF_IOREQ_EV_CLEANUP_SUCCESS; 22928c2ecf20Sopenharmony_ci else 22938c2ecf20Sopenharmony_ci io_req->event = QEDF_IOREQ_EV_CLEANUP_FAILED; 22948c2ecf20Sopenharmony_ci 22958c2ecf20Sopenharmony_ci return rc; 22968c2ecf20Sopenharmony_ci} 22978c2ecf20Sopenharmony_ci 22988c2ecf20Sopenharmony_civoid qedf_process_cleanup_compl(struct qedf_ctx *qedf, struct fcoe_cqe *cqe, 22998c2ecf20Sopenharmony_ci struct qedf_ioreq *io_req) 23008c2ecf20Sopenharmony_ci{ 23018c2ecf20Sopenharmony_ci QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_IO, "Entered xid = 0x%x\n", 23028c2ecf20Sopenharmony_ci io_req->xid); 23038c2ecf20Sopenharmony_ci 23048c2ecf20Sopenharmony_ci clear_bit(QEDF_CMD_IN_CLEANUP, &io_req->flags); 23058c2ecf20Sopenharmony_ci 23068c2ecf20Sopenharmony_ci /* Complete so we can finish cleaning up the I/O */ 23078c2ecf20Sopenharmony_ci complete(&io_req->cleanup_done); 23088c2ecf20Sopenharmony_ci} 23098c2ecf20Sopenharmony_ci 23108c2ecf20Sopenharmony_cistatic int qedf_execute_tmf(struct qedf_rport *fcport, struct scsi_cmnd *sc_cmd, 23118c2ecf20Sopenharmony_ci uint8_t tm_flags) 23128c2ecf20Sopenharmony_ci{ 23138c2ecf20Sopenharmony_ci struct qedf_ioreq *io_req; 23148c2ecf20Sopenharmony_ci struct e4_fcoe_task_context *task; 23158c2ecf20Sopenharmony_ci struct qedf_ctx *qedf = fcport->qedf; 23168c2ecf20Sopenharmony_ci struct fc_lport *lport = qedf->lport; 23178c2ecf20Sopenharmony_ci int rc = 0; 23188c2ecf20Sopenharmony_ci uint16_t xid; 23198c2ecf20Sopenharmony_ci int tmo = 0; 23208c2ecf20Sopenharmony_ci int lun = 0; 23218c2ecf20Sopenharmony_ci unsigned long flags; 23228c2ecf20Sopenharmony_ci struct fcoe_wqe *sqe; 23238c2ecf20Sopenharmony_ci u16 sqe_idx; 23248c2ecf20Sopenharmony_ci 23258c2ecf20Sopenharmony_ci if (!sc_cmd) { 23268c2ecf20Sopenharmony_ci QEDF_ERR(&qedf->dbg_ctx, "sc_cmd is NULL\n"); 23278c2ecf20Sopenharmony_ci return FAILED; 23288c2ecf20Sopenharmony_ci } 23298c2ecf20Sopenharmony_ci 23308c2ecf20Sopenharmony_ci lun = (int)sc_cmd->device->lun; 23318c2ecf20Sopenharmony_ci if (!test_bit(QEDF_RPORT_SESSION_READY, &fcport->flags)) { 23328c2ecf20Sopenharmony_ci QEDF_ERR(&(qedf->dbg_ctx), "fcport not offloaded\n"); 23338c2ecf20Sopenharmony_ci rc = FAILED; 23348c2ecf20Sopenharmony_ci goto no_flush; 23358c2ecf20Sopenharmony_ci } 23368c2ecf20Sopenharmony_ci 23378c2ecf20Sopenharmony_ci io_req = qedf_alloc_cmd(fcport, QEDF_TASK_MGMT_CMD); 23388c2ecf20Sopenharmony_ci if (!io_req) { 23398c2ecf20Sopenharmony_ci QEDF_ERR(&(qedf->dbg_ctx), "Failed TMF"); 23408c2ecf20Sopenharmony_ci rc = -EAGAIN; 23418c2ecf20Sopenharmony_ci goto no_flush; 23428c2ecf20Sopenharmony_ci } 23438c2ecf20Sopenharmony_ci 23448c2ecf20Sopenharmony_ci if (tm_flags == FCP_TMF_LUN_RESET) 23458c2ecf20Sopenharmony_ci qedf->lun_resets++; 23468c2ecf20Sopenharmony_ci else if (tm_flags == FCP_TMF_TGT_RESET) 23478c2ecf20Sopenharmony_ci qedf->target_resets++; 23488c2ecf20Sopenharmony_ci 23498c2ecf20Sopenharmony_ci /* Initialize rest of io_req fields */ 23508c2ecf20Sopenharmony_ci io_req->sc_cmd = sc_cmd; 23518c2ecf20Sopenharmony_ci io_req->fcport = fcport; 23528c2ecf20Sopenharmony_ci io_req->cmd_type = QEDF_TASK_MGMT_CMD; 23538c2ecf20Sopenharmony_ci 23548c2ecf20Sopenharmony_ci /* Record which cpu this request is associated with */ 23558c2ecf20Sopenharmony_ci io_req->cpu = smp_processor_id(); 23568c2ecf20Sopenharmony_ci 23578c2ecf20Sopenharmony_ci /* Set TM flags */ 23588c2ecf20Sopenharmony_ci io_req->io_req_flags = QEDF_READ; 23598c2ecf20Sopenharmony_ci io_req->data_xfer_len = 0; 23608c2ecf20Sopenharmony_ci io_req->tm_flags = tm_flags; 23618c2ecf20Sopenharmony_ci 23628c2ecf20Sopenharmony_ci /* Default is to return a SCSI command when an error occurs */ 23638c2ecf20Sopenharmony_ci io_req->return_scsi_cmd_on_abts = false; 23648c2ecf20Sopenharmony_ci 23658c2ecf20Sopenharmony_ci /* Obtain exchange id */ 23668c2ecf20Sopenharmony_ci xid = io_req->xid; 23678c2ecf20Sopenharmony_ci 23688c2ecf20Sopenharmony_ci QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_SCSI_TM, "TMF io_req xid = " 23698c2ecf20Sopenharmony_ci "0x%x\n", xid); 23708c2ecf20Sopenharmony_ci 23718c2ecf20Sopenharmony_ci /* Initialize task context for this IO request */ 23728c2ecf20Sopenharmony_ci task = qedf_get_task_mem(&qedf->tasks, xid); 23738c2ecf20Sopenharmony_ci 23748c2ecf20Sopenharmony_ci init_completion(&io_req->tm_done); 23758c2ecf20Sopenharmony_ci 23768c2ecf20Sopenharmony_ci spin_lock_irqsave(&fcport->rport_lock, flags); 23778c2ecf20Sopenharmony_ci 23788c2ecf20Sopenharmony_ci sqe_idx = qedf_get_sqe_idx(fcport); 23798c2ecf20Sopenharmony_ci sqe = &fcport->sq[sqe_idx]; 23808c2ecf20Sopenharmony_ci memset(sqe, 0, sizeof(struct fcoe_wqe)); 23818c2ecf20Sopenharmony_ci 23828c2ecf20Sopenharmony_ci qedf_init_task(fcport, lport, io_req, task, sqe); 23838c2ecf20Sopenharmony_ci qedf_ring_doorbell(fcport); 23848c2ecf20Sopenharmony_ci 23858c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&fcport->rport_lock, flags); 23868c2ecf20Sopenharmony_ci 23878c2ecf20Sopenharmony_ci set_bit(QEDF_CMD_OUTSTANDING, &io_req->flags); 23888c2ecf20Sopenharmony_ci tmo = wait_for_completion_timeout(&io_req->tm_done, 23898c2ecf20Sopenharmony_ci QEDF_TM_TIMEOUT * HZ); 23908c2ecf20Sopenharmony_ci 23918c2ecf20Sopenharmony_ci if (!tmo) { 23928c2ecf20Sopenharmony_ci rc = FAILED; 23938c2ecf20Sopenharmony_ci QEDF_ERR(&(qedf->dbg_ctx), "wait for tm_cmpl timeout!\n"); 23948c2ecf20Sopenharmony_ci /* Clear outstanding bit since command timed out */ 23958c2ecf20Sopenharmony_ci clear_bit(QEDF_CMD_OUTSTANDING, &io_req->flags); 23968c2ecf20Sopenharmony_ci io_req->sc_cmd = NULL; 23978c2ecf20Sopenharmony_ci } else { 23988c2ecf20Sopenharmony_ci /* Check TMF response code */ 23998c2ecf20Sopenharmony_ci if (io_req->fcp_rsp_code == 0) 24008c2ecf20Sopenharmony_ci rc = SUCCESS; 24018c2ecf20Sopenharmony_ci else 24028c2ecf20Sopenharmony_ci rc = FAILED; 24038c2ecf20Sopenharmony_ci } 24048c2ecf20Sopenharmony_ci /* 24058c2ecf20Sopenharmony_ci * Double check that fcport has not gone into an uploading state before 24068c2ecf20Sopenharmony_ci * executing the command flush for the LUN/target. 24078c2ecf20Sopenharmony_ci */ 24088c2ecf20Sopenharmony_ci if (test_bit(QEDF_RPORT_UPLOADING_CONNECTION, &fcport->flags)) { 24098c2ecf20Sopenharmony_ci QEDF_ERR(&qedf->dbg_ctx, 24108c2ecf20Sopenharmony_ci "fcport is uploading, not executing flush.\n"); 24118c2ecf20Sopenharmony_ci goto no_flush; 24128c2ecf20Sopenharmony_ci } 24138c2ecf20Sopenharmony_ci /* We do not need this io_req any more */ 24148c2ecf20Sopenharmony_ci kref_put(&io_req->refcount, qedf_release_cmd); 24158c2ecf20Sopenharmony_ci 24168c2ecf20Sopenharmony_ci 24178c2ecf20Sopenharmony_ci if (tm_flags == FCP_TMF_LUN_RESET) 24188c2ecf20Sopenharmony_ci qedf_flush_active_ios(fcport, lun); 24198c2ecf20Sopenharmony_ci else 24208c2ecf20Sopenharmony_ci qedf_flush_active_ios(fcport, -1); 24218c2ecf20Sopenharmony_ci 24228c2ecf20Sopenharmony_cino_flush: 24238c2ecf20Sopenharmony_ci if (rc != SUCCESS) { 24248c2ecf20Sopenharmony_ci QEDF_ERR(&(qedf->dbg_ctx), "task mgmt command failed...\n"); 24258c2ecf20Sopenharmony_ci rc = FAILED; 24268c2ecf20Sopenharmony_ci } else { 24278c2ecf20Sopenharmony_ci QEDF_ERR(&(qedf->dbg_ctx), "task mgmt command success...\n"); 24288c2ecf20Sopenharmony_ci rc = SUCCESS; 24298c2ecf20Sopenharmony_ci } 24308c2ecf20Sopenharmony_ci return rc; 24318c2ecf20Sopenharmony_ci} 24328c2ecf20Sopenharmony_ci 24338c2ecf20Sopenharmony_ciint qedf_initiate_tmf(struct scsi_cmnd *sc_cmd, u8 tm_flags) 24348c2ecf20Sopenharmony_ci{ 24358c2ecf20Sopenharmony_ci struct fc_rport *rport = starget_to_rport(scsi_target(sc_cmd->device)); 24368c2ecf20Sopenharmony_ci struct fc_rport_libfc_priv *rp = rport->dd_data; 24378c2ecf20Sopenharmony_ci struct qedf_rport *fcport = (struct qedf_rport *)&rp[1]; 24388c2ecf20Sopenharmony_ci struct qedf_ctx *qedf; 24398c2ecf20Sopenharmony_ci struct fc_lport *lport = shost_priv(sc_cmd->device->host); 24408c2ecf20Sopenharmony_ci int rc = SUCCESS; 24418c2ecf20Sopenharmony_ci int rval; 24428c2ecf20Sopenharmony_ci struct qedf_ioreq *io_req = NULL; 24438c2ecf20Sopenharmony_ci int ref_cnt = 0; 24448c2ecf20Sopenharmony_ci struct fc_rport_priv *rdata = fcport->rdata; 24458c2ecf20Sopenharmony_ci 24468c2ecf20Sopenharmony_ci QEDF_ERR(NULL, 24478c2ecf20Sopenharmony_ci "tm_flags 0x%x sc_cmd %p op = 0x%02x target_id = 0x%x lun=%d\n", 24488c2ecf20Sopenharmony_ci tm_flags, sc_cmd, sc_cmd->cmd_len ? sc_cmd->cmnd[0] : 0xff, 24498c2ecf20Sopenharmony_ci rport->scsi_target_id, (int)sc_cmd->device->lun); 24508c2ecf20Sopenharmony_ci 24518c2ecf20Sopenharmony_ci if (!rdata || !kref_get_unless_zero(&rdata->kref)) { 24528c2ecf20Sopenharmony_ci QEDF_ERR(NULL, "stale rport\n"); 24538c2ecf20Sopenharmony_ci return FAILED; 24548c2ecf20Sopenharmony_ci } 24558c2ecf20Sopenharmony_ci 24568c2ecf20Sopenharmony_ci QEDF_ERR(NULL, "portid=%06x tm_flags =%s\n", rdata->ids.port_id, 24578c2ecf20Sopenharmony_ci (tm_flags == FCP_TMF_TGT_RESET) ? "TARGET RESET" : 24588c2ecf20Sopenharmony_ci "LUN RESET"); 24598c2ecf20Sopenharmony_ci 24608c2ecf20Sopenharmony_ci if (sc_cmd->SCp.ptr) { 24618c2ecf20Sopenharmony_ci io_req = (struct qedf_ioreq *)sc_cmd->SCp.ptr; 24628c2ecf20Sopenharmony_ci ref_cnt = kref_read(&io_req->refcount); 24638c2ecf20Sopenharmony_ci QEDF_ERR(NULL, 24648c2ecf20Sopenharmony_ci "orig io_req = %p xid = 0x%x ref_cnt = %d.\n", 24658c2ecf20Sopenharmony_ci io_req, io_req->xid, ref_cnt); 24668c2ecf20Sopenharmony_ci } 24678c2ecf20Sopenharmony_ci 24688c2ecf20Sopenharmony_ci rval = fc_remote_port_chkready(rport); 24698c2ecf20Sopenharmony_ci if (rval) { 24708c2ecf20Sopenharmony_ci QEDF_ERR(NULL, "device_reset rport not ready\n"); 24718c2ecf20Sopenharmony_ci rc = FAILED; 24728c2ecf20Sopenharmony_ci goto tmf_err; 24738c2ecf20Sopenharmony_ci } 24748c2ecf20Sopenharmony_ci 24758c2ecf20Sopenharmony_ci rc = fc_block_scsi_eh(sc_cmd); 24768c2ecf20Sopenharmony_ci if (rc) 24778c2ecf20Sopenharmony_ci goto tmf_err; 24788c2ecf20Sopenharmony_ci 24798c2ecf20Sopenharmony_ci if (!fcport) { 24808c2ecf20Sopenharmony_ci QEDF_ERR(NULL, "device_reset: rport is NULL\n"); 24818c2ecf20Sopenharmony_ci rc = FAILED; 24828c2ecf20Sopenharmony_ci goto tmf_err; 24838c2ecf20Sopenharmony_ci } 24848c2ecf20Sopenharmony_ci 24858c2ecf20Sopenharmony_ci qedf = fcport->qedf; 24868c2ecf20Sopenharmony_ci 24878c2ecf20Sopenharmony_ci if (!qedf) { 24888c2ecf20Sopenharmony_ci QEDF_ERR(NULL, "qedf is NULL.\n"); 24898c2ecf20Sopenharmony_ci rc = FAILED; 24908c2ecf20Sopenharmony_ci goto tmf_err; 24918c2ecf20Sopenharmony_ci } 24928c2ecf20Sopenharmony_ci 24938c2ecf20Sopenharmony_ci if (test_bit(QEDF_RPORT_UPLOADING_CONNECTION, &fcport->flags)) { 24948c2ecf20Sopenharmony_ci QEDF_ERR(&qedf->dbg_ctx, "Connection is getting uploaded.\n"); 24958c2ecf20Sopenharmony_ci rc = SUCCESS; 24968c2ecf20Sopenharmony_ci goto tmf_err; 24978c2ecf20Sopenharmony_ci } 24988c2ecf20Sopenharmony_ci 24998c2ecf20Sopenharmony_ci if (test_bit(QEDF_UNLOADING, &qedf->flags) || 25008c2ecf20Sopenharmony_ci test_bit(QEDF_DBG_STOP_IO, &qedf->flags)) { 25018c2ecf20Sopenharmony_ci rc = SUCCESS; 25028c2ecf20Sopenharmony_ci goto tmf_err; 25038c2ecf20Sopenharmony_ci } 25048c2ecf20Sopenharmony_ci 25058c2ecf20Sopenharmony_ci if (lport->state != LPORT_ST_READY || !(lport->link_up)) { 25068c2ecf20Sopenharmony_ci QEDF_ERR(&(qedf->dbg_ctx), "link is not ready\n"); 25078c2ecf20Sopenharmony_ci rc = FAILED; 25088c2ecf20Sopenharmony_ci goto tmf_err; 25098c2ecf20Sopenharmony_ci } 25108c2ecf20Sopenharmony_ci 25118c2ecf20Sopenharmony_ci if (test_bit(QEDF_RPORT_UPLOADING_CONNECTION, &fcport->flags)) { 25128c2ecf20Sopenharmony_ci if (!fcport->rdata) 25138c2ecf20Sopenharmony_ci QEDF_ERR(&qedf->dbg_ctx, "fcport %p is uploading.\n", 25148c2ecf20Sopenharmony_ci fcport); 25158c2ecf20Sopenharmony_ci else 25168c2ecf20Sopenharmony_ci QEDF_ERR(&qedf->dbg_ctx, 25178c2ecf20Sopenharmony_ci "fcport %p port_id=%06x is uploading.\n", 25188c2ecf20Sopenharmony_ci fcport, fcport->rdata->ids.port_id); 25198c2ecf20Sopenharmony_ci rc = FAILED; 25208c2ecf20Sopenharmony_ci goto tmf_err; 25218c2ecf20Sopenharmony_ci } 25228c2ecf20Sopenharmony_ci 25238c2ecf20Sopenharmony_ci rc = qedf_execute_tmf(fcport, sc_cmd, tm_flags); 25248c2ecf20Sopenharmony_ci 25258c2ecf20Sopenharmony_citmf_err: 25268c2ecf20Sopenharmony_ci kref_put(&rdata->kref, fc_rport_destroy); 25278c2ecf20Sopenharmony_ci return rc; 25288c2ecf20Sopenharmony_ci} 25298c2ecf20Sopenharmony_ci 25308c2ecf20Sopenharmony_civoid qedf_process_tmf_compl(struct qedf_ctx *qedf, struct fcoe_cqe *cqe, 25318c2ecf20Sopenharmony_ci struct qedf_ioreq *io_req) 25328c2ecf20Sopenharmony_ci{ 25338c2ecf20Sopenharmony_ci struct fcoe_cqe_rsp_info *fcp_rsp; 25348c2ecf20Sopenharmony_ci 25358c2ecf20Sopenharmony_ci clear_bit(QEDF_CMD_OUTSTANDING, &io_req->flags); 25368c2ecf20Sopenharmony_ci 25378c2ecf20Sopenharmony_ci fcp_rsp = &cqe->cqe_info.rsp_info; 25388c2ecf20Sopenharmony_ci qedf_parse_fcp_rsp(io_req, fcp_rsp); 25398c2ecf20Sopenharmony_ci 25408c2ecf20Sopenharmony_ci io_req->sc_cmd = NULL; 25418c2ecf20Sopenharmony_ci complete(&io_req->tm_done); 25428c2ecf20Sopenharmony_ci} 25438c2ecf20Sopenharmony_ci 25448c2ecf20Sopenharmony_civoid qedf_process_unsol_compl(struct qedf_ctx *qedf, uint16_t que_idx, 25458c2ecf20Sopenharmony_ci struct fcoe_cqe *cqe) 25468c2ecf20Sopenharmony_ci{ 25478c2ecf20Sopenharmony_ci unsigned long flags; 25488c2ecf20Sopenharmony_ci uint16_t pktlen = cqe->cqe_info.unsolic_info.pkt_len; 25498c2ecf20Sopenharmony_ci u32 payload_len, crc; 25508c2ecf20Sopenharmony_ci struct fc_frame_header *fh; 25518c2ecf20Sopenharmony_ci struct fc_frame *fp; 25528c2ecf20Sopenharmony_ci struct qedf_io_work *io_work; 25538c2ecf20Sopenharmony_ci u32 bdq_idx; 25548c2ecf20Sopenharmony_ci void *bdq_addr; 25558c2ecf20Sopenharmony_ci struct scsi_bd *p_bd_info; 25568c2ecf20Sopenharmony_ci 25578c2ecf20Sopenharmony_ci p_bd_info = &cqe->cqe_info.unsolic_info.bd_info; 25588c2ecf20Sopenharmony_ci QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_UNSOL, 25598c2ecf20Sopenharmony_ci "address.hi=%x, address.lo=%x, opaque_data.hi=%x, opaque_data.lo=%x, bdq_prod_idx=%u, len=%u\n", 25608c2ecf20Sopenharmony_ci le32_to_cpu(p_bd_info->address.hi), 25618c2ecf20Sopenharmony_ci le32_to_cpu(p_bd_info->address.lo), 25628c2ecf20Sopenharmony_ci le32_to_cpu(p_bd_info->opaque.fcoe_opaque.hi), 25638c2ecf20Sopenharmony_ci le32_to_cpu(p_bd_info->opaque.fcoe_opaque.lo), 25648c2ecf20Sopenharmony_ci qedf->bdq_prod_idx, pktlen); 25658c2ecf20Sopenharmony_ci 25668c2ecf20Sopenharmony_ci bdq_idx = le32_to_cpu(p_bd_info->opaque.fcoe_opaque.lo); 25678c2ecf20Sopenharmony_ci if (bdq_idx >= QEDF_BDQ_SIZE) { 25688c2ecf20Sopenharmony_ci QEDF_ERR(&(qedf->dbg_ctx), "bdq_idx is out of range %d.\n", 25698c2ecf20Sopenharmony_ci bdq_idx); 25708c2ecf20Sopenharmony_ci goto increment_prod; 25718c2ecf20Sopenharmony_ci } 25728c2ecf20Sopenharmony_ci 25738c2ecf20Sopenharmony_ci bdq_addr = qedf->bdq[bdq_idx].buf_addr; 25748c2ecf20Sopenharmony_ci if (!bdq_addr) { 25758c2ecf20Sopenharmony_ci QEDF_ERR(&(qedf->dbg_ctx), "bdq_addr is NULL, dropping " 25768c2ecf20Sopenharmony_ci "unsolicited packet.\n"); 25778c2ecf20Sopenharmony_ci goto increment_prod; 25788c2ecf20Sopenharmony_ci } 25798c2ecf20Sopenharmony_ci 25808c2ecf20Sopenharmony_ci if (qedf_dump_frames) { 25818c2ecf20Sopenharmony_ci QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_UNSOL, 25828c2ecf20Sopenharmony_ci "BDQ frame is at addr=%p.\n", bdq_addr); 25838c2ecf20Sopenharmony_ci print_hex_dump(KERN_WARNING, "bdq ", DUMP_PREFIX_OFFSET, 16, 1, 25848c2ecf20Sopenharmony_ci (void *)bdq_addr, pktlen, false); 25858c2ecf20Sopenharmony_ci } 25868c2ecf20Sopenharmony_ci 25878c2ecf20Sopenharmony_ci /* Allocate frame */ 25888c2ecf20Sopenharmony_ci payload_len = pktlen - sizeof(struct fc_frame_header); 25898c2ecf20Sopenharmony_ci fp = fc_frame_alloc(qedf->lport, payload_len); 25908c2ecf20Sopenharmony_ci if (!fp) { 25918c2ecf20Sopenharmony_ci QEDF_ERR(&(qedf->dbg_ctx), "Could not allocate fp.\n"); 25928c2ecf20Sopenharmony_ci goto increment_prod; 25938c2ecf20Sopenharmony_ci } 25948c2ecf20Sopenharmony_ci 25958c2ecf20Sopenharmony_ci /* Copy data from BDQ buffer into fc_frame struct */ 25968c2ecf20Sopenharmony_ci fh = (struct fc_frame_header *)fc_frame_header_get(fp); 25978c2ecf20Sopenharmony_ci memcpy(fh, (void *)bdq_addr, pktlen); 25988c2ecf20Sopenharmony_ci 25998c2ecf20Sopenharmony_ci QEDF_WARN(&qedf->dbg_ctx, 26008c2ecf20Sopenharmony_ci "Processing Unsolicated frame, src=%06x dest=%06x r_ctl=0x%x type=0x%x cmd=%02x\n", 26018c2ecf20Sopenharmony_ci ntoh24(fh->fh_s_id), ntoh24(fh->fh_d_id), fh->fh_r_ctl, 26028c2ecf20Sopenharmony_ci fh->fh_type, fc_frame_payload_op(fp)); 26038c2ecf20Sopenharmony_ci 26048c2ecf20Sopenharmony_ci /* Initialize the frame so libfc sees it as a valid frame */ 26058c2ecf20Sopenharmony_ci crc = fcoe_fc_crc(fp); 26068c2ecf20Sopenharmony_ci fc_frame_init(fp); 26078c2ecf20Sopenharmony_ci fr_dev(fp) = qedf->lport; 26088c2ecf20Sopenharmony_ci fr_sof(fp) = FC_SOF_I3; 26098c2ecf20Sopenharmony_ci fr_eof(fp) = FC_EOF_T; 26108c2ecf20Sopenharmony_ci fr_crc(fp) = cpu_to_le32(~crc); 26118c2ecf20Sopenharmony_ci 26128c2ecf20Sopenharmony_ci /* 26138c2ecf20Sopenharmony_ci * We need to return the frame back up to libfc in a non-atomic 26148c2ecf20Sopenharmony_ci * context 26158c2ecf20Sopenharmony_ci */ 26168c2ecf20Sopenharmony_ci io_work = mempool_alloc(qedf->io_mempool, GFP_ATOMIC); 26178c2ecf20Sopenharmony_ci if (!io_work) { 26188c2ecf20Sopenharmony_ci QEDF_WARN(&(qedf->dbg_ctx), "Could not allocate " 26198c2ecf20Sopenharmony_ci "work for I/O completion.\n"); 26208c2ecf20Sopenharmony_ci fc_frame_free(fp); 26218c2ecf20Sopenharmony_ci goto increment_prod; 26228c2ecf20Sopenharmony_ci } 26238c2ecf20Sopenharmony_ci memset(io_work, 0, sizeof(struct qedf_io_work)); 26248c2ecf20Sopenharmony_ci 26258c2ecf20Sopenharmony_ci INIT_WORK(&io_work->work, qedf_fp_io_handler); 26268c2ecf20Sopenharmony_ci 26278c2ecf20Sopenharmony_ci /* Copy contents of CQE for deferred processing */ 26288c2ecf20Sopenharmony_ci memcpy(&io_work->cqe, cqe, sizeof(struct fcoe_cqe)); 26298c2ecf20Sopenharmony_ci 26308c2ecf20Sopenharmony_ci io_work->qedf = qedf; 26318c2ecf20Sopenharmony_ci io_work->fp = fp; 26328c2ecf20Sopenharmony_ci 26338c2ecf20Sopenharmony_ci queue_work_on(smp_processor_id(), qedf_io_wq, &io_work->work); 26348c2ecf20Sopenharmony_ciincrement_prod: 26358c2ecf20Sopenharmony_ci spin_lock_irqsave(&qedf->hba_lock, flags); 26368c2ecf20Sopenharmony_ci 26378c2ecf20Sopenharmony_ci /* Increment producer to let f/w know we've handled the frame */ 26388c2ecf20Sopenharmony_ci qedf->bdq_prod_idx++; 26398c2ecf20Sopenharmony_ci 26408c2ecf20Sopenharmony_ci /* Producer index wraps at uint16_t boundary */ 26418c2ecf20Sopenharmony_ci if (qedf->bdq_prod_idx == 0xffff) 26428c2ecf20Sopenharmony_ci qedf->bdq_prod_idx = 0; 26438c2ecf20Sopenharmony_ci 26448c2ecf20Sopenharmony_ci writew(qedf->bdq_prod_idx, qedf->bdq_primary_prod); 26458c2ecf20Sopenharmony_ci readw(qedf->bdq_primary_prod); 26468c2ecf20Sopenharmony_ci writew(qedf->bdq_prod_idx, qedf->bdq_secondary_prod); 26478c2ecf20Sopenharmony_ci readw(qedf->bdq_secondary_prod); 26488c2ecf20Sopenharmony_ci 26498c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&qedf->hba_lock, flags); 26508c2ecf20Sopenharmony_ci} 2651