Page MenuHomeFreeBSD

D11399.id30189.diff
No OneTemporary

D11399.id30189.diff

Index: sbin/nvmecontrol/Makefile
===================================================================
--- sbin/nvmecontrol/Makefile
+++ sbin/nvmecontrol/Makefile
@@ -3,7 +3,7 @@
PACKAGE=runtime
PROG= nvmecontrol
SRCS= nvmecontrol.c devlist.c firmware.c identify.c logpage.c \
- perftest.c reset.c nvme_util.c power.c util.c wdc.c
+ perftest.c reset.c nvme_util.c power.c util.c wdc.c ns.c
MAN= nvmecontrol.8
.PATH: ${SRCTOP}/sys/dev/nvme
Index: sbin/nvmecontrol/identify.c
===================================================================
--- sbin/nvmecontrol/identify.c
+++ sbin/nvmecontrol/identify.c
@@ -66,7 +66,7 @@
printf("Unlimited\n");
else
printf("%d\n", PAGE_SIZE * (1 << cdata->mdts));
-
+ printf("Controller ID: 0x%02x\n", cdata->ctrlr_id);
printf("\n");
printf("Admin Command Set Attributes\n");
printf("============================\n");
Index: sbin/nvmecontrol/ns.c
===================================================================
--- /dev/null
+++ sbin/nvmecontrol/ns.c
@@ -0,0 +1,357 @@
+/*-
+ * Copyright (c) 2017 Netflix, Inc
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer,
+ * without modification, immediately at the beginning of the file.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/ioccom.h>
+
+#include <err.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "nvmecontrol.h"
+
+/* handles NVME_OPC_NAMESPACE_MANAGEMENT and ATTACHMENT admin cmds */
+
+static void
+nscreate_usage(void)
+{
+ fprintf(stderr, "usage:\n");
+ fprintf(stderr, NSCREATE_USAGE);
+ exit(1);
+}
+static void
+nsdelete_usage(void)
+{
+ fprintf(stderr, "usage:\n");
+ fprintf(stderr, NSDELETE_USAGE);
+ exit(1);
+}
+static void
+nsattach_usage(void)
+{
+ fprintf(stderr, "usage:\n");
+ fprintf(stderr, NSATTACH_USAGE);
+ exit(1);
+}
+static void
+nsdetach_usage(void)
+{
+ fprintf(stderr, "usage:\n");
+ fprintf(stderr, NSDETACH_USAGE);
+ exit(1);
+}
+
+/* which tbl of error values to look in */
+#define ADMIN 0
+#define ATTACH 1
+
+struct ns_result_str {
+ uint16_t res;
+ const char * str;
+};
+
+static struct ns_result_str ns_result[] = {
+ { 0x2, "Invalid Feild"},
+ { 0xa, "Invalid Format"},
+ { 0xb, "Invalid Namespace or format"},
+ { 0x15, "Namespace insufficent capacity"},
+ { 0x16, "Namespace ID unavaliable"},
+ { 0x18, "Namespace already attached"},
+ { 0x19, "Namespace is private"},
+ { 0x1a, "Namespace is not attached"},
+ { 0x1b, "Thin provisioning not supported"},
+ { 0x1c, "Controller list invalid"},
+ { 0xFFFF, "Unknown"}
+};
+
+static const char *
+get_res_str(uint16_t res)
+{
+ struct ns_result_str *t = ns_result;
+
+ while (t->res != 0xFFFF) {
+ if (t->res == res)
+ return (t->str);
+ t++;
+ }
+ return t->str;
+}
+
+/*
+ * NS MGMT Command specific status values:
+ * 0xa = Invalid Format
+ * 0x15 = Namespace Insuffience capacity
+ * 0x16 = Namespace ID unavailable (number namespaces exceeded)
+ * 0xb = Thin Provisioning Not supported
+ */
+void
+nscreate(int argc, char *argv[])
+{
+ struct nvme_pt_command pt;
+ struct nvme_namespace_data nsdata;
+
+ int64_t nsze = -1;
+ int64_t cap = -1;
+ int ch, fd, result, format = -1;
+
+ if (optind >= argc)
+ nscreate_usage();
+
+ while ((ch = getopt(argc, argv, "s:c:f:")) != -1) {
+ switch (ch) {
+ case 's':
+ nsze = atol(optarg);
+ break;
+ case 'c':
+ cap = atol(optarg);
+ break;
+ case 'f':
+ format = atoi(optarg);
+ break;
+ default:
+ nscreate_usage();
+ }
+ }
+
+ if (optind >= argc)
+ nscreate_usage();
+
+ if (nsze == -1 || cap == -1)
+ nscreate_usage();
+
+ nsdata.nsze = (uint64_t)nsze;
+ nsdata.ncap = (uint64_t)cap;
+
+ if (format == -1) {
+ nsdata.flbas.format = 0x2;
+ }
+
+ memset(&pt, 0, sizeof(pt));
+ pt.cmd.opc = NVME_OPC_NAMESPACE_MANAGEMENT;
+
+ pt.cmd.cdw10 = 0; /* create */
+ pt.buf = &nsdata;
+ pt.len = sizeof(struct nvme_namespace_data);
+ pt.is_read = 0; /* passthrough writes data to ctrlr */
+ open_dev(argv[optind], &fd, 1, 1);
+ if ((result = ioctl(fd, NVME_PASSTHROUGH_CMD, &pt)) < 0)
+ errx(1, "ioctl request to %s failed: %d", argv[optind], result);
+
+ if (nvme_completion_is_error(&pt.cpl)) {
+ printf("%s: nscreate failed - %s\n", argv[optind],
+ get_res_str(pt.cpl.status.sc));
+ exit(-1);
+ }
+ printf("%s: new namespace created nsid: %d\n",
+ argv[optind], pt.cpl.cdw0);
+
+ exit(0);
+}
+#define LINELEN 80
+void
+nsdelete(int argc, char *argv[])
+{
+ struct nvme_pt_command pt;
+ int ch, fd, result, nsid = -2;
+ char answer[LINELEN];
+ char buf[2];
+
+ if (optind >= argc)
+ nsdelete_usage();
+
+ while ((ch = getopt(argc, argv, "n:")) != -1) {
+ switch ((char)ch) {
+ case 'n':
+ nsid = atoi(optarg);
+ break;
+ default:
+ nsdelete_usage();
+ }
+ }
+ if (optind >= argc || nsid == -2)
+ nsdelete_usage();
+
+
+ if (nsid == -1) { /* delete all hurts */
+ printf("using -1 as nsid will remove ALL namespaces, are you sure? [yes|no] \n");
+ fgets(answer, LINELEN, stdin);
+ if (strncmp(answer,"yes",3) != 0) {
+ printf("nsdelete cancelled.\n");
+ exit(0);
+ }
+ }
+
+ memset(&pt, 0, sizeof(pt));
+ pt.cmd.opc = NVME_OPC_NAMESPACE_MANAGEMENT;
+ pt.cmd.cdw10 = 1; /* delete */
+ pt.buf = buf;
+ pt.len = sizeof(buf);
+ pt.is_read = 1;
+ pt.cmd.nsid = (uint32_t)nsid;
+
+ open_dev(argv[optind], &fd, 1, 1);
+ if ((result = ioctl(fd, NVME_PASSTHROUGH_CMD, &pt)) < 0)
+ errx(1, "ioctl request to %s failed: %d", argv[optind], result);
+
+ if (nvme_completion_is_error(&pt.cpl)) {
+ printf("%s nsdelete failed - %s\n", argv[optind],
+ get_res_str(pt.cpl.status.sc));
+ exit(-1);
+ }
+ printf("%s namespace nsid: %d deleted\n", argv[optind], nsid);
+ exit(0);
+}
+
+/*
+ * Attach and Detach use Dword 10, and a controller list (section 4.9)
+ * This struct is 4096 bytes in size.
+ * 0h = attach
+ * 1h = detach
+ *
+ * Result values for both attach/detach:
+ *
+ * Completion 18h = Already attached
+ * 19h = NS is private and already attached to a controller
+ * 1Ah = Not attached, request could not be completed
+ * 1Ch = Controller list invalid.
+ *
+ * 0x2 Invalid Field can occur if ctrlrid d.n.e in system.
+ */
+void
+nsattach(int argc, char *argv[])
+{
+ struct nvme_pt_command pt;
+ struct ctrlr_list clist;
+ int ctrlrid = -1;
+ int fd, ch, result, nsid = -1;
+
+ if (optind >= argc)
+ nsattach_usage();
+
+ while ((ch = getopt(argc, argv, "n:c:")) != -1) {
+ switch (ch) {
+ case 'n':
+ nsid = atoi(optarg);
+ break;
+ case 'c':
+ ctrlrid = atoi(optarg);
+ break;
+ default:
+ nsattach_usage();
+ }
+ }
+
+ if (optind >= argc)
+ nsattach_usage();
+
+ if (ctrlrid == -1 || nsid == -1 )
+ nsattach_usage();
+
+ clist.ctrlr_cnt = 1;
+ clist.ctrlrs[0] = (uint16_t)ctrlrid;
+
+ memset(&pt, 0, sizeof(pt));
+ pt.cmd.opc = NVME_OPC_NAMESPACE_ATTACHMENT;
+ pt.cmd.cdw10 = 0; /* attach */
+ pt.cmd.nsid = (uint32_t)nsid;
+ pt.buf = &clist;
+ pt.len = sizeof(clist);
+
+ open_dev(argv[optind], &fd, 1, 1);
+ if ((result = ioctl(fd, NVME_PASSTHROUGH_CMD, &pt)) < 0)
+ errx(1, "ioctl request to %s failed: %d", argv[optind], result);
+
+ if (nvme_completion_is_error(&pt.cpl)) {
+ printf("%s: nsdetach failed - %s\n", argv[optind],
+ get_res_str(pt.cpl.status.sc));
+ exit(-1);
+ } else {
+ fprintf(stderr,"%s nsid %d attached\n", argv[optind],
+ nsid);
+ }
+ exit(0);
+}
+
+void
+nsdetach(int argc, char *argv[])
+{
+ struct nvme_pt_command pt;
+ struct ctrlr_list clist;
+ int ctrlrid = -1;
+ int fd, ch, result, nsid = -1;
+
+ if (optind >= argc)
+ nsdetach_usage();
+
+ while ((ch = getopt(argc, argv, "n:c:")) != -1) {
+ switch (ch) {
+ case 'n':
+ nsid = atoi(optarg);
+ break;
+ case 'c':
+ ctrlrid = atoi(optarg);
+ break;
+ default:
+ nsdetach_usage();
+ }
+ }
+
+ if (optind >= argc)
+ nsdetach_usage();
+
+ if (ctrlrid == -1 || nsid == -1)
+ nsdetach_usage();
+
+ clist.ctrlr_cnt = 1;
+ clist.ctrlrs[0] = (uint16_t)ctrlrid; /* shared not supported */
+
+ memset(&pt, 0, sizeof(pt));
+ pt.cmd.opc = NVME_OPC_NAMESPACE_ATTACHMENT;
+ pt.cmd.cdw10 = 1; /* detach */
+ pt.cmd.nsid = (uint32_t)nsid;
+ pt.buf = &clist;
+ pt.len = sizeof(clist);
+
+ open_dev(argv[optind], &fd, 1, 1);
+ if ((result = ioctl(fd, NVME_PASSTHROUGH_CMD, &pt)) < 0)
+ errx(1, "ioctl request to %s failed: %d", argv[optind], result);
+
+ if (nvme_completion_is_error(&pt.cpl)) {
+ printf("%s: nsdetach failed - %s\n", argv[optind],
+ get_res_str(pt.cpl.status.sc));
+ exit(-1);
+ } else {
+ fprintf(stderr,"nsid %d detached from %s\n",
+ nsid, argv[optind]);
+ }
+ exit(0);
+}
Index: sbin/nvmecontrol/nvmecontrol.h
===================================================================
--- sbin/nvmecontrol/nvmecontrol.h
+++ sbin/nvmecontrol/nvmecontrol.h
@@ -69,6 +69,18 @@
#define WDC_USAGE \
" nvmecontrol wdc (cap-diag|drive-log|get-crash-dump|purge|purge-montior)\n"
+#define NSCREATE_USAGE \
+" nvmecontrol nscreate -s nssize -c capacity [-f format] nvmeN\n"
+
+#define NSDELETE_USAGE \
+" nvmecontrol nsdelete -n namespace id nvmeN\n"
+
+#define NSATTACH_USAGE \
+" nvmecontrol nsattach -n namespace id -c controller id nvmeN \n"
+
+#define NSDETACH_USAGE \
+" nvmecontrol nsdetach -n namespace id -c controller id nvmeN\n"
+
void devlist(int argc, char *argv[]);
void identify(int argc, char *argv[]);
void perftest(int argc, char *argv[]);
@@ -77,6 +89,10 @@
void firmware(int argc, char *argv[]);
void power(int argc, char *argv[]);
void wdc(int argc, char *argv[]);
+void nscreate(int argc, char *argv[]);
+void nsdelete(int argc, char *argv[]);
+void nsattach(int argc, char *argv[]);
+void nsdetach(int argc, char *argv[]);
int open_dev(const char *str, int *fd, int show_error, int exit_on_error);
void parse_ns_str(const char *ns_str, char *ctrlr_str, int *nsid);
Index: sbin/nvmecontrol/nvmecontrol.c
===================================================================
--- sbin/nvmecontrol/nvmecontrol.c
+++ sbin/nvmecontrol/nvmecontrol.c
@@ -55,6 +55,10 @@
{"firmware", firmware, FIRMWARE_USAGE},
{"power", power, POWER_USAGE},
{"wdc", wdc, WDC_USAGE},
+ {"nscreate", nscreate, NSCREATE_USAGE},
+ {"nsdelete", nsdelete, NSDELETE_USAGE},
+ {"nsattach", nsattach, NSATTACH_USAGE},
+ {"nsdetach", nsdetach, NSDETACH_USAGE},
{NULL, NULL, NULL},
};
Index: sys/dev/nvd/nvd.c
===================================================================
--- sys/dev/nvd/nvd.c
+++ sys/dev/nvd/nvd.c
@@ -35,10 +35,10 @@
#include <sys/sysctl.h>
#include <sys/systm.h>
#include <sys/taskqueue.h>
-
+#include <sys/queue.h>
#include <geom/geom.h>
#include <geom/geom_disk.h>
-
+#include <dev/nvme/nvme_private.h> /* xxx */
#include <dev/nvme/nvme.h>
#define NVD_STR "nvd"
@@ -56,7 +56,7 @@
static void *nvd_new_controller(struct nvme_controller *ctrlr);
static void nvd_controller_fail(void *ctrlr);
-
+static void *nvd_new_controller(struct nvme_controller *ctrlr);
static int nvd_load(void);
static void nvd_unload(void);
@@ -139,7 +139,7 @@
TAILQ_INIT(&disk_head);
consumer_handle = nvme_register_consumer(nvd_new_disk,
- nvd_new_controller, NULL, nvd_controller_fail);
+ nvd_new_controller, NULL, nvd_controller_fail, nvd_remove_disk);
return (consumer_handle != NULL ? 0 : -1);
}
@@ -419,6 +419,32 @@
mtx_destroy(&ndisk->bioqlock);
}
+/*
+ * namemspace disks are removed at detach time
+ * from the periph's perspective.
+ */
+void *
+nvd_remove_disk(int nsid, void *ctrlr_arg) {
+
+ struct nvd_controller *ctrlr = ctrlr_arg;
+ struct nvd_disk *disk, *tdisk;
+
+ if (TAILQ_EMPTY(&ctrlr->disk_head)) {
+ return (NULL);
+ }
+
+ TAILQ_FOREACH_SAFE(disk, (&ctrlr->disk_head), ctrlr_tailq, tdisk ) {
+ if (disk->ns->id == nsid) {
+ TAILQ_REMOVE(&disk_head, disk, global_tailq);
+ TAILQ_REMOVE(&ctrlr->disk_head, disk, ctrlr_tailq);
+ destroy_geom_disk(disk);
+ free(disk, M_NVD);
+ return (NULL);
+ }
+ }
+ return (NULL);
+}
+
static void
nvd_controller_fail(void *ctrlr_arg)
{
Index: sys/dev/nvme/nvme.h
===================================================================
--- sys/dev/nvme/nvme.h
+++ sys/dev/nvme/nvme.h
@@ -863,6 +863,7 @@
* by the caller.
*/
struct mtx * driver_lock;
+ struct nvme_controller *ctrlr;
};
#define nvme_completion_is_error(cpl) \
@@ -885,6 +886,7 @@
typedef void (*nvme_cons_async_fn_t)(void *, const struct nvme_completion *,
uint32_t, void *, uint32_t);
typedef void (*nvme_cons_fail_fn_t)(void *);
+typedef void *(*nvme_cons_rm_ns_fn_t)(int nsid, void *);
enum nvme_namespace_flags {
NVME_NS_DEALLOCATE_SUPPORTED = 0x1,
@@ -934,6 +936,7 @@
nvme_cons_ctrlr_fn_t ctrlr_fn,
nvme_cons_async_fn_t async_fn,
nvme_cons_fail_fn_t fail_fn);
+ nvme_cons_rm_ns_fn_t rm_ns_fn);
void nvme_unregister_consumer(struct nvme_consumer *consumer);
/* Controller helper functions */
Index: sys/dev/nvme/nvme.c
===================================================================
--- sys/dev/nvme/nvme.c
+++ sys/dev/nvme/nvme.c
@@ -45,6 +45,7 @@
nvme_cons_ctrlr_fn_t ctrlr_fn;
nvme_cons_async_fn_t async_fn;
nvme_cons_fail_fn_t fail_fn;
+ nvme_cons_rm_ns_fn_t rm_ns_fn;
};
struct nvme_consumer nvme_consumer[NVME_MAX_CONSUMERS];
@@ -290,13 +291,49 @@
return (0);
}
+/*
+ * For geom plumbed periph consumer(s) use notify to call the
+ * given namespace function (new disk)
+ *
+ */
+void
+nvme_notify_namespace(struct nvme_controller *ctrlr, int ns_idx, int op)
+{
+ struct nvme_namespace *ns;
+ struct nvme_consumer *cons;
+ void *ctrlr_cookie = NULL;
+ int i;
+
+ for (i = 0; i < NVME_MAX_CONSUMERS; i++) {
+
+ if (nvme_consumer[i].id != INVALID_CONSUMER_ID) {
+ ns = &ctrlr->ns[ns_idx];
+ cons = &nvme_consumer[i];
+
+ if (ns->data.nsze == 0) {
+ continue;
+ }
+ ctrlr_cookie = ctrlr->cons_cookie[i];
+
+ if (op && cons->ns_fn != NULL) {
+ ns->cons_cookie[cons->id] =
+ (*cons->ns_fn)(ns, ctrlr_cookie);
+
+ } else {
+ ns->cons_cookie[cons->id] =
+ (*cons->rm_ns_fn)(ns_idx, ctrlr_cookie);
+ }
+ }
+ }
+}
+
static void
nvme_notify(struct nvme_consumer *cons,
struct nvme_controller *ctrlr)
{
struct nvme_namespace *ns;
void *ctrlr_cookie;
- int cmpset, ns_idx;
+ int ns_idx;
/*
* The consumer may register itself after the nvme devices
@@ -308,16 +345,18 @@
if (!ctrlr->is_initialized)
return;
- cmpset = atomic_cmpset_32(&ctrlr->notification_sent, 0, 1);
-
- if (cmpset == 0)
- return;
+ if (ctrlr->cons_cookie[cons->id] == NULL) {
+ if (cons->ctrlr_fn != NULL) {
+ ctrlr_cookie = (*cons->ctrlr_fn)(ctrlr);
+ } else {
+ ctrlr_cookie = NULL;
+ }
+ } else {
+ ctrlr_cookie = ctrlr->cons_cookie[cons->id];
+ }
- if (cons->ctrlr_fn != NULL)
- ctrlr_cookie = (*cons->ctrlr_fn)(ctrlr);
- else
- ctrlr_cookie = NULL;
ctrlr->cons_cookie[cons->id] = ctrlr_cookie;
+
if (ctrlr->is_failed) {
if (cons->fail_fn != NULL)
(*cons->fail_fn)(ctrlr_cookie);
@@ -408,8 +447,8 @@
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,
- nvme_cons_fail_fn_t fail_fn)
+ nvme_cons_async_fn_t async_fn,
+ nvme_cons_fail_fn_t fail_fn, nvme_cons_rm_ns_fn_t rm_ns_fn)
{
int i;
@@ -424,7 +463,7 @@
nvme_consumer[i].ctrlr_fn = ctrlr_fn;
nvme_consumer[i].async_fn = async_fn;
nvme_consumer[i].fail_fn = fail_fn;
-
+ nvme_consumer[i].rm_ns_fn = rm_ns_fn;
nvme_notify_new_consumer(&nvme_consumer[i]);
return (&nvme_consumer[i]);
}
Index: sys/dev/nvme/nvme_ctrlr.c
===================================================================
--- sys/dev/nvme/nvme_ctrlr.c
+++ sys/dev/nvme/nvme_ctrlr.c
@@ -850,6 +850,96 @@
return (0);
}
+struct ns_create_arg {
+ uint16_t nsid;
+ struct nvme_controller *ctrlr;
+};
+
+static void
+nvme_ns_create(void *arg, int pending)
+{
+ struct nvme_controller *ctrlr;
+ struct nvme_sim_softc *sc;
+ struct ns_create_arg *nsarg = (struct ns_create_arg *)arg;
+ int nsid = nsarg->nsid;
+
+ ctrlr = nsarg->ctrlr;
+ sc = ctrlr->sim_softc;
+ nvme_ns_construct(&ctrlr->ns[nsid], nsid, ctrlr);
+ nvme_notify_namespace(ctrlr, nsid, 1); /* new disk */
+ free(arg, M_NVME);
+ return;
+}
+
+static void nvme_ns_detach(void *arg, int pending)
+{
+ struct ns_create_arg *nsarg = arg;
+ struct nvme_controller *ctrlr = nsarg->ctrlr;
+ int nsid = nsarg->nsid;
+
+ nvme_notify_namespace(ctrlr, nsid, 0); /* remove disk */
+}
+
+static void
+nvme_ns_mgmt_done(void *arg, const struct nvme_completion *cpl)
+{
+ struct nvme_pt_command *pt = (struct nvme_pt_command *)arg;
+ struct nvme_controller *ctrlr = pt->ctrlr;
+
+ bzero(&pt->cpl, sizeof(pt->cpl));
+ pt->cpl.cdw0 = cpl->cdw0;
+ pt->cpl.status = cpl->status;
+ pt->cpl.status.p = 0;
+
+ if (pt->cmd.cdw10 == 1 && cpl->status.sc == 0) { /* good delete */
+ memset(&ctrlr->ns[pt->cmd.nsid], 0, sizeof(struct nvme_namespace));
+ }
+
+ mtx_lock(pt->driver_lock);
+ wakeup(pt);
+ mtx_unlock(pt->driver_lock);
+}
+
+
+
+static void
+nvme_ns_attachment_done(void *arg, const struct nvme_completion *cpl)
+{
+ struct nvme_pt_command *pt = arg;
+ struct ns_create_arg *ns_arg = NULL;
+ struct nvme_controller *ctrlr = pt->ctrlr;
+
+ bzero(&pt->cpl, sizeof(pt->cpl));
+ pt->cpl.cdw0 = cpl->cdw0;
+ pt->cpl.status = cpl->status;
+ pt->cpl.status.p = 0;
+
+ if (cpl->status.sc == 0) { /* setup task entry */
+ ns_arg = malloc(sizeof(struct ns_create_arg), M_NVME, M_ZERO | M_NOWAIT);
+ ns_arg->nsid = pt->cmd.nsid;
+ ns_arg->ctrlr = ctrlr;
+ memset(&ctrlr->ns_task, 0, sizeof (struct task));
+
+ ctrlr->ns_task.ta_context = ns_arg;
+ ctrlr->ns_task.ta_pending = 0;
+
+ if (pt->cmd.cdw10 == 0) { /* good attach */
+ ctrlr->ns_task.ta_func = nvme_ns_create; /* create + attach = usable create xxx */
+
+ } else if (pt->cmd.cdw10 == 1) { /* good detach */
+ ctrlr->ns_task.ta_func = nvme_ns_detach;;
+ }
+ taskqueue_enqueue(ctrlr->taskqueue, &ctrlr->ns_task);
+
+ }
+
+ mtx_lock(pt->driver_lock);
+ wakeup(pt);
+ mtx_unlock(pt->driver_lock);
+
+}
+
+
static void
nvme_pt_done(void *arg, const struct nvme_completion *cpl)
{
@@ -912,12 +1002,27 @@
ret = EFAULT;
goto err;
}
- req = nvme_allocate_request_vaddr(buf->b_data, pt->len,
- nvme_pt_done, pt);
- } else
- req = nvme_allocate_request_vaddr(pt->buf, pt->len,
- nvme_pt_done, pt);
- } else
+
+ if (is_admin_cmd && pt->cmd.opc == NVME_OPC_NAMESPACE_MANAGEMENT) {
+ pt->ctrlr = ctrlr;
+ req = nvme_allocate_request_vaddr(buf->b_data, pt->len,
+ nvme_ns_mgmt_done, pt);
+ } else if (is_admin_cmd && pt->cmd.opc == NVME_OPC_NAMESPACE_ATTACHMENT) {
+ pt->ctrlr = ctrlr;
+ req = nvme_allocate_request_vaddr(buf->b_data, pt->len,
+ nvme_ns_attachment_done, pt);
+
+ } else if (pt->cmd.opc == NVME_OPC_NAMESPACE_ATTACHMENT) {
+ req = nvme_allocate_request_vaddr(buf->b_data, pt->len,
+ nvme_ns_attachment_done, pt);
+ } else {
+ req = nvme_allocate_request_vaddr(buf->b_data, pt->len,
+ nvme_pt_done, pt);
+ }
+ } else
+ req = nvme_allocate_request_vaddr(buf->b_data, pt->len,
+ nvme_pt_done, pt);
+ } else
req = nvme_allocate_request_null(nvme_pt_done, pt);
req->cmd.opc = pt->cmd.opc;
Index: sys/dev/nvme/nvme_ns.c
===================================================================
--- sys/dev/nvme/nvme_ns.c
+++ sys/dev/nvme/nvme_ns.c
@@ -508,6 +508,7 @@
DELAY(5);
if (nvme_completion_is_error(&status.cpl)) {
nvme_printf(ctrlr, "nvme_identify_namespace failed\n");
+ ns->id = 0;
return (ENXIO);
}
@@ -517,9 +518,10 @@
* standard says the entire id will be zeros, so this is a
* cheap way to test for that.
*/
- if (ns->data.nsze == 0)
+ if (ns->data.nsze == 0) {
+ ns->id = 0;
return (ENXIO);
-
+ }
/*
* Note: format is a 0-based value, so > is appropriate here,
* not >=.
Index: sys/dev/nvme/nvme_private.h
===================================================================
--- sys/dev/nvme/nvme_private.h
+++ sys/dev/nvme/nvme_private.h
@@ -319,6 +319,9 @@
uint32_t notification_sent;
boolean_t is_failed;
+ void *sim_softc;
+ struct task ns_task;
+
STAILQ_HEAD(, nvme_request) fail_req;
};
@@ -527,4 +530,6 @@
void nvme_ctrlr_intx_handler(void *arg);
+void nvme_notify_namespace(struct nvme_controller *ctrlr, int nsid, int op);
+
#endif /* __NVME_PRIVATE_H__ */
Index: sys/dev/nvme/nvme_sim.c
===================================================================
--- sys/dev/nvme/nvme_sim.c
+++ sys/dev/nvme/nvme_sim.c
@@ -40,6 +40,7 @@
#include <cam/cam.h>
#include <cam/cam_ccb.h>
#include <cam/cam_sim.h>
+#include <cam/cam_periph.h>
#include <cam/cam_xpt_sim.h>
#include <cam/cam_xpt_internal.h> // Yes, this is wrong.
#include <cam/cam_debug.h>
@@ -169,7 +170,7 @@
cpi->hba_eng_cnt = 0;
cpi->max_target = 0;
cpi->max_lun = ctrlr->cdata.nn;
- cpi->maxio = nvme_ns_get_max_io_xfer_size(ns);
+ cpi->maxio = ctrlr->max_xfer_size;
cpi->initiator_id = 0;
cpi->bus_id = cam_sim_bus(sim);
cpi->base_transfer_speed = 4000000; /* 4 GB/s 4 lanes pcie 3 */
@@ -181,7 +182,14 @@
cpi->transport_version = 1; /* XXX Get PCIe spec ? */
cpi->protocol = PROTO_NVME;
cpi->protocol_version = NVME_REV_1; /* Groks all 1.x NVMe cards */
- cpi->xport_specific.nvme.nsid = ns->id;
+ /* it's only the first base namespace that suffers from
+ * a path inq before it's created
+ */
+ if (ns) {
+ cpi->xport_specific.nvme.nsid = ns->id;
+ } else {
+ cpi->xport_specific.nvme.nsid = 1;
+ }
cpi->ccb_h.status = CAM_REQ_CMP;
break;
}
@@ -248,12 +256,14 @@
int max_trans;
int unit;
struct nvme_sim_softc *sc = NULL;
+ int err;
max_trans = 256;/* XXX not so simple -- must match queues */
+ // max_trans = ctrlr->num_io_queues; /* correct here? */
unit = device_get_unit(ctrlr->dev);
devq = cam_simq_alloc(max_trans);
if (devq == NULL)
- return NULL;
+ return (NULL);
sc = malloc(sizeof(*sc), M_NVME, M_ZERO | M_WAITOK);
@@ -265,9 +275,14 @@
printf("Failed to allocate a sim\n");
cam_simq_free(devq);
free(sc, M_NVME);
- return NULL;
+ return (NULL);
}
-
+ err = xpt_bus_register(sc->s_sim, ctrlr->dev, 0);
+ if (err != CAM_SUCCESS) {
+ nvme_printf(ctrlr,"new ctrlr: failed xpt_bus_register : %d\n",
+ err);
+ }
+ ctrlr->sim_softc = sc;
return sc;
}
@@ -296,25 +311,9 @@
{
struct nvme_sim_softc *sc = sc_arg;
struct nvme_controller *ctrlr = sc->s_ctrlr;
- int i;
sc->s_ns = ns;
-
- /*
- * XXX this is creating one bus per ns, but it should be one
- * XXX target per controller, and one LUN per namespace.
- * XXX Current drives only support one NS, so there's time
- * XXX to fix it later when new drives arrive.
- *
- * XXX I'm pretty sure the xpt_bus_register() call below is
- * XXX like super lame and it really belongs in the sim_new_ctrlr
- * XXX callback. Then the create_path below would be pretty close
- * XXX to being right. Except we should be per-ns not per-ctrlr
- * XXX data.
- */
-
mtx_lock(&ctrlr->lock);
-/* Create bus */
/*
* XXX do I need to lock ctrlr->lock ?
@@ -324,36 +323,22 @@
* time, and nothing is in parallel.
*/
- i = 0;
- if (xpt_bus_register(sc->s_sim, ctrlr->dev, 0) != CAM_SUCCESS)
- goto error;
- i++;
if (xpt_create_path(&sc->s_path, /*periph*/NULL, cam_sim_path(sc->s_sim),
- 1, ns->id) != CAM_REQ_CMP)
- goto error;
- i++;
+ 1, ns->id) != CAM_REQ_CMP) {
+ mtx_unlock(&ctrlr->lock);
+ cam_sim_free(sc->s_sim, /*free_devq*/TRUE);
+ return (NULL);
+ }
sc->s_path->device->nvme_data = nvme_ns_get_data(ns);
sc->s_path->device->nvme_cdata = nvme_ctrlr_get_data(ns->ctrlr);
/* Scan bus */
- nvme_sim_rescan_target(ctrlr, sc->s_path);
+ nvme_sim_rescan_target(ctrlr, sc->s_path);
mtx_unlock(&ctrlr->lock);
- return ns;
-
-error:
- switch (i) {
- case 2:
- xpt_free_path(sc->s_path);
- case 1:
- xpt_bus_deregister(cam_sim_path(sc->s_sim));
- case 0:
- cam_sim_free(sc->s_sim, /*free_devq*/TRUE);
- }
- mtx_unlock(&ctrlr->lock);
- return NULL;
+ return (ns);
}
static void
@@ -361,6 +346,15 @@
{
/* XXX cleanup XXX */
}
+static void *
+nvme_sim_rm_namespace(int nsid, void *ctrlr_arg)
+{
+ struct nvme_sim_softc *sc = ctrlr_arg;
+
+ xpt_async(AC_LOST_DEVICE, sc->s_path, NULL);
+ xpt_free_path(sc->s_path);
+ return (NULL);
+}
struct nvme_consumer *consumer_cookie;
@@ -369,7 +363,10 @@
{
consumer_cookie = nvme_register_consumer(nvme_sim_new_ns,
- nvme_sim_new_controller, NULL, nvme_sim_controller_fail);
+ nvme_sim_new_controller,
+ NULL,
+ nvme_sim_controller_fail,
+ nvme_sim_rm_namespace);
}
SYSINIT(nvme_sim_register, SI_SUB_DRIVERS, SI_ORDER_ANY,

File Metadata

Mime Type
text/plain
Expires
Mon, Mar 9, 12:43 AM (20 h, 22 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
29425657
Default Alt Text
D11399.id30189.diff (25 KB)

Event Timeline