1848c7085STyrel Datwyler /* SPDX-License-Identifier: GPL-2.0-or-later */ 2848c7085STyrel Datwyler 3848c7085STyrel Datwyler /* 4848c7085STyrel Datwyler * ibmvfc-nvme.c -- IBM Power Virtual Fibre Channel NVMeoF HBA driver 5848c7085STyrel Datwyler * 6848c7085STyrel Datwyler * Written By: Tyrel Datwyler <tyreld@linux.ibm.com>, IBM Corporation 7848c7085STyrel Datwyler * 8848c7085STyrel Datwyler * Copyright (C) IBM Corporation, 2026 9848c7085STyrel Datwyler */ 10848c7085STyrel Datwyler 1173c13e30STyrel Datwyler #include <linux/dmapool.h> 12848c7085STyrel Datwyler #include <scsi/scsi_transport_fc.h> 13848c7085STyrel Datwyler 14848c7085STyrel Datwyler #include "ibmvfc-nvme.h" 15848c7085STyrel Datwyler 1620bec08fSTyrel Datwyler static unsigned int default_timeout = IBMVFC_DEFAULT_TIMEOUT; 1720bec08fSTyrel Datwyler 18848c7085STyrel Datwyler static void ibmvfc_nvme_localport_delete(struct nvme_fc_local_port *lport) 19848c7085STyrel Datwyler { 2013b7fdf3STyrel Datwyler struct ibmvfc_host *vhost = lport->private; 2113b7fdf3STyrel Datwyler 2213b7fdf3STyrel Datwyler vhost->nvme_local_port = NULL; 2313b7fdf3STyrel Datwyler complete(&vhost->nvme_delete_done); 24848c7085STyrel Datwyler } 25848c7085STyrel Datwyler 26848c7085STyrel Datwyler static void ibmvfc_nvme_remoteport_delete(struct nvme_fc_remote_port *rport) 27848c7085STyrel Datwyler { 2813b7fdf3STyrel Datwyler struct ibmvfc_target *tgt = rport->private; 2913b7fdf3STyrel Datwyler 3013b7fdf3STyrel Datwyler tgt->nvme_remote_port = NULL; 3113b7fdf3STyrel Datwyler complete(&tgt->nvme_delete_done); 32848c7085STyrel Datwyler } 33848c7085STyrel Datwyler 3486e49535STyrel Datwyler static int ibmvfc_nvme_create_queue(struct nvme_fc_local_port *lport, unsigned int qidx, 3586e49535STyrel Datwyler u16 qsize, void **handle) 3686e49535STyrel Datwyler { 3786e49535STyrel Datwyler struct ibmvfc_host *vhost = lport->private; 3886e49535STyrel Datwyler struct ibmvfc_nvme_qhandle *qhandle; 3986e49535STyrel Datwyler 4086e49535STyrel Datwyler if (!vhost->nvme_scrqs.active_queues) 4186e49535STyrel Datwyler return -ENODEV; 4286e49535STyrel Datwyler 4386e49535STyrel Datwyler qhandle = kzalloc_obj(struct ibmvfc_nvme_qhandle); 4486e49535STyrel Datwyler if (!qhandle) 4586e49535STyrel Datwyler return -ENOMEM; 4686e49535STyrel Datwyler 4786e49535STyrel Datwyler qhandle->cpu_id = raw_smp_processor_id(); 4886e49535STyrel Datwyler qhandle->qidx = qidx; 4986e49535STyrel Datwyler 5086e49535STyrel Datwyler /* Admin and first IO queue are both mapped to index 0 */ 5186e49535STyrel Datwyler if (qidx) 5286e49535STyrel Datwyler qhandle->index = (qidx - 1) % vhost->nvme_scrqs.active_queues; 5386e49535STyrel Datwyler else 5486e49535STyrel Datwyler qhandle->index = qidx; 5586e49535STyrel Datwyler 5686e49535STyrel Datwyler qhandle->queue = &vhost->nvme_scrqs.scrqs[qhandle->index]; 5786e49535STyrel Datwyler 5886e49535STyrel Datwyler *handle = qhandle; 5986e49535STyrel Datwyler return 0; 6086e49535STyrel Datwyler } 6186e49535STyrel Datwyler 6286e49535STyrel Datwyler static void ibmvfc_nvme_delete_queue(struct nvme_fc_local_port *lport, unsigned int qidx, 6386e49535STyrel Datwyler void *handle) 6486e49535STyrel Datwyler { 6586e49535STyrel Datwyler kfree(handle); 6686e49535STyrel Datwyler } 6786e49535STyrel Datwyler 687088e1c8STyrel Datwyler static void ibmvfc_ls_req_done(struct ibmvfc_event *evt) 697088e1c8STyrel Datwyler { 707088e1c8STyrel Datwyler struct ibmvfc_target *tgt = evt->tgt; 717088e1c8STyrel Datwyler struct ibmvfc_passthru_mad *mad = &evt->xfer_iu->passthru; 727088e1c8STyrel Datwyler struct fcnvme_ls_rqst_w0 *ls_rqst; 737088e1c8STyrel Datwyler struct fcnvme_ls_cr_assoc_acc *ls_resp; 747088e1c8STyrel Datwyler u32 status = be16_to_cpu(mad->common.status); 757088e1c8STyrel Datwyler int rc = 0; 767088e1c8STyrel Datwyler 777088e1c8STyrel Datwyler ls_rqst = (struct fcnvme_ls_rqst_w0 *)evt->ls_req->rqstaddr; 787088e1c8STyrel Datwyler ls_resp = (struct fcnvme_ls_cr_assoc_acc *)evt->ls_req->rspaddr; 797088e1c8STyrel Datwyler 807088e1c8STyrel Datwyler switch (status) { 817088e1c8STyrel Datwyler case IBMVFC_MAD_SUCCESS: 827088e1c8STyrel Datwyler tgt_dbg(tgt, "ls_req succeeded\n"); 837088e1c8STyrel Datwyler if ((ls_rqst->ls_cmd == FCNVME_LS_CREATE_ASSOCIATION) && 847088e1c8STyrel Datwyler (ls_resp->hdr.w0.ls_cmd == FCNVME_LS_ACC)) { 857088e1c8STyrel Datwyler tgt->assoc_id = be64_to_cpu(ls_resp->associd.association_id); 867088e1c8STyrel Datwyler tgt_dbg(tgt, "assoc_id 0x%llx\n", tgt->assoc_id); 877088e1c8STyrel Datwyler } 887088e1c8STyrel Datwyler break; 897088e1c8STyrel Datwyler case IBMVFC_MAD_DRIVER_FAILED: 907088e1c8STyrel Datwyler break; 917088e1c8STyrel Datwyler case IBMVFC_MAD_FAILED: 927088e1c8STyrel Datwyler default: 937088e1c8STyrel Datwyler tgt_info(tgt, "ls_req failed: %s (%x:%x) rc=0x%02X\n", 947088e1c8STyrel Datwyler ibmvfc_get_cmd_error(be16_to_cpu(mad->iu.status), be16_to_cpu(mad->iu.error)), 957088e1c8STyrel Datwyler be16_to_cpu(mad->iu.status), be16_to_cpu(mad->iu.error), status); 967088e1c8STyrel Datwyler break; 977088e1c8STyrel Datwyler } 987088e1c8STyrel Datwyler 997088e1c8STyrel Datwyler if (status) 1007088e1c8STyrel Datwyler rc = -EIO; 1017088e1c8STyrel Datwyler 1027088e1c8STyrel Datwyler evt->ls_req->done(evt->ls_req, rc); 1037088e1c8STyrel Datwyler 1047088e1c8STyrel Datwyler kref_put(&tgt->kref, ibmvfc_release_tgt); 1057088e1c8STyrel Datwyler ibmvfc_free_event(evt); 1067088e1c8STyrel Datwyler } 1077088e1c8STyrel Datwyler 1087088e1c8STyrel Datwyler static void ibmvfc_init_ls_req(struct ibmvfc_event *evt, struct nvmefc_ls_req *ls_req) 1097088e1c8STyrel Datwyler { 1107088e1c8STyrel Datwyler struct ibmvfc_passthru_mad *mad = &evt->iu.passthru; 1117088e1c8STyrel Datwyler 1127088e1c8STyrel Datwyler memset(mad, 0, sizeof(*mad)); 1137088e1c8STyrel Datwyler mad->common.version = cpu_to_be32(2); 1147088e1c8STyrel Datwyler mad->common.opcode = cpu_to_be32(IBMVFC_NVMF_PASSTHRU); 1157088e1c8STyrel Datwyler mad->common.length = cpu_to_be16(sizeof(*mad) - sizeof(mad->fc_iu) - sizeof(mad->iu)); 1167088e1c8STyrel Datwyler mad->cmd_ioba.va = cpu_to_be64((u64)be64_to_cpu(evt->crq.ioba) + 1177088e1c8STyrel Datwyler offsetof(struct ibmvfc_passthru_mad, iu)); 1187088e1c8STyrel Datwyler mad->cmd_ioba.len = cpu_to_be32(sizeof(mad->iu)); 1197088e1c8STyrel Datwyler mad->iu.cmd_len = cpu_to_be32(ls_req->rqstlen); 1207088e1c8STyrel Datwyler mad->iu.rsp_len = cpu_to_be32(ls_req->rsplen); 1217088e1c8STyrel Datwyler mad->iu.cmd.va = cpu_to_be64(ls_req->rqstdma); 1227088e1c8STyrel Datwyler mad->iu.cmd.len = cpu_to_be32(ls_req->rqstlen); 1237088e1c8STyrel Datwyler mad->iu.rsp.va = cpu_to_be64(ls_req->rspdma); 1247088e1c8STyrel Datwyler mad->iu.rsp.len = cpu_to_be32(ls_req->rsplen); 1257088e1c8STyrel Datwyler } 1267088e1c8STyrel Datwyler 127848c7085STyrel Datwyler static int ibmvfc_nvme_ls_req(struct nvme_fc_local_port *lport, 128848c7085STyrel Datwyler struct nvme_fc_remote_port *rport, 129848c7085STyrel Datwyler struct nvmefc_ls_req *ls_req) 130848c7085STyrel Datwyler { 1317088e1c8STyrel Datwyler struct ibmvfc_host *vhost = lport->private; 1327088e1c8STyrel Datwyler struct ibmvfc_target *tgt = rport->private; 1337088e1c8STyrel Datwyler struct ibmvfc_passthru_mad *mad; 1347088e1c8STyrel Datwyler struct ibmvfc_event *evt; 1357088e1c8STyrel Datwyler 1367088e1c8STyrel Datwyler kref_get(&tgt->kref); 1377088e1c8STyrel Datwyler evt = ibmvfc_get_event(&vhost->crq); 1387088e1c8STyrel Datwyler if (!evt) { 1397088e1c8STyrel Datwyler kref_put(&tgt->kref, ibmvfc_release_tgt); 1407088e1c8STyrel Datwyler return -EBUSY; 1417088e1c8STyrel Datwyler } 1427088e1c8STyrel Datwyler 1437088e1c8STyrel Datwyler ibmvfc_init_event(evt, ibmvfc_ls_req_done, IBMVFC_MAD_FORMAT); 1447088e1c8STyrel Datwyler evt->tgt = tgt; 1457088e1c8STyrel Datwyler evt->ls_req = ls_req; 1467088e1c8STyrel Datwyler ls_req->private = evt; 1477088e1c8STyrel Datwyler 1487088e1c8STyrel Datwyler ibmvfc_init_ls_req(evt, ls_req); 1497088e1c8STyrel Datwyler mad = &evt->iu.passthru; 1507088e1c8STyrel Datwyler mad->iu.flags = cpu_to_be32(IBMVFC_FC4_LS_DSC_CTRL); 1517088e1c8STyrel Datwyler mad->iu.scsi_id = cpu_to_be64(tgt->scsi_id); 1527088e1c8STyrel Datwyler mad->iu.cancel_key = cpu_to_be32((u64)evt); 1537088e1c8STyrel Datwyler mad->iu.target_wwpn = cpu_to_be64(tgt->wwpn); 1547088e1c8STyrel Datwyler 1557088e1c8STyrel Datwyler ibmvfc_dbg(vhost, "nvme_ls_req\n"); 1567088e1c8STyrel Datwyler if (ibmvfc_send_event(evt, vhost, IBMVFC_FC4_LS_PLUS_CANCEL_TIMEOUT)) { 1577088e1c8STyrel Datwyler kref_put(&tgt->kref, ibmvfc_release_tgt); 1587088e1c8STyrel Datwyler return -ENXIO; 1597088e1c8STyrel Datwyler } 1607088e1c8STyrel Datwyler 161848c7085STyrel Datwyler return 0; 162848c7085STyrel Datwyler } 163848c7085STyrel Datwyler 16420bec08fSTyrel Datwyler static void ibmvfc_sync_nvme_completion(struct ibmvfc_event *evt) 16520bec08fSTyrel Datwyler { 16620bec08fSTyrel Datwyler /* copy the response back */ 16720bec08fSTyrel Datwyler if (evt->sync_iu) 16820bec08fSTyrel Datwyler *evt->sync_iu = *evt->xfer_iu; 16920bec08fSTyrel Datwyler 17020bec08fSTyrel Datwyler complete(&evt->comp); 17120bec08fSTyrel Datwyler } 17220bec08fSTyrel Datwyler 17320bec08fSTyrel Datwyler static void ibmvfc_init_ls_abort(struct ibmvfc_event *evt, struct nvmefc_ls_req *ls_abort) 17420bec08fSTyrel Datwyler { 17520bec08fSTyrel Datwyler struct ibmvfc_tmf *tmf; 17620bec08fSTyrel Datwyler struct ibmvfc_event *abt_evt = ls_abort->private; 17720bec08fSTyrel Datwyler struct ibmvfc_target *tgt = abt_evt->tgt; 17820bec08fSTyrel Datwyler struct ibmvfc_host *vhost = evt->vhost; 17920bec08fSTyrel Datwyler 18020bec08fSTyrel Datwyler tmf = &evt->iu.tmf; 18120bec08fSTyrel Datwyler memset(tmf, 0, sizeof(*tmf)); 18220bec08fSTyrel Datwyler tmf->common.version = cpu_to_be32(2); 18320bec08fSTyrel Datwyler tmf->target_wwpn = cpu_to_be64(tgt->wwpn); 18420bec08fSTyrel Datwyler tmf->common.opcode = cpu_to_be32(IBMVFC_NVMF_TMF_MAD); 18520bec08fSTyrel Datwyler tmf->common.length = cpu_to_be16(sizeof(*tmf)); 18620bec08fSTyrel Datwyler if (vhost->state != IBMVFC_ACTIVE) 18720bec08fSTyrel Datwyler if (!ibmvfc_check_caps(vhost, IBMVFC_CAN_SUPPRESS_ABTS)) 18820bec08fSTyrel Datwyler tmf->flags = cpu_to_be32(IBMVFC_TMF_SUPPRESS_ABTS); 18920bec08fSTyrel Datwyler tmf->cancel_key = cpu_to_be32((u64)abt_evt); 19020bec08fSTyrel Datwyler tmf->my_cancel_key = cpu_to_be32((u64)evt); 19120bec08fSTyrel Datwyler tmf->assoc_id = cpu_to_be64(tgt->assoc_id); 19220bec08fSTyrel Datwyler 19320bec08fSTyrel Datwyler init_completion(&evt->comp); 19420bec08fSTyrel Datwyler } 19520bec08fSTyrel Datwyler 196848c7085STyrel Datwyler static void ibmvfc_nvme_ls_abort(struct nvme_fc_local_port *lport, 197848c7085STyrel Datwyler struct nvme_fc_remote_port *rport, 198848c7085STyrel Datwyler struct nvmefc_ls_req *ls_abort) 199848c7085STyrel Datwyler { 20020bec08fSTyrel Datwyler struct ibmvfc_host *vhost = lport->private; 20120bec08fSTyrel Datwyler struct ibmvfc_target *tgt = rport->private; 20220bec08fSTyrel Datwyler struct ibmvfc_event *evt; 20320bec08fSTyrel Datwyler union ibmvfc_iu rsp; 20420bec08fSTyrel Datwyler unsigned long flags; 20520bec08fSTyrel Datwyler u16 status; 20620bec08fSTyrel Datwyler 20720bec08fSTyrel Datwyler evt = ibmvfc_get_event(&vhost->crq); 20820bec08fSTyrel Datwyler if (!vhost->logged_in || !evt) 20920bec08fSTyrel Datwyler return; 21020bec08fSTyrel Datwyler 21120bec08fSTyrel Datwyler spin_lock_irqsave(vhost->host->host_lock, flags); 21220bec08fSTyrel Datwyler kref_get(&tgt->kref); 21320bec08fSTyrel Datwyler ibmvfc_init_event(evt, ibmvfc_sync_nvme_completion, IBMVFC_MAD_FORMAT); 21420bec08fSTyrel Datwyler ibmvfc_init_ls_abort(evt, ls_abort); 21520bec08fSTyrel Datwyler evt->sync_iu = &rsp; 21620bec08fSTyrel Datwyler 21720bec08fSTyrel Datwyler if (ibmvfc_send_event(evt, vhost, default_timeout)) 21820bec08fSTyrel Datwyler goto out; 21920bec08fSTyrel Datwyler 22020bec08fSTyrel Datwyler spin_unlock_irqrestore(vhost->host->host_lock, flags); 22120bec08fSTyrel Datwyler 22220bec08fSTyrel Datwyler wait_for_completion(&evt->comp); 22320bec08fSTyrel Datwyler status = be16_to_cpu(rsp.mad_common.status); 22420bec08fSTyrel Datwyler spin_lock_irqsave(vhost->host->host_lock, flags); 22520bec08fSTyrel Datwyler ibmvfc_free_event(evt); 22620bec08fSTyrel Datwyler out: 22720bec08fSTyrel Datwyler spin_unlock_irqrestore(vhost->host->host_lock, flags); 22820bec08fSTyrel Datwyler ibmvfc_dbg(vhost, "ls_abort: cancel failed with rc=%x\n", status); 22920bec08fSTyrel Datwyler kref_put(&tgt->kref, ibmvfc_release_tgt); 230848c7085STyrel Datwyler } 231848c7085STyrel Datwyler 23273c13e30STyrel Datwyler static void ibmvfc_nvme_done(struct ibmvfc_event *evt) 23373c13e30STyrel Datwyler { 23473c13e30STyrel Datwyler struct ibmvfc_cmd *vfc_cmd = &evt->xfer_iu->cmd; 23573c13e30STyrel Datwyler struct nvmefc_fcp_req *fcp_req = evt->fcp_req; 23673c13e30STyrel Datwyler struct nvme_fc_ersp_iu *ersp = (struct nvme_fc_ersp_iu *)fcp_req->rspaddr; 23773c13e30STyrel Datwyler struct nvme_completion *cqe = &ersp->cqe; 23873c13e30STyrel Datwyler struct nvme_command *sqe = &((struct nvme_fc_cmd_iu *)fcp_req->cmdaddr)->sqe; 23973c13e30STyrel Datwyler 24073c13e30STyrel Datwyler ibmvfc_dbg(evt->vhost, "fc_done: (%x:%x)\n", be16_to_cpu(vfc_cmd->status), 24173c13e30STyrel Datwyler be16_to_cpu(vfc_cmd->error)); 24273c13e30STyrel Datwyler ibmvfc_dbg(evt->vhost, "fc_done: cmdlen: %d, rsplen %d, payload_len %d\n", 24373c13e30STyrel Datwyler fcp_req->cmdlen, fcp_req->rsplen, fcp_req->payload_length); 24473c13e30STyrel Datwyler 24573c13e30STyrel Datwyler fcp_req->status = 0; 24673c13e30STyrel Datwyler if (!vfc_cmd->status) { 24773c13e30STyrel Datwyler fcp_req->rcv_rsplen = NVME_FC_SIZEOF_ZEROS_RSP; 24873c13e30STyrel Datwyler fcp_req->transferred_length = fcp_req->payload_length; 24973c13e30STyrel Datwyler } else if (be16_to_cpu(vfc_cmd->status) & IBMVFC_FC_NVME_STATUS) { 25073c13e30STyrel Datwyler fcp_req->rcv_rsplen = sizeof(struct nvme_fc_ersp_iu); 25173c13e30STyrel Datwyler fcp_req->transferred_length = be32_to_cpu(ersp->xfrd_len); 25273c13e30STyrel Datwyler if (be16_to_cpu(vfc_cmd->error) & IBMVFC_NVMS_VALID_NODMA_CQE) 25373c13e30STyrel Datwyler cqe->command_id = sqe->common.command_id; 25473c13e30STyrel Datwyler } else { 25573c13e30STyrel Datwyler fcp_req->rcv_rsplen = 0; 25673c13e30STyrel Datwyler fcp_req->transferred_length = 0; 25773c13e30STyrel Datwyler fcp_req->status = NVME_SC_INTERNAL; 25873c13e30STyrel Datwyler } 25973c13e30STyrel Datwyler 26073c13e30STyrel Datwyler fcp_req->done(fcp_req); 26173c13e30STyrel Datwyler ibmvfc_free_event(evt); 26273c13e30STyrel Datwyler } 26373c13e30STyrel Datwyler 26473c13e30STyrel Datwyler static struct ibmvfc_cmd *ibmvfc_nvme_init_vfc_cmd(struct ibmvfc_event *evt, 26573c13e30STyrel Datwyler struct nvme_fc_remote_port *rport, 26673c13e30STyrel Datwyler struct nvmefc_fcp_req *fcp_req) 26773c13e30STyrel Datwyler { 26873c13e30STyrel Datwyler struct ibmvfc_target *tgt = rport->private; 26973c13e30STyrel Datwyler struct ibmvfc_cmd *vfc_cmd = &evt->iu.cmd; 27073c13e30STyrel Datwyler 27173c13e30STyrel Datwyler memset(vfc_cmd, 0, sizeof(*vfc_cmd)); 27273c13e30STyrel Datwyler 27373c13e30STyrel Datwyler vfc_cmd->resp.va = cpu_to_be64(fcp_req->rspdma); 27473c13e30STyrel Datwyler vfc_cmd->resp.len = cpu_to_be32(fcp_req->rsplen); 27573c13e30STyrel Datwyler vfc_cmd->frame_type = cpu_to_be32(IBMVFC_NVME_FCP_TYPE); 27673c13e30STyrel Datwyler vfc_cmd->flags |= cpu_to_be16(IBMVFC_NVMEOF_PROTOCOL); 27773c13e30STyrel Datwyler vfc_cmd->payload_len = cpu_to_be32(fcp_req->cmdlen); 27873c13e30STyrel Datwyler vfc_cmd->resp_len = cpu_to_be32(fcp_req->rsplen); 27973c13e30STyrel Datwyler vfc_cmd->cancel_key = cpu_to_be32((u64)evt); 28073c13e30STyrel Datwyler vfc_cmd->target_wwpn = cpu_to_be64(rport->port_name); 28173c13e30STyrel Datwyler vfc_cmd->tgt_scsi_id = cpu_to_be64(rport->port_id); 28273c13e30STyrel Datwyler vfc_cmd->assoc_id = cpu_to_be64(tgt->assoc_id); 28373c13e30STyrel Datwyler 28473c13e30STyrel Datwyler memcpy(&vfc_cmd->v3nvme.iu, fcp_req->cmdaddr, fcp_req->cmdlen); 28573c13e30STyrel Datwyler 28673c13e30STyrel Datwyler return vfc_cmd; 28773c13e30STyrel Datwyler } 28873c13e30STyrel Datwyler 28973c13e30STyrel Datwyler static void ibmvfc_nvme_map_sg_list(struct nvmefc_fcp_req *fcp_req, 29073c13e30STyrel Datwyler struct srp_direct_buf *md) 29173c13e30STyrel Datwyler { 29273c13e30STyrel Datwyler int i; 29373c13e30STyrel Datwyler struct scatterlist *sg; 29473c13e30STyrel Datwyler 29573c13e30STyrel Datwyler for_each_sg(fcp_req->first_sgl, sg, fcp_req->sg_cnt, i) { 29673c13e30STyrel Datwyler md[i].va = cpu_to_be64(sg_dma_address(sg)); 29773c13e30STyrel Datwyler md[i].len = cpu_to_be32(sg_dma_len(sg)); 29873c13e30STyrel Datwyler md[i].key = 0; 29973c13e30STyrel Datwyler } 30073c13e30STyrel Datwyler } 30173c13e30STyrel Datwyler 30273c13e30STyrel Datwyler static int ibmvfc_nvme_map_sg_data(struct nvmefc_fcp_req *fcp_req, 30373c13e30STyrel Datwyler struct ibmvfc_event *evt, 30473c13e30STyrel Datwyler struct ibmvfc_cmd *vfc_cmd) 30573c13e30STyrel Datwyler { 30673c13e30STyrel Datwyler struct srp_direct_buf *data = &vfc_cmd->ioba; 30773c13e30STyrel Datwyler struct ibmvfc_host *vhost = evt->vhost; 30873c13e30STyrel Datwyler 30973c13e30STyrel Datwyler if (!fcp_req->sg_cnt) { 31073c13e30STyrel Datwyler vfc_cmd->flags |= cpu_to_be16(IBMVFC_NO_MEM_DESC); 31173c13e30STyrel Datwyler return 0; 31273c13e30STyrel Datwyler } 31373c13e30STyrel Datwyler 31473c13e30STyrel Datwyler if (fcp_req->io_dir == NVMEFC_FCP_WRITE) 31573c13e30STyrel Datwyler vfc_cmd->flags |= cpu_to_be16(IBMVFC_WRITE); 31673c13e30STyrel Datwyler else 31773c13e30STyrel Datwyler vfc_cmd->flags |= cpu_to_be16(IBMVFC_READ); 31873c13e30STyrel Datwyler 31973c13e30STyrel Datwyler if (fcp_req->sg_cnt == 1) { 32073c13e30STyrel Datwyler ibmvfc_nvme_map_sg_list(fcp_req, data); 32173c13e30STyrel Datwyler return 0; 32273c13e30STyrel Datwyler } 32373c13e30STyrel Datwyler 32473c13e30STyrel Datwyler vfc_cmd->flags |= cpu_to_be16(IBMVFC_SCATTERLIST); 32573c13e30STyrel Datwyler 32673c13e30STyrel Datwyler if (!evt->ext_list) { 32773c13e30STyrel Datwyler evt->ext_list = dma_pool_alloc(vhost->sg_pool, GFP_ATOMIC, 32873c13e30STyrel Datwyler &evt->ext_list_token); 32973c13e30STyrel Datwyler 33073c13e30STyrel Datwyler if (!evt->ext_list) 33173c13e30STyrel Datwyler return -ENOMEM; 33273c13e30STyrel Datwyler } 33373c13e30STyrel Datwyler 33473c13e30STyrel Datwyler ibmvfc_nvme_map_sg_list(fcp_req, evt->ext_list); 33573c13e30STyrel Datwyler 33673c13e30STyrel Datwyler data->va = cpu_to_be64(evt->ext_list_token); 33773c13e30STyrel Datwyler data->len = cpu_to_be32(fcp_req->sg_cnt * sizeof(struct srp_direct_buf)); 33873c13e30STyrel Datwyler data->key = 0; 33973c13e30STyrel Datwyler return 0; 34073c13e30STyrel Datwyler } 34173c13e30STyrel Datwyler 342848c7085STyrel Datwyler static int ibmvfc_nvme_fcp_io(struct nvme_fc_local_port *lport, 343848c7085STyrel Datwyler struct nvme_fc_remote_port *rport, 344848c7085STyrel Datwyler void *hw_queue_handle, 345848c7085STyrel Datwyler struct nvmefc_fcp_req *fcp_req) 346848c7085STyrel Datwyler { 34773c13e30STyrel Datwyler struct ibmvfc_host *vhost = lport->private; 34873c13e30STyrel Datwyler struct ibmvfc_nvme_qhandle *qhandle = hw_queue_handle; 34973c13e30STyrel Datwyler struct ibmvfc_cmd *vfc_cmd; 35073c13e30STyrel Datwyler struct ibmvfc_event *evt; 35173c13e30STyrel Datwyler int rc; 35273c13e30STyrel Datwyler 35373c13e30STyrel Datwyler ibmvfc_dbg(vhost, "nvme_fcp_io\n"); 35473c13e30STyrel Datwyler evt = ibmvfc_get_event(qhandle->queue); 35573c13e30STyrel Datwyler if (!evt) 35673c13e30STyrel Datwyler return -EBUSY; 35773c13e30STyrel Datwyler 35873c13e30STyrel Datwyler evt->hwq = qhandle->index; 35973c13e30STyrel Datwyler ibmvfc_dbg(vhost, "vfc-nvme-mq-%d\n", evt->hwq); 36073c13e30STyrel Datwyler 36173c13e30STyrel Datwyler ibmvfc_init_event(evt, ibmvfc_nvme_done, IBMVFC_CMD_FORMAT); 36273c13e30STyrel Datwyler evt->fcp_req = fcp_req; 36373c13e30STyrel Datwyler fcp_req->private = evt; 36473c13e30STyrel Datwyler 36573c13e30STyrel Datwyler vfc_cmd = ibmvfc_nvme_init_vfc_cmd(evt, rport, fcp_req); 36673c13e30STyrel Datwyler 36773c13e30STyrel Datwyler vfc_cmd->correlation = cpu_to_be64((u64)evt); 36873c13e30STyrel Datwyler 36973c13e30STyrel Datwyler if (likely(!(rc = ibmvfc_nvme_map_sg_data(fcp_req, evt, vfc_cmd)))) 37073c13e30STyrel Datwyler return ibmvfc_send_event(evt, vhost, 0); 37173c13e30STyrel Datwyler 37273c13e30STyrel Datwyler ibmvfc_free_event(evt); 37373c13e30STyrel Datwyler 37473c13e30STyrel Datwyler return rc; 375848c7085STyrel Datwyler } 376848c7085STyrel Datwyler 377*4e70b879STyrel Datwyler static void ibmvfc_init_fcp_abort(struct ibmvfc_event *evt, 378*4e70b879STyrel Datwyler struct nvmefc_fcp_req *abort_req) 379*4e70b879STyrel Datwyler { 380*4e70b879STyrel Datwyler struct ibmvfc_tmf *tmf; 381*4e70b879STyrel Datwyler struct ibmvfc_event *abt_evt = abort_req->private; 382*4e70b879STyrel Datwyler struct ibmvfc_target *tgt = abt_evt->tgt; 383*4e70b879STyrel Datwyler 384*4e70b879STyrel Datwyler tmf = &evt->iu.tmf; 385*4e70b879STyrel Datwyler memset(tmf, 0, sizeof(*tmf)); 386*4e70b879STyrel Datwyler tmf->common.version = cpu_to_be32(2); 387*4e70b879STyrel Datwyler tmf->common.opcode = cpu_to_be32(IBMVFC_NVMF_TMF_MAD); 388*4e70b879STyrel Datwyler tmf->common.length = cpu_to_be16(sizeof(*tmf)); 389*4e70b879STyrel Datwyler tmf->flags = cpu_to_be32(IBMVFC_TMF_ABORT_TASK | IBMVFC_TMF_NVMF_ASSOC); 390*4e70b879STyrel Datwyler tmf->cancel_key = cpu_to_be32((u64)abt_evt); 391*4e70b879STyrel Datwyler tmf->my_cancel_key = cpu_to_be32((u64)evt); 392*4e70b879STyrel Datwyler tmf->target_wwpn = cpu_to_be64(tgt->wwpn); 393*4e70b879STyrel Datwyler tmf->assoc_id = cpu_to_be64(tgt->assoc_id); 394*4e70b879STyrel Datwyler tmf->task_tag = cpu_to_be64((u64)abt_evt); 395*4e70b879STyrel Datwyler 396*4e70b879STyrel Datwyler init_completion(&evt->comp); 397*4e70b879STyrel Datwyler } 398*4e70b879STyrel Datwyler 399848c7085STyrel Datwyler static void ibmvfc_nvme_fcp_abort(struct nvme_fc_local_port *lport, 400848c7085STyrel Datwyler struct nvme_fc_remote_port *rport, 401848c7085STyrel Datwyler void *hw_queue_handle, 402848c7085STyrel Datwyler struct nvmefc_fcp_req *abort_req) 403848c7085STyrel Datwyler { 404*4e70b879STyrel Datwyler struct ibmvfc_host *vhost = lport->private; 405*4e70b879STyrel Datwyler struct ibmvfc_target *tgt = rport->private; 406*4e70b879STyrel Datwyler struct ibmvfc_event *evt, *abt_evt = abort_req->private; 407*4e70b879STyrel Datwyler struct ibmvfc_queue *queue; 408*4e70b879STyrel Datwyler union ibmvfc_iu rsp; 409*4e70b879STyrel Datwyler unsigned long flags; 410*4e70b879STyrel Datwyler u16 status = 0; 411*4e70b879STyrel Datwyler 412*4e70b879STyrel Datwyler if (!abt_evt) 413*4e70b879STyrel Datwyler return; 414*4e70b879STyrel Datwyler 415*4e70b879STyrel Datwyler queue = abt_evt->queue; 416*4e70b879STyrel Datwyler if (!vhost->logged_in || !queue) 417*4e70b879STyrel Datwyler return; 418*4e70b879STyrel Datwyler 419*4e70b879STyrel Datwyler evt = ibmvfc_get_event(queue); 420*4e70b879STyrel Datwyler if (!evt) 421*4e70b879STyrel Datwyler return; 422*4e70b879STyrel Datwyler 423*4e70b879STyrel Datwyler spin_lock_irqsave(queue->q_lock, flags); 424*4e70b879STyrel Datwyler kref_get(&tgt->kref); 425*4e70b879STyrel Datwyler ibmvfc_init_event(evt, ibmvfc_sync_nvme_completion, IBMVFC_MAD_FORMAT); 426*4e70b879STyrel Datwyler ibmvfc_init_fcp_abort(evt, abort_req); 427*4e70b879STyrel Datwyler evt->sync_iu = &rsp; 428*4e70b879STyrel Datwyler 429*4e70b879STyrel Datwyler if (ibmvfc_send_event(evt, vhost, default_timeout)) 430*4e70b879STyrel Datwyler goto out; 431*4e70b879STyrel Datwyler 432*4e70b879STyrel Datwyler spin_unlock_irqrestore(queue->q_lock, flags); 433*4e70b879STyrel Datwyler 434*4e70b879STyrel Datwyler wait_for_completion(&evt->comp); 435*4e70b879STyrel Datwyler status = be16_to_cpu(rsp.mad_common.status); 436*4e70b879STyrel Datwyler 437*4e70b879STyrel Datwyler spin_lock_irqsave(queue->q_lock, flags); 438*4e70b879STyrel Datwyler ibmvfc_free_event(evt); 439*4e70b879STyrel Datwyler out: 440*4e70b879STyrel Datwyler spin_unlock_irqrestore(queue->q_lock, flags); 441*4e70b879STyrel Datwyler 442*4e70b879STyrel Datwyler if (status) 443*4e70b879STyrel Datwyler ibmvfc_dbg(vhost, "fcp_abort: cancel failed with rc=%x\n", status); 444*4e70b879STyrel Datwyler 445*4e70b879STyrel Datwyler kref_put(&tgt->kref, ibmvfc_release_tgt); 446848c7085STyrel Datwyler } 447848c7085STyrel Datwyler 448848c7085STyrel Datwyler static struct nvme_fc_port_template ibmvfc_nvme_fc_transport = { 449848c7085STyrel Datwyler .localport_delete = ibmvfc_nvme_localport_delete, 450848c7085STyrel Datwyler .remoteport_delete = ibmvfc_nvme_remoteport_delete, 45186e49535STyrel Datwyler .create_queue = ibmvfc_nvme_create_queue, 45286e49535STyrel Datwyler .delete_queue = ibmvfc_nvme_delete_queue, 453848c7085STyrel Datwyler .ls_req = ibmvfc_nvme_ls_req, 454848c7085STyrel Datwyler .ls_abort = ibmvfc_nvme_ls_abort, 455848c7085STyrel Datwyler .fcp_io = ibmvfc_nvme_fcp_io, 456848c7085STyrel Datwyler .fcp_abort = ibmvfc_nvme_fcp_abort, 457848c7085STyrel Datwyler .map_queues = NULL, 458848c7085STyrel Datwyler .max_hw_queues = IBMVFC_NVME_HW_QUEUES, 459848c7085STyrel Datwyler .max_sgl_segments = 1024, 460848c7085STyrel Datwyler .max_dif_sgl_segments = 64, 461848c7085STyrel Datwyler .dma_boundary = 0xFFFFFFFF, 462848c7085STyrel Datwyler .local_priv_sz = sizeof(struct ibmvfc_host *), 463848c7085STyrel Datwyler .remote_priv_sz = sizeof(struct ibmvfc_target *), 464848c7085STyrel Datwyler .lsrqst_priv_sz = sizeof(struct ibmvfc_event *), 465848c7085STyrel Datwyler .fcprqst_priv_sz = sizeof(struct ibmvfc_event *), 466848c7085STyrel Datwyler }; 467848c7085STyrel Datwyler 468848c7085STyrel Datwyler int ibmvfc_nvme_register_remoteport(struct ibmvfc_target *tgt) 469848c7085STyrel Datwyler { 47013b7fdf3STyrel Datwyler struct ibmvfc_host *vhost = tgt->vhost; 47113b7fdf3STyrel Datwyler struct nvme_fc_port_info pinfo; 47213b7fdf3STyrel Datwyler int rc; 47313b7fdf3STyrel Datwyler 474848c7085STyrel Datwyler if (!IS_ENABLED(CONFIG_NVME_FC)) 475848c7085STyrel Datwyler return 0; 476848c7085STyrel Datwyler 47713b7fdf3STyrel Datwyler if (!vhost->nvme_local_port) { 47813b7fdf3STyrel Datwyler dev_err(vhost->dev, "Attempt to register NVMe fc remoteport without valid localport\n"); 47913b7fdf3STyrel Datwyler return -EINVAL; 48013b7fdf3STyrel Datwyler } 48113b7fdf3STyrel Datwyler 48213b7fdf3STyrel Datwyler memset(&pinfo, 0, sizeof(struct nvme_fc_port_info)); 48313b7fdf3STyrel Datwyler pinfo.node_name = tgt->ids.node_name; 48413b7fdf3STyrel Datwyler pinfo.port_name = tgt->ids.port_name; 48513b7fdf3STyrel Datwyler pinfo.port_id = tgt->ids.port_id; 48613b7fdf3STyrel Datwyler pinfo.port_role = FC_PORT_ROLE_NVME_TARGET; 48713b7fdf3STyrel Datwyler 48813b7fdf3STyrel Datwyler rc = nvme_fc_register_remoteport(vhost->nvme_local_port, &pinfo, 48913b7fdf3STyrel Datwyler &tgt->nvme_remote_port); 49013b7fdf3STyrel Datwyler 49113b7fdf3STyrel Datwyler if (!rc) { 49213b7fdf3STyrel Datwyler ibmvfc_log(vhost, 2, "register_remoteport: traddr=nn-0x%llx:pn-0x%llx PortID:%x\n", 49313b7fdf3STyrel Datwyler pinfo.node_name, pinfo.port_name, pinfo.port_id); 49413b7fdf3STyrel Datwyler tgt->nvme_remote_port->private = tgt; 49513b7fdf3STyrel Datwyler } 49613b7fdf3STyrel Datwyler 49713b7fdf3STyrel Datwyler return rc; 498848c7085STyrel Datwyler } 499848c7085STyrel Datwyler 500848c7085STyrel Datwyler void ibmvfc_nvme_unregister_remoteport(struct ibmvfc_target *tgt) 501848c7085STyrel Datwyler { 50213b7fdf3STyrel Datwyler struct ibmvfc_host *vhost = tgt->vhost; 50313b7fdf3STyrel Datwyler struct nvme_fc_remote_port *rport = tgt->nvme_remote_port; 50413b7fdf3STyrel Datwyler int rc; 50513b7fdf3STyrel Datwyler 506848c7085STyrel Datwyler if (!IS_ENABLED(CONFIG_NVME_FC)) 507848c7085STyrel Datwyler return; 50813b7fdf3STyrel Datwyler 50913b7fdf3STyrel Datwyler if (!tgt->nvme_remote_port) 51013b7fdf3STyrel Datwyler return; 51113b7fdf3STyrel Datwyler 51213b7fdf3STyrel Datwyler ibmvfc_log(vhost, 2, "unregister_remoteport: traddr=nn-0x%llx:pn-0x%llx PortID:%x\n", 51313b7fdf3STyrel Datwyler rport->node_name, rport->port_name, rport->port_id); 51413b7fdf3STyrel Datwyler init_completion(&tgt->nvme_delete_done); 51513b7fdf3STyrel Datwyler rc = nvme_fc_unregister_remoteport(tgt->nvme_remote_port); 51613b7fdf3STyrel Datwyler 51713b7fdf3STyrel Datwyler if (!rc) { 51813b7fdf3STyrel Datwyler wait_for_completion(&tgt->nvme_delete_done); 51913b7fdf3STyrel Datwyler } 520848c7085STyrel Datwyler } 521848c7085STyrel Datwyler 522848c7085STyrel Datwyler int ibmvfc_nvme_register(struct ibmvfc_host *vhost) 523848c7085STyrel Datwyler { 52413b7fdf3STyrel Datwyler struct nvme_fc_port_info pinfo; 52513b7fdf3STyrel Datwyler int rc; 52613b7fdf3STyrel Datwyler 527848c7085STyrel Datwyler if (!IS_ENABLED(CONFIG_NVME_FC)) 528848c7085STyrel Datwyler return 0; 529848c7085STyrel Datwyler 53013b7fdf3STyrel Datwyler pinfo.node_name = fc_host_node_name(vhost->host); 53113b7fdf3STyrel Datwyler pinfo.port_name = fc_host_port_name(vhost->host); 53213b7fdf3STyrel Datwyler pinfo.port_id = fc_host_port_id(vhost->host); 53313b7fdf3STyrel Datwyler pinfo.port_role = FC_PORT_ROLE_NVME_INITIATOR; 53413b7fdf3STyrel Datwyler pinfo.dev_loss_tmo = 0; 53513b7fdf3STyrel Datwyler 53613b7fdf3STyrel Datwyler rc = nvme_fc_register_localport(&pinfo, &ibmvfc_nvme_fc_transport, 5373831863fSTyrel Datwyler get_device(vhost->dev), 5383831863fSTyrel Datwyler &vhost->nvme_local_port); 53913b7fdf3STyrel Datwyler 54013b7fdf3STyrel Datwyler if (!rc) { 54113b7fdf3STyrel Datwyler ibmvfc_log(vhost, 2, "register_localport: host-traddr=nn-0x%llx:pn-0x%llx on portID:%x\n", 54213b7fdf3STyrel Datwyler pinfo.node_name, pinfo.port_name, pinfo.port_id); 54313b7fdf3STyrel Datwyler vhost->nvme_local_port->private = vhost; 5443831863fSTyrel Datwyler } else { 54513b7fdf3STyrel Datwyler dev_err(vhost->dev, "Failed to register NVMe fc localport (%d)\n", rc); 5463831863fSTyrel Datwyler put_device(vhost->dev); 5473831863fSTyrel Datwyler } 54813b7fdf3STyrel Datwyler 54913b7fdf3STyrel Datwyler return rc; 550848c7085STyrel Datwyler } 551848c7085STyrel Datwyler 552848c7085STyrel Datwyler void ibmvfc_nvme_unregister(struct ibmvfc_host *vhost) 553848c7085STyrel Datwyler { 55413b7fdf3STyrel Datwyler int rc; 55513b7fdf3STyrel Datwyler 556848c7085STyrel Datwyler if (!IS_ENABLED(CONFIG_NVME_FC)) 557848c7085STyrel Datwyler return; 55813b7fdf3STyrel Datwyler 55913b7fdf3STyrel Datwyler if (vhost->nvme_local_port) { 5603831863fSTyrel Datwyler ibmvfc_log(vhost, 2, "unregister_localport: host-traddr=nn-0x%llx:pn-0x%llx on portID:%x\n", 5613831863fSTyrel Datwyler vhost->nvme_local_port->node_name, 5623831863fSTyrel Datwyler vhost->nvme_local_port->port_name, 5633831863fSTyrel Datwyler vhost->nvme_local_port->port_id); 56413b7fdf3STyrel Datwyler init_completion(&vhost->nvme_delete_done); 56513b7fdf3STyrel Datwyler rc = nvme_fc_unregister_localport(vhost->nvme_local_port); 5663831863fSTyrel Datwyler if (!rc) { 56713b7fdf3STyrel Datwyler wait_for_completion(&vhost->nvme_delete_done); 5683831863fSTyrel Datwyler } else 5693831863fSTyrel Datwyler dev_err(vhost->dev, "Failed to unregister NVMe fc localport (%d)\n", rc); 5703831863fSTyrel Datwyler 5713831863fSTyrel Datwyler put_device(vhost->dev); 57213b7fdf3STyrel Datwyler } 573848c7085STyrel Datwyler } 574