18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * QLogic Fibre Channel HBA Driver 48c2ecf20Sopenharmony_ci * Copyright (c) 2003-2017 QLogic Corporation 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci#include "qla_nvme.h" 78c2ecf20Sopenharmony_ci#include <linux/scatterlist.h> 88c2ecf20Sopenharmony_ci#include <linux/delay.h> 98c2ecf20Sopenharmony_ci#include <linux/nvme.h> 108c2ecf20Sopenharmony_ci#include <linux/nvme-fc.h> 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_cistatic struct nvme_fc_port_template qla_nvme_fc_transport; 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ciint qla_nvme_register_remote(struct scsi_qla_host *vha, struct fc_port *fcport) 158c2ecf20Sopenharmony_ci{ 168c2ecf20Sopenharmony_ci struct qla_nvme_rport *rport; 178c2ecf20Sopenharmony_ci struct nvme_fc_port_info req; 188c2ecf20Sopenharmony_ci int ret; 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci if (!IS_ENABLED(CONFIG_NVME_FC)) 218c2ecf20Sopenharmony_ci return 0; 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci if (!vha->flags.nvme_enabled) { 248c2ecf20Sopenharmony_ci ql_log(ql_log_info, vha, 0x2100, 258c2ecf20Sopenharmony_ci "%s: Not registering target since Host NVME is not enabled\n", 268c2ecf20Sopenharmony_ci __func__); 278c2ecf20Sopenharmony_ci return 0; 288c2ecf20Sopenharmony_ci } 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci if (qla_nvme_register_hba(vha)) 318c2ecf20Sopenharmony_ci return 0; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci if (!vha->nvme_local_port) 348c2ecf20Sopenharmony_ci return 0; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci if (!(fcport->nvme_prli_service_param & 378c2ecf20Sopenharmony_ci (NVME_PRLI_SP_TARGET | NVME_PRLI_SP_DISCOVERY)) || 388c2ecf20Sopenharmony_ci (fcport->nvme_flag & NVME_FLAG_REGISTERED)) 398c2ecf20Sopenharmony_ci return 0; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci fcport->nvme_flag &= ~NVME_FLAG_RESETTING; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci memset(&req, 0, sizeof(struct nvme_fc_port_info)); 448c2ecf20Sopenharmony_ci req.port_name = wwn_to_u64(fcport->port_name); 458c2ecf20Sopenharmony_ci req.node_name = wwn_to_u64(fcport->node_name); 468c2ecf20Sopenharmony_ci req.port_role = 0; 478c2ecf20Sopenharmony_ci req.dev_loss_tmo = 0; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci if (fcport->nvme_prli_service_param & NVME_PRLI_SP_INITIATOR) 508c2ecf20Sopenharmony_ci req.port_role = FC_PORT_ROLE_NVME_INITIATOR; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci if (fcport->nvme_prli_service_param & NVME_PRLI_SP_TARGET) 538c2ecf20Sopenharmony_ci req.port_role |= FC_PORT_ROLE_NVME_TARGET; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci if (fcport->nvme_prli_service_param & NVME_PRLI_SP_DISCOVERY) 568c2ecf20Sopenharmony_ci req.port_role |= FC_PORT_ROLE_NVME_DISCOVERY; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci req.port_id = fcport->d_id.b24; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci ql_log(ql_log_info, vha, 0x2102, 618c2ecf20Sopenharmony_ci "%s: traddr=nn-0x%016llx:pn-0x%016llx PortID:%06x\n", 628c2ecf20Sopenharmony_ci __func__, req.node_name, req.port_name, 638c2ecf20Sopenharmony_ci req.port_id); 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci ret = nvme_fc_register_remoteport(vha->nvme_local_port, &req, 668c2ecf20Sopenharmony_ci &fcport->nvme_remote_port); 678c2ecf20Sopenharmony_ci if (ret) { 688c2ecf20Sopenharmony_ci ql_log(ql_log_warn, vha, 0x212e, 698c2ecf20Sopenharmony_ci "Failed to register remote port. Transport returned %d\n", 708c2ecf20Sopenharmony_ci ret); 718c2ecf20Sopenharmony_ci return ret; 728c2ecf20Sopenharmony_ci } 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci if (fcport->nvme_prli_service_param & NVME_PRLI_SP_SLER) 758c2ecf20Sopenharmony_ci ql_log(ql_log_info, vha, 0x212a, 768c2ecf20Sopenharmony_ci "PortID:%06x Supports SLER\n", req.port_id); 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci if (fcport->nvme_prli_service_param & NVME_PRLI_SP_PI_CTRL) 798c2ecf20Sopenharmony_ci ql_log(ql_log_info, vha, 0x212b, 808c2ecf20Sopenharmony_ci "PortID:%06x Supports PI control\n", req.port_id); 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci rport = fcport->nvme_remote_port->private; 838c2ecf20Sopenharmony_ci rport->fcport = fcport; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci fcport->nvme_flag |= NVME_FLAG_REGISTERED; 868c2ecf20Sopenharmony_ci return 0; 878c2ecf20Sopenharmony_ci} 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci/* Allocate a queue for NVMe traffic */ 908c2ecf20Sopenharmony_cistatic int qla_nvme_alloc_queue(struct nvme_fc_local_port *lport, 918c2ecf20Sopenharmony_ci unsigned int qidx, u16 qsize, void **handle) 928c2ecf20Sopenharmony_ci{ 938c2ecf20Sopenharmony_ci struct scsi_qla_host *vha; 948c2ecf20Sopenharmony_ci struct qla_hw_data *ha; 958c2ecf20Sopenharmony_ci struct qla_qpair *qpair; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci /* Map admin queue and 1st IO queue to index 0 */ 988c2ecf20Sopenharmony_ci if (qidx) 998c2ecf20Sopenharmony_ci qidx--; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci vha = (struct scsi_qla_host *)lport->private; 1028c2ecf20Sopenharmony_ci ha = vha->hw; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci ql_log(ql_log_info, vha, 0x2104, 1058c2ecf20Sopenharmony_ci "%s: handle %p, idx =%d, qsize %d\n", 1068c2ecf20Sopenharmony_ci __func__, handle, qidx, qsize); 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci if (qidx > qla_nvme_fc_transport.max_hw_queues) { 1098c2ecf20Sopenharmony_ci ql_log(ql_log_warn, vha, 0x212f, 1108c2ecf20Sopenharmony_ci "%s: Illegal qidx=%d. Max=%d\n", 1118c2ecf20Sopenharmony_ci __func__, qidx, qla_nvme_fc_transport.max_hw_queues); 1128c2ecf20Sopenharmony_ci return -EINVAL; 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci /* Use base qpair if max_qpairs is 0 */ 1168c2ecf20Sopenharmony_ci if (!ha->max_qpairs) { 1178c2ecf20Sopenharmony_ci qpair = ha->base_qpair; 1188c2ecf20Sopenharmony_ci } else { 1198c2ecf20Sopenharmony_ci if (ha->queue_pair_map[qidx]) { 1208c2ecf20Sopenharmony_ci *handle = ha->queue_pair_map[qidx]; 1218c2ecf20Sopenharmony_ci ql_log(ql_log_info, vha, 0x2121, 1228c2ecf20Sopenharmony_ci "Returning existing qpair of %p for idx=%x\n", 1238c2ecf20Sopenharmony_ci *handle, qidx); 1248c2ecf20Sopenharmony_ci return 0; 1258c2ecf20Sopenharmony_ci } 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci qpair = qla2xxx_create_qpair(vha, 5, vha->vp_idx, true); 1288c2ecf20Sopenharmony_ci if (!qpair) { 1298c2ecf20Sopenharmony_ci ql_log(ql_log_warn, vha, 0x2122, 1308c2ecf20Sopenharmony_ci "Failed to allocate qpair\n"); 1318c2ecf20Sopenharmony_ci return -EINVAL; 1328c2ecf20Sopenharmony_ci } 1338c2ecf20Sopenharmony_ci } 1348c2ecf20Sopenharmony_ci *handle = qpair; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci return 0; 1378c2ecf20Sopenharmony_ci} 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_cistatic void qla_nvme_release_fcp_cmd_kref(struct kref *kref) 1408c2ecf20Sopenharmony_ci{ 1418c2ecf20Sopenharmony_ci struct srb *sp = container_of(kref, struct srb, cmd_kref); 1428c2ecf20Sopenharmony_ci struct nvme_private *priv = (struct nvme_private *)sp->priv; 1438c2ecf20Sopenharmony_ci struct nvmefc_fcp_req *fd; 1448c2ecf20Sopenharmony_ci struct srb_iocb *nvme; 1458c2ecf20Sopenharmony_ci unsigned long flags; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci if (!priv) 1488c2ecf20Sopenharmony_ci goto out; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci nvme = &sp->u.iocb_cmd; 1518c2ecf20Sopenharmony_ci fd = nvme->u.nvme.desc; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->cmd_lock, flags); 1548c2ecf20Sopenharmony_ci priv->sp = NULL; 1558c2ecf20Sopenharmony_ci sp->priv = NULL; 1568c2ecf20Sopenharmony_ci if (priv->comp_status == QLA_SUCCESS) { 1578c2ecf20Sopenharmony_ci fd->rcv_rsplen = le16_to_cpu(nvme->u.nvme.rsp_pyld_len); 1588c2ecf20Sopenharmony_ci fd->status = NVME_SC_SUCCESS; 1598c2ecf20Sopenharmony_ci } else { 1608c2ecf20Sopenharmony_ci fd->rcv_rsplen = 0; 1618c2ecf20Sopenharmony_ci fd->transferred_length = 0; 1628c2ecf20Sopenharmony_ci fd->status = NVME_SC_INTERNAL; 1638c2ecf20Sopenharmony_ci } 1648c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->cmd_lock, flags); 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci fd->done(fd); 1678c2ecf20Sopenharmony_ciout: 1688c2ecf20Sopenharmony_ci qla2xxx_rel_qpair_sp(sp->qpair, sp); 1698c2ecf20Sopenharmony_ci} 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_cistatic void qla_nvme_release_ls_cmd_kref(struct kref *kref) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci struct srb *sp = container_of(kref, struct srb, cmd_kref); 1748c2ecf20Sopenharmony_ci struct nvme_private *priv = (struct nvme_private *)sp->priv; 1758c2ecf20Sopenharmony_ci struct nvmefc_ls_req *fd; 1768c2ecf20Sopenharmony_ci unsigned long flags; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci if (!priv) 1798c2ecf20Sopenharmony_ci goto out; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->cmd_lock, flags); 1828c2ecf20Sopenharmony_ci priv->sp = NULL; 1838c2ecf20Sopenharmony_ci sp->priv = NULL; 1848c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->cmd_lock, flags); 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci fd = priv->fd; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci fd->done(fd, priv->comp_status); 1898c2ecf20Sopenharmony_ciout: 1908c2ecf20Sopenharmony_ci qla2x00_rel_sp(sp); 1918c2ecf20Sopenharmony_ci} 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_cistatic void qla_nvme_ls_complete(struct work_struct *work) 1948c2ecf20Sopenharmony_ci{ 1958c2ecf20Sopenharmony_ci struct nvme_private *priv = 1968c2ecf20Sopenharmony_ci container_of(work, struct nvme_private, ls_work); 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci kref_put(&priv->sp->cmd_kref, qla_nvme_release_ls_cmd_kref); 1998c2ecf20Sopenharmony_ci} 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_cistatic void qla_nvme_sp_ls_done(srb_t *sp, int res) 2028c2ecf20Sopenharmony_ci{ 2038c2ecf20Sopenharmony_ci struct nvme_private *priv = sp->priv; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(kref_read(&sp->cmd_kref) == 0)) 2068c2ecf20Sopenharmony_ci return; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci if (res) 2098c2ecf20Sopenharmony_ci res = -EINVAL; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci priv->comp_status = res; 2128c2ecf20Sopenharmony_ci INIT_WORK(&priv->ls_work, qla_nvme_ls_complete); 2138c2ecf20Sopenharmony_ci schedule_work(&priv->ls_work); 2148c2ecf20Sopenharmony_ci} 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci/* it assumed that QPair lock is held. */ 2178c2ecf20Sopenharmony_cistatic void qla_nvme_sp_done(srb_t *sp, int res) 2188c2ecf20Sopenharmony_ci{ 2198c2ecf20Sopenharmony_ci struct nvme_private *priv = sp->priv; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci priv->comp_status = res; 2228c2ecf20Sopenharmony_ci kref_put(&sp->cmd_kref, qla_nvme_release_fcp_cmd_kref); 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci return; 2258c2ecf20Sopenharmony_ci} 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_cistatic void qla_nvme_abort_work(struct work_struct *work) 2288c2ecf20Sopenharmony_ci{ 2298c2ecf20Sopenharmony_ci struct nvme_private *priv = 2308c2ecf20Sopenharmony_ci container_of(work, struct nvme_private, abort_work); 2318c2ecf20Sopenharmony_ci srb_t *sp = priv->sp; 2328c2ecf20Sopenharmony_ci fc_port_t *fcport = sp->fcport; 2338c2ecf20Sopenharmony_ci struct qla_hw_data *ha = fcport->vha->hw; 2348c2ecf20Sopenharmony_ci int rval; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_io, fcport->vha, 0xffff, 2378c2ecf20Sopenharmony_ci "%s called for sp=%p, hndl=%x on fcport=%p deleted=%d\n", 2388c2ecf20Sopenharmony_ci __func__, sp, sp->handle, fcport, fcport->deleted); 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci if (!ha->flags.fw_started && fcport->deleted) 2418c2ecf20Sopenharmony_ci goto out; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci if (ha->flags.host_shutting_down) { 2448c2ecf20Sopenharmony_ci ql_log(ql_log_info, sp->fcport->vha, 0xffff, 2458c2ecf20Sopenharmony_ci "%s Calling done on sp: %p, type: 0x%x\n", 2468c2ecf20Sopenharmony_ci __func__, sp, sp->type); 2478c2ecf20Sopenharmony_ci sp->done(sp, 0); 2488c2ecf20Sopenharmony_ci goto out; 2498c2ecf20Sopenharmony_ci } 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci rval = ha->isp_ops->abort_command(sp); 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_io, fcport->vha, 0x212b, 2548c2ecf20Sopenharmony_ci "%s: %s command for sp=%p, handle=%x on fcport=%p rval=%x\n", 2558c2ecf20Sopenharmony_ci __func__, (rval != QLA_SUCCESS) ? "Failed to abort" : "Aborted", 2568c2ecf20Sopenharmony_ci sp, sp->handle, fcport, rval); 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ciout: 2598c2ecf20Sopenharmony_ci /* kref_get was done before work was schedule. */ 2608c2ecf20Sopenharmony_ci kref_put(&sp->cmd_kref, sp->put_fn); 2618c2ecf20Sopenharmony_ci} 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_cistatic void qla_nvme_ls_abort(struct nvme_fc_local_port *lport, 2648c2ecf20Sopenharmony_ci struct nvme_fc_remote_port *rport, struct nvmefc_ls_req *fd) 2658c2ecf20Sopenharmony_ci{ 2668c2ecf20Sopenharmony_ci struct nvme_private *priv = fd->private; 2678c2ecf20Sopenharmony_ci unsigned long flags; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->cmd_lock, flags); 2708c2ecf20Sopenharmony_ci if (!priv->sp) { 2718c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->cmd_lock, flags); 2728c2ecf20Sopenharmony_ci return; 2738c2ecf20Sopenharmony_ci } 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci if (!kref_get_unless_zero(&priv->sp->cmd_kref)) { 2768c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->cmd_lock, flags); 2778c2ecf20Sopenharmony_ci return; 2788c2ecf20Sopenharmony_ci } 2798c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->cmd_lock, flags); 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci INIT_WORK(&priv->abort_work, qla_nvme_abort_work); 2828c2ecf20Sopenharmony_ci schedule_work(&priv->abort_work); 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_cistatic int qla_nvme_ls_req(struct nvme_fc_local_port *lport, 2868c2ecf20Sopenharmony_ci struct nvme_fc_remote_port *rport, struct nvmefc_ls_req *fd) 2878c2ecf20Sopenharmony_ci{ 2888c2ecf20Sopenharmony_ci struct qla_nvme_rport *qla_rport = rport->private; 2898c2ecf20Sopenharmony_ci fc_port_t *fcport = qla_rport->fcport; 2908c2ecf20Sopenharmony_ci struct srb_iocb *nvme; 2918c2ecf20Sopenharmony_ci struct nvme_private *priv = fd->private; 2928c2ecf20Sopenharmony_ci struct scsi_qla_host *vha; 2938c2ecf20Sopenharmony_ci int rval = QLA_FUNCTION_FAILED; 2948c2ecf20Sopenharmony_ci struct qla_hw_data *ha; 2958c2ecf20Sopenharmony_ci srb_t *sp; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci if (!fcport || (fcport && fcport->deleted)) 2998c2ecf20Sopenharmony_ci return rval; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci vha = fcport->vha; 3028c2ecf20Sopenharmony_ci ha = vha->hw; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci if (!ha->flags.fw_started) 3058c2ecf20Sopenharmony_ci return rval; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci /* Alloc SRB structure */ 3088c2ecf20Sopenharmony_ci sp = qla2x00_get_sp(vha, fcport, GFP_ATOMIC); 3098c2ecf20Sopenharmony_ci if (!sp) 3108c2ecf20Sopenharmony_ci return rval; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci sp->type = SRB_NVME_LS; 3138c2ecf20Sopenharmony_ci sp->name = "nvme_ls"; 3148c2ecf20Sopenharmony_ci sp->done = qla_nvme_sp_ls_done; 3158c2ecf20Sopenharmony_ci sp->put_fn = qla_nvme_release_ls_cmd_kref; 3168c2ecf20Sopenharmony_ci sp->priv = priv; 3178c2ecf20Sopenharmony_ci priv->sp = sp; 3188c2ecf20Sopenharmony_ci kref_init(&sp->cmd_kref); 3198c2ecf20Sopenharmony_ci spin_lock_init(&priv->cmd_lock); 3208c2ecf20Sopenharmony_ci nvme = &sp->u.iocb_cmd; 3218c2ecf20Sopenharmony_ci priv->fd = fd; 3228c2ecf20Sopenharmony_ci nvme->u.nvme.desc = fd; 3238c2ecf20Sopenharmony_ci nvme->u.nvme.dir = 0; 3248c2ecf20Sopenharmony_ci nvme->u.nvme.dl = 0; 3258c2ecf20Sopenharmony_ci nvme->u.nvme.cmd_len = fd->rqstlen; 3268c2ecf20Sopenharmony_ci nvme->u.nvme.rsp_len = fd->rsplen; 3278c2ecf20Sopenharmony_ci nvme->u.nvme.rsp_dma = fd->rspdma; 3288c2ecf20Sopenharmony_ci nvme->u.nvme.timeout_sec = fd->timeout; 3298c2ecf20Sopenharmony_ci nvme->u.nvme.cmd_dma = fd->rqstdma; 3308c2ecf20Sopenharmony_ci dma_sync_single_for_device(&ha->pdev->dev, nvme->u.nvme.cmd_dma, 3318c2ecf20Sopenharmony_ci fd->rqstlen, DMA_TO_DEVICE); 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci rval = qla2x00_start_sp(sp); 3348c2ecf20Sopenharmony_ci if (rval != QLA_SUCCESS) { 3358c2ecf20Sopenharmony_ci ql_log(ql_log_warn, vha, 0x700e, 3368c2ecf20Sopenharmony_ci "qla2x00_start_sp failed = %d\n", rval); 3378c2ecf20Sopenharmony_ci sp->priv = NULL; 3388c2ecf20Sopenharmony_ci priv->sp = NULL; 3398c2ecf20Sopenharmony_ci qla2x00_rel_sp(sp); 3408c2ecf20Sopenharmony_ci return rval; 3418c2ecf20Sopenharmony_ci } 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci return rval; 3448c2ecf20Sopenharmony_ci} 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_cistatic void qla_nvme_fcp_abort(struct nvme_fc_local_port *lport, 3478c2ecf20Sopenharmony_ci struct nvme_fc_remote_port *rport, void *hw_queue_handle, 3488c2ecf20Sopenharmony_ci struct nvmefc_fcp_req *fd) 3498c2ecf20Sopenharmony_ci{ 3508c2ecf20Sopenharmony_ci struct nvme_private *priv = fd->private; 3518c2ecf20Sopenharmony_ci unsigned long flags; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->cmd_lock, flags); 3548c2ecf20Sopenharmony_ci if (!priv->sp) { 3558c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->cmd_lock, flags); 3568c2ecf20Sopenharmony_ci return; 3578c2ecf20Sopenharmony_ci } 3588c2ecf20Sopenharmony_ci if (!kref_get_unless_zero(&priv->sp->cmd_kref)) { 3598c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->cmd_lock, flags); 3608c2ecf20Sopenharmony_ci return; 3618c2ecf20Sopenharmony_ci } 3628c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->cmd_lock, flags); 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci INIT_WORK(&priv->abort_work, qla_nvme_abort_work); 3658c2ecf20Sopenharmony_ci schedule_work(&priv->abort_work); 3668c2ecf20Sopenharmony_ci} 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_cistatic inline int qla2x00_start_nvme_mq(srb_t *sp) 3698c2ecf20Sopenharmony_ci{ 3708c2ecf20Sopenharmony_ci unsigned long flags; 3718c2ecf20Sopenharmony_ci uint32_t *clr_ptr; 3728c2ecf20Sopenharmony_ci uint32_t handle; 3738c2ecf20Sopenharmony_ci struct cmd_nvme *cmd_pkt; 3748c2ecf20Sopenharmony_ci uint16_t cnt, i; 3758c2ecf20Sopenharmony_ci uint16_t req_cnt; 3768c2ecf20Sopenharmony_ci uint16_t tot_dsds; 3778c2ecf20Sopenharmony_ci uint16_t avail_dsds; 3788c2ecf20Sopenharmony_ci struct dsd64 *cur_dsd; 3798c2ecf20Sopenharmony_ci struct req_que *req = NULL; 3808c2ecf20Sopenharmony_ci struct scsi_qla_host *vha = sp->fcport->vha; 3818c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 3828c2ecf20Sopenharmony_ci struct qla_qpair *qpair = sp->qpair; 3838c2ecf20Sopenharmony_ci struct srb_iocb *nvme = &sp->u.iocb_cmd; 3848c2ecf20Sopenharmony_ci struct scatterlist *sgl, *sg; 3858c2ecf20Sopenharmony_ci struct nvmefc_fcp_req *fd = nvme->u.nvme.desc; 3868c2ecf20Sopenharmony_ci struct nvme_fc_cmd_iu *cmd = fd->cmdaddr; 3878c2ecf20Sopenharmony_ci uint32_t rval = QLA_SUCCESS; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci /* Setup qpair pointers */ 3908c2ecf20Sopenharmony_ci req = qpair->req; 3918c2ecf20Sopenharmony_ci tot_dsds = fd->sg_cnt; 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci /* Acquire qpair specific lock */ 3948c2ecf20Sopenharmony_ci spin_lock_irqsave(&qpair->qp_lock, flags); 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci handle = qla2xxx_get_next_handle(req); 3978c2ecf20Sopenharmony_ci if (handle == 0) { 3988c2ecf20Sopenharmony_ci rval = -EBUSY; 3998c2ecf20Sopenharmony_ci goto queuing_error; 4008c2ecf20Sopenharmony_ci } 4018c2ecf20Sopenharmony_ci req_cnt = qla24xx_calc_iocbs(vha, tot_dsds); 4028c2ecf20Sopenharmony_ci if (req->cnt < (req_cnt + 2)) { 4038c2ecf20Sopenharmony_ci if (IS_SHADOW_REG_CAPABLE(ha)) { 4048c2ecf20Sopenharmony_ci cnt = *req->out_ptr; 4058c2ecf20Sopenharmony_ci } else { 4068c2ecf20Sopenharmony_ci cnt = rd_reg_dword_relaxed(req->req_q_out); 4078c2ecf20Sopenharmony_ci if (qla2x00_check_reg16_for_disconnect(vha, cnt)) 4088c2ecf20Sopenharmony_ci goto queuing_error; 4098c2ecf20Sopenharmony_ci } 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci if (req->ring_index < cnt) 4128c2ecf20Sopenharmony_ci req->cnt = cnt - req->ring_index; 4138c2ecf20Sopenharmony_ci else 4148c2ecf20Sopenharmony_ci req->cnt = req->length - (req->ring_index - cnt); 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci if (req->cnt < (req_cnt + 2)){ 4178c2ecf20Sopenharmony_ci rval = -EBUSY; 4188c2ecf20Sopenharmony_ci goto queuing_error; 4198c2ecf20Sopenharmony_ci } 4208c2ecf20Sopenharmony_ci } 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci if (unlikely(!fd->sqid)) { 4238c2ecf20Sopenharmony_ci if (cmd->sqe.common.opcode == nvme_admin_async_event) { 4248c2ecf20Sopenharmony_ci nvme->u.nvme.aen_op = 1; 4258c2ecf20Sopenharmony_ci atomic_inc(&ha->nvme_active_aen_cnt); 4268c2ecf20Sopenharmony_ci } 4278c2ecf20Sopenharmony_ci } 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci /* Build command packet. */ 4308c2ecf20Sopenharmony_ci req->current_outstanding_cmd = handle; 4318c2ecf20Sopenharmony_ci req->outstanding_cmds[handle] = sp; 4328c2ecf20Sopenharmony_ci sp->handle = handle; 4338c2ecf20Sopenharmony_ci req->cnt -= req_cnt; 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci cmd_pkt = (struct cmd_nvme *)req->ring_ptr; 4368c2ecf20Sopenharmony_ci cmd_pkt->handle = make_handle(req->id, handle); 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci /* Zero out remaining portion of packet. */ 4398c2ecf20Sopenharmony_ci clr_ptr = (uint32_t *)cmd_pkt + 2; 4408c2ecf20Sopenharmony_ci memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8); 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci cmd_pkt->entry_status = 0; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci /* Update entry type to indicate Command NVME IOCB */ 4458c2ecf20Sopenharmony_ci cmd_pkt->entry_type = COMMAND_NVME; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci /* No data transfer how do we check buffer len == 0?? */ 4488c2ecf20Sopenharmony_ci if (fd->io_dir == NVMEFC_FCP_READ) { 4498c2ecf20Sopenharmony_ci cmd_pkt->control_flags = cpu_to_le16(CF_READ_DATA); 4508c2ecf20Sopenharmony_ci qpair->counters.input_bytes += fd->payload_length; 4518c2ecf20Sopenharmony_ci qpair->counters.input_requests++; 4528c2ecf20Sopenharmony_ci } else if (fd->io_dir == NVMEFC_FCP_WRITE) { 4538c2ecf20Sopenharmony_ci cmd_pkt->control_flags = cpu_to_le16(CF_WRITE_DATA); 4548c2ecf20Sopenharmony_ci if ((vha->flags.nvme_first_burst) && 4558c2ecf20Sopenharmony_ci (sp->fcport->nvme_prli_service_param & 4568c2ecf20Sopenharmony_ci NVME_PRLI_SP_FIRST_BURST)) { 4578c2ecf20Sopenharmony_ci if ((fd->payload_length <= 4588c2ecf20Sopenharmony_ci sp->fcport->nvme_first_burst_size) || 4598c2ecf20Sopenharmony_ci (sp->fcport->nvme_first_burst_size == 0)) 4608c2ecf20Sopenharmony_ci cmd_pkt->control_flags |= 4618c2ecf20Sopenharmony_ci cpu_to_le16(CF_NVME_FIRST_BURST_ENABLE); 4628c2ecf20Sopenharmony_ci } 4638c2ecf20Sopenharmony_ci qpair->counters.output_bytes += fd->payload_length; 4648c2ecf20Sopenharmony_ci qpair->counters.output_requests++; 4658c2ecf20Sopenharmony_ci } else if (fd->io_dir == 0) { 4668c2ecf20Sopenharmony_ci cmd_pkt->control_flags = 0; 4678c2ecf20Sopenharmony_ci } 4688c2ecf20Sopenharmony_ci /* Set BIT_13 of control flags for Async event */ 4698c2ecf20Sopenharmony_ci if (vha->flags.nvme2_enabled && 4708c2ecf20Sopenharmony_ci cmd->sqe.common.opcode == nvme_admin_async_event) { 4718c2ecf20Sopenharmony_ci cmd_pkt->control_flags |= cpu_to_le16(CF_ADMIN_ASYNC_EVENT); 4728c2ecf20Sopenharmony_ci } 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci /* Set NPORT-ID */ 4758c2ecf20Sopenharmony_ci cmd_pkt->nport_handle = cpu_to_le16(sp->fcport->loop_id); 4768c2ecf20Sopenharmony_ci cmd_pkt->port_id[0] = sp->fcport->d_id.b.al_pa; 4778c2ecf20Sopenharmony_ci cmd_pkt->port_id[1] = sp->fcport->d_id.b.area; 4788c2ecf20Sopenharmony_ci cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain; 4798c2ecf20Sopenharmony_ci cmd_pkt->vp_index = sp->fcport->vha->vp_idx; 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci /* NVME RSP IU */ 4828c2ecf20Sopenharmony_ci cmd_pkt->nvme_rsp_dsd_len = cpu_to_le16(fd->rsplen); 4838c2ecf20Sopenharmony_ci put_unaligned_le64(fd->rspdma, &cmd_pkt->nvme_rsp_dseg_address); 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci /* NVME CNMD IU */ 4868c2ecf20Sopenharmony_ci cmd_pkt->nvme_cmnd_dseg_len = cpu_to_le16(fd->cmdlen); 4878c2ecf20Sopenharmony_ci cmd_pkt->nvme_cmnd_dseg_address = cpu_to_le64(fd->cmddma); 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci cmd_pkt->dseg_count = cpu_to_le16(tot_dsds); 4908c2ecf20Sopenharmony_ci cmd_pkt->byte_count = cpu_to_le32(fd->payload_length); 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci /* One DSD is available in the Command Type NVME IOCB */ 4938c2ecf20Sopenharmony_ci avail_dsds = 1; 4948c2ecf20Sopenharmony_ci cur_dsd = &cmd_pkt->nvme_dsd; 4958c2ecf20Sopenharmony_ci sgl = fd->first_sgl; 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci /* Load data segments */ 4988c2ecf20Sopenharmony_ci for_each_sg(sgl, sg, tot_dsds, i) { 4998c2ecf20Sopenharmony_ci cont_a64_entry_t *cont_pkt; 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci /* Allocate additional continuation packets? */ 5028c2ecf20Sopenharmony_ci if (avail_dsds == 0) { 5038c2ecf20Sopenharmony_ci /* 5048c2ecf20Sopenharmony_ci * Five DSDs are available in the Continuation 5058c2ecf20Sopenharmony_ci * Type 1 IOCB. 5068c2ecf20Sopenharmony_ci */ 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci /* Adjust ring index */ 5098c2ecf20Sopenharmony_ci req->ring_index++; 5108c2ecf20Sopenharmony_ci if (req->ring_index == req->length) { 5118c2ecf20Sopenharmony_ci req->ring_index = 0; 5128c2ecf20Sopenharmony_ci req->ring_ptr = req->ring; 5138c2ecf20Sopenharmony_ci } else { 5148c2ecf20Sopenharmony_ci req->ring_ptr++; 5158c2ecf20Sopenharmony_ci } 5168c2ecf20Sopenharmony_ci cont_pkt = (cont_a64_entry_t *)req->ring_ptr; 5178c2ecf20Sopenharmony_ci put_unaligned_le32(CONTINUE_A64_TYPE, 5188c2ecf20Sopenharmony_ci &cont_pkt->entry_type); 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci cur_dsd = cont_pkt->dsd; 5218c2ecf20Sopenharmony_ci avail_dsds = ARRAY_SIZE(cont_pkt->dsd); 5228c2ecf20Sopenharmony_ci } 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci append_dsd64(&cur_dsd, sg); 5258c2ecf20Sopenharmony_ci avail_dsds--; 5268c2ecf20Sopenharmony_ci } 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci /* Set total entry count. */ 5298c2ecf20Sopenharmony_ci cmd_pkt->entry_count = (uint8_t)req_cnt; 5308c2ecf20Sopenharmony_ci wmb(); 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci /* Adjust ring index. */ 5338c2ecf20Sopenharmony_ci req->ring_index++; 5348c2ecf20Sopenharmony_ci if (req->ring_index == req->length) { 5358c2ecf20Sopenharmony_ci req->ring_index = 0; 5368c2ecf20Sopenharmony_ci req->ring_ptr = req->ring; 5378c2ecf20Sopenharmony_ci } else { 5388c2ecf20Sopenharmony_ci req->ring_ptr++; 5398c2ecf20Sopenharmony_ci } 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci /* Set chip new ring index. */ 5428c2ecf20Sopenharmony_ci wrt_reg_dword(req->req_q_in, req->ring_index); 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ciqueuing_error: 5458c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&qpair->qp_lock, flags); 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci return rval; 5488c2ecf20Sopenharmony_ci} 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci/* Post a command */ 5518c2ecf20Sopenharmony_cistatic int qla_nvme_post_cmd(struct nvme_fc_local_port *lport, 5528c2ecf20Sopenharmony_ci struct nvme_fc_remote_port *rport, void *hw_queue_handle, 5538c2ecf20Sopenharmony_ci struct nvmefc_fcp_req *fd) 5548c2ecf20Sopenharmony_ci{ 5558c2ecf20Sopenharmony_ci fc_port_t *fcport; 5568c2ecf20Sopenharmony_ci struct srb_iocb *nvme; 5578c2ecf20Sopenharmony_ci struct scsi_qla_host *vha; 5588c2ecf20Sopenharmony_ci int rval; 5598c2ecf20Sopenharmony_ci srb_t *sp; 5608c2ecf20Sopenharmony_ci struct qla_qpair *qpair = hw_queue_handle; 5618c2ecf20Sopenharmony_ci struct nvme_private *priv = fd->private; 5628c2ecf20Sopenharmony_ci struct qla_nvme_rport *qla_rport = rport->private; 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci if (!priv) { 5658c2ecf20Sopenharmony_ci /* nvme association has been torn down */ 5668c2ecf20Sopenharmony_ci return -ENODEV; 5678c2ecf20Sopenharmony_ci } 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci fcport = qla_rport->fcport; 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci if (!qpair || !fcport) 5728c2ecf20Sopenharmony_ci return -ENODEV; 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci if (!qpair->fw_started || fcport->deleted) 5758c2ecf20Sopenharmony_ci return -EBUSY; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci vha = fcport->vha; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci if (!(fcport->nvme_flag & NVME_FLAG_REGISTERED)) 5808c2ecf20Sopenharmony_ci return -ENODEV; 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci if (test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) || 5838c2ecf20Sopenharmony_ci (qpair && !qpair->fw_started) || fcport->deleted) 5848c2ecf20Sopenharmony_ci return -EBUSY; 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci /* 5878c2ecf20Sopenharmony_ci * If we know the dev is going away while the transport is still sending 5888c2ecf20Sopenharmony_ci * IO's return busy back to stall the IO Q. This happens when the 5898c2ecf20Sopenharmony_ci * link goes away and fw hasn't notified us yet, but IO's are being 5908c2ecf20Sopenharmony_ci * returned. If the dev comes back quickly we won't exhaust the IO 5918c2ecf20Sopenharmony_ci * retry count at the core. 5928c2ecf20Sopenharmony_ci */ 5938c2ecf20Sopenharmony_ci if (fcport->nvme_flag & NVME_FLAG_RESETTING) 5948c2ecf20Sopenharmony_ci return -EBUSY; 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci /* Alloc SRB structure */ 5978c2ecf20Sopenharmony_ci sp = qla2xxx_get_qpair_sp(vha, qpair, fcport, GFP_ATOMIC); 5988c2ecf20Sopenharmony_ci if (!sp) 5998c2ecf20Sopenharmony_ci return -EBUSY; 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci kref_init(&sp->cmd_kref); 6028c2ecf20Sopenharmony_ci spin_lock_init(&priv->cmd_lock); 6038c2ecf20Sopenharmony_ci sp->priv = priv; 6048c2ecf20Sopenharmony_ci priv->sp = sp; 6058c2ecf20Sopenharmony_ci sp->type = SRB_NVME_CMD; 6068c2ecf20Sopenharmony_ci sp->name = "nvme_cmd"; 6078c2ecf20Sopenharmony_ci sp->done = qla_nvme_sp_done; 6088c2ecf20Sopenharmony_ci sp->put_fn = qla_nvme_release_fcp_cmd_kref; 6098c2ecf20Sopenharmony_ci sp->qpair = qpair; 6108c2ecf20Sopenharmony_ci sp->vha = vha; 6118c2ecf20Sopenharmony_ci nvme = &sp->u.iocb_cmd; 6128c2ecf20Sopenharmony_ci nvme->u.nvme.desc = fd; 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci rval = qla2x00_start_nvme_mq(sp); 6158c2ecf20Sopenharmony_ci if (rval != QLA_SUCCESS) { 6168c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_io + ql_dbg_verbose, vha, 0x212d, 6178c2ecf20Sopenharmony_ci "qla2x00_start_nvme_mq failed = %d\n", rval); 6188c2ecf20Sopenharmony_ci sp->priv = NULL; 6198c2ecf20Sopenharmony_ci priv->sp = NULL; 6208c2ecf20Sopenharmony_ci qla2xxx_rel_qpair_sp(sp->qpair, sp); 6218c2ecf20Sopenharmony_ci } 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci return rval; 6248c2ecf20Sopenharmony_ci} 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_cistatic void qla_nvme_localport_delete(struct nvme_fc_local_port *lport) 6278c2ecf20Sopenharmony_ci{ 6288c2ecf20Sopenharmony_ci struct scsi_qla_host *vha = lport->private; 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci ql_log(ql_log_info, vha, 0x210f, 6318c2ecf20Sopenharmony_ci "localport delete of %p completed.\n", vha->nvme_local_port); 6328c2ecf20Sopenharmony_ci vha->nvme_local_port = NULL; 6338c2ecf20Sopenharmony_ci complete(&vha->nvme_del_done); 6348c2ecf20Sopenharmony_ci} 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_cistatic void qla_nvme_remoteport_delete(struct nvme_fc_remote_port *rport) 6378c2ecf20Sopenharmony_ci{ 6388c2ecf20Sopenharmony_ci fc_port_t *fcport; 6398c2ecf20Sopenharmony_ci struct qla_nvme_rport *qla_rport = rport->private; 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci fcport = qla_rport->fcport; 6428c2ecf20Sopenharmony_ci fcport->nvme_remote_port = NULL; 6438c2ecf20Sopenharmony_ci fcport->nvme_flag &= ~NVME_FLAG_REGISTERED; 6448c2ecf20Sopenharmony_ci fcport->nvme_flag &= ~NVME_FLAG_DELETING; 6458c2ecf20Sopenharmony_ci ql_log(ql_log_info, fcport->vha, 0x2110, 6468c2ecf20Sopenharmony_ci "remoteport_delete of %p %8phN completed.\n", 6478c2ecf20Sopenharmony_ci fcport, fcport->port_name); 6488c2ecf20Sopenharmony_ci complete(&fcport->nvme_del_done); 6498c2ecf20Sopenharmony_ci} 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_cistatic struct nvme_fc_port_template qla_nvme_fc_transport = { 6528c2ecf20Sopenharmony_ci .localport_delete = qla_nvme_localport_delete, 6538c2ecf20Sopenharmony_ci .remoteport_delete = qla_nvme_remoteport_delete, 6548c2ecf20Sopenharmony_ci .create_queue = qla_nvme_alloc_queue, 6558c2ecf20Sopenharmony_ci .delete_queue = NULL, 6568c2ecf20Sopenharmony_ci .ls_req = qla_nvme_ls_req, 6578c2ecf20Sopenharmony_ci .ls_abort = qla_nvme_ls_abort, 6588c2ecf20Sopenharmony_ci .fcp_io = qla_nvme_post_cmd, 6598c2ecf20Sopenharmony_ci .fcp_abort = qla_nvme_fcp_abort, 6608c2ecf20Sopenharmony_ci .max_hw_queues = 8, 6618c2ecf20Sopenharmony_ci .max_sgl_segments = 1024, 6628c2ecf20Sopenharmony_ci .max_dif_sgl_segments = 64, 6638c2ecf20Sopenharmony_ci .dma_boundary = 0xFFFFFFFF, 6648c2ecf20Sopenharmony_ci .local_priv_sz = 8, 6658c2ecf20Sopenharmony_ci .remote_priv_sz = sizeof(struct qla_nvme_rport), 6668c2ecf20Sopenharmony_ci .lsrqst_priv_sz = sizeof(struct nvme_private), 6678c2ecf20Sopenharmony_ci .fcprqst_priv_sz = sizeof(struct nvme_private), 6688c2ecf20Sopenharmony_ci}; 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_civoid qla_nvme_unregister_remote_port(struct fc_port *fcport) 6718c2ecf20Sopenharmony_ci{ 6728c2ecf20Sopenharmony_ci int ret; 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci if (!IS_ENABLED(CONFIG_NVME_FC)) 6758c2ecf20Sopenharmony_ci return; 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci ql_log(ql_log_warn, NULL, 0x2112, 6788c2ecf20Sopenharmony_ci "%s: unregister remoteport on %p %8phN\n", 6798c2ecf20Sopenharmony_ci __func__, fcport, fcport->port_name); 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci if (test_bit(PFLG_DRIVER_REMOVING, &fcport->vha->pci_flags)) 6828c2ecf20Sopenharmony_ci nvme_fc_set_remoteport_devloss(fcport->nvme_remote_port, 0); 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci init_completion(&fcport->nvme_del_done); 6858c2ecf20Sopenharmony_ci ret = nvme_fc_unregister_remoteport(fcport->nvme_remote_port); 6868c2ecf20Sopenharmony_ci if (ret) 6878c2ecf20Sopenharmony_ci ql_log(ql_log_info, fcport->vha, 0x2114, 6888c2ecf20Sopenharmony_ci "%s: Failed to unregister nvme_remote_port (%d)\n", 6898c2ecf20Sopenharmony_ci __func__, ret); 6908c2ecf20Sopenharmony_ci wait_for_completion(&fcport->nvme_del_done); 6918c2ecf20Sopenharmony_ci} 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_civoid qla_nvme_delete(struct scsi_qla_host *vha) 6948c2ecf20Sopenharmony_ci{ 6958c2ecf20Sopenharmony_ci int nv_ret; 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci if (!IS_ENABLED(CONFIG_NVME_FC)) 6988c2ecf20Sopenharmony_ci return; 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci if (vha->nvme_local_port) { 7018c2ecf20Sopenharmony_ci init_completion(&vha->nvme_del_done); 7028c2ecf20Sopenharmony_ci ql_log(ql_log_info, vha, 0x2116, 7038c2ecf20Sopenharmony_ci "unregister localport=%p\n", 7048c2ecf20Sopenharmony_ci vha->nvme_local_port); 7058c2ecf20Sopenharmony_ci nv_ret = nvme_fc_unregister_localport(vha->nvme_local_port); 7068c2ecf20Sopenharmony_ci if (nv_ret) 7078c2ecf20Sopenharmony_ci ql_log(ql_log_info, vha, 0x2115, 7088c2ecf20Sopenharmony_ci "Unregister of localport failed\n"); 7098c2ecf20Sopenharmony_ci else 7108c2ecf20Sopenharmony_ci wait_for_completion(&vha->nvme_del_done); 7118c2ecf20Sopenharmony_ci } 7128c2ecf20Sopenharmony_ci} 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ciint qla_nvme_register_hba(struct scsi_qla_host *vha) 7158c2ecf20Sopenharmony_ci{ 7168c2ecf20Sopenharmony_ci struct nvme_fc_port_template *tmpl; 7178c2ecf20Sopenharmony_ci struct qla_hw_data *ha; 7188c2ecf20Sopenharmony_ci struct nvme_fc_port_info pinfo; 7198c2ecf20Sopenharmony_ci int ret = -EINVAL; 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci if (!IS_ENABLED(CONFIG_NVME_FC)) 7228c2ecf20Sopenharmony_ci return ret; 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci ha = vha->hw; 7258c2ecf20Sopenharmony_ci tmpl = &qla_nvme_fc_transport; 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci WARN_ON(vha->nvme_local_port); 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci qla_nvme_fc_transport.max_hw_queues = 7308c2ecf20Sopenharmony_ci min((uint8_t)(qla_nvme_fc_transport.max_hw_queues), 7318c2ecf20Sopenharmony_ci (uint8_t)(ha->max_qpairs ? ha->max_qpairs : 1)); 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci pinfo.node_name = wwn_to_u64(vha->node_name); 7348c2ecf20Sopenharmony_ci pinfo.port_name = wwn_to_u64(vha->port_name); 7358c2ecf20Sopenharmony_ci pinfo.port_role = FC_PORT_ROLE_NVME_INITIATOR; 7368c2ecf20Sopenharmony_ci pinfo.port_id = vha->d_id.b24; 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci ql_log(ql_log_info, vha, 0xffff, 7398c2ecf20Sopenharmony_ci "register_localport: host-traddr=nn-0x%llx:pn-0x%llx on portID:%x\n", 7408c2ecf20Sopenharmony_ci pinfo.node_name, pinfo.port_name, pinfo.port_id); 7418c2ecf20Sopenharmony_ci qla_nvme_fc_transport.dma_boundary = vha->host->dma_boundary; 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci ret = nvme_fc_register_localport(&pinfo, tmpl, 7448c2ecf20Sopenharmony_ci get_device(&ha->pdev->dev), &vha->nvme_local_port); 7458c2ecf20Sopenharmony_ci if (ret) { 7468c2ecf20Sopenharmony_ci ql_log(ql_log_warn, vha, 0xffff, 7478c2ecf20Sopenharmony_ci "register_localport failed: ret=%x\n", ret); 7488c2ecf20Sopenharmony_ci } else { 7498c2ecf20Sopenharmony_ci vha->nvme_local_port->private = vha; 7508c2ecf20Sopenharmony_ci } 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci return ret; 7538c2ecf20Sopenharmony_ci} 754