nvd: Connect nvme_if methods

Conenct methods to manage namespaces explicitly to replace the old
consumer interface.

Sponsored by:		Netflix
Differential Revision:	https://reviews.freebsd.org/D51388
This commit is contained in:
Warner Losh 2025-12-10 15:52:38 -07:00
parent a21f12840f
commit aed44717a1
6 changed files with 168 additions and 158 deletions

View file

@ -29,6 +29,7 @@
#include <sys/param.h>
#include <sys/bio.h>
#include <sys/bus.h>
#include <sys/devicestat.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
@ -47,6 +48,8 @@
#include <dev/pci/pcivar.h>
#include "nvme_if.h"
#define NVD_STR "nvd"
struct nvd_disk;
@ -385,17 +388,96 @@ nvd_bioq_process(void *arg, int pending)
}
}
static void
nvd_new_disk(struct nvme_namespace *ns, struct nvd_controller *ctrlr)
static int
nvdc_controller_failed(device_t dev)
{
struct nvd_controller *nvd_ctrlr = device_get_softc(dev);
struct nvd_disk *ndisk;
mtx_lock(&nvd_lock);
TAILQ_REMOVE(&ctrlr_head, nvd_ctrlr, tailq);
TAILQ_FOREACH(ndisk, &nvd_ctrlr->disk_head, ctrlr_tailq)
nvd_gone(ndisk);
while (!TAILQ_EMPTY(&nvd_ctrlr->disk_head))
msleep(&nvd_ctrlr->disk_head, &nvd_lock, 0, "nvd_fail", 0);
mtx_unlock(&nvd_lock);
return (0);
}
static int
nvdc_probe(device_t dev)
{
if (!nvme_use_nvd)
return (ENXIO);
device_set_desc(dev, "nvme storage namespace");
return (BUS_PROBE_DEFAULT);
}
static int
nvdc_attach(device_t dev)
{
struct nvd_controller *nvd_ctrlr = device_get_softc(dev);
struct nvme_controller *ctrlr = device_get_ivars(dev);
nvd_ctrlr->ctrlr = ctrlr;
TAILQ_INIT(&nvd_ctrlr->disk_head);
mtx_lock(&nvd_lock);
TAILQ_INSERT_TAIL(&ctrlr_head, nvd_ctrlr, tailq);
mtx_unlock(&nvd_lock);
return (0);
}
static int
nvdc_detach(device_t dev)
{
return (nvdc_controller_failed(dev));
}
static struct nvd_disk *
nvd_nsid_to_disk(struct nvd_controller *nvd_ctrlr, uint32_t nsid)
{
struct nvd_disk *ndisk;
mtx_lock(&nvd_lock);
TAILQ_FOREACH(ndisk, &nvd_ctrlr->disk_head, ctrlr_tailq) {
if (ndisk->ns->id != nsid)
continue;
break;
}
mtx_unlock(&nvd_lock);
return ndisk;
}
static struct nvd_disk *
nvd_ns_to_disk(struct nvd_controller *nvd_ctrlr, struct nvme_namespace *ns)
{
struct nvd_disk *ndisk;
mtx_lock(&nvd_lock);
TAILQ_FOREACH(ndisk, &nvd_ctrlr->disk_head, ctrlr_tailq) {
if (ndisk->ns != ns)
continue;
break;
}
mtx_unlock(&nvd_lock);
return ndisk;
}
static int
nvdc_ns_added(device_t dev, struct nvme_namespace *ns)
{
struct nvd_controller *nvd_ctrlr = device_get_softc(dev);
struct nvd_disk *ndisk;
uint8_t descr[NVME_MODEL_NUMBER_LENGTH+1];
struct nvd_disk *ndisk, *tnd;
struct nvd_disk *tnd;
struct disk *disk;
device_t dev = ctrlr->ctrlr->dev;
int unit;
device_t pdev = nvd_ctrlr->ctrlr->dev;
int unit;
ndisk = malloc(sizeof(struct nvd_disk), M_NVD, M_ZERO | M_WAITOK);
ndisk->ctrlr = ctrlr;
ndisk->ctrlr = nvd_ctrlr;
ndisk->ns = ns;
ndisk->cur_depth = 0;
ndisk->ordered_in_flight = 0;
@ -415,7 +497,7 @@ nvd_new_disk(struct nvme_namespace *ns, struct nvd_controller *ctrlr)
TAILQ_INSERT_BEFORE(tnd, ndisk, global_tailq);
else
TAILQ_INSERT_TAIL(&disk_head, ndisk, global_tailq);
TAILQ_INSERT_TAIL(&ctrlr->disk_head, ndisk, ctrlr_tailq);
TAILQ_INSERT_TAIL(&nvd_ctrlr->disk_head, ndisk, ctrlr_tailq);
mtx_unlock(&nvd_lock);
ndisk->tq = taskqueue_create("nvd_taskq", M_WAITOK,
@ -464,14 +546,14 @@ nvd_new_disk(struct nvme_namespace *ns, struct nvd_controller *ctrlr)
* which has no access to the config space for this controller, report
* the AHCI controller's data.
*/
if (ctrlr->ctrlr->quirks & QUIRK_AHCI)
dev = device_get_parent(dev);
disk->d_hba_vendor = pci_get_vendor(dev);
disk->d_hba_device = pci_get_device(dev);
disk->d_hba_subvendor = pci_get_subvendor(dev);
disk->d_hba_subdevice = pci_get_subdevice(dev);
if (nvd_ctrlr->ctrlr->quirks & QUIRK_AHCI)
pdev = device_get_parent(pdev);
disk->d_hba_vendor = pci_get_vendor(pdev);
disk->d_hba_device = pci_get_device(pdev);
disk->d_hba_subvendor = pci_get_subvendor(pdev);
disk->d_hba_subdevice = pci_get_subdevice(pdev);
disk->d_rotation_rate = DISK_RR_NON_ROTATING;
strlcpy(disk->d_attachment, device_get_nameunit(dev),
strlcpy(disk->d_attachment, device_get_nameunit(pdev),
sizeof(disk->d_attachment));
disk_create(disk, DISK_VERSION);
@ -481,14 +563,35 @@ nvd_new_disk(struct nvme_namespace *ns, struct nvd_controller *ctrlr)
(uintmax_t)disk->d_mediasize / (1024*1024),
(uintmax_t)disk->d_mediasize / disk->d_sectorsize,
disk->d_sectorsize);
return (0);
}
#if 0
static void
nvd_resize(struct nvd_disk *ndisk)
static int
nvdc_ns_removed(device_t dev, struct nvme_namespace *ns)
{
struct disk *disk = ndisk->disk;
struct nvme_namespace *ns = ndisk->ns;
struct nvd_controller *nvd_ctrlr = device_get_softc(dev);
struct nvd_disk *ndisk = nvd_ns_to_disk(nvd_ctrlr, ns);
if (ndisk == NULL)
panic("nvdc: no namespace found for ns %p", ns);
nvd_gone(ndisk);
/* gonecb removes it from the list -- no need to wait */
return (0);
}
static int
nvdc_ns_changed(device_t dev, uint32_t nsid)
{
struct nvd_controller *nvd_ctrlr = device_get_softc(dev);
struct nvd_disk *ndisk = nvd_nsid_to_disk(nvd_ctrlr, nsid);
struct disk *disk;
struct nvme_namespace *ns;
if (ndisk == NULL)
panic("nvdc: no namespace found for %d", nsid);
disk = ndisk->disk;
ns = ndisk->ns;
disk->d_sectorsize = nvme_ns_get_sector_size(ns);
disk->d_mediasize = (off_t)nvme_ns_get_size(ns);
@ -504,98 +607,28 @@ nvd_resize(struct nvd_disk *ndisk)
(uintmax_t)disk->d_mediasize / (1024*1024),
(uintmax_t)disk->d_mediasize / disk->d_sectorsize,
disk->d_sectorsize);
}
#endif
static int
nvdc_fail(device_t dev)
{
return ENXIO;
}
#if 0
static void *
nvd_ns_changed(struct nvme_namespace *ns, void *ctrlr_arg)
{
struct nvd_disk *ndisk;
struct nvd_controller *ctrlr = ctrlr_arg;
if ((ns->flags & NVME_NS_DELTA) == 0) {
nvd_new_disk(ns, ctrlr_arg);
return (ctrlr_arg);
}
mtx_lock(&nvd_lock);
TAILQ_FOREACH(ndisk, &ctrlr->disk_head, ctrlr_tailq) {
if (ndisk->ns->id != ns->id)
continue;
nvd_resize(ndisk);
break;
}
mtx_unlock(&nvd_lock);
return (ctrlr_arg);
}
static void
nvd_controller_fail(void *ctrlr_arg)
{
struct nvd_controller *ctrlr = ctrlr_arg;
struct nvd_disk *ndisk;
mtx_lock(&nvd_lock);
TAILQ_REMOVE(&ctrlr_head, ctrlr, tailq);
TAILQ_FOREACH(ndisk, &ctrlr->disk_head, ctrlr_tailq)
nvd_gone(ndisk);
while (!TAILQ_EMPTY(&ctrlr->disk_head))
msleep(&ctrlr->disk_head, &nvd_lock, 0, "nvd_fail", 0);
mtx_unlock(&nvd_lock);
}
#endif
static int
nvdc_probe(device_t dev)
{
if (!nvme_use_nvd)
return (ENXIO);
device_set_desc(dev, "nvme storage namespace");
return (BUS_PROBE_DEFAULT);
}
static int
nvdc_attach(device_t dev)
{
struct nvd_controller *nvd_ctrlr = device_get_softc(dev);
struct nvme_controller *ctrlr = device_get_ivars(dev);
nvd_ctrlr->ctrlr = ctrlr;
TAILQ_INIT(&nvd_ctrlr->disk_head);
mtx_lock(&nvd_lock);
TAILQ_INSERT_TAIL(&ctrlr_head, nvd_ctrlr, tailq);
mtx_unlock(&nvd_lock);
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;
nvd_new_disk(ns, nvd_ctrlr);
}
return (0);
}
static int
nvdc_detach(device_t dev)
nvdc_handle_aen(device_t dev, const struct nvme_completion *cpl,
uint32_t pg_nr, void *page, uint32_t page_len)
{
return (nvdc_fail(dev));
/* Do nothing */
return (0);
}
static device_method_t nvdc_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, nvdc_probe),
DEVMETHOD(device_attach, nvdc_attach),
DEVMETHOD(device_detach, nvdc_detach),
DEVMETHOD(device_probe, nvdc_probe),
DEVMETHOD(device_attach, nvdc_attach),
DEVMETHOD(device_detach, nvdc_detach),
/* Nvme controller messages */
DEVMETHOD(nvme_ns_added, nvdc_ns_added),
DEVMETHOD(nvme_ns_removed, nvdc_ns_removed),
DEVMETHOD(nvme_ns_changed, nvdc_ns_changed),
DEVMETHOD(nvme_controller_failed, nvdc_controller_failed),
DEVMETHOD(nvme_handle_aen, nvdc_handle_aen),
{ 0, 0 }
};

View file

@ -170,18 +170,6 @@ nvme_notify(struct nvme_consumer *cons,
}
}
void
nvme_notify_new_controller(struct nvme_controller *ctrlr)
{
int i;
for (i = 0; i < NVME_MAX_CONSUMERS; i++) {
if (nvme_consumer[i].id != INVALID_CONSUMER_ID) {
nvme_notify(&nvme_consumer[i], ctrlr);
}
}
}
static void
nvme_notify_new_consumer(struct nvme_consumer *cons)
{
@ -247,30 +235,6 @@ nvme_notify_fail_consumers(struct nvme_controller *ctrlr)
}
}
void
nvme_notify_ns(struct nvme_controller *ctrlr, int nsid)
{
struct nvme_consumer *cons;
struct nvme_namespace *ns;
void *ctrlr_cookie;
uint32_t i;
KASSERT(nsid <= NVME_MAX_NAMESPACES,
("%s: Namespace notification to nsid %d exceeds range\n",
device_get_nameunit(ctrlr->dev), nsid));
if (!ctrlr->is_initialized)
return;
ns = &ctrlr->ns[nsid - 1];
for (i = 0; i < NVME_MAX_CONSUMERS; i++) {
cons = &nvme_consumer[i];
if (cons->id != INVALID_CONSUMER_ID && cons->ns_fn != NULL &&
(ctrlr_cookie = ctrlr->cons_cookie[i]) != NULL)
ns->cons_cookie[i] = (*cons->ns_fn)(ns, ctrlr_cookie);
}
}
struct nvme_consumer *
nvme_register_consumer(nvme_cons_ns_fn_t ns_fn, nvme_cons_ctrlr_fn_t ctrlr_fn,
nvme_cons_async_fn_t async_fn,

View file

@ -48,6 +48,8 @@
#include "nvme_private.h"
#include "nvme_linux.h"
#include "nvme_if.h"
#define B4_CHK_RDY_DELAY_MS 2300 /* work around controller bug */
static void nvme_ctrlr_construct_and_submit_aer(struct nvme_controller *ctrlr,
@ -1082,10 +1084,20 @@ nvme_ctrlr_start_config_hook(void *arg)
device_t child;
ctrlr->is_initialized = true;
nvme_notify_new_controller(ctrlr);
child = device_add_child(ctrlr->dev, NULL, DEVICE_UNIT_ANY);
device_set_ivars(child, ctrlr);
bus_attach_children(ctrlr->dev);
/*
* Now notify the child of all the known namepsaces
*/
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_NS_ADDED(child, ns);
}
}
TSEXIT();
}
@ -1223,23 +1235,26 @@ nvme_ctrlr_aer_task(void *arg, int pending)
nvme_ctrlr_cmd_set_async_event_config(aer->ctrlr,
aer->ctrlr->async_event_config, NULL, NULL);
} else if (aer->log_page_id == NVME_LOG_CHANGED_NAMESPACE) {
struct nvme_ns_list *nsl =
(struct nvme_ns_list *)aer->log_page_buffer;
struct nvme_controller *ctrlr = aer->ctrlr;
device_t *children;
int n_children;
struct nvme_ns_list *nsl;
for (int i = 0; i < nitems(nsl->ns) && nsl->ns[i] != 0; i++) {
struct nvme_namespace *ns;
uint32_t id = nsl->ns[i];
if (nsl->ns[i] > NVME_MAX_NAMESPACES)
break;
ns = &ctrlr->ns[id - 1];
ns->flags |= NVME_NS_DELTA;
nvme_ns_construct(ns, id, ctrlr);
nvme_notify_ns(ctrlr, id);
ns->flags &= ~NVME_NS_DELTA;
if (device_get_children(aer->ctrlr->dev, &children, &n_children) != 0) {
children = NULL;
n_children = 0;
}
nsl = (struct nvme_ns_list *)aer->log_page_buffer;
for (int i = 0; i < nitems(nsl->ns) && nsl->ns[i] != 0; i++) {
/*
* I think we need to query the name space here and see
* if it went away, arrived, or changed in size and call
* the nuanced routine (after constructing or before
* destructing the namespace). XXX needs more work XXX.
*/
for (int j = 0; j < n_children; j++)
NVME_NS_CHANGED(children[j], nsl->ns[i]);
}
free(children, M_TEMP);
}
/*

View file

@ -33,7 +33,7 @@ METHOD int ns_removed {
#
METHOD int ns_changed {
device_t dev; /* nvme device */
struct nvme_namespace *ns; /* information about the namespace */
uint32_t nsid; /* nsid that just changed */
};
#

View file

@ -561,8 +561,6 @@ void nvme_notify_async_consumers(struct nvme_controller *ctrlr,
uint32_t log_page_id, void *log_page_buffer,
uint32_t log_page_size);
void nvme_notify_fail_consumers(struct nvme_controller *ctrlr);
void nvme_notify_new_controller(struct nvme_controller *ctrlr);
void nvme_notify_ns(struct nvme_controller *ctrlr, int nsid);
void nvme_ctrlr_shared_handler(void *arg);
void nvme_ctrlr_poll(struct nvme_controller *ctrlr);

View file

@ -1,6 +1,6 @@
.PATH: ${SRCTOP}/sys/dev/nvd
KMOD= nvd
SRCS= nvd.c opt_geom.h device_if.h bus_if.h pci_if.h
SRCS= nvd.c opt_geom.h device_if.h bus_if.h nvme_if.h pci_if.h
.include <bsd.kmod.mk>