mirror of
https://git.freebsd.org/src.git
synced 2026-01-12 06:54:03 +00:00
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:
parent
a21f12840f
commit
aed44717a1
6 changed files with 168 additions and 158 deletions
|
|
@ -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 }
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
};
|
||||
|
||||
#
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue