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