Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 10 Dec 2025 22:53:51 +0000
From:      Warner Losh <imp@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: 1e39b5d4833e - main - nvme_sim: Attach as a child of nvme
Message-ID:  <6939f9ff.b819.65552ec6@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help

The branch main has been updated by imp:

URL: https://cgit.FreeBSD.org/src/commit/?id=1e39b5d4833e3be0261ff9cc2d360aa36698c3dc

commit 1e39b5d4833e3be0261ff9cc2d360aa36698c3dc
Author:     Warner Losh <imp@FreeBSD.org>
AuthorDate: 2025-12-10 22:52:23 +0000
Commit:     Warner Losh <imp@FreeBSD.org>
CommitDate: 2025-12-10 22:52:23 +0000

    nvme_sim: Attach as a child of nvme
    
    Rather than registering as a consumer of the nvme controller, hook into
    the child device and use that.
    
    This is a small regression at the moment: we don't fail the device when
    that happens at runtime, and we don't handle new namespaces when they
    arrive (though that feature is currently fragile).
    
    Sponsored by:           Netflix
    Differential Revision:  https://reviews.freebsd.org/D51384
---
 sys/dev/nvme/nvme_sim.c | 138 +++++++++++++++++++++++++++++-------------------
 1 file changed, 85 insertions(+), 53 deletions(-)

diff --git a/sys/dev/nvme/nvme_sim.c b/sys/dev/nvme/nvme_sim.c
index e015fbe4d072..88d777f556ed 100644
--- a/sys/dev/nvme/nvme_sim.c
+++ b/sys/dev/nvme/nvme_sim.c
@@ -304,61 +304,101 @@ nvme_sim_poll(struct cam_sim *sim)
 	nvme_ctrlr_poll(sim2ctrlr(sim));
 }
 
-static void *
-nvme_sim_new_controller(struct nvme_controller *ctrlr)
+static void
+nvme_sim_ns_change(struct nvme_namespace *ns, struct nvme_sim_softc *sc)
+{
+	union ccb *ccb;
+
+	/*
+	 * We map the NVMe namespace idea onto the CAM unit LUN. For each new
+	 * namespace, we create a new CAM path for it. We then rescan the path
+	 * to get it to enumerate.
+	 */
+	ccb = xpt_alloc_ccb();
+	if (xpt_create_path(&ccb->ccb_h.path, /*periph*/NULL,
+	    cam_sim_path(sc->s_sim), 0, ns->id) != CAM_REQ_CMP) {
+		printf("unable to create path for rescan\n");
+		xpt_free_ccb(ccb);
+		return;
+	}
+	xpt_rescan(ccb);
+}
+
+static int
+nvme_sim_probe(device_t dev)
+{
+	if (nvme_use_nvd)
+		return (ENXIO);
+
+	device_set_desc(dev, "nvme cam");
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+nvme_sim_attach(device_t dev)
 {
-	struct nvme_sim_softc *sc;
 	struct cam_devq *devq;
 	int max_trans;
+	int err = ENOMEM;
+	struct nvme_sim_softc *sc = device_get_softc(dev);
+	struct nvme_controller	*ctrlr = device_get_ivars(dev);
 
 	max_trans = ctrlr->max_hw_pend_io;
 	devq = cam_simq_alloc(max_trans);
 	if (devq == NULL)
-		return (NULL);
+		return (ENOMEM);
 
-	sc = malloc(sizeof(*sc), M_NVME, M_ZERO | M_WAITOK);
 	sc->s_ctrlr = ctrlr;
 
 	sc->s_sim = cam_sim_alloc(nvme_sim_action, nvme_sim_poll,
-	    "nvme", sc, device_get_unit(ctrlr->dev),
+	    "nvme", sc, device_get_unit(dev),
 	    NULL, max_trans, max_trans, devq);
 	if (sc->s_sim == NULL) {
-		printf("Failed to allocate a sim\n");
+		device_printf(dev, "Failed to allocate a sim\n");
 		cam_simq_free(devq);
 		goto err1;
 	}
-	if (xpt_bus_register(sc->s_sim, ctrlr->dev, 0) != CAM_SUCCESS) {
-		printf("Failed to create a bus\n");
+	if (xpt_bus_register(sc->s_sim, dev, 0) != CAM_SUCCESS) {
+		err = ENXIO;
+		device_printf(dev, "Failed to create a bus\n");
 		goto err2;
 	}
 	if (xpt_create_path(&sc->s_path, /*periph*/NULL, cam_sim_path(sc->s_sim),
 	    CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
-		printf("Failed to create a path\n");
+		err = ENXIO;
+		device_printf(dev, "Failed to create a path\n");
 		goto err3;
 	}
 
-	return (sc);
+	for (int i = 0; i < min(ctrlr->cdata.nn, NVME_MAX_NAMESPACES); i++) {
+		struct nvme_namespace	*ns = &ctrlr->ns[i];
+
+		if (ns->data.nsze == 0)
+			continue;
+		nvme_sim_ns_change(ns, sc);
+	}
 
+	return (0);
 err3:
 	xpt_bus_deregister(cam_sim_path(sc->s_sim));
 err2:
 	cam_sim_free(sc->s_sim, /*free_devq*/TRUE);
 err1:
 	free(sc, M_NVME);
-	return (NULL);
+	return (err);
 }
 
-static void *
-nvme_sim_ns_change(struct nvme_namespace *ns, void *sc_arg)
+static int
+nvme_sim_fail(device_t dev, struct nvme_namespace *ns)
 {
-	struct nvme_sim_softc *sc = sc_arg;
+	struct nvme_sim_softc *sc = device_get_softc(dev);
 	struct cam_path *tmppath;
 	union ccb *ccb;
 
 	if (xpt_create_path(&tmppath, /*periph*/NULL,
 	    cam_sim_path(sc->s_sim), 0, ns->id) != CAM_REQ_CMP) {
-		printf("unable to create path for rescan\n");
-		return (NULL);
+		device_printf(dev, "unable to create path for rescan\n");
+		return (ENOMEM);
 	}
 	/*
 	 * If it's gone, then signal that and leave.
@@ -366,13 +406,13 @@ nvme_sim_ns_change(struct nvme_namespace *ns, void *sc_arg)
 	if (ns->flags & NVME_NS_GONE) {
 		xpt_async(AC_LOST_DEVICE, tmppath, NULL);
 		xpt_free_path(tmppath);
-		return (sc_arg);
+		return (0);
 	}
 
 	ccb = xpt_alloc_ccb_nowait();
 	if (ccb == NULL) {
-		printf("unable to alloc CCB for rescan\n");
-		return (NULL);
+		device_printf(dev, "unable to alloc CCB for rescan\n");
+		return (ENOMEM);
 	}
 	ccb->ccb_h.path = tmppath;
 
@@ -383,45 +423,37 @@ nvme_sim_ns_change(struct nvme_namespace *ns, void *sc_arg)
 	 */
 	xpt_rescan(ccb);
 
-	return (sc_arg);
+	return (0);
 }
 
-static void
-nvme_sim_controller_fail(void *ctrlr_arg)
+static int
+nvme_sim_detach(device_t dev)
 {
-	struct nvme_sim_softc *sc = ctrlr_arg;
+	struct nvme_controller	*ctrlr = device_get_ivars(dev);
 
-	xpt_async(AC_LOST_DEVICE, sc->s_path, NULL);
-	xpt_free_path(sc->s_path);
-	xpt_bus_deregister(cam_sim_path(sc->s_sim));
-	cam_sim_free(sc->s_sim, /*free_devq*/TRUE);
-	free(sc, M_NVME);
-}
+	for (int i = 0; i < min(ctrlr->cdata.nn, NVME_MAX_NAMESPACES); i++) {
+		struct nvme_namespace	*ns = &ctrlr->ns[i];
 
-struct nvme_consumer *consumer_cookie;
-
-static void
-nvme_sim_init(void *dummy __unused)
-{
-	if (nvme_use_nvd)
-		return;
-
-	consumer_cookie = nvme_register_consumer(nvme_sim_ns_change,
-	    nvme_sim_new_controller, NULL, nvme_sim_controller_fail);
+		if (ns->data.nsze == 0)
+			continue;
+		nvme_sim_fail(dev, ns);
+	}
+	return (0);
 }
 
-SYSINIT(nvme_sim_register, SI_SUB_DRIVERS, SI_ORDER_ANY,
-    nvme_sim_init, NULL);
-
-static void
-nvme_sim_uninit(void *dummy __unused)
-{
-	if (nvme_use_nvd)
-		return;
-	/* XXX Cleanup */
+static device_method_t nvme_sim_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,     nvme_sim_probe),
+	DEVMETHOD(device_attach,    nvme_sim_attach),
+	DEVMETHOD(device_detach,    nvme_sim_detach),
+	{ 0, 0 }
+};
 
-	nvme_unregister_consumer(consumer_cookie);
-}
+static driver_t nvme_sim_driver = {
+	"nvme_sim",
+	nvme_sim_methods,
+	sizeof(struct nvme_sim_softc),
+};
 
-SYSUNINIT(nvme_sim_unregister, SI_SUB_DRIVERS, SI_ORDER_ANY,
-    nvme_sim_uninit, NULL);
+DRIVER_MODULE(nvme_sim, nvme, nvme_sim_driver, NULL, NULL);
+MODULE_VERSION(nvme_shim, 1);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?6939f9ff.b819.65552ec6>