From 038a5ee403e9cbe06c77f576d32524bbd70eeaf9 Mon Sep 17 00:00:00 2001 From: Jim Harris Date: Tue, 26 Mar 2013 18:39:54 +0000 Subject: [PATCH] Add an interface for nvme shim drivers (i.e. nvd) to register for notifications when new nvme controllers are added to the system. Sponsored by: Intel --- sys/dev/nvd/nvd.c | 10 +++--- sys/dev/nvme/nvme.c | 63 ++++++++++++++++++++++++++++--------- sys/dev/nvme/nvme.h | 14 +++++++-- sys/dev/nvme/nvme_ctrlr.c | 9 ++++++ sys/dev/nvme/nvme_private.h | 6 ++++ 5 files changed, 81 insertions(+), 21 deletions(-) diff --git a/sys/dev/nvd/nvd.c b/sys/dev/nvd/nvd.c index d221375245aa..5072889fbe7b 100644 --- a/sys/dev/nvd/nvd.c +++ b/sys/dev/nvd/nvd.c @@ -45,7 +45,7 @@ struct nvd_disk; static disk_ioctl_t nvd_ioctl; static disk_strategy_t nvd_strategy; -static void create_geom_disk(void *, struct nvme_namespace *ns); +static void *create_geom_disk(struct nvme_namespace *ns, void *ctrlr); static void destroy_geom_disk(struct nvd_disk *ndisk); static int nvd_load(void); @@ -105,7 +105,7 @@ nvd_load() { TAILQ_INIT(&nvd_head); - consumer_handle = nvme_register_consumer(create_geom_disk, NULL); + consumer_handle = nvme_register_consumer(create_geom_disk, NULL, NULL); return (consumer_handle != NULL ? 0 : -1); } @@ -233,8 +233,8 @@ nvd_bioq_process(void *arg, int pending) } } -static void -create_geom_disk(void *arg, struct nvme_namespace *ns) +static void * +create_geom_disk(struct nvme_namespace *ns, void *ctrlr) { struct nvd_disk *ndisk; struct disk *disk; @@ -287,6 +287,8 @@ create_geom_disk(void *arg, struct nvme_namespace *ns) taskqueue_start_threads(&ndisk->tq, 1, PI_DISK, "nvd taskq"); TAILQ_INSERT_HEAD(&nvd_head, ndisk, tailq); + + return (NULL); } static void diff --git a/sys/dev/nvme/nvme.c b/sys/dev/nvme/nvme.c index ab7f65199c4b..b5e010ef4399 100644 --- a/sys/dev/nvme/nvme.c +++ b/sys/dev/nvme/nvme.c @@ -40,11 +40,14 @@ __FBSDID("$FreeBSD$"); #include "nvme_private.h" struct nvme_consumer { - nvme_consumer_cb_fn_t cb_fn; - void *cb_arg; + uint32_t id; + nvme_cons_ns_fn_t ns_fn; + nvme_cons_ctrlr_fn_t ctrlr_fn; + nvme_cons_async_fn_t async_fn; }; struct nvme_consumer nvme_consumer[NVME_MAX_CONSUMERS]; +#define INVALID_CONSUMER_ID 0xFFFF uma_zone_t nvme_request_zone; @@ -118,8 +121,13 @@ nvme_probe (device_t device) static void nvme_init(void) { + uint32_t i; + nvme_request_zone = uma_zcreate("nvme_request", sizeof(struct nvme_request), NULL, NULL, NULL, NULL, 0, 0); + + for (i = 0; i < NVME_MAX_CONSUMERS; i++) + nvme_consumer[i].id = INVALID_CONSUMER_ID; } SYSINIT(nvme_register, SI_SUB_DRIVERS, SI_ORDER_SECOND, nvme_init, NULL); @@ -292,26 +300,52 @@ nvme_detach (device_t dev) } static void -nvme_notify_consumer(struct nvme_consumer *consumer) +nvme_notify_consumer(struct nvme_consumer *cons) { device_t *devlist; struct nvme_controller *ctrlr; - int dev, ns, devcount; + struct nvme_namespace *ns; + void *ctrlr_cookie; + int dev_idx, ns_idx, devcount; if (devclass_get_devices(nvme_devclass, &devlist, &devcount)) return; - for (dev = 0; dev < devcount; dev++) { - ctrlr = DEVICE2SOFTC(devlist[dev]); - for (ns = 0; ns < ctrlr->cdata.nn; ns++) - (*consumer->cb_fn)(consumer->cb_arg, &ctrlr->ns[ns]); + for (dev_idx = 0; dev_idx < devcount; dev_idx++) { + ctrlr = DEVICE2SOFTC(devlist[dev_idx]); + if (cons->ctrlr_fn != NULL) + ctrlr_cookie = (*cons->ctrlr_fn)(ctrlr); + else + ctrlr_cookie = NULL; + ctrlr->cons_cookie[cons->id] = ctrlr_cookie; + for (ns_idx = 0; ns_idx < ctrlr->cdata.nn; ns_idx++) { + ns = &ctrlr->ns[ns_idx]; + if (cons->ns_fn != NULL) + ns->cons_cookie[cons->id] = + (*cons->ns_fn)(ns, ctrlr_cookie); + } } free(devlist, M_TEMP); } +void +nvme_notify_async_consumers(struct nvme_controller *ctrlr, + const struct nvme_completion *async_cpl) +{ + struct nvme_consumer *cons; + uint32_t i; + + for (i = 0; i < NVME_MAX_CONSUMERS; i++) { + cons = &nvme_consumer[i]; + if (cons->id != INVALID_CONSUMER_ID && cons->async_fn != NULL) + (*cons->async_fn)(ctrlr->cons_cookie[i], async_cpl); + } +} + struct nvme_consumer * -nvme_register_consumer(nvme_consumer_cb_fn_t cb_fn, void *cb_arg) +nvme_register_consumer(nvme_cons_ns_fn_t ns_fn, nvme_cons_ctrlr_fn_t ctrlr_fn, + nvme_cons_async_fn_t async_fn) { int i; @@ -320,9 +354,11 @@ nvme_register_consumer(nvme_consumer_cb_fn_t cb_fn, void *cb_arg) * right now since we only have one nvme consumer - nvd(4). */ for (i = 0; i < NVME_MAX_CONSUMERS; i++) - if (nvme_consumer[i].cb_fn == NULL) { - nvme_consumer[i].cb_fn = cb_fn; - nvme_consumer[i].cb_arg = cb_arg; + if (nvme_consumer[i].id == INVALID_CONSUMER_ID) { + nvme_consumer[i].id = i; + nvme_consumer[i].ns_fn = ns_fn; + nvme_consumer[i].ctrlr_fn = ctrlr_fn; + nvme_consumer[i].async_fn = async_fn; nvme_notify_consumer(&nvme_consumer[i]); return (&nvme_consumer[i]); @@ -336,7 +372,6 @@ void nvme_unregister_consumer(struct nvme_consumer *consumer) { - consumer->cb_fn = NULL; - consumer->cb_arg = NULL; + consumer->id = INVALID_CONSUMER_ID; } diff --git a/sys/dev/nvme/nvme.h b/sys/dev/nvme/nvme.h index bb9e945a332f..afdb0041e4e1 100644 --- a/sys/dev/nvme/nvme.h +++ b/sys/dev/nvme/nvme.h @@ -690,10 +690,14 @@ enum nvme_io_test_flags { struct bio; struct nvme_namespace; +struct nvme_controller; struct nvme_consumer; typedef void (*nvme_cb_fn_t)(void *, const struct nvme_completion *); -typedef void (*nvme_consumer_cb_fn_t)(void *, struct nvme_namespace *); + +typedef void *(*nvme_cons_ns_fn_t)(struct nvme_namespace *, void *); +typedef void *(*nvme_cons_ctrlr_fn_t)(struct nvme_controller *); +typedef void (*nvme_cons_async_fn_t)(void *, const struct nvme_completion *); enum nvme_namespace_flags { NVME_NS_DEALLOCATE_SUPPORTED = 0x1, @@ -714,10 +718,14 @@ int nvme_ns_cmd_flush(struct nvme_namespace *ns, nvme_cb_fn_t cb_fn, void *cb_arg); /* Registration functions */ -struct nvme_consumer * nvme_register_consumer(nvme_consumer_cb_fn_t cb_fn, - void *cb_arg); +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); void nvme_unregister_consumer(struct nvme_consumer *consumer); +/* Controller helper functions */ +device_t nvme_ctrlr_get_device(struct nvme_controller *ctrlr); + /* Namespace helper functions */ uint32_t nvme_ns_get_max_io_xfer_size(struct nvme_namespace *ns); uint32_t nvme_ns_get_sector_size(struct nvme_namespace *ns); diff --git a/sys/dev/nvme/nvme_ctrlr.c b/sys/dev/nvme/nvme_ctrlr.c index 74cacd9a6f5d..668ac7f04fbe 100644 --- a/sys/dev/nvme/nvme_ctrlr.c +++ b/sys/dev/nvme/nvme_ctrlr.c @@ -551,6 +551,8 @@ nvme_ctrlr_async_event_cb(void *arg, const struct nvme_completion *cpl) return; } + nvme_notify_async_consumers(aer->ctrlr, cpl); + /* TODO: decode async event type based on status */ /* @@ -909,3 +911,10 @@ nvme_ctrlr_submit_io_request(struct nvme_controller *ctrlr, nvme_qpair_submit_request(qpair, req); } + +device_t +nvme_ctrlr_get_device(struct nvme_controller *ctrlr) +{ + + return (ctrlr->dev); +} diff --git a/sys/dev/nvme/nvme_private.h b/sys/dev/nvme/nvme_private.h index 6874449329b3..b44fc62f194b 100644 --- a/sys/dev/nvme/nvme_private.h +++ b/sys/dev/nvme/nvme_private.h @@ -190,6 +190,7 @@ struct nvme_namespace { uint16_t id; uint16_t flags; struct cdev *cdev; + void *cons_cookie[NVME_MAX_CONSUMERS]; }; /* @@ -264,6 +265,8 @@ struct nvme_controller { uint32_t num_aers; struct nvme_async_event_request aer[NVME_MAX_ASYNC_EVENTS]; + void *cons_cookie[NVME_MAX_CONSUMERS]; + #ifdef CHATHAM2 uint64_t chatham_size; uint64_t chatham_lbas; @@ -446,4 +449,7 @@ nvme_allocate_request_uio(struct uio *uio, nvme_cb_fn_t cb_fn, void *cb_arg) #define nvme_free_request(req) uma_zfree(nvme_request_zone, req) +void nvme_notify_async_consumers(struct nvme_controller *ctrlr, + const struct nvme_completion *async_cpl); + #endif /* __NVME_PRIVATE_H__ */