Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F147062630
D11399.id30189.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
25 KB
Referenced Files
None
Subscribers
None
D11399.id30189.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D11399: nvme: Add namespace mgmt and attachment support.
Attached
Detach File
Event Timeline
Log In to Comment