[PATCH 19/29] ibmvfc: implement NVMe/FC stubs for local/remote port registration
From: Tyrel Datwyler <tyreld@linux.ibm.com>
Date: 2026-06-23 01:31:08
Also in:
linux-scsi, lkml
Subsystem:
ibm power virtual fc device drivers, linux for powerpc (32-bit and 64-bit), scsi subsystem, the rest · Maintainers:
Tyrel Datwyler, Madhavan Srinivasan, Michael Ellerman, "James E.J. Bottomley", "Martin K. Petersen", Linus Torvalds
Implement the initial NVMe/FC local-port and remote-port registration functions that notify the NVMe-FC midlayr of port discovery and loss. Register the local port with the NVMe-FC transport, register discovered remote ports against that local port, and add matching unregister paths that wait for the NVMe-FC core to complete asynchronous deletion before dropping driver references. Also store driver-private host and target pointers in the registered NVMe-FC port objects. Signed-off-by: Tyrel Datwyler <tyreld@linux.ibm.com> --- drivers/scsi/ibmvscsi/ibmvfc-nvme.c | 79 ++++++++++++++++++++++++++++- drivers/scsi/ibmvscsi/ibmvfc-nvme.h | 4 +- drivers/scsi/ibmvscsi/ibmvfc.h | 4 ++ 3 files changed, 83 insertions(+), 4 deletions(-)
diff --git a/drivers/scsi/ibmvscsi/ibmvfc-nvme.c b/drivers/scsi/ibmvscsi/ibmvfc-nvme.c
index 4a66cde8a8d2..202e8d0b0081 100644
--- a/drivers/scsi/ibmvscsi/ibmvfc-nvme.c
+++ b/drivers/scsi/ibmvscsi/ibmvfc-nvme.c@@ -14,10 +14,18 @@ static void ibmvfc_nvme_localport_delete(struct nvme_fc_local_port *lport) { + struct ibmvfc_host *vhost = lport->private; + + vhost->nvme_local_port = NULL; + complete(&vhost->nvme_delete_done); } static void ibmvfc_nvme_remoteport_delete(struct nvme_fc_remote_port *rport) { + struct ibmvfc_target *tgt = rport->private; + + tgt->nvme_remote_port = NULL; + complete(&tgt->nvme_delete_done); } static int ibmvfc_nvme_ls_req(struct nvme_fc_local_port *lport,
@@ -70,18 +78,85 @@ static struct nvme_fc_port_template ibmvfc_nvme_fc_transport = { int ibmvfc_nvme_register_remoteport(struct ibmvfc_target *tgt) { - return 0; + struct ibmvfc_host *vhost = tgt->vhost; + struct nvme_fc_port_info pinfo; + int rc; + + if (!vhost->nvme_local_port) { + dev_err(vhost->dev, "Attempt to register NVMe fc remoteport without valid localport\n"); + return -EINVAL; + } + + memset(&pinfo, 0, sizeof(struct nvme_fc_port_info)); + pinfo.node_name = tgt->ids.node_name; + pinfo.port_name = tgt->ids.port_name; + pinfo.port_id = tgt->ids.port_id; + pinfo.port_role = FC_PORT_ROLE_NVME_TARGET; + + rc = nvme_fc_register_remoteport(vhost->nvme_local_port, &pinfo, + &tgt->nvme_remote_port); + + if (!rc) { + ibmvfc_log(vhost, 2, "register_remoteport: traddr=nn-0x%llx:pn-0x%llx PortID:%x\n", + pinfo.node_name, pinfo.port_name, pinfo.port_id); + tgt->nvme_remote_port->private = tgt; + } + + return rc; } void ibmvfc_nvme_unregister_remoteport(struct ibmvfc_target *tgt) { + struct ibmvfc_host *vhost = tgt->vhost; + struct nvme_fc_remote_port *rport = tgt->nvme_remote_port; + int rc; + + if (!tgt->nvme_remote_port) + return; + + ibmvfc_log(vhost, 2, "unregister_remoteport: traddr=nn-0x%llx:pn-0x%llx PortID:%x\n", + rport->node_name, rport->port_name, rport->port_id); + init_completion(&tgt->nvme_delete_done); + rc = nvme_fc_unregister_remoteport(tgt->nvme_remote_port); + + if (!rc) { + wait_for_completion(&tgt->nvme_delete_done); + tgt->nvme_remote_port->private = NULL; + } } int ibmvfc_nvme_register(struct ibmvfc_host *vhost) { - return 0; + struct nvme_fc_port_info pinfo; + int rc; + + pinfo.node_name = fc_host_node_name(vhost->host); + pinfo.port_name = fc_host_port_name(vhost->host); + pinfo.port_id = fc_host_port_id(vhost->host); + pinfo.port_role = FC_PORT_ROLE_NVME_INITIATOR; + pinfo.dev_loss_tmo = 0; + + rc = nvme_fc_register_localport(&pinfo, &ibmvfc_nvme_fc_transport, + vhost->dev, &vhost->nvme_local_port); + + if (!rc) { + ibmvfc_log(vhost, 2, "register_localport: host-traddr=nn-0x%llx:pn-0x%llx on portID:%x\n", + pinfo.node_name, pinfo.port_name, pinfo.port_id); + vhost->nvme_local_port->private = vhost; + } else + dev_err(vhost->dev, "Failed to register NVMe fc localport (%d)\n", rc); + + return rc; } void ibmvfc_nvme_unregister(struct ibmvfc_host *vhost) { + int rc; + + if (vhost->nvme_local_port) { + init_completion(&vhost->nvme_delete_done); + rc = nvme_fc_unregister_localport(vhost->nvme_local_port); + if (!rc) + wait_for_completion(&vhost->nvme_delete_done); + } }
diff --git a/drivers/scsi/ibmvscsi/ibmvfc-nvme.h b/drivers/scsi/ibmvscsi/ibmvfc-nvme.h
index 97e267871df2..0465e8719881 100644
--- a/drivers/scsi/ibmvscsi/ibmvfc-nvme.h
+++ b/drivers/scsi/ibmvscsi/ibmvfc-nvme.h@@ -11,8 +11,8 @@ #ifndef _IBMVFC_NVME_H #define _IBMVFC_NVME_H -#include <uapi/scsi/fc/fc_fs.h> -#include <uapi/scsi/fc/fc_els.h> +#include <scsi/fc/fc_fs.h> +#include <scsi/fc/fc_els.h> #include <linux/nvme-fc-driver.h> #include "ibmvfc.h"
diff --git a/drivers/scsi/ibmvscsi/ibmvfc.h b/drivers/scsi/ibmvscsi/ibmvfc.h
index 66025e6ffeed..d8c2e5f1fdec 100644
--- a/drivers/scsi/ibmvscsi/ibmvfc.h
+++ b/drivers/scsi/ibmvscsi/ibmvfc.h@@ -839,6 +839,8 @@ struct ibmvfc_target { void (*job_step) (struct ibmvfc_target *); struct timer_list timer; struct kref kref; + struct completion nvme_delete_done; + struct nvme_fc_remote_port *nvme_remote_port; }; /* a unit of work for the hosting partition */
@@ -1015,6 +1017,8 @@ struct ibmvfc_host { struct work_struct rport_add_work_q; wait_queue_head_t init_wait_q; wait_queue_head_t work_wait_q; + struct nvme_fc_local_port *nvme_local_port; + struct completion nvme_delete_done; }; static inline struct ibmvfc_host *ibmvfc_channels_to_vhost(struct ibmvfc_channels *channels)
--
2.54.0