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