162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * QLogic Fibre Channel HBA Driver
462306a36Sopenharmony_ci * Copyright (c)  2003-2017 QLogic Corporation
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci#include "qla_nvme.h"
762306a36Sopenharmony_ci#include <linux/scatterlist.h>
862306a36Sopenharmony_ci#include <linux/delay.h>
962306a36Sopenharmony_ci#include <linux/nvme.h>
1062306a36Sopenharmony_ci#include <linux/nvme-fc.h>
1162306a36Sopenharmony_ci#include <linux/blk-mq-pci.h>
1262306a36Sopenharmony_ci#include <linux/blk-mq.h>
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_cistatic struct nvme_fc_port_template qla_nvme_fc_transport;
1562306a36Sopenharmony_cistatic int qla_nvme_ls_reject_iocb(struct scsi_qla_host *vha,
1662306a36Sopenharmony_ci				   struct qla_qpair *qp,
1762306a36Sopenharmony_ci				   struct qla_nvme_lsrjt_pt_arg *a,
1862306a36Sopenharmony_ci				   bool is_xchg_terminate);
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_cistruct qla_nvme_unsol_ctx {
2162306a36Sopenharmony_ci	struct list_head elem;
2262306a36Sopenharmony_ci	struct scsi_qla_host *vha;
2362306a36Sopenharmony_ci	struct fc_port *fcport;
2462306a36Sopenharmony_ci	struct srb *sp;
2562306a36Sopenharmony_ci	struct nvmefc_ls_rsp lsrsp;
2662306a36Sopenharmony_ci	struct nvmefc_ls_rsp *fd_rsp;
2762306a36Sopenharmony_ci	struct work_struct lsrsp_work;
2862306a36Sopenharmony_ci	struct work_struct abort_work;
2962306a36Sopenharmony_ci	__le32 exchange_address;
3062306a36Sopenharmony_ci	__le16 nport_handle;
3162306a36Sopenharmony_ci	__le16 ox_id;
3262306a36Sopenharmony_ci	int comp_status;
3362306a36Sopenharmony_ci	spinlock_t cmd_lock;
3462306a36Sopenharmony_ci};
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ciint qla_nvme_register_remote(struct scsi_qla_host *vha, struct fc_port *fcport)
3762306a36Sopenharmony_ci{
3862306a36Sopenharmony_ci	struct qla_nvme_rport *rport;
3962306a36Sopenharmony_ci	struct nvme_fc_port_info req;
4062306a36Sopenharmony_ci	int ret;
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	if (!IS_ENABLED(CONFIG_NVME_FC))
4362306a36Sopenharmony_ci		return 0;
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	if (!vha->flags.nvme_enabled) {
4662306a36Sopenharmony_ci		ql_log(ql_log_info, vha, 0x2100,
4762306a36Sopenharmony_ci		    "%s: Not registering target since Host NVME is not enabled\n",
4862306a36Sopenharmony_ci		    __func__);
4962306a36Sopenharmony_ci		return 0;
5062306a36Sopenharmony_ci	}
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	if (!vha->nvme_local_port && qla_nvme_register_hba(vha))
5362306a36Sopenharmony_ci		return 0;
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	if (!(fcport->nvme_prli_service_param &
5662306a36Sopenharmony_ci	    (NVME_PRLI_SP_TARGET | NVME_PRLI_SP_DISCOVERY)) ||
5762306a36Sopenharmony_ci		(fcport->nvme_flag & NVME_FLAG_REGISTERED))
5862306a36Sopenharmony_ci		return 0;
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	fcport->nvme_flag &= ~NVME_FLAG_RESETTING;
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	memset(&req, 0, sizeof(struct nvme_fc_port_info));
6362306a36Sopenharmony_ci	req.port_name = wwn_to_u64(fcport->port_name);
6462306a36Sopenharmony_ci	req.node_name = wwn_to_u64(fcport->node_name);
6562306a36Sopenharmony_ci	req.port_role = 0;
6662306a36Sopenharmony_ci	req.dev_loss_tmo = fcport->dev_loss_tmo;
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	if (fcport->nvme_prli_service_param & NVME_PRLI_SP_INITIATOR)
6962306a36Sopenharmony_ci		req.port_role = FC_PORT_ROLE_NVME_INITIATOR;
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	if (fcport->nvme_prli_service_param & NVME_PRLI_SP_TARGET)
7262306a36Sopenharmony_ci		req.port_role |= FC_PORT_ROLE_NVME_TARGET;
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	if (fcport->nvme_prli_service_param & NVME_PRLI_SP_DISCOVERY)
7562306a36Sopenharmony_ci		req.port_role |= FC_PORT_ROLE_NVME_DISCOVERY;
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	req.port_id = fcport->d_id.b24;
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	ql_log(ql_log_info, vha, 0x2102,
8062306a36Sopenharmony_ci	    "%s: traddr=nn-0x%016llx:pn-0x%016llx PortID:%06x\n",
8162306a36Sopenharmony_ci	    __func__, req.node_name, req.port_name,
8262306a36Sopenharmony_ci	    req.port_id);
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	ret = nvme_fc_register_remoteport(vha->nvme_local_port, &req,
8562306a36Sopenharmony_ci	    &fcport->nvme_remote_port);
8662306a36Sopenharmony_ci	if (ret) {
8762306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x212e,
8862306a36Sopenharmony_ci		    "Failed to register remote port. Transport returned %d\n",
8962306a36Sopenharmony_ci		    ret);
9062306a36Sopenharmony_ci		return ret;
9162306a36Sopenharmony_ci	}
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	nvme_fc_set_remoteport_devloss(fcport->nvme_remote_port,
9462306a36Sopenharmony_ci				       fcport->dev_loss_tmo);
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	if (fcport->nvme_prli_service_param & NVME_PRLI_SP_SLER)
9762306a36Sopenharmony_ci		ql_log(ql_log_info, vha, 0x212a,
9862306a36Sopenharmony_ci		       "PortID:%06x Supports SLER\n", req.port_id);
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	if (fcport->nvme_prli_service_param & NVME_PRLI_SP_PI_CTRL)
10162306a36Sopenharmony_ci		ql_log(ql_log_info, vha, 0x212b,
10262306a36Sopenharmony_ci		       "PortID:%06x Supports PI control\n", req.port_id);
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	rport = fcport->nvme_remote_port->private;
10562306a36Sopenharmony_ci	rport->fcport = fcport;
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	fcport->nvme_flag |= NVME_FLAG_REGISTERED;
10862306a36Sopenharmony_ci	return 0;
10962306a36Sopenharmony_ci}
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci/* Allocate a queue for NVMe traffic */
11262306a36Sopenharmony_cistatic int qla_nvme_alloc_queue(struct nvme_fc_local_port *lport,
11362306a36Sopenharmony_ci    unsigned int qidx, u16 qsize, void **handle)
11462306a36Sopenharmony_ci{
11562306a36Sopenharmony_ci	struct scsi_qla_host *vha;
11662306a36Sopenharmony_ci	struct qla_hw_data *ha;
11762306a36Sopenharmony_ci	struct qla_qpair *qpair;
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	/* Map admin queue and 1st IO queue to index 0 */
12062306a36Sopenharmony_ci	if (qidx)
12162306a36Sopenharmony_ci		qidx--;
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	vha = (struct scsi_qla_host *)lport->private;
12462306a36Sopenharmony_ci	ha = vha->hw;
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	ql_log(ql_log_info, vha, 0x2104,
12762306a36Sopenharmony_ci	    "%s: handle %p, idx =%d, qsize %d\n",
12862306a36Sopenharmony_ci	    __func__, handle, qidx, qsize);
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	if (qidx > qla_nvme_fc_transport.max_hw_queues) {
13162306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x212f,
13262306a36Sopenharmony_ci		    "%s: Illegal qidx=%d. Max=%d\n",
13362306a36Sopenharmony_ci		    __func__, qidx, qla_nvme_fc_transport.max_hw_queues);
13462306a36Sopenharmony_ci		return -EINVAL;
13562306a36Sopenharmony_ci	}
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	/* Use base qpair if max_qpairs is 0 */
13862306a36Sopenharmony_ci	if (!ha->max_qpairs) {
13962306a36Sopenharmony_ci		qpair = ha->base_qpair;
14062306a36Sopenharmony_ci	} else {
14162306a36Sopenharmony_ci		if (ha->queue_pair_map[qidx]) {
14262306a36Sopenharmony_ci			*handle = ha->queue_pair_map[qidx];
14362306a36Sopenharmony_ci			ql_log(ql_log_info, vha, 0x2121,
14462306a36Sopenharmony_ci			       "Returning existing qpair of %p for idx=%x\n",
14562306a36Sopenharmony_ci			       *handle, qidx);
14662306a36Sopenharmony_ci			return 0;
14762306a36Sopenharmony_ci		}
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci		qpair = qla2xxx_create_qpair(vha, 5, vha->vp_idx, true);
15062306a36Sopenharmony_ci		if (!qpair) {
15162306a36Sopenharmony_ci			ql_log(ql_log_warn, vha, 0x2122,
15262306a36Sopenharmony_ci			       "Failed to allocate qpair\n");
15362306a36Sopenharmony_ci			return -EINVAL;
15462306a36Sopenharmony_ci		}
15562306a36Sopenharmony_ci		qla_adjust_iocb_limit(vha);
15662306a36Sopenharmony_ci	}
15762306a36Sopenharmony_ci	*handle = qpair;
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	return 0;
16062306a36Sopenharmony_ci}
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_cistatic void qla_nvme_release_fcp_cmd_kref(struct kref *kref)
16362306a36Sopenharmony_ci{
16462306a36Sopenharmony_ci	struct srb *sp = container_of(kref, struct srb, cmd_kref);
16562306a36Sopenharmony_ci	struct nvme_private *priv = (struct nvme_private *)sp->priv;
16662306a36Sopenharmony_ci	struct nvmefc_fcp_req *fd;
16762306a36Sopenharmony_ci	struct srb_iocb *nvme;
16862306a36Sopenharmony_ci	unsigned long flags;
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	if (!priv)
17162306a36Sopenharmony_ci		goto out;
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	nvme = &sp->u.iocb_cmd;
17462306a36Sopenharmony_ci	fd = nvme->u.nvme.desc;
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	spin_lock_irqsave(&priv->cmd_lock, flags);
17762306a36Sopenharmony_ci	priv->sp = NULL;
17862306a36Sopenharmony_ci	sp->priv = NULL;
17962306a36Sopenharmony_ci	if (priv->comp_status == QLA_SUCCESS) {
18062306a36Sopenharmony_ci		fd->rcv_rsplen = le16_to_cpu(nvme->u.nvme.rsp_pyld_len);
18162306a36Sopenharmony_ci		fd->status = NVME_SC_SUCCESS;
18262306a36Sopenharmony_ci	} else {
18362306a36Sopenharmony_ci		fd->rcv_rsplen = 0;
18462306a36Sopenharmony_ci		fd->transferred_length = 0;
18562306a36Sopenharmony_ci		fd->status = NVME_SC_INTERNAL;
18662306a36Sopenharmony_ci	}
18762306a36Sopenharmony_ci	spin_unlock_irqrestore(&priv->cmd_lock, flags);
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	fd->done(fd);
19062306a36Sopenharmony_ciout:
19162306a36Sopenharmony_ci	qla2xxx_rel_qpair_sp(sp->qpair, sp);
19262306a36Sopenharmony_ci}
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_cistatic void qla_nvme_release_ls_cmd_kref(struct kref *kref)
19562306a36Sopenharmony_ci{
19662306a36Sopenharmony_ci	struct srb *sp = container_of(kref, struct srb, cmd_kref);
19762306a36Sopenharmony_ci	struct nvme_private *priv = (struct nvme_private *)sp->priv;
19862306a36Sopenharmony_ci	struct nvmefc_ls_req *fd;
19962306a36Sopenharmony_ci	unsigned long flags;
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	if (!priv)
20262306a36Sopenharmony_ci		goto out;
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	spin_lock_irqsave(&priv->cmd_lock, flags);
20562306a36Sopenharmony_ci	priv->sp = NULL;
20662306a36Sopenharmony_ci	sp->priv = NULL;
20762306a36Sopenharmony_ci	spin_unlock_irqrestore(&priv->cmd_lock, flags);
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	fd = priv->fd;
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	fd->done(fd, priv->comp_status);
21262306a36Sopenharmony_ciout:
21362306a36Sopenharmony_ci	qla2x00_rel_sp(sp);
21462306a36Sopenharmony_ci}
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_cistatic void qla_nvme_ls_complete(struct work_struct *work)
21762306a36Sopenharmony_ci{
21862306a36Sopenharmony_ci	struct nvme_private *priv =
21962306a36Sopenharmony_ci		container_of(work, struct nvme_private, ls_work);
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	kref_put(&priv->sp->cmd_kref, qla_nvme_release_ls_cmd_kref);
22262306a36Sopenharmony_ci}
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_cistatic void qla_nvme_sp_ls_done(srb_t *sp, int res)
22562306a36Sopenharmony_ci{
22662306a36Sopenharmony_ci	struct nvme_private *priv = sp->priv;
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	if (WARN_ON_ONCE(kref_read(&sp->cmd_kref) == 0))
22962306a36Sopenharmony_ci		return;
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	if (res)
23262306a36Sopenharmony_ci		res = -EINVAL;
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	priv->comp_status = res;
23562306a36Sopenharmony_ci	INIT_WORK(&priv->ls_work, qla_nvme_ls_complete);
23662306a36Sopenharmony_ci	schedule_work(&priv->ls_work);
23762306a36Sopenharmony_ci}
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_cistatic void qla_nvme_release_lsrsp_cmd_kref(struct kref *kref)
24062306a36Sopenharmony_ci{
24162306a36Sopenharmony_ci	struct srb *sp = container_of(kref, struct srb, cmd_kref);
24262306a36Sopenharmony_ci	struct qla_nvme_unsol_ctx *uctx = sp->priv;
24362306a36Sopenharmony_ci	struct nvmefc_ls_rsp *fd_rsp;
24462306a36Sopenharmony_ci	unsigned long flags;
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	if (!uctx) {
24762306a36Sopenharmony_ci		qla2x00_rel_sp(sp);
24862306a36Sopenharmony_ci		return;
24962306a36Sopenharmony_ci	}
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	spin_lock_irqsave(&uctx->cmd_lock, flags);
25262306a36Sopenharmony_ci	uctx->sp = NULL;
25362306a36Sopenharmony_ci	sp->priv = NULL;
25462306a36Sopenharmony_ci	spin_unlock_irqrestore(&uctx->cmd_lock, flags);
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	fd_rsp = uctx->fd_rsp;
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	list_del(&uctx->elem);
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	fd_rsp->done(fd_rsp);
26162306a36Sopenharmony_ci	kfree(uctx);
26262306a36Sopenharmony_ci	qla2x00_rel_sp(sp);
26362306a36Sopenharmony_ci}
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_cistatic void qla_nvme_lsrsp_complete(struct work_struct *work)
26662306a36Sopenharmony_ci{
26762306a36Sopenharmony_ci	struct qla_nvme_unsol_ctx *uctx =
26862306a36Sopenharmony_ci		container_of(work, struct qla_nvme_unsol_ctx, lsrsp_work);
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	kref_put(&uctx->sp->cmd_kref, qla_nvme_release_lsrsp_cmd_kref);
27162306a36Sopenharmony_ci}
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_cistatic void qla_nvme_sp_lsrsp_done(srb_t *sp, int res)
27462306a36Sopenharmony_ci{
27562306a36Sopenharmony_ci	struct qla_nvme_unsol_ctx *uctx = sp->priv;
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	if (WARN_ON_ONCE(kref_read(&sp->cmd_kref) == 0))
27862306a36Sopenharmony_ci		return;
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	if (res)
28162306a36Sopenharmony_ci		res = -EINVAL;
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	uctx->comp_status = res;
28462306a36Sopenharmony_ci	INIT_WORK(&uctx->lsrsp_work, qla_nvme_lsrsp_complete);
28562306a36Sopenharmony_ci	schedule_work(&uctx->lsrsp_work);
28662306a36Sopenharmony_ci}
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci/* it assumed that QPair lock is held. */
28962306a36Sopenharmony_cistatic void qla_nvme_sp_done(srb_t *sp, int res)
29062306a36Sopenharmony_ci{
29162306a36Sopenharmony_ci	struct nvme_private *priv = sp->priv;
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	priv->comp_status = res;
29462306a36Sopenharmony_ci	kref_put(&sp->cmd_kref, qla_nvme_release_fcp_cmd_kref);
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	return;
29762306a36Sopenharmony_ci}
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_cistatic void qla_nvme_abort_work(struct work_struct *work)
30062306a36Sopenharmony_ci{
30162306a36Sopenharmony_ci	struct nvme_private *priv =
30262306a36Sopenharmony_ci		container_of(work, struct nvme_private, abort_work);
30362306a36Sopenharmony_ci	srb_t *sp = priv->sp;
30462306a36Sopenharmony_ci	fc_port_t *fcport = sp->fcport;
30562306a36Sopenharmony_ci	struct qla_hw_data *ha = fcport->vha->hw;
30662306a36Sopenharmony_ci	int rval, abts_done_called = 1;
30762306a36Sopenharmony_ci	bool io_wait_for_abort_done;
30862306a36Sopenharmony_ci	uint32_t handle;
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	ql_dbg(ql_dbg_io, fcport->vha, 0xffff,
31162306a36Sopenharmony_ci	       "%s called for sp=%p, hndl=%x on fcport=%p desc=%p deleted=%d\n",
31262306a36Sopenharmony_ci	       __func__, sp, sp->handle, fcport, sp->u.iocb_cmd.u.nvme.desc, fcport->deleted);
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	if (!ha->flags.fw_started || fcport->deleted == QLA_SESS_DELETED)
31562306a36Sopenharmony_ci		goto out;
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	if (ha->flags.host_shutting_down) {
31862306a36Sopenharmony_ci		ql_log(ql_log_info, sp->fcport->vha, 0xffff,
31962306a36Sopenharmony_ci		    "%s Calling done on sp: %p, type: 0x%x\n",
32062306a36Sopenharmony_ci		    __func__, sp, sp->type);
32162306a36Sopenharmony_ci		sp->done(sp, 0);
32262306a36Sopenharmony_ci		goto out;
32362306a36Sopenharmony_ci	}
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	/*
32662306a36Sopenharmony_ci	 * sp may not be valid after abort_command if return code is either
32762306a36Sopenharmony_ci	 * SUCCESS or ERR_FROM_FW codes, so cache the value here.
32862306a36Sopenharmony_ci	 */
32962306a36Sopenharmony_ci	io_wait_for_abort_done = ql2xabts_wait_nvme &&
33062306a36Sopenharmony_ci					QLA_ABTS_WAIT_ENABLED(sp);
33162306a36Sopenharmony_ci	handle = sp->handle;
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	rval = ha->isp_ops->abort_command(sp);
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	ql_dbg(ql_dbg_io, fcport->vha, 0x212b,
33662306a36Sopenharmony_ci	    "%s: %s command for sp=%p, handle=%x on fcport=%p rval=%x\n",
33762306a36Sopenharmony_ci	    __func__, (rval != QLA_SUCCESS) ? "Failed to abort" : "Aborted",
33862306a36Sopenharmony_ci	    sp, handle, fcport, rval);
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	/*
34162306a36Sopenharmony_ci	 * If async tmf is enabled, the abort callback is called only on
34262306a36Sopenharmony_ci	 * return codes QLA_SUCCESS and QLA_ERR_FROM_FW.
34362306a36Sopenharmony_ci	 */
34462306a36Sopenharmony_ci	if (ql2xasynctmfenable &&
34562306a36Sopenharmony_ci	    rval != QLA_SUCCESS && rval != QLA_ERR_FROM_FW)
34662306a36Sopenharmony_ci		abts_done_called = 0;
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	/*
34962306a36Sopenharmony_ci	 * Returned before decreasing kref so that I/O requests
35062306a36Sopenharmony_ci	 * are waited until ABTS complete. This kref is decreased
35162306a36Sopenharmony_ci	 * at qla24xx_abort_sp_done function.
35262306a36Sopenharmony_ci	 */
35362306a36Sopenharmony_ci	if (abts_done_called && io_wait_for_abort_done)
35462306a36Sopenharmony_ci		return;
35562306a36Sopenharmony_ciout:
35662306a36Sopenharmony_ci	/* kref_get was done before work was schedule. */
35762306a36Sopenharmony_ci	kref_put(&sp->cmd_kref, sp->put_fn);
35862306a36Sopenharmony_ci}
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_cistatic int qla_nvme_xmt_ls_rsp(struct nvme_fc_local_port *lport,
36162306a36Sopenharmony_ci			       struct nvme_fc_remote_port *rport,
36262306a36Sopenharmony_ci			       struct nvmefc_ls_rsp *fd_resp)
36362306a36Sopenharmony_ci{
36462306a36Sopenharmony_ci	struct qla_nvme_unsol_ctx *uctx = container_of(fd_resp,
36562306a36Sopenharmony_ci				struct qla_nvme_unsol_ctx, lsrsp);
36662306a36Sopenharmony_ci	struct qla_nvme_rport *qla_rport = rport->private;
36762306a36Sopenharmony_ci	fc_port_t *fcport = qla_rport->fcport;
36862306a36Sopenharmony_ci	struct scsi_qla_host *vha = uctx->vha;
36962306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
37062306a36Sopenharmony_ci	struct qla_nvme_lsrjt_pt_arg a;
37162306a36Sopenharmony_ci	struct srb_iocb *nvme;
37262306a36Sopenharmony_ci	srb_t *sp;
37362306a36Sopenharmony_ci	int rval = QLA_FUNCTION_FAILED;
37462306a36Sopenharmony_ci	uint8_t cnt = 0;
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	if (!fcport || fcport->deleted)
37762306a36Sopenharmony_ci		goto out;
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	if (!ha->flags.fw_started)
38062306a36Sopenharmony_ci		goto out;
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	/* Alloc SRB structure */
38362306a36Sopenharmony_ci	sp = qla2x00_get_sp(vha, fcport, GFP_ATOMIC);
38462306a36Sopenharmony_ci	if (!sp)
38562306a36Sopenharmony_ci		goto out;
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	sp->type = SRB_NVME_LS;
38862306a36Sopenharmony_ci	sp->name = "nvme_ls";
38962306a36Sopenharmony_ci	sp->done = qla_nvme_sp_lsrsp_done;
39062306a36Sopenharmony_ci	sp->put_fn = qla_nvme_release_lsrsp_cmd_kref;
39162306a36Sopenharmony_ci	sp->priv = (void *)uctx;
39262306a36Sopenharmony_ci	sp->unsol_rsp = 1;
39362306a36Sopenharmony_ci	uctx->sp = sp;
39462306a36Sopenharmony_ci	spin_lock_init(&uctx->cmd_lock);
39562306a36Sopenharmony_ci	nvme = &sp->u.iocb_cmd;
39662306a36Sopenharmony_ci	uctx->fd_rsp = fd_resp;
39762306a36Sopenharmony_ci	nvme->u.nvme.desc = fd_resp;
39862306a36Sopenharmony_ci	nvme->u.nvme.dir = 0;
39962306a36Sopenharmony_ci	nvme->u.nvme.dl = 0;
40062306a36Sopenharmony_ci	nvme->u.nvme.timeout_sec = 0;
40162306a36Sopenharmony_ci	nvme->u.nvme.cmd_dma = fd_resp->rspdma;
40262306a36Sopenharmony_ci	nvme->u.nvme.cmd_len = cpu_to_le32(fd_resp->rsplen);
40362306a36Sopenharmony_ci	nvme->u.nvme.rsp_len = 0;
40462306a36Sopenharmony_ci	nvme->u.nvme.rsp_dma = 0;
40562306a36Sopenharmony_ci	nvme->u.nvme.exchange_address = uctx->exchange_address;
40662306a36Sopenharmony_ci	nvme->u.nvme.nport_handle = uctx->nport_handle;
40762306a36Sopenharmony_ci	nvme->u.nvme.ox_id = uctx->ox_id;
40862306a36Sopenharmony_ci	dma_sync_single_for_device(&ha->pdev->dev, nvme->u.nvme.cmd_dma,
40962306a36Sopenharmony_ci				   fd_resp->rsplen, DMA_TO_DEVICE);
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	ql_dbg(ql_dbg_unsol, vha, 0x2122,
41262306a36Sopenharmony_ci	       "Unsol lsreq portid=%06x %8phC exchange_address 0x%x ox_id 0x%x hdl 0x%x\n",
41362306a36Sopenharmony_ci	       fcport->d_id.b24, fcport->port_name, uctx->exchange_address,
41462306a36Sopenharmony_ci	       uctx->ox_id, uctx->nport_handle);
41562306a36Sopenharmony_ciretry:
41662306a36Sopenharmony_ci	rval = qla2x00_start_sp(sp);
41762306a36Sopenharmony_ci	switch (rval) {
41862306a36Sopenharmony_ci	case QLA_SUCCESS:
41962306a36Sopenharmony_ci		break;
42062306a36Sopenharmony_ci	case EAGAIN:
42162306a36Sopenharmony_ci		msleep(PURLS_MSLEEP_INTERVAL);
42262306a36Sopenharmony_ci		cnt++;
42362306a36Sopenharmony_ci		if (cnt < PURLS_RETRY_COUNT)
42462306a36Sopenharmony_ci			goto retry;
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci		fallthrough;
42762306a36Sopenharmony_ci	default:
42862306a36Sopenharmony_ci		ql_dbg(ql_log_warn, vha, 0x2123,
42962306a36Sopenharmony_ci		       "Failed to xmit Unsol ls response = %d\n", rval);
43062306a36Sopenharmony_ci		rval = -EIO;
43162306a36Sopenharmony_ci		qla2x00_rel_sp(sp);
43262306a36Sopenharmony_ci		goto out;
43362306a36Sopenharmony_ci	}
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	return 0;
43662306a36Sopenharmony_ciout:
43762306a36Sopenharmony_ci	memset((void *)&a, 0, sizeof(a));
43862306a36Sopenharmony_ci	a.vp_idx = vha->vp_idx;
43962306a36Sopenharmony_ci	a.nport_handle = uctx->nport_handle;
44062306a36Sopenharmony_ci	a.xchg_address = uctx->exchange_address;
44162306a36Sopenharmony_ci	qla_nvme_ls_reject_iocb(vha, ha->base_qpair, &a, true);
44262306a36Sopenharmony_ci	kfree(uctx);
44362306a36Sopenharmony_ci	return rval;
44462306a36Sopenharmony_ci}
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_cistatic void qla_nvme_ls_abort(struct nvme_fc_local_port *lport,
44762306a36Sopenharmony_ci    struct nvme_fc_remote_port *rport, struct nvmefc_ls_req *fd)
44862306a36Sopenharmony_ci{
44962306a36Sopenharmony_ci	struct nvme_private *priv = fd->private;
45062306a36Sopenharmony_ci	unsigned long flags;
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci	spin_lock_irqsave(&priv->cmd_lock, flags);
45362306a36Sopenharmony_ci	if (!priv->sp) {
45462306a36Sopenharmony_ci		spin_unlock_irqrestore(&priv->cmd_lock, flags);
45562306a36Sopenharmony_ci		return;
45662306a36Sopenharmony_ci	}
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci	if (!kref_get_unless_zero(&priv->sp->cmd_kref)) {
45962306a36Sopenharmony_ci		spin_unlock_irqrestore(&priv->cmd_lock, flags);
46062306a36Sopenharmony_ci		return;
46162306a36Sopenharmony_ci	}
46262306a36Sopenharmony_ci	spin_unlock_irqrestore(&priv->cmd_lock, flags);
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	INIT_WORK(&priv->abort_work, qla_nvme_abort_work);
46562306a36Sopenharmony_ci	schedule_work(&priv->abort_work);
46662306a36Sopenharmony_ci}
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_cistatic int qla_nvme_ls_req(struct nvme_fc_local_port *lport,
46962306a36Sopenharmony_ci    struct nvme_fc_remote_port *rport, struct nvmefc_ls_req *fd)
47062306a36Sopenharmony_ci{
47162306a36Sopenharmony_ci	struct qla_nvme_rport *qla_rport = rport->private;
47262306a36Sopenharmony_ci	fc_port_t *fcport = qla_rport->fcport;
47362306a36Sopenharmony_ci	struct srb_iocb   *nvme;
47462306a36Sopenharmony_ci	struct nvme_private *priv = fd->private;
47562306a36Sopenharmony_ci	struct scsi_qla_host *vha;
47662306a36Sopenharmony_ci	int     rval = QLA_FUNCTION_FAILED;
47762306a36Sopenharmony_ci	struct qla_hw_data *ha;
47862306a36Sopenharmony_ci	srb_t           *sp;
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	if (!fcport || fcport->deleted)
48162306a36Sopenharmony_ci		return rval;
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	vha = fcport->vha;
48462306a36Sopenharmony_ci	ha = vha->hw;
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	if (!ha->flags.fw_started)
48762306a36Sopenharmony_ci		return rval;
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci	/* Alloc SRB structure */
49062306a36Sopenharmony_ci	sp = qla2x00_get_sp(vha, fcport, GFP_ATOMIC);
49162306a36Sopenharmony_ci	if (!sp)
49262306a36Sopenharmony_ci		return rval;
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	sp->type = SRB_NVME_LS;
49562306a36Sopenharmony_ci	sp->name = "nvme_ls";
49662306a36Sopenharmony_ci	sp->done = qla_nvme_sp_ls_done;
49762306a36Sopenharmony_ci	sp->put_fn = qla_nvme_release_ls_cmd_kref;
49862306a36Sopenharmony_ci	sp->priv = priv;
49962306a36Sopenharmony_ci	priv->sp = sp;
50062306a36Sopenharmony_ci	kref_init(&sp->cmd_kref);
50162306a36Sopenharmony_ci	spin_lock_init(&priv->cmd_lock);
50262306a36Sopenharmony_ci	nvme = &sp->u.iocb_cmd;
50362306a36Sopenharmony_ci	priv->fd = fd;
50462306a36Sopenharmony_ci	nvme->u.nvme.desc = fd;
50562306a36Sopenharmony_ci	nvme->u.nvme.dir = 0;
50662306a36Sopenharmony_ci	nvme->u.nvme.dl = 0;
50762306a36Sopenharmony_ci	nvme->u.nvme.cmd_len = cpu_to_le32(fd->rqstlen);
50862306a36Sopenharmony_ci	nvme->u.nvme.rsp_len = cpu_to_le32(fd->rsplen);
50962306a36Sopenharmony_ci	nvme->u.nvme.rsp_dma = fd->rspdma;
51062306a36Sopenharmony_ci	nvme->u.nvme.timeout_sec = fd->timeout;
51162306a36Sopenharmony_ci	nvme->u.nvme.cmd_dma = fd->rqstdma;
51262306a36Sopenharmony_ci	dma_sync_single_for_device(&ha->pdev->dev, nvme->u.nvme.cmd_dma,
51362306a36Sopenharmony_ci	    fd->rqstlen, DMA_TO_DEVICE);
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci	rval = qla2x00_start_sp(sp);
51662306a36Sopenharmony_ci	if (rval != QLA_SUCCESS) {
51762306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x700e,
51862306a36Sopenharmony_ci		    "qla2x00_start_sp failed = %d\n", rval);
51962306a36Sopenharmony_ci		sp->priv = NULL;
52062306a36Sopenharmony_ci		priv->sp = NULL;
52162306a36Sopenharmony_ci		qla2x00_rel_sp(sp);
52262306a36Sopenharmony_ci		return rval;
52362306a36Sopenharmony_ci	}
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	return rval;
52662306a36Sopenharmony_ci}
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_cistatic void qla_nvme_fcp_abort(struct nvme_fc_local_port *lport,
52962306a36Sopenharmony_ci    struct nvme_fc_remote_port *rport, void *hw_queue_handle,
53062306a36Sopenharmony_ci    struct nvmefc_fcp_req *fd)
53162306a36Sopenharmony_ci{
53262306a36Sopenharmony_ci	struct nvme_private *priv = fd->private;
53362306a36Sopenharmony_ci	unsigned long flags;
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci	spin_lock_irqsave(&priv->cmd_lock, flags);
53662306a36Sopenharmony_ci	if (!priv->sp) {
53762306a36Sopenharmony_ci		spin_unlock_irqrestore(&priv->cmd_lock, flags);
53862306a36Sopenharmony_ci		return;
53962306a36Sopenharmony_ci	}
54062306a36Sopenharmony_ci	if (!kref_get_unless_zero(&priv->sp->cmd_kref)) {
54162306a36Sopenharmony_ci		spin_unlock_irqrestore(&priv->cmd_lock, flags);
54262306a36Sopenharmony_ci		return;
54362306a36Sopenharmony_ci	}
54462306a36Sopenharmony_ci	spin_unlock_irqrestore(&priv->cmd_lock, flags);
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	INIT_WORK(&priv->abort_work, qla_nvme_abort_work);
54762306a36Sopenharmony_ci	schedule_work(&priv->abort_work);
54862306a36Sopenharmony_ci}
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_cistatic inline int qla2x00_start_nvme_mq(srb_t *sp)
55162306a36Sopenharmony_ci{
55262306a36Sopenharmony_ci	unsigned long   flags;
55362306a36Sopenharmony_ci	uint32_t        *clr_ptr;
55462306a36Sopenharmony_ci	uint32_t        handle;
55562306a36Sopenharmony_ci	struct cmd_nvme *cmd_pkt;
55662306a36Sopenharmony_ci	uint16_t        cnt, i;
55762306a36Sopenharmony_ci	uint16_t        req_cnt;
55862306a36Sopenharmony_ci	uint16_t        tot_dsds;
55962306a36Sopenharmony_ci	uint16_t	avail_dsds;
56062306a36Sopenharmony_ci	struct dsd64	*cur_dsd;
56162306a36Sopenharmony_ci	struct req_que *req = NULL;
56262306a36Sopenharmony_ci	struct rsp_que *rsp = NULL;
56362306a36Sopenharmony_ci	struct scsi_qla_host *vha = sp->fcport->vha;
56462306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
56562306a36Sopenharmony_ci	struct qla_qpair *qpair = sp->qpair;
56662306a36Sopenharmony_ci	struct srb_iocb *nvme = &sp->u.iocb_cmd;
56762306a36Sopenharmony_ci	struct scatterlist *sgl, *sg;
56862306a36Sopenharmony_ci	struct nvmefc_fcp_req *fd = nvme->u.nvme.desc;
56962306a36Sopenharmony_ci	struct nvme_fc_cmd_iu *cmd = fd->cmdaddr;
57062306a36Sopenharmony_ci	uint32_t        rval = QLA_SUCCESS;
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci	/* Setup qpair pointers */
57362306a36Sopenharmony_ci	req = qpair->req;
57462306a36Sopenharmony_ci	rsp = qpair->rsp;
57562306a36Sopenharmony_ci	tot_dsds = fd->sg_cnt;
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci	/* Acquire qpair specific lock */
57862306a36Sopenharmony_ci	spin_lock_irqsave(&qpair->qp_lock, flags);
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci	handle = qla2xxx_get_next_handle(req);
58162306a36Sopenharmony_ci	if (handle == 0) {
58262306a36Sopenharmony_ci		rval = -EBUSY;
58362306a36Sopenharmony_ci		goto queuing_error;
58462306a36Sopenharmony_ci	}
58562306a36Sopenharmony_ci	req_cnt = qla24xx_calc_iocbs(vha, tot_dsds);
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	sp->iores.res_type = RESOURCE_IOCB | RESOURCE_EXCH;
58862306a36Sopenharmony_ci	sp->iores.exch_cnt = 1;
58962306a36Sopenharmony_ci	sp->iores.iocb_cnt = req_cnt;
59062306a36Sopenharmony_ci	if (qla_get_fw_resources(sp->qpair, &sp->iores)) {
59162306a36Sopenharmony_ci		rval = -EBUSY;
59262306a36Sopenharmony_ci		goto queuing_error;
59362306a36Sopenharmony_ci	}
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	if (req->cnt < (req_cnt + 2)) {
59662306a36Sopenharmony_ci		if (IS_SHADOW_REG_CAPABLE(ha)) {
59762306a36Sopenharmony_ci			cnt = *req->out_ptr;
59862306a36Sopenharmony_ci		} else {
59962306a36Sopenharmony_ci			cnt = rd_reg_dword_relaxed(req->req_q_out);
60062306a36Sopenharmony_ci			if (qla2x00_check_reg16_for_disconnect(vha, cnt)) {
60162306a36Sopenharmony_ci				rval = -EBUSY;
60262306a36Sopenharmony_ci				goto queuing_error;
60362306a36Sopenharmony_ci			}
60462306a36Sopenharmony_ci		}
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci		if (req->ring_index < cnt)
60762306a36Sopenharmony_ci			req->cnt = cnt - req->ring_index;
60862306a36Sopenharmony_ci		else
60962306a36Sopenharmony_ci			req->cnt = req->length - (req->ring_index - cnt);
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci		if (req->cnt < (req_cnt + 2)){
61262306a36Sopenharmony_ci			rval = -EBUSY;
61362306a36Sopenharmony_ci			goto queuing_error;
61462306a36Sopenharmony_ci		}
61562306a36Sopenharmony_ci	}
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci	if (unlikely(!fd->sqid)) {
61862306a36Sopenharmony_ci		if (cmd->sqe.common.opcode == nvme_admin_async_event) {
61962306a36Sopenharmony_ci			nvme->u.nvme.aen_op = 1;
62062306a36Sopenharmony_ci			atomic_inc(&ha->nvme_active_aen_cnt);
62162306a36Sopenharmony_ci		}
62262306a36Sopenharmony_ci	}
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci	/* Build command packet. */
62562306a36Sopenharmony_ci	req->current_outstanding_cmd = handle;
62662306a36Sopenharmony_ci	req->outstanding_cmds[handle] = sp;
62762306a36Sopenharmony_ci	sp->handle = handle;
62862306a36Sopenharmony_ci	req->cnt -= req_cnt;
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci	cmd_pkt = (struct cmd_nvme *)req->ring_ptr;
63162306a36Sopenharmony_ci	cmd_pkt->handle = make_handle(req->id, handle);
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci	/* Zero out remaining portion of packet. */
63462306a36Sopenharmony_ci	clr_ptr = (uint32_t *)cmd_pkt + 2;
63562306a36Sopenharmony_ci	memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8);
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci	cmd_pkt->entry_status = 0;
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci	/* Update entry type to indicate Command NVME IOCB */
64062306a36Sopenharmony_ci	cmd_pkt->entry_type = COMMAND_NVME;
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci	/* No data transfer how do we check buffer len == 0?? */
64362306a36Sopenharmony_ci	if (fd->io_dir == NVMEFC_FCP_READ) {
64462306a36Sopenharmony_ci		cmd_pkt->control_flags = cpu_to_le16(CF_READ_DATA);
64562306a36Sopenharmony_ci		qpair->counters.input_bytes += fd->payload_length;
64662306a36Sopenharmony_ci		qpair->counters.input_requests++;
64762306a36Sopenharmony_ci	} else if (fd->io_dir == NVMEFC_FCP_WRITE) {
64862306a36Sopenharmony_ci		cmd_pkt->control_flags = cpu_to_le16(CF_WRITE_DATA);
64962306a36Sopenharmony_ci		if ((vha->flags.nvme_first_burst) &&
65062306a36Sopenharmony_ci		    (sp->fcport->nvme_prli_service_param &
65162306a36Sopenharmony_ci			NVME_PRLI_SP_FIRST_BURST)) {
65262306a36Sopenharmony_ci			if ((fd->payload_length <=
65362306a36Sopenharmony_ci			    sp->fcport->nvme_first_burst_size) ||
65462306a36Sopenharmony_ci				(sp->fcport->nvme_first_burst_size == 0))
65562306a36Sopenharmony_ci				cmd_pkt->control_flags |=
65662306a36Sopenharmony_ci					cpu_to_le16(CF_NVME_FIRST_BURST_ENABLE);
65762306a36Sopenharmony_ci		}
65862306a36Sopenharmony_ci		qpair->counters.output_bytes += fd->payload_length;
65962306a36Sopenharmony_ci		qpair->counters.output_requests++;
66062306a36Sopenharmony_ci	} else if (fd->io_dir == 0) {
66162306a36Sopenharmony_ci		cmd_pkt->control_flags = 0;
66262306a36Sopenharmony_ci	}
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	if (sp->fcport->edif.enable && fd->io_dir != 0)
66562306a36Sopenharmony_ci		cmd_pkt->control_flags |= cpu_to_le16(CF_EN_EDIF);
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci	/* Set BIT_13 of control flags for Async event */
66862306a36Sopenharmony_ci	if (vha->flags.nvme2_enabled &&
66962306a36Sopenharmony_ci	    cmd->sqe.common.opcode == nvme_admin_async_event) {
67062306a36Sopenharmony_ci		cmd_pkt->control_flags |= cpu_to_le16(CF_ADMIN_ASYNC_EVENT);
67162306a36Sopenharmony_ci	}
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci	/* Set NPORT-ID */
67462306a36Sopenharmony_ci	cmd_pkt->nport_handle = cpu_to_le16(sp->fcport->loop_id);
67562306a36Sopenharmony_ci	cmd_pkt->port_id[0] = sp->fcport->d_id.b.al_pa;
67662306a36Sopenharmony_ci	cmd_pkt->port_id[1] = sp->fcport->d_id.b.area;
67762306a36Sopenharmony_ci	cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain;
67862306a36Sopenharmony_ci	cmd_pkt->vp_index = sp->fcport->vha->vp_idx;
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci	/* NVME RSP IU */
68162306a36Sopenharmony_ci	cmd_pkt->nvme_rsp_dsd_len = cpu_to_le16(fd->rsplen);
68262306a36Sopenharmony_ci	put_unaligned_le64(fd->rspdma, &cmd_pkt->nvme_rsp_dseg_address);
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci	/* NVME CNMD IU */
68562306a36Sopenharmony_ci	cmd_pkt->nvme_cmnd_dseg_len = cpu_to_le16(fd->cmdlen);
68662306a36Sopenharmony_ci	cmd_pkt->nvme_cmnd_dseg_address = cpu_to_le64(fd->cmddma);
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci	cmd_pkt->dseg_count = cpu_to_le16(tot_dsds);
68962306a36Sopenharmony_ci	cmd_pkt->byte_count = cpu_to_le32(fd->payload_length);
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci	/* One DSD is available in the Command Type NVME IOCB */
69262306a36Sopenharmony_ci	avail_dsds = 1;
69362306a36Sopenharmony_ci	cur_dsd = &cmd_pkt->nvme_dsd;
69462306a36Sopenharmony_ci	sgl = fd->first_sgl;
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci	/* Load data segments */
69762306a36Sopenharmony_ci	for_each_sg(sgl, sg, tot_dsds, i) {
69862306a36Sopenharmony_ci		cont_a64_entry_t *cont_pkt;
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci		/* Allocate additional continuation packets? */
70162306a36Sopenharmony_ci		if (avail_dsds == 0) {
70262306a36Sopenharmony_ci			/*
70362306a36Sopenharmony_ci			 * Five DSDs are available in the Continuation
70462306a36Sopenharmony_ci			 * Type 1 IOCB.
70562306a36Sopenharmony_ci			 */
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci			/* Adjust ring index */
70862306a36Sopenharmony_ci			req->ring_index++;
70962306a36Sopenharmony_ci			if (req->ring_index == req->length) {
71062306a36Sopenharmony_ci				req->ring_index = 0;
71162306a36Sopenharmony_ci				req->ring_ptr = req->ring;
71262306a36Sopenharmony_ci			} else {
71362306a36Sopenharmony_ci				req->ring_ptr++;
71462306a36Sopenharmony_ci			}
71562306a36Sopenharmony_ci			cont_pkt = (cont_a64_entry_t *)req->ring_ptr;
71662306a36Sopenharmony_ci			put_unaligned_le32(CONTINUE_A64_TYPE,
71762306a36Sopenharmony_ci					   &cont_pkt->entry_type);
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci			cur_dsd = cont_pkt->dsd;
72062306a36Sopenharmony_ci			avail_dsds = ARRAY_SIZE(cont_pkt->dsd);
72162306a36Sopenharmony_ci		}
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci		append_dsd64(&cur_dsd, sg);
72462306a36Sopenharmony_ci		avail_dsds--;
72562306a36Sopenharmony_ci	}
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci	/* Set total entry count. */
72862306a36Sopenharmony_ci	cmd_pkt->entry_count = (uint8_t)req_cnt;
72962306a36Sopenharmony_ci	wmb();
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci	/* Adjust ring index. */
73262306a36Sopenharmony_ci	req->ring_index++;
73362306a36Sopenharmony_ci	if (req->ring_index == req->length) {
73462306a36Sopenharmony_ci		req->ring_index = 0;
73562306a36Sopenharmony_ci		req->ring_ptr = req->ring;
73662306a36Sopenharmony_ci	} else {
73762306a36Sopenharmony_ci		req->ring_ptr++;
73862306a36Sopenharmony_ci	}
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_ci	/* ignore nvme async cmd due to long timeout */
74162306a36Sopenharmony_ci	if (!nvme->u.nvme.aen_op)
74262306a36Sopenharmony_ci		sp->qpair->cmd_cnt++;
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_ci	/* Set chip new ring index. */
74562306a36Sopenharmony_ci	wrt_reg_dword(req->req_q_in, req->ring_index);
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci	if (vha->flags.process_response_queue &&
74862306a36Sopenharmony_ci	    rsp->ring_ptr->signature != RESPONSE_PROCESSED)
74962306a36Sopenharmony_ci		qla24xx_process_response_queue(vha, rsp);
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ciqueuing_error:
75262306a36Sopenharmony_ci	if (rval)
75362306a36Sopenharmony_ci		qla_put_fw_resources(sp->qpair, &sp->iores);
75462306a36Sopenharmony_ci	spin_unlock_irqrestore(&qpair->qp_lock, flags);
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_ci	return rval;
75762306a36Sopenharmony_ci}
75862306a36Sopenharmony_ci
75962306a36Sopenharmony_ci/* Post a command */
76062306a36Sopenharmony_cistatic int qla_nvme_post_cmd(struct nvme_fc_local_port *lport,
76162306a36Sopenharmony_ci    struct nvme_fc_remote_port *rport, void *hw_queue_handle,
76262306a36Sopenharmony_ci    struct nvmefc_fcp_req *fd)
76362306a36Sopenharmony_ci{
76462306a36Sopenharmony_ci	fc_port_t *fcport;
76562306a36Sopenharmony_ci	struct srb_iocb *nvme;
76662306a36Sopenharmony_ci	struct scsi_qla_host *vha;
76762306a36Sopenharmony_ci	struct qla_hw_data *ha;
76862306a36Sopenharmony_ci	int rval;
76962306a36Sopenharmony_ci	srb_t *sp;
77062306a36Sopenharmony_ci	struct qla_qpair *qpair = hw_queue_handle;
77162306a36Sopenharmony_ci	struct nvme_private *priv = fd->private;
77262306a36Sopenharmony_ci	struct qla_nvme_rport *qla_rport = rport->private;
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_ci	if (!priv) {
77562306a36Sopenharmony_ci		/* nvme association has been torn down */
77662306a36Sopenharmony_ci		return -ENODEV;
77762306a36Sopenharmony_ci	}
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ci	fcport = qla_rport->fcport;
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci	if (unlikely(!qpair || !fcport || fcport->deleted))
78262306a36Sopenharmony_ci		return -EBUSY;
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ci	if (!(fcport->nvme_flag & NVME_FLAG_REGISTERED))
78562306a36Sopenharmony_ci		return -ENODEV;
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_ci	vha = fcport->vha;
78862306a36Sopenharmony_ci	ha = vha->hw;
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_ci	if (test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags))
79162306a36Sopenharmony_ci		return -EBUSY;
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_ci	/*
79462306a36Sopenharmony_ci	 * If we know the dev is going away while the transport is still sending
79562306a36Sopenharmony_ci	 * IO's return busy back to stall the IO Q.  This happens when the
79662306a36Sopenharmony_ci	 * link goes away and fw hasn't notified us yet, but IO's are being
79762306a36Sopenharmony_ci	 * returned. If the dev comes back quickly we won't exhaust the IO
79862306a36Sopenharmony_ci	 * retry count at the core.
79962306a36Sopenharmony_ci	 */
80062306a36Sopenharmony_ci	if (fcport->nvme_flag & NVME_FLAG_RESETTING)
80162306a36Sopenharmony_ci		return -EBUSY;
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_ci	qpair = qla_mapq_nvme_select_qpair(ha, qpair);
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci	/* Alloc SRB structure */
80662306a36Sopenharmony_ci	sp = qla2xxx_get_qpair_sp(vha, qpair, fcport, GFP_ATOMIC);
80762306a36Sopenharmony_ci	if (!sp)
80862306a36Sopenharmony_ci		return -EBUSY;
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci	kref_init(&sp->cmd_kref);
81162306a36Sopenharmony_ci	spin_lock_init(&priv->cmd_lock);
81262306a36Sopenharmony_ci	sp->priv = priv;
81362306a36Sopenharmony_ci	priv->sp = sp;
81462306a36Sopenharmony_ci	sp->type = SRB_NVME_CMD;
81562306a36Sopenharmony_ci	sp->name = "nvme_cmd";
81662306a36Sopenharmony_ci	sp->done = qla_nvme_sp_done;
81762306a36Sopenharmony_ci	sp->put_fn = qla_nvme_release_fcp_cmd_kref;
81862306a36Sopenharmony_ci	sp->qpair = qpair;
81962306a36Sopenharmony_ci	sp->vha = vha;
82062306a36Sopenharmony_ci	sp->cmd_sp = sp;
82162306a36Sopenharmony_ci	nvme = &sp->u.iocb_cmd;
82262306a36Sopenharmony_ci	nvme->u.nvme.desc = fd;
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_ci	rval = qla2x00_start_nvme_mq(sp);
82562306a36Sopenharmony_ci	if (rval != QLA_SUCCESS) {
82662306a36Sopenharmony_ci		ql_dbg(ql_dbg_io + ql_dbg_verbose, vha, 0x212d,
82762306a36Sopenharmony_ci		    "qla2x00_start_nvme_mq failed = %d\n", rval);
82862306a36Sopenharmony_ci		sp->priv = NULL;
82962306a36Sopenharmony_ci		priv->sp = NULL;
83062306a36Sopenharmony_ci		qla2xxx_rel_qpair_sp(sp->qpair, sp);
83162306a36Sopenharmony_ci	}
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_ci	return rval;
83462306a36Sopenharmony_ci}
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_cistatic void qla_nvme_map_queues(struct nvme_fc_local_port *lport,
83762306a36Sopenharmony_ci		struct blk_mq_queue_map *map)
83862306a36Sopenharmony_ci{
83962306a36Sopenharmony_ci	struct scsi_qla_host *vha = lport->private;
84062306a36Sopenharmony_ci
84162306a36Sopenharmony_ci	blk_mq_pci_map_queues(map, vha->hw->pdev, vha->irq_offset);
84262306a36Sopenharmony_ci}
84362306a36Sopenharmony_ci
84462306a36Sopenharmony_cistatic void qla_nvme_localport_delete(struct nvme_fc_local_port *lport)
84562306a36Sopenharmony_ci{
84662306a36Sopenharmony_ci	struct scsi_qla_host *vha = lport->private;
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci	ql_log(ql_log_info, vha, 0x210f,
84962306a36Sopenharmony_ci	    "localport delete of %p completed.\n", vha->nvme_local_port);
85062306a36Sopenharmony_ci	vha->nvme_local_port = NULL;
85162306a36Sopenharmony_ci	complete(&vha->nvme_del_done);
85262306a36Sopenharmony_ci}
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_cistatic void qla_nvme_remoteport_delete(struct nvme_fc_remote_port *rport)
85562306a36Sopenharmony_ci{
85662306a36Sopenharmony_ci	fc_port_t *fcport;
85762306a36Sopenharmony_ci	struct qla_nvme_rport *qla_rport = rport->private;
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_ci	fcport = qla_rport->fcport;
86062306a36Sopenharmony_ci	fcport->nvme_remote_port = NULL;
86162306a36Sopenharmony_ci	fcport->nvme_flag &= ~NVME_FLAG_REGISTERED;
86262306a36Sopenharmony_ci	fcport->nvme_flag &= ~NVME_FLAG_DELETING;
86362306a36Sopenharmony_ci	ql_log(ql_log_info, fcport->vha, 0x2110,
86462306a36Sopenharmony_ci	    "remoteport_delete of %p %8phN completed.\n",
86562306a36Sopenharmony_ci	    fcport, fcport->port_name);
86662306a36Sopenharmony_ci	complete(&fcport->nvme_del_done);
86762306a36Sopenharmony_ci}
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_cistatic struct nvme_fc_port_template qla_nvme_fc_transport = {
87062306a36Sopenharmony_ci	.localport_delete = qla_nvme_localport_delete,
87162306a36Sopenharmony_ci	.remoteport_delete = qla_nvme_remoteport_delete,
87262306a36Sopenharmony_ci	.create_queue   = qla_nvme_alloc_queue,
87362306a36Sopenharmony_ci	.delete_queue 	= NULL,
87462306a36Sopenharmony_ci	.ls_req		= qla_nvme_ls_req,
87562306a36Sopenharmony_ci	.ls_abort	= qla_nvme_ls_abort,
87662306a36Sopenharmony_ci	.fcp_io		= qla_nvme_post_cmd,
87762306a36Sopenharmony_ci	.fcp_abort	= qla_nvme_fcp_abort,
87862306a36Sopenharmony_ci	.xmt_ls_rsp	= qla_nvme_xmt_ls_rsp,
87962306a36Sopenharmony_ci	.map_queues	= qla_nvme_map_queues,
88062306a36Sopenharmony_ci	.max_hw_queues  = DEF_NVME_HW_QUEUES,
88162306a36Sopenharmony_ci	.max_sgl_segments = 1024,
88262306a36Sopenharmony_ci	.max_dif_sgl_segments = 64,
88362306a36Sopenharmony_ci	.dma_boundary = 0xFFFFFFFF,
88462306a36Sopenharmony_ci	.local_priv_sz  = 8,
88562306a36Sopenharmony_ci	.remote_priv_sz = sizeof(struct qla_nvme_rport),
88662306a36Sopenharmony_ci	.lsrqst_priv_sz = sizeof(struct nvme_private),
88762306a36Sopenharmony_ci	.fcprqst_priv_sz = sizeof(struct nvme_private),
88862306a36Sopenharmony_ci};
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_civoid qla_nvme_unregister_remote_port(struct fc_port *fcport)
89162306a36Sopenharmony_ci{
89262306a36Sopenharmony_ci	int ret;
89362306a36Sopenharmony_ci
89462306a36Sopenharmony_ci	if (!IS_ENABLED(CONFIG_NVME_FC))
89562306a36Sopenharmony_ci		return;
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_ci	ql_log(ql_log_warn, fcport->vha, 0x2112,
89862306a36Sopenharmony_ci	    "%s: unregister remoteport on %p %8phN\n",
89962306a36Sopenharmony_ci	    __func__, fcport, fcport->port_name);
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_ci	if (test_bit(PFLG_DRIVER_REMOVING, &fcport->vha->pci_flags))
90262306a36Sopenharmony_ci		nvme_fc_set_remoteport_devloss(fcport->nvme_remote_port, 0);
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ci	init_completion(&fcport->nvme_del_done);
90562306a36Sopenharmony_ci	ret = nvme_fc_unregister_remoteport(fcport->nvme_remote_port);
90662306a36Sopenharmony_ci	if (ret)
90762306a36Sopenharmony_ci		ql_log(ql_log_info, fcport->vha, 0x2114,
90862306a36Sopenharmony_ci			"%s: Failed to unregister nvme_remote_port (%d)\n",
90962306a36Sopenharmony_ci			    __func__, ret);
91062306a36Sopenharmony_ci	wait_for_completion(&fcport->nvme_del_done);
91162306a36Sopenharmony_ci}
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_civoid qla_nvme_delete(struct scsi_qla_host *vha)
91462306a36Sopenharmony_ci{
91562306a36Sopenharmony_ci	int nv_ret;
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_ci	if (!IS_ENABLED(CONFIG_NVME_FC))
91862306a36Sopenharmony_ci		return;
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_ci	if (vha->nvme_local_port) {
92162306a36Sopenharmony_ci		init_completion(&vha->nvme_del_done);
92262306a36Sopenharmony_ci		ql_log(ql_log_info, vha, 0x2116,
92362306a36Sopenharmony_ci			"unregister localport=%p\n",
92462306a36Sopenharmony_ci			vha->nvme_local_port);
92562306a36Sopenharmony_ci		nv_ret = nvme_fc_unregister_localport(vha->nvme_local_port);
92662306a36Sopenharmony_ci		if (nv_ret)
92762306a36Sopenharmony_ci			ql_log(ql_log_info, vha, 0x2115,
92862306a36Sopenharmony_ci			    "Unregister of localport failed\n");
92962306a36Sopenharmony_ci		else
93062306a36Sopenharmony_ci			wait_for_completion(&vha->nvme_del_done);
93162306a36Sopenharmony_ci	}
93262306a36Sopenharmony_ci}
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_ciint qla_nvme_register_hba(struct scsi_qla_host *vha)
93562306a36Sopenharmony_ci{
93662306a36Sopenharmony_ci	struct nvme_fc_port_template *tmpl;
93762306a36Sopenharmony_ci	struct qla_hw_data *ha;
93862306a36Sopenharmony_ci	struct nvme_fc_port_info pinfo;
93962306a36Sopenharmony_ci	int ret = -EINVAL;
94062306a36Sopenharmony_ci
94162306a36Sopenharmony_ci	if (!IS_ENABLED(CONFIG_NVME_FC))
94262306a36Sopenharmony_ci		return ret;
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_ci	ha = vha->hw;
94562306a36Sopenharmony_ci	tmpl = &qla_nvme_fc_transport;
94662306a36Sopenharmony_ci
94762306a36Sopenharmony_ci	if (ql2xnvme_queues < MIN_NVME_HW_QUEUES) {
94862306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0xfffd,
94962306a36Sopenharmony_ci		    "ql2xnvme_queues=%d is lower than minimum queues: %d. Resetting ql2xnvme_queues to:%d\n",
95062306a36Sopenharmony_ci		    ql2xnvme_queues, MIN_NVME_HW_QUEUES, DEF_NVME_HW_QUEUES);
95162306a36Sopenharmony_ci		ql2xnvme_queues = DEF_NVME_HW_QUEUES;
95262306a36Sopenharmony_ci	} else if (ql2xnvme_queues > (ha->max_qpairs - 1)) {
95362306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0xfffd,
95462306a36Sopenharmony_ci		       "ql2xnvme_queues=%d is greater than available IRQs: %d. Resetting ql2xnvme_queues to: %d\n",
95562306a36Sopenharmony_ci		       ql2xnvme_queues, (ha->max_qpairs - 1),
95662306a36Sopenharmony_ci		       (ha->max_qpairs - 1));
95762306a36Sopenharmony_ci		ql2xnvme_queues = ((ha->max_qpairs - 1));
95862306a36Sopenharmony_ci	}
95962306a36Sopenharmony_ci
96062306a36Sopenharmony_ci	qla_nvme_fc_transport.max_hw_queues =
96162306a36Sopenharmony_ci	    min((uint8_t)(ql2xnvme_queues),
96262306a36Sopenharmony_ci		(uint8_t)((ha->max_qpairs - 1) ? (ha->max_qpairs - 1) : 1));
96362306a36Sopenharmony_ci
96462306a36Sopenharmony_ci	ql_log(ql_log_info, vha, 0xfffb,
96562306a36Sopenharmony_ci	       "Number of NVME queues used for this port: %d\n",
96662306a36Sopenharmony_ci	    qla_nvme_fc_transport.max_hw_queues);
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_ci	pinfo.node_name = wwn_to_u64(vha->node_name);
96962306a36Sopenharmony_ci	pinfo.port_name = wwn_to_u64(vha->port_name);
97062306a36Sopenharmony_ci	pinfo.port_role = FC_PORT_ROLE_NVME_INITIATOR;
97162306a36Sopenharmony_ci	pinfo.port_id = vha->d_id.b24;
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_ci	mutex_lock(&ha->vport_lock);
97462306a36Sopenharmony_ci	/*
97562306a36Sopenharmony_ci	 * Check again for nvme_local_port to see if any other thread raced
97662306a36Sopenharmony_ci	 * with this one and finished registration.
97762306a36Sopenharmony_ci	 */
97862306a36Sopenharmony_ci	if (!vha->nvme_local_port) {
97962306a36Sopenharmony_ci		ql_log(ql_log_info, vha, 0xffff,
98062306a36Sopenharmony_ci		    "register_localport: host-traddr=nn-0x%llx:pn-0x%llx on portID:%x\n",
98162306a36Sopenharmony_ci		    pinfo.node_name, pinfo.port_name, pinfo.port_id);
98262306a36Sopenharmony_ci		qla_nvme_fc_transport.dma_boundary = vha->host->dma_boundary;
98362306a36Sopenharmony_ci
98462306a36Sopenharmony_ci		ret = nvme_fc_register_localport(&pinfo, tmpl,
98562306a36Sopenharmony_ci						 get_device(&ha->pdev->dev),
98662306a36Sopenharmony_ci						 &vha->nvme_local_port);
98762306a36Sopenharmony_ci		mutex_unlock(&ha->vport_lock);
98862306a36Sopenharmony_ci	} else {
98962306a36Sopenharmony_ci		mutex_unlock(&ha->vport_lock);
99062306a36Sopenharmony_ci		return 0;
99162306a36Sopenharmony_ci	}
99262306a36Sopenharmony_ci	if (ret) {
99362306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0xffff,
99462306a36Sopenharmony_ci		    "register_localport failed: ret=%x\n", ret);
99562306a36Sopenharmony_ci	} else {
99662306a36Sopenharmony_ci		vha->nvme_local_port->private = vha;
99762306a36Sopenharmony_ci	}
99862306a36Sopenharmony_ci
99962306a36Sopenharmony_ci	return ret;
100062306a36Sopenharmony_ci}
100162306a36Sopenharmony_ci
100262306a36Sopenharmony_civoid qla_nvme_abort_set_option(struct abort_entry_24xx *abt, srb_t *orig_sp)
100362306a36Sopenharmony_ci{
100462306a36Sopenharmony_ci	struct qla_hw_data *ha;
100562306a36Sopenharmony_ci
100662306a36Sopenharmony_ci	if (!(ql2xabts_wait_nvme && QLA_ABTS_WAIT_ENABLED(orig_sp)))
100762306a36Sopenharmony_ci		return;
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_ci	ha = orig_sp->fcport->vha->hw;
101062306a36Sopenharmony_ci
101162306a36Sopenharmony_ci	WARN_ON_ONCE(abt->options & cpu_to_le16(BIT_0));
101262306a36Sopenharmony_ci	/* Use Driver Specified Retry Count */
101362306a36Sopenharmony_ci	abt->options |= cpu_to_le16(AOF_ABTS_RTY_CNT);
101462306a36Sopenharmony_ci	abt->drv.abts_rty_cnt = cpu_to_le16(2);
101562306a36Sopenharmony_ci	/* Use specified response timeout */
101662306a36Sopenharmony_ci	abt->options |= cpu_to_le16(AOF_RSP_TIMEOUT);
101762306a36Sopenharmony_ci	/* set it to 2 * r_a_tov in secs */
101862306a36Sopenharmony_ci	abt->drv.rsp_timeout = cpu_to_le16(2 * (ha->r_a_tov / 10));
101962306a36Sopenharmony_ci}
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_civoid qla_nvme_abort_process_comp_status(struct abort_entry_24xx *abt, srb_t *orig_sp)
102262306a36Sopenharmony_ci{
102362306a36Sopenharmony_ci	u16	comp_status;
102462306a36Sopenharmony_ci	struct scsi_qla_host *vha;
102562306a36Sopenharmony_ci
102662306a36Sopenharmony_ci	if (!(ql2xabts_wait_nvme && QLA_ABTS_WAIT_ENABLED(orig_sp)))
102762306a36Sopenharmony_ci		return;
102862306a36Sopenharmony_ci
102962306a36Sopenharmony_ci	vha = orig_sp->fcport->vha;
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_ci	comp_status = le16_to_cpu(abt->comp_status);
103262306a36Sopenharmony_ci	switch (comp_status) {
103362306a36Sopenharmony_ci	case CS_RESET:		/* reset event aborted */
103462306a36Sopenharmony_ci	case CS_ABORTED:	/* IOCB was cleaned */
103562306a36Sopenharmony_ci	/* N_Port handle is not currently logged in */
103662306a36Sopenharmony_ci	case CS_TIMEOUT:
103762306a36Sopenharmony_ci	/* N_Port handle was logged out while waiting for ABTS to complete */
103862306a36Sopenharmony_ci	case CS_PORT_UNAVAILABLE:
103962306a36Sopenharmony_ci	/* Firmware found that the port name changed */
104062306a36Sopenharmony_ci	case CS_PORT_LOGGED_OUT:
104162306a36Sopenharmony_ci	/* BA_RJT was received for the ABTS */
104262306a36Sopenharmony_ci	case CS_PORT_CONFIG_CHG:
104362306a36Sopenharmony_ci		ql_dbg(ql_dbg_async, vha, 0xf09d,
104462306a36Sopenharmony_ci		       "Abort I/O IOCB completed with error, comp_status=%x\n",
104562306a36Sopenharmony_ci		comp_status);
104662306a36Sopenharmony_ci		break;
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_ci	/* BA_RJT was received for the ABTS */
104962306a36Sopenharmony_ci	case CS_REJECT_RECEIVED:
105062306a36Sopenharmony_ci		ql_dbg(ql_dbg_async, vha, 0xf09e,
105162306a36Sopenharmony_ci		       "BA_RJT was received for the ABTS rjt_vendorUnique = %u",
105262306a36Sopenharmony_ci			abt->fw.ba_rjt_vendorUnique);
105362306a36Sopenharmony_ci		ql_dbg(ql_dbg_async + ql_dbg_mbx, vha, 0xf09e,
105462306a36Sopenharmony_ci		       "ba_rjt_reasonCodeExpl = %u, ba_rjt_reasonCode = %u\n",
105562306a36Sopenharmony_ci		       abt->fw.ba_rjt_reasonCodeExpl, abt->fw.ba_rjt_reasonCode);
105662306a36Sopenharmony_ci		break;
105762306a36Sopenharmony_ci
105862306a36Sopenharmony_ci	case CS_COMPLETE:
105962306a36Sopenharmony_ci		ql_dbg(ql_dbg_async + ql_dbg_verbose, vha, 0xf09f,
106062306a36Sopenharmony_ci		       "IOCB request is completed successfully comp_status=%x\n",
106162306a36Sopenharmony_ci		comp_status);
106262306a36Sopenharmony_ci		break;
106362306a36Sopenharmony_ci
106462306a36Sopenharmony_ci	case CS_IOCB_ERROR:
106562306a36Sopenharmony_ci		ql_dbg(ql_dbg_async, vha, 0xf0a0,
106662306a36Sopenharmony_ci		       "IOCB request is failed, comp_status=%x\n", comp_status);
106762306a36Sopenharmony_ci		break;
106862306a36Sopenharmony_ci
106962306a36Sopenharmony_ci	default:
107062306a36Sopenharmony_ci		ql_dbg(ql_dbg_async, vha, 0xf0a1,
107162306a36Sopenharmony_ci		       "Invalid Abort IO IOCB Completion Status %x\n",
107262306a36Sopenharmony_ci		comp_status);
107362306a36Sopenharmony_ci		break;
107462306a36Sopenharmony_ci	}
107562306a36Sopenharmony_ci}
107662306a36Sopenharmony_ci
107762306a36Sopenharmony_ciinline void qla_wait_nvme_release_cmd_kref(srb_t *orig_sp)
107862306a36Sopenharmony_ci{
107962306a36Sopenharmony_ci	if (!(ql2xabts_wait_nvme && QLA_ABTS_WAIT_ENABLED(orig_sp)))
108062306a36Sopenharmony_ci		return;
108162306a36Sopenharmony_ci	kref_put(&orig_sp->cmd_kref, orig_sp->put_fn);
108262306a36Sopenharmony_ci}
108362306a36Sopenharmony_ci
108462306a36Sopenharmony_cistatic void qla_nvme_fc_format_rjt(void *buf, u8 ls_cmd, u8 reason,
108562306a36Sopenharmony_ci				   u8 explanation, u8 vendor)
108662306a36Sopenharmony_ci{
108762306a36Sopenharmony_ci	struct fcnvme_ls_rjt *rjt = buf;
108862306a36Sopenharmony_ci
108962306a36Sopenharmony_ci	rjt->w0.ls_cmd = FCNVME_LSDESC_RQST;
109062306a36Sopenharmony_ci	rjt->desc_list_len = fcnvme_lsdesc_len(sizeof(struct fcnvme_ls_rjt));
109162306a36Sopenharmony_ci	rjt->rqst.desc_tag = cpu_to_be32(FCNVME_LSDESC_RQST);
109262306a36Sopenharmony_ci	rjt->rqst.desc_len =
109362306a36Sopenharmony_ci		fcnvme_lsdesc_len(sizeof(struct fcnvme_lsdesc_rqst));
109462306a36Sopenharmony_ci	rjt->rqst.w0.ls_cmd = ls_cmd;
109562306a36Sopenharmony_ci	rjt->rjt.desc_tag = cpu_to_be32(FCNVME_LSDESC_RJT);
109662306a36Sopenharmony_ci	rjt->rjt.desc_len = fcnvme_lsdesc_len(sizeof(struct fcnvme_lsdesc_rjt));
109762306a36Sopenharmony_ci	rjt->rjt.reason_code = reason;
109862306a36Sopenharmony_ci	rjt->rjt.reason_explanation = explanation;
109962306a36Sopenharmony_ci	rjt->rjt.vendor = vendor;
110062306a36Sopenharmony_ci}
110162306a36Sopenharmony_ci
110262306a36Sopenharmony_cistatic void qla_nvme_lsrjt_pt_iocb(struct scsi_qla_host *vha,
110362306a36Sopenharmony_ci				   struct pt_ls4_request *lsrjt_iocb,
110462306a36Sopenharmony_ci				   struct qla_nvme_lsrjt_pt_arg *a)
110562306a36Sopenharmony_ci{
110662306a36Sopenharmony_ci	lsrjt_iocb->entry_type = PT_LS4_REQUEST;
110762306a36Sopenharmony_ci	lsrjt_iocb->entry_count = 1;
110862306a36Sopenharmony_ci	lsrjt_iocb->sys_define = 0;
110962306a36Sopenharmony_ci	lsrjt_iocb->entry_status = 0;
111062306a36Sopenharmony_ci	lsrjt_iocb->handle = QLA_SKIP_HANDLE;
111162306a36Sopenharmony_ci	lsrjt_iocb->nport_handle = a->nport_handle;
111262306a36Sopenharmony_ci	lsrjt_iocb->exchange_address = a->xchg_address;
111362306a36Sopenharmony_ci	lsrjt_iocb->vp_index = a->vp_idx;
111462306a36Sopenharmony_ci
111562306a36Sopenharmony_ci	lsrjt_iocb->control_flags = cpu_to_le16(a->control_flags);
111662306a36Sopenharmony_ci
111762306a36Sopenharmony_ci	put_unaligned_le64(a->tx_addr, &lsrjt_iocb->dsd[0].address);
111862306a36Sopenharmony_ci	lsrjt_iocb->dsd[0].length = cpu_to_le32(a->tx_byte_count);
111962306a36Sopenharmony_ci	lsrjt_iocb->tx_dseg_count = cpu_to_le16(1);
112062306a36Sopenharmony_ci	lsrjt_iocb->tx_byte_count = cpu_to_le32(a->tx_byte_count);
112162306a36Sopenharmony_ci
112262306a36Sopenharmony_ci	put_unaligned_le64(a->rx_addr, &lsrjt_iocb->dsd[1].address);
112362306a36Sopenharmony_ci	lsrjt_iocb->dsd[1].length = 0;
112462306a36Sopenharmony_ci	lsrjt_iocb->rx_dseg_count = 0;
112562306a36Sopenharmony_ci	lsrjt_iocb->rx_byte_count = 0;
112662306a36Sopenharmony_ci}
112762306a36Sopenharmony_ci
112862306a36Sopenharmony_cistatic int
112962306a36Sopenharmony_ciqla_nvme_ls_reject_iocb(struct scsi_qla_host *vha, struct qla_qpair *qp,
113062306a36Sopenharmony_ci			struct qla_nvme_lsrjt_pt_arg *a, bool is_xchg_terminate)
113162306a36Sopenharmony_ci{
113262306a36Sopenharmony_ci	struct pt_ls4_request *lsrjt_iocb;
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_ci	lsrjt_iocb = __qla2x00_alloc_iocbs(qp, NULL);
113562306a36Sopenharmony_ci	if (!lsrjt_iocb) {
113662306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x210e,
113762306a36Sopenharmony_ci		       "qla2x00_alloc_iocbs failed.\n");
113862306a36Sopenharmony_ci		return QLA_FUNCTION_FAILED;
113962306a36Sopenharmony_ci	}
114062306a36Sopenharmony_ci
114162306a36Sopenharmony_ci	if (!is_xchg_terminate) {
114262306a36Sopenharmony_ci		qla_nvme_fc_format_rjt((void *)vha->hw->lsrjt.c, a->opcode,
114362306a36Sopenharmony_ci				       a->reason, a->explanation, 0);
114462306a36Sopenharmony_ci
114562306a36Sopenharmony_ci		a->tx_byte_count = sizeof(struct fcnvme_ls_rjt);
114662306a36Sopenharmony_ci		a->tx_addr = vha->hw->lsrjt.cdma;
114762306a36Sopenharmony_ci		a->control_flags = CF_LS4_RESPONDER << CF_LS4_SHIFT;
114862306a36Sopenharmony_ci
114962306a36Sopenharmony_ci		ql_dbg(ql_dbg_unsol, vha, 0x211f,
115062306a36Sopenharmony_ci		       "Sending nvme fc ls reject ox_id %04x op %04x\n",
115162306a36Sopenharmony_ci		       a->ox_id, a->opcode);
115262306a36Sopenharmony_ci		ql_dump_buffer(ql_dbg_unsol + ql_dbg_verbose, vha, 0x210f,
115362306a36Sopenharmony_ci			       vha->hw->lsrjt.c, sizeof(*vha->hw->lsrjt.c));
115462306a36Sopenharmony_ci	} else {
115562306a36Sopenharmony_ci		a->tx_byte_count = 0;
115662306a36Sopenharmony_ci		a->control_flags = CF_LS4_RESPONDER_TERM << CF_LS4_SHIFT;
115762306a36Sopenharmony_ci		ql_dbg(ql_dbg_unsol, vha, 0x2110,
115862306a36Sopenharmony_ci		       "Terminate nvme ls xchg 0x%x\n", a->xchg_address);
115962306a36Sopenharmony_ci	}
116062306a36Sopenharmony_ci
116162306a36Sopenharmony_ci	qla_nvme_lsrjt_pt_iocb(vha, lsrjt_iocb, a);
116262306a36Sopenharmony_ci	/* flush iocb to mem before notifying hw doorbell */
116362306a36Sopenharmony_ci	wmb();
116462306a36Sopenharmony_ci	qla2x00_start_iocbs(vha, qp->req);
116562306a36Sopenharmony_ci	return 0;
116662306a36Sopenharmony_ci}
116762306a36Sopenharmony_ci
116862306a36Sopenharmony_ci/*
116962306a36Sopenharmony_ci * qla2xxx_process_purls_pkt() - Pass-up Unsolicited
117062306a36Sopenharmony_ci * Received FC-NVMe Link Service pkt to nvme_fc_rcv_ls_req().
117162306a36Sopenharmony_ci * LLDD need to provide memory for response buffer, which
117262306a36Sopenharmony_ci * will be used to reference the exchange corresponding
117362306a36Sopenharmony_ci * to the LS when issuing an ls response. LLDD will have to free
117462306a36Sopenharmony_ci * response buffer in lport->ops->xmt_ls_rsp().
117562306a36Sopenharmony_ci *
117662306a36Sopenharmony_ci * @vha: SCSI qla host
117762306a36Sopenharmony_ci * @item: ptr to purex_item
117862306a36Sopenharmony_ci */
117962306a36Sopenharmony_cistatic void
118062306a36Sopenharmony_ciqla2xxx_process_purls_pkt(struct scsi_qla_host *vha, struct purex_item *item)
118162306a36Sopenharmony_ci{
118262306a36Sopenharmony_ci	struct qla_nvme_unsol_ctx *uctx = item->purls_context;
118362306a36Sopenharmony_ci	struct qla_nvme_lsrjt_pt_arg a;
118462306a36Sopenharmony_ci	int ret = 1;
118562306a36Sopenharmony_ci
118662306a36Sopenharmony_ci#if (IS_ENABLED(CONFIG_NVME_FC))
118762306a36Sopenharmony_ci	ret = nvme_fc_rcv_ls_req(uctx->fcport->nvme_remote_port, &uctx->lsrsp,
118862306a36Sopenharmony_ci				 &item->iocb, item->size);
118962306a36Sopenharmony_ci#endif
119062306a36Sopenharmony_ci	if (ret) {
119162306a36Sopenharmony_ci		ql_dbg(ql_dbg_unsol, vha, 0x2125, "NVMe transport ls_req failed\n");
119262306a36Sopenharmony_ci		memset((void *)&a, 0, sizeof(a));
119362306a36Sopenharmony_ci		a.vp_idx = vha->vp_idx;
119462306a36Sopenharmony_ci		a.nport_handle = uctx->nport_handle;
119562306a36Sopenharmony_ci		a.xchg_address = uctx->exchange_address;
119662306a36Sopenharmony_ci		qla_nvme_ls_reject_iocb(vha, vha->hw->base_qpair, &a, true);
119762306a36Sopenharmony_ci		list_del(&uctx->elem);
119862306a36Sopenharmony_ci		kfree(uctx);
119962306a36Sopenharmony_ci	}
120062306a36Sopenharmony_ci}
120162306a36Sopenharmony_ci
120262306a36Sopenharmony_cistatic scsi_qla_host_t *
120362306a36Sopenharmony_ciqla2xxx_get_vha_from_vp_idx(struct qla_hw_data *ha, uint16_t vp_index)
120462306a36Sopenharmony_ci{
120562306a36Sopenharmony_ci	scsi_qla_host_t *base_vha, *vha, *tvp;
120662306a36Sopenharmony_ci	unsigned long flags;
120762306a36Sopenharmony_ci
120862306a36Sopenharmony_ci	base_vha = pci_get_drvdata(ha->pdev);
120962306a36Sopenharmony_ci
121062306a36Sopenharmony_ci	if (!vp_index && !ha->num_vhosts)
121162306a36Sopenharmony_ci		return base_vha;
121262306a36Sopenharmony_ci
121362306a36Sopenharmony_ci	spin_lock_irqsave(&ha->vport_slock, flags);
121462306a36Sopenharmony_ci	list_for_each_entry_safe(vha, tvp, &ha->vp_list, list) {
121562306a36Sopenharmony_ci		if (vha->vp_idx == vp_index) {
121662306a36Sopenharmony_ci			spin_unlock_irqrestore(&ha->vport_slock, flags);
121762306a36Sopenharmony_ci			return vha;
121862306a36Sopenharmony_ci		}
121962306a36Sopenharmony_ci	}
122062306a36Sopenharmony_ci	spin_unlock_irqrestore(&ha->vport_slock, flags);
122162306a36Sopenharmony_ci
122262306a36Sopenharmony_ci	return NULL;
122362306a36Sopenharmony_ci}
122462306a36Sopenharmony_ci
122562306a36Sopenharmony_civoid qla2xxx_process_purls_iocb(void **pkt, struct rsp_que **rsp)
122662306a36Sopenharmony_ci{
122762306a36Sopenharmony_ci	struct nvme_fc_remote_port *rport;
122862306a36Sopenharmony_ci	struct qla_nvme_rport *qla_rport;
122962306a36Sopenharmony_ci	struct qla_nvme_lsrjt_pt_arg a;
123062306a36Sopenharmony_ci	struct pt_ls4_rx_unsol *p = *pkt;
123162306a36Sopenharmony_ci	struct qla_nvme_unsol_ctx *uctx;
123262306a36Sopenharmony_ci	struct rsp_que *rsp_q = *rsp;
123362306a36Sopenharmony_ci	struct qla_hw_data *ha;
123462306a36Sopenharmony_ci	scsi_qla_host_t	*vha;
123562306a36Sopenharmony_ci	fc_port_t *fcport = NULL;
123662306a36Sopenharmony_ci	struct purex_item *item;
123762306a36Sopenharmony_ci	port_id_t d_id = {0};
123862306a36Sopenharmony_ci	port_id_t id = {0};
123962306a36Sopenharmony_ci	u8 *opcode;
124062306a36Sopenharmony_ci	bool xmt_reject = false;
124162306a36Sopenharmony_ci
124262306a36Sopenharmony_ci	ha = rsp_q->hw;
124362306a36Sopenharmony_ci
124462306a36Sopenharmony_ci	vha = qla2xxx_get_vha_from_vp_idx(ha, p->vp_index);
124562306a36Sopenharmony_ci	if (!vha) {
124662306a36Sopenharmony_ci		ql_log(ql_log_warn, NULL, 0x2110, "Invalid vp index %d\n", p->vp_index);
124762306a36Sopenharmony_ci		WARN_ON_ONCE(1);
124862306a36Sopenharmony_ci		return;
124962306a36Sopenharmony_ci	}
125062306a36Sopenharmony_ci
125162306a36Sopenharmony_ci	memset((void *)&a, 0, sizeof(a));
125262306a36Sopenharmony_ci	opcode = (u8 *)&p->payload[0];
125362306a36Sopenharmony_ci	a.opcode = opcode[3];
125462306a36Sopenharmony_ci	a.vp_idx = p->vp_index;
125562306a36Sopenharmony_ci	a.nport_handle = p->nport_handle;
125662306a36Sopenharmony_ci	a.ox_id = p->ox_id;
125762306a36Sopenharmony_ci	a.xchg_address = p->exchange_address;
125862306a36Sopenharmony_ci
125962306a36Sopenharmony_ci	id.b.domain = p->s_id.domain;
126062306a36Sopenharmony_ci	id.b.area   = p->s_id.area;
126162306a36Sopenharmony_ci	id.b.al_pa  = p->s_id.al_pa;
126262306a36Sopenharmony_ci	d_id.b.domain = p->d_id[2];
126362306a36Sopenharmony_ci	d_id.b.area   = p->d_id[1];
126462306a36Sopenharmony_ci	d_id.b.al_pa  = p->d_id[0];
126562306a36Sopenharmony_ci
126662306a36Sopenharmony_ci	fcport = qla2x00_find_fcport_by_nportid(vha, &id, 0);
126762306a36Sopenharmony_ci	if (!fcport) {
126862306a36Sopenharmony_ci		ql_dbg(ql_dbg_unsol, vha, 0x211e,
126962306a36Sopenharmony_ci		       "Failed to find sid=%06x did=%06x\n",
127062306a36Sopenharmony_ci		       id.b24, d_id.b24);
127162306a36Sopenharmony_ci		a.reason = FCNVME_RJT_RC_INV_ASSOC;
127262306a36Sopenharmony_ci		a.explanation = FCNVME_RJT_EXP_NONE;
127362306a36Sopenharmony_ci		xmt_reject = true;
127462306a36Sopenharmony_ci		goto out;
127562306a36Sopenharmony_ci	}
127662306a36Sopenharmony_ci	rport = fcport->nvme_remote_port;
127762306a36Sopenharmony_ci	qla_rport = rport->private;
127862306a36Sopenharmony_ci
127962306a36Sopenharmony_ci	item = qla27xx_copy_multiple_pkt(vha, pkt, rsp, true, false);
128062306a36Sopenharmony_ci	if (!item) {
128162306a36Sopenharmony_ci		a.reason = FCNVME_RJT_RC_LOGIC;
128262306a36Sopenharmony_ci		a.explanation = FCNVME_RJT_EXP_NONE;
128362306a36Sopenharmony_ci		xmt_reject = true;
128462306a36Sopenharmony_ci		goto out;
128562306a36Sopenharmony_ci	}
128662306a36Sopenharmony_ci
128762306a36Sopenharmony_ci	uctx = kzalloc(sizeof(*uctx), GFP_ATOMIC);
128862306a36Sopenharmony_ci	if (!uctx) {
128962306a36Sopenharmony_ci		ql_log(ql_log_info, vha, 0x2126, "Failed allocate memory\n");
129062306a36Sopenharmony_ci		a.reason = FCNVME_RJT_RC_LOGIC;
129162306a36Sopenharmony_ci		a.explanation = FCNVME_RJT_EXP_NONE;
129262306a36Sopenharmony_ci		xmt_reject = true;
129362306a36Sopenharmony_ci		kfree(item);
129462306a36Sopenharmony_ci		goto out;
129562306a36Sopenharmony_ci	}
129662306a36Sopenharmony_ci
129762306a36Sopenharmony_ci	uctx->vha = vha;
129862306a36Sopenharmony_ci	uctx->fcport = fcport;
129962306a36Sopenharmony_ci	uctx->exchange_address = p->exchange_address;
130062306a36Sopenharmony_ci	uctx->nport_handle = p->nport_handle;
130162306a36Sopenharmony_ci	uctx->ox_id = p->ox_id;
130262306a36Sopenharmony_ci	qla_rport->uctx = uctx;
130362306a36Sopenharmony_ci	INIT_LIST_HEAD(&uctx->elem);
130462306a36Sopenharmony_ci	list_add_tail(&uctx->elem, &fcport->unsol_ctx_head);
130562306a36Sopenharmony_ci	item->purls_context = (void *)uctx;
130662306a36Sopenharmony_ci
130762306a36Sopenharmony_ci	ql_dbg(ql_dbg_unsol, vha, 0x2121,
130862306a36Sopenharmony_ci	       "PURLS OP[%01x] size %d xchg addr 0x%x portid %06x\n",
130962306a36Sopenharmony_ci	       item->iocb.iocb[3], item->size, uctx->exchange_address,
131062306a36Sopenharmony_ci	       fcport->d_id.b24);
131162306a36Sopenharmony_ci	/* +48    0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
131262306a36Sopenharmony_ci	 * ----- -----------------------------------------------
131362306a36Sopenharmony_ci	 * 0000: 00 00 00 05 28 00 00 00 07 00 00 00 08 00 00 00
131462306a36Sopenharmony_ci	 * 0010: ab ec 0f cc 00 00 8d 7d 05 00 00 00 10 00 00 00
131562306a36Sopenharmony_ci	 * 0020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
131662306a36Sopenharmony_ci	 */
131762306a36Sopenharmony_ci	ql_dump_buffer(ql_dbg_unsol + ql_dbg_verbose, vha, 0x2120,
131862306a36Sopenharmony_ci		       &item->iocb, item->size);
131962306a36Sopenharmony_ci
132062306a36Sopenharmony_ci	qla24xx_queue_purex_item(vha, item, qla2xxx_process_purls_pkt);
132162306a36Sopenharmony_ciout:
132262306a36Sopenharmony_ci	if (xmt_reject) {
132362306a36Sopenharmony_ci		qla_nvme_ls_reject_iocb(vha, (*rsp)->qpair, &a, false);
132462306a36Sopenharmony_ci		__qla_consume_iocb(vha, pkt, rsp);
132562306a36Sopenharmony_ci	}
132662306a36Sopenharmony_ci}
1327