Page MenuHomeFreeBSD

D20788.diff
No OneTemporary

D20788.diff

Index: sbin/nvmecontrol/Makefile
===================================================================
--- sbin/nvmecontrol/Makefile
+++ sbin/nvmecontrol/Makefile
@@ -2,8 +2,9 @@
PACKAGE=runtime
PROG= nvmecontrol
-SRCS= nvmecontrol.c devlist.c firmware.c format.c identify.c identify_ext.c logpage.c \
+SRCS= opts.c nvmecontrol.c devlist.c firmware.c format.c identify.c identify_ext.c logpage.c \
perftest.c reset.c ns.c nvme_util.c power.c nc_util.c
+SRCS+= passthru.c
MAN= nvmecontrol.8
LDFLAGS+= -rdynamic
SUBDIR= modules
Index: sbin/nvmecontrol/devlist.c
===================================================================
--- sbin/nvmecontrol/devlist.c
+++ sbin/nvmecontrol/devlist.c
@@ -45,6 +45,8 @@
#define DEVLIST_USAGE \
"devlist\n"
+#define DEVLIST_DESCR \
+ "Display a list of NVMe controllers and namespaces."
#define NVME_MAX_UNIT 256
@@ -120,4 +122,4 @@
exit(1);
}
-NVME_COMMAND(top, devlist, devlist, DEVLIST_USAGE);
+NVME_COMMAND(top, devlist, devlist, DEVLIST_USAGE, NULL, DEVLIST_DESCR);
Index: sbin/nvmecontrol/firmware.c
===================================================================
--- sbin/nvmecontrol/firmware.c
+++ sbin/nvmecontrol/firmware.c
@@ -50,8 +50,13 @@
#include "nvmecontrol.h"
-#define FIRMWARE_USAGE \
+#define FIRMWARE_USAGE \
"firmware [-s slot] [-f path_to_firmware] [-a] <controller id>\n"
+#define FIRMWARE_ARGS \
+ "<controller id>"
+#define FIRMWARE_DESCR \
+ "Download firmware image to controller."
+
static int
slot_has_valid_firmware(int fd, int slot)
@@ -333,4 +338,4 @@
exit(0);
}
-NVME_COMMAND(top, firmware, firmware, FIRMWARE_USAGE);
+NVME_COMMAND(top, firmware, firmware, FIRMWARE_USAGE, FIRMWARE_ARGS, FIRMWARE_DESCR);
Index: sbin/nvmecontrol/format.c
===================================================================
--- sbin/nvmecontrol/format.c
+++ sbin/nvmecontrol/format.c
@@ -43,8 +43,12 @@
#include "nvmecontrol.h"
-#define FORMAT_USAGE \
+#define FORMAT_USAGE \
"format [-f fmt] [-m mset] [-p pi] [-l pil] [-E] [-C] <controller id|namespace id>\n"
+#define FORMAT_ARGS \
+ "<controller id|namespace id>"
+#define FORMAT_DESCR \
+ "Format/erase one or all the namespaces."
static void
format(const struct nvme_function *nf, int argc, char *argv[])
@@ -181,4 +185,4 @@
exit(0);
}
-NVME_COMMAND(top, format, format, FORMAT_USAGE);
+NVME_COMMAND(top, format, format, FORMAT_USAGE, FORMAT_ARGS, FORMAT_DESCR);
Index: sbin/nvmecontrol/identify.c
===================================================================
--- sbin/nvmecontrol/identify.c
+++ sbin/nvmecontrol/identify.c
@@ -45,6 +45,10 @@
#define IDENTIFY_USAGE \
"identify [-x [-v]] <controller id|namespace id>\n"
+#define IDENTIFY_ARGS \
+ "<controller id|namespace id>"
+#define IDENTIFY_DESCR \
+ "Print a human-readable summary of the IDENTIFY information from namespace or controller"
static void
print_namespace(struct nvme_namespace_data *nsdata)
@@ -299,4 +303,4 @@
identify_ns(nf, argc, argv);
}
-NVME_COMMAND(top, identify, identify, IDENTIFY_USAGE);
+NVME_COMMAND(top, identify, identify, IDENTIFY_USAGE, IDENTIFY_ARGS, IDENTIFY_DESCR);
Index: sbin/nvmecontrol/logpage.c
===================================================================
--- sbin/nvmecontrol/logpage.c
+++ sbin/nvmecontrol/logpage.c
@@ -49,7 +49,11 @@
#include "nvmecontrol.h"
#define LOGPAGE_USAGE \
- "logpage <-p page_id> [-b] [-v vendor] [-x] <controller id|namespace id>\n" \
+ "logpage <-p page_id> [-b] [-v vendor] [-x] <controller id|namespace id>\n"
+#define LOGPAGE_ARGS \
+ "<controller id|namespace id>"
+#define LOGPAGE_DESCR \
+ "Print logpages in human-readable form"
#define MAX_FW_SLOTS (7)
@@ -471,4 +475,4 @@
exit(0);
}
-NVME_COMMAND(top, logpage, logpage, LOGPAGE_USAGE);
+NVME_COMMAND(top, logpage, logpage, LOGPAGE_USAGE, LOGPAGE_ARGS, LOGPAGE_DESCR);
Index: sbin/nvmecontrol/modules/wdc/wdc.c
===================================================================
--- sbin/nvmecontrol/modules/wdc/wdc.c
+++ sbin/nvmecontrol/modules/wdc/wdc.c
@@ -41,8 +41,12 @@
#include "nvmecontrol.h"
-#define WDC_USAGE \
+#define WDC_USAGE \
"wdc (cap-diag)\n"
+#define WDC_ARGS \
+ "subcommand"
+#define WDC_DESCR \
+ "Western Digital (WDC, HGST) specific commands"
NVME_CMD_DECLARE(wdc, struct nvme_function);
@@ -54,8 +58,10 @@
static void wdc_cap_diag(const struct nvme_function *nf, int argc, char *argv[]);
#define WDC_CAP_DIAG_USAGE "wdc cap-diag [-o path-template]\n"
+#define WDC_CAP_ARGS "<controller-id>"
+#define WDC_CAP_DESCR "Retrieve the drive's cap-diag logs"
-NVME_COMMAND(wdc, cap-diag, wdc_cap_diag, WDC_CAP_DIAG_USAGE);
+NVME_COMMAND(wdc, cap-diag, wdc_cap_diag, WDC_CAP_DIAG_USAGE, WDC_CAP_ARGS, WDC_CAP_DESCR);
static void
wdc_append_serial_name(int fd, char *buf, size_t len, const char *suffix)
@@ -593,4 +599,4 @@
NVME_LOGPAGE(wdc_info,
HGST_INFO_LOG, "wdc", "Detailed Health/SMART",
print_hgst_info_log, DEFAULT_SIZE);
-NVME_COMMAND(top, wdc, wdc, WDC_USAGE);
+NVME_COMMAND(top, wdc, wdc, WDC_USAGE, WDC_ARGS, WDC_DESCR);
Index: sbin/nvmecontrol/ns.c
===================================================================
--- sbin/nvmecontrol/ns.c
+++ sbin/nvmecontrol/ns.c
@@ -60,15 +60,29 @@
#define NSDETACH_USAGE \
"ns detach -n nsid [-c ctrlrid] nvmeN\n"
+#define CREATE_DESCR \
+ "Create a new namespace"
+#define DELETE_DESCR \
+ "Delete a new namespace"
+#define ATTACH_DESCR \
+ "Attach a new namespace"
+#define DETACH_DESCR \
+ "Detach a new namespace"
+
+#define NS_ARGS \
+ "<controller-id>"
+#define NS_DESCR \
+ "Various commands to create and manage namespaces"
+
static void nscreate(const struct nvme_function *nf, int argc, char *argv[]);
static void nsdelete(const struct nvme_function *nf, int argc, char *argv[]);
static void nsattach(const struct nvme_function *nf, int argc, char *argv[]);
static void nsdetach(const struct nvme_function *nf, int argc, char *argv[]);
-NVME_COMMAND(ns, create, nscreate, NSCREATE_USAGE);
-NVME_COMMAND(ns, delete, nsdelete, NSDELETE_USAGE);
-NVME_COMMAND(ns, attach, nsattach, NSATTACH_USAGE);
-NVME_COMMAND(ns, detach, nsdetach, NSDETACH_USAGE);
+NVME_COMMAND(ns, create, nscreate, NSCREATE_USAGE, NS_ARGS, CREATE_DESCR);
+NVME_COMMAND(ns, delete, nsdelete, NSDELETE_USAGE, NS_ARGS, DELETE_DESCR);
+NVME_COMMAND(ns, attach, nsattach, NSATTACH_USAGE, NS_ARGS, ATTACH_DESCR);
+NVME_COMMAND(ns, detach, nsdetach, NSDETACH_USAGE, NS_ARGS, DETACH_DESCR);
struct ns_result_str {
uint16_t res;
@@ -443,4 +457,4 @@
DISPATCH(argc, argv, ns);
}
-NVME_COMMAND(top, ns, ns, NS_USAGE);
+NVME_COMMAND(top, ns, ns, NS_USAGE, NS_ARGS, NS_DESCR);
Index: sbin/nvmecontrol/nvmecontrol.h
===================================================================
--- sbin/nvmecontrol/nvmecontrol.h
+++ sbin/nvmecontrol/nvmecontrol.h
@@ -42,13 +42,16 @@
const char *name;
nvme_fn_t fn;
const char *usage;
+ const char *args;
+ const char *descr;
};
#define NVME_SETNAME(set) set
#define NVME_CMDSET(set, sym) DATA_SET(NVME_SETNAME(set), sym)
-#define NVME_COMMAND(set, nam, function, usage_str) \
+#define NVME_COMMAND(set, nam, function, usage_str, args_str, descr_str) \
static struct nvme_function function ## _nvme_cmd = \
- { .name = #nam, .fn = function, .usage = usage_str }; \
+ { .name = #nam, .fn = function, .usage = usage_str, \
+ .args = args_str, .descr = descr_str }; \
NVME_CMDSET(set, function ## _nvme_cmd)
#define NVME_CMD_BEGIN(set) SET_BEGIN(NVME_SETNAME(set))
#define NVME_CMD_LIMIT(set) SET_LIMIT(NVME_SETNAME(set))
@@ -127,6 +130,9 @@
(const struct nvme_function * const *)NVME_CMD_BEGIN(set), \
(const struct nvme_function * const *)NVME_CMD_LIMIT(set)) \
+struct args;
+int arg_parse_and_open(int argc, char * const * argv, const char *desc, const struct args *args);
+
/* Utility Routines */
/*
* 128-bit integer augments to standard values. On i386 this
Index: sbin/nvmecontrol/nvmecontrol.c
===================================================================
--- sbin/nvmecontrol/nvmecontrol.c
+++ sbin/nvmecontrol/nvmecontrol.c
@@ -48,9 +48,21 @@
#include <unistd.h>
#include "nvmecontrol.h"
+#include "opts.h"
SET_CONCAT_DEF(top, struct nvme_function);
+int
+arg_parse_and_open(int argc, char * const * argv, const char *desc, const struct args *args)
+{
+ int fd;
+
+ if (arg_parse(argc, argv, desc, args))
+ return (-1);
+ open_dev(argv[optind], &fd, 1, 1);
+ return (fd);
+}
+
static void
print_usage(const struct nvme_function *f)
{
Index: sbin/nvmecontrol/opts.h
===================================================================
--- sbin/nvmecontrol/opts.h
+++ sbin/nvmecontrol/opts.h
@@ -1,8 +1,7 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
*
- * Copyright (C) 2012-2013 Intel Corporation
- * All rights reserved.
+ * Copyright (c) 2019 Netflix, Inc
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -24,47 +23,33 @@
* 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.
+ *
+ * $FreeBSD$
*/
-#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"
-
-#define RESET_USAGE \
- "reset <controller id>\n"
+#ifndef ARG_H
+#define ARG_H
-static void
-reset(const struct nvme_function *nf, int argc, char *argv[])
-{
- int ch, fd;
-
- while ((ch = getopt(argc, argv, "")) != -1) {
- switch ((char)ch) {
- default:
- usage(nf);
- }
- }
-
- /* Check that a controller was specified. */
- if (optind >= argc)
- usage(nf);
-
- open_dev(argv[optind], &fd, 1, 1);
- if (ioctl(fd, NVME_RESET_CONTROLLER) < 0)
- err(1, "reset request to %s failed", argv[optind]);
-
- exit(0);
-}
+/*
+ * Regularized parsing of simple arguments built on top of getopt_long.
+ */
-NVME_COMMAND(top, reset, reset, RESET_USAGE);
+typedef enum arg_type {
+ arg_none = 0,
+ arg_uint8,
+ arg_uint16,
+ arg_uint32,
+ arg_string,
+ arg_path,
+} arg_type;
+
+struct args {
+ const char *long_arg;
+ int short_arg;
+ arg_type at;
+ void *ptr;
+ const char *descr;
+};
+
+int arg_parse(int argc, char * const * argv, const char *desc, const struct args *);
+#endif /* ARG_H */
Index: sbin/nvmecontrol/opts.c
===================================================================
--- /dev/null
+++ sbin/nvmecontrol/opts.c
@@ -0,0 +1,162 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2019 Netflix, Inc
+ *
+ * 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.
+ * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 <ctype.h>
+#include <err.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "opts.h"
+
+static void
+arg_suffix(char *buf, size_t len, arg_type at)
+{
+ switch (at) {
+ case arg_none:
+ break;
+ case arg_string:
+ strlcat(buf, "=<STRING>", len);
+ break;
+ case arg_path:
+ strlcat(buf, "=<FILE>", len);
+ break;
+ default:
+ strlcat(buf, "=<NUM>", len);
+ break;
+ }
+}
+
+static void
+arg_help(int argc __unused, char * const *argv, const char *desc, const struct args *args)
+{
+ int i;
+ char buf[41];
+ char *cp;
+
+ if (argv[optind])
+ fprintf(stderr, "Unknown argument: %s\n", argv[optind]);
+ fprintf(stderr, "Usage:\n nvmecontrol %s device <args>\n", argv[0]);
+ fprintf(stderr, "\n%s\n", desc);
+ fprintf(stderr, "Options:\n");
+ for (i = 0; args[i].long_arg != NULL; i++) {
+ strlcpy(buf, " [ --", sizeof(buf));
+ strlcat(buf, args[i].long_arg, sizeof(buf));
+ arg_suffix(buf, sizeof(buf), args[i].at);
+ if (isprint(args[i].short_arg)) {
+ strlcat(buf, ", -", sizeof(buf));
+ cp = buf + strlen(buf);
+ if (cp - buf < (ptrdiff_t)sizeof(buf) - 2) {
+ *cp++ = args[i].short_arg;
+ *cp++ = '\0';
+ }
+ arg_suffix(buf, sizeof(buf), args[i].at);
+ }
+ strlcat(buf, " ]", sizeof(buf));
+ fprintf(stderr, "%-40.40s - %s\n", buf, args[i].descr);
+ }
+ exit(1);
+}
+
+int
+arg_parse(int argc, char * const * argv, const char *desc, const struct args *args)
+{
+ int i, n, idx, ch;
+ unsigned long v;
+ struct option *opts;
+ char *shortopts, *p;
+
+ for (n = 0; args[n].long_arg != NULL;)
+ n++;
+ opts = malloc((n + 2) * sizeof(struct option));
+ if (opts == NULL)
+ err(1, "option memory");
+ p = shortopts = malloc((n + 3) * sizeof(char));
+ if (shortopts == NULL)
+ err(1, "shortopts memory");
+ for (i = 0; i < n; i++) {
+ opts[i].name = args[i].long_arg;
+ opts[i].has_arg = args[i].at == arg_none ? no_argument : required_argument;
+ opts[i].flag = NULL;
+ opts[i].val = args[i].short_arg;
+ if (isprint(args[i].short_arg))
+ *p++ = args[i].short_arg;
+ }
+ opts[n].name = "help";
+ opts[n].has_arg = no_argument;
+ opts[n].flag = NULL;
+ opts[n].val = '?';
+ *p++ = '?';
+ *p++ = '\0';
+ memset(opts + n + 1, 0, sizeof(struct option));
+ while ((ch = getopt_long(argc, argv, shortopts, opts, &idx)) != -1) {
+ if (idx == n)
+ arg_help(argc, argv, desc, args);
+ switch (args[idx].at) {
+ case arg_none:
+ *(bool *)args[idx].ptr = true;
+ break;
+ case arg_string:
+ case arg_path:
+ *(const char **)args[idx].ptr = optarg;
+ break;
+ case arg_uint8:
+ v = strtoul(optarg, NULL, 0);
+ if (v > 0xff)
+ goto bad_arg;
+ *(uint8_t *)args[idx].ptr = v;
+ break;
+ case arg_uint16:
+ v = strtoul(optarg, NULL, 0);
+ if (v > 0xffff)
+ goto bad_arg;
+ *(uint16_t *)args[idx].ptr = v;
+ break;
+ case arg_uint32:
+ v = strtoul(optarg, NULL, 0);
+ if (v > 0xffffffff)
+ goto bad_arg;
+ *(uint32_t *)args[idx].ptr = v;
+ break;
+ }
+ }
+ return (0);
+bad_arg:
+ fprintf(stderr, "Bad value to --%s: %s\n", args[idx].long_arg, optarg);
+ exit(1);
+}
Index: sbin/nvmecontrol/passthru.c
===================================================================
--- /dev/null
+++ sbin/nvmecontrol/passthru.c
@@ -0,0 +1,276 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (C) 2012-2013 Intel Corporation
+ * 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.
+ * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "opts.h"
+#include "nvmecontrol.h"
+
+#define ADMIN_USAGE \
+ "admin-passthru >>args<<\n"
+#define ADMIN_ARGS \
+ "<controller-id>"
+#define ADMIN_DESCR \
+ "Send a raw administrative command to the controller via a passthrough interface."
+#define IO_USAGE \
+ "io-passthru >>args<<\n"
+#define IO_ARGS \
+ "<namespace-id>"
+#define IO_DESCR \
+ "Send a raw I/O command to the controller via a passthrough interface."
+
+static void
+passthru(const struct nvme_function *nf __unused, int argc, char *argv[], const char *desc)
+{
+ int fd = -1, ifd = -1;
+ void *data = NULL, *metadata = NULL;
+ struct nvme_pt_command pt;
+
+ struct options {
+ uint8_t opcode;
+ uint8_t flags;
+ uint16_t rsvd;
+ uint32_t nsid;
+ uint32_t data_len;
+ uint32_t metadata_len;
+ uint32_t timeout;
+ uint32_t cdw2;
+ uint32_t cdw3;
+ uint32_t cdw10;
+ uint32_t cdw11;
+ uint32_t cdw12;
+ uint32_t cdw13;
+ uint32_t cdw14;
+ uint32_t cdw15;
+ const char *ifn;
+ bool binary;
+ bool show_command;
+ bool dry_run;
+ bool read;
+ bool write;
+ uint8_t prefill;
+ } opt = {
+ .binary = false,
+ .cdw10 = 0,
+ .cdw11 = 0,
+ .cdw12 = 0,
+ .cdw13 = 0,
+ .cdw14 = 0,
+ .cdw15 = 0,
+ .cdw2 = 0,
+ .cdw3 = 0,
+ .data_len = 0,
+ .dry_run = false,
+ .flags = 0,
+ .ifn = "",
+ .metadata_len = 0,
+ .nsid = 0,
+ .opcode = 0,
+ .prefill = 0,
+ .read = false,
+ .rsvd = 0,
+ .show_command = false,
+ .timeout = 0,
+ .write = false,
+ };
+
+ const char *opcode = "NVMe command opcode (required)";
+ const char *flags = "NVMe command flags";
+ const char *rsvd = "Reserved field value";
+ const char *nsid = "Namespace id (ignored on FreeBSD)";
+ const char *data_len = "Length of data for I/O (bytes)";
+ const char *metadata_len = "Length of metadata segment (bytes) (igored)";
+ const char *cdw2 = "Command dword 2 value";
+ const char *cdw3 = "Command dword 3 value";
+ const char *cdw10 = "Command dword 10 value";
+ const char *cdw11 = "Command dword 11 value";
+ const char *cdw12 = "Command dword 12 value";
+ const char *cdw13 = "Command dword 13 value";
+ const char *cdw14 = "Command dword 14 value";
+ const char *cdw15 = "Command dword 15 value";
+ const char *inf = "Input file to send (default stdin)";
+ const char *timeout = "Command timeout (ms)";
+ const char *raw = "Output in binary format";
+ const char *prefill = "Value to prefill payload with";
+ const char *dry_run = "Don't actually execute the command";
+ const char *rd = "Command reads data from device";
+ const char *wr = "Command writes data to device";
+ const char *show = "Show all the command values on stdout";
+ /*
+ * Argument names and short names selected to match the nvme-cli program
+ * so vendor-siupplied formulas work out of the box on FreeBSD with a simple
+ * s/nvme/nvmecontrol/.
+ */
+ const struct args args[] = {
+ { "opcode", 'o', arg_uint8, &opt.opcode, opcode},
+ { "cdw2", '2', arg_uint32, &opt.cdw2, cdw2},
+ { "cdw3", '3', arg_uint32, &opt.cdw3, cdw3},
+ { "cdw10", '4', arg_uint32, &opt.cdw10, cdw10},
+ { "cdw11", '5', arg_uint32, &opt.cdw11, cdw11},
+ { "cdw12", '6', arg_uint32, &opt.cdw12, cdw12},
+ { "cdw13", '7', arg_uint32, &opt.cdw13, cdw13},
+ { "cdw14", '8', arg_uint32, &opt.cdw14, cdw14},
+ { "cdw15", '9', arg_uint32, &opt.cdw15, cdw15},
+ { "data-len", 'l', arg_uint32, &opt.data_len, data_len},
+ { "metadata-len", 'm', arg_uint32, &opt.metadata_len, metadata_len},
+ { "flags", 'f', arg_uint8, &opt.flags, flags},
+ { "input-file", 'i', arg_path, &opt.ifn, inf},
+ { "namespace-id", 'n', arg_uint32, &opt.nsid, nsid},
+ { "prefill", 'p', arg_uint8, &opt.prefill, prefill},
+ { "rsvd", 'R', arg_uint16, &opt.rsvd, rsvd},
+ { "timeout", 't', arg_uint32, &opt.timeout, timeout},
+ { "raw-binary", 'b', arg_none, &opt.binary, raw},
+ { "dry-run", 'd', arg_none, &opt.dry_run, dry_run},
+ { "read", 'r', arg_none, &opt.read, rd},
+ { "show-command", 's', arg_none, &opt.show_command, show},
+ { "write", 'w', arg_none, &opt.write, wr},
+ { NULL, 0, arg_none, NULL, NULL }
+ };
+
+ fd = arg_parse_and_open(argc, argv, desc, args);
+ if (fd == -1)
+ err(1, "open %s", argv[optind]);
+
+ if (opt.read && opt.write)
+ errx(1, "need exactly one of --read or --write");
+ if (opt.data_len != 0 && !opt.read && !opt.write)
+ errx(1, "need exactly one of --read or --write");
+ if (*opt.ifn && (ifd = open(opt.ifn, O_RDONLY)) == -1) {
+ warn("open %s", opt.ifn);
+ goto cleanup;
+ }
+#if notyet /* No support in kernel for this */
+ if (opt.metadata_len != 0) {
+ if (posix_memalign(&metadata, getpagesize(), opt.metadata_len)) {
+ warn("can't allocate %d bytes for metadata", metadata_len);
+ goto cleanup;
+ }
+ }
+#else
+ if (opt.metadata_len != 0)
+ errx(1, "metadata not supported on FreeBSD");
+#endif
+ if (opt.data_len) {
+ if (posix_memalign(&data, getpagesize(), opt.data_len)) {
+ warn("can't allocate %d bytes for data", opt.data_len);
+ goto cleanup;
+ }
+ memset(data, opt.prefill, opt.data_len);
+ if (opt.write && read(ifd, data, opt.data_len) < 0) {
+ warn("read %s", *opt.ifn ? opt.ifn : "stdin");
+ goto cleanup;
+ }
+ }
+ if (opt.show_command) {
+ fprintf(stderr, "opcode : %#02x\n", opt.opcode);
+ fprintf(stderr, "flags : %#02x\n", opt.flags);
+ fprintf(stderr, "rsvd1 : %#04x\n", opt.rsvd);
+ fprintf(stderr, "nsid : %#04x\n", opt.nsid);
+ fprintf(stderr, "cdw2 : %#08x\n", opt.cdw2);
+ fprintf(stderr, "cdw3 : %#08x\n", opt.cdw3);
+ fprintf(stderr, "data_len : %#08x\n", opt.data_len);
+ fprintf(stderr, "metadata_len : %#08x\n", opt.metadata_len);
+ fprintf(stderr, "data : %p\n", data);
+ fprintf(stderr, "metadata : %p\n", metadata);
+ fprintf(stderr, "cdw10 : %#08x\n", opt.cdw10);
+ fprintf(stderr, "cdw11 : %#08x\n", opt.cdw11);
+ fprintf(stderr, "cdw12 : %#08x\n", opt.cdw12);
+ fprintf(stderr, "cdw13 : %#08x\n", opt.cdw13);
+ fprintf(stderr, "cdw14 : %#08x\n", opt.cdw14);
+ fprintf(stderr, "cdw15 : %#08x\n", opt.cdw15);
+ fprintf(stderr, "timeout_ms : %d\n", opt.timeout);
+ }
+ if (opt.dry_run) {
+ errno = 0;
+ goto cleanup;
+ }
+
+ memset(&pt, 0, sizeof(pt));
+ pt.cmd.opc = opt.opcode;
+ pt.cmd.fuse = opt.flags;
+ pt.cmd.cid = htole16(opt.rsvd);
+ pt.cmd.nsid = opt.nsid; /* XXX note: kernel overrides this */
+ pt.cmd.rsvd2 = htole32(opt.cdw2);
+ pt.cmd.rsvd3 = htole32(opt.cdw3);
+ pt.cmd.cdw10 = htole32(opt.cdw10);
+ pt.cmd.cdw11 = htole32(opt.cdw11);
+ pt.cmd.cdw12 = htole32(opt.cdw12);
+ pt.cmd.cdw13 = htole32(opt.cdw13);
+ pt.cmd.cdw14 = htole32(opt.cdw14);
+ pt.cmd.cdw15 = htole32(opt.cdw15);
+ pt.buf = data;
+ pt.len = opt.data_len;
+ pt.is_read = opt.read;
+
+ if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
+ err(1, "passthrough request failed");
+ /* XXX report status */
+ if (opt.read) {
+ if (opt.binary)
+ write(STDOUT_FILENO, data, opt.data_len);
+ else {
+ /* print status here */
+ print_hex(data, opt.data_len);
+ }
+ }
+cleanup:
+ if (errno)
+ exit(1);
+}
+
+static void
+admin_passthru(const struct nvme_function *nf, int argc, char *argv[])
+{
+ const char *desc = "Send a pass through Admin command to the specified device\n";
+
+ passthru(nf, argc, argv, desc);
+}
+
+static void
+io_passthru(const struct nvme_function *nf, int argc, char *argv[])
+{
+ const char *desc = "Send a pass through I/O command to the specified device\n";
+
+ passthru(nf, argc, argv, desc);
+}
+
+NVME_COMMAND(top, admin-passthru, admin_passthru, ADMIN_USAGE, ADMIN_ARGS, ADMIN_DESCR);
+NVME_COMMAND(top, admin-passthru, io_passthru, IO_USAGE, IO_ARGS, IO_DESCR);
Index: sbin/nvmecontrol/perftest.c
===================================================================
--- sbin/nvmecontrol/perftest.c
+++ sbin/nvmecontrol/perftest.c
@@ -50,6 +50,10 @@
" <-s size_in_bytes> <-t time_in_seconds>\n" \
" <-i intr|wait> [-f refthread] [-p]\n" \
" <namespace id>\n"
+#define PERFTEST_ARGS \
+ "<namespace id>"
+#define PERFTEST_DESCR \
+ "PErform low-level driver performance testing."
static void
print_perftest(struct nvme_io_test *io_test, bool perthread)
@@ -176,4 +180,4 @@
exit(0);
}
-NVME_COMMAND(top, perftest, perftest, PERFTEST_USAGE);
+NVME_COMMAND(top, perftest, perftest, PERFTEST_USAGE, PERFTEST_ARGS, PERFTEST_DESCR);
Index: sbin/nvmecontrol/power.c
===================================================================
--- sbin/nvmecontrol/power.c
+++ sbin/nvmecontrol/power.c
@@ -43,8 +43,12 @@
_Static_assert(sizeof(struct nvme_power_state) == 256 / NBBY,
"nvme_power_state size wrong");
-#define POWER_USAGE \
+#define POWER_USAGE \
"power [-l] [-p new-state [-w workload-hint]] <controller id>\n"
+#define POWER_ARGS \
+ "<controller-id>"
+#define POWER_DESCR \
+ "Manage power states for the drive"
static void
power_list_one(int i, struct nvme_power_state *nps)
@@ -188,4 +192,4 @@
exit(0);
}
-NVME_COMMAND(top, power, power, POWER_USAGE);
+NVME_COMMAND(top, power, power, POWER_USAGE, POWER_ARGS, POWER_DESCR);
Index: sbin/nvmecontrol/reset.c
===================================================================
--- sbin/nvmecontrol/reset.c
+++ sbin/nvmecontrol/reset.c
@@ -41,8 +41,12 @@
#include "nvmecontrol.h"
-#define RESET_USAGE \
+#define RESET_USAGE \
"reset <controller id>\n"
+#define RESET_ARGS \
+ "<controller id>"
+#define RESET_DESCR \
+ "Perform a controller-level reset."
static void
reset(const struct nvme_function *nf, int argc, char *argv[])
@@ -67,4 +71,4 @@
exit(0);
}
-NVME_COMMAND(top, reset, reset, RESET_USAGE);
+NVME_COMMAND(top, reset, reset, RESET_USAGE, RESET_ARGS, RESET_DESCR);

File Metadata

Mime Type
text/plain
Expires
Fri, Apr 24, 9:52 AM (16 h, 32 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
32071523
Default Alt Text
D20788.diff (26 KB)

Event Timeline