xref: /linux/drivers/scsi/ibmvscsi/ibmvfc-nvme.c (revision 35748ddd3b2c91555bd86b8cf88edc90e7317e57)
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