[Midnightbsd-cvs] src [9819] trunk/sbin: add nvmecontrol(8)

laffer1 at midnightbsd.org laffer1 at midnightbsd.org
Wed Apr 25 19:38:17 EDT 2018


Revision: 9819
          http://svnweb.midnightbsd.org/src/?rev=9819
Author:   laffer1
Date:     2018-04-25 19:38:10 -0400 (Wed, 25 Apr 2018)
Log Message:
-----------
add nvmecontrol(8)

Modified Paths:
--------------
    trunk/sbin/Makefile

Added Paths:
-----------
    trunk/sbin/nvmecontrol/
    trunk/sbin/nvmecontrol/Makefile
    trunk/sbin/nvmecontrol/devlist.c
    trunk/sbin/nvmecontrol/firmware.c
    trunk/sbin/nvmecontrol/identify.c
    trunk/sbin/nvmecontrol/logpage.c
    trunk/sbin/nvmecontrol/nvmecontrol.8
    trunk/sbin/nvmecontrol/nvmecontrol.c
    trunk/sbin/nvmecontrol/nvmecontrol.h
    trunk/sbin/nvmecontrol/perftest.c
    trunk/sbin/nvmecontrol/reset.c

Modified: trunk/sbin/Makefile
===================================================================
--- trunk/sbin/Makefile	2018-04-25 23:35:40 UTC (rev 9818)
+++ trunk/sbin/Makefile	2018-04-25 23:38:10 UTC (rev 9819)
@@ -59,6 +59,7 @@
 	newfs_msdos \
 	nfsiod \
 	nos-tun \
+	nvmecontrol \
 	ping \
 	rcorder \
 	reboot \

Added: trunk/sbin/nvmecontrol/Makefile
===================================================================
--- trunk/sbin/nvmecontrol/Makefile	                        (rev 0)
+++ trunk/sbin/nvmecontrol/Makefile	2018-04-25 23:38:10 UTC (rev 9819)
@@ -0,0 +1,10 @@
+# $MidnightBSD$
+
+PROG=	nvmecontrol
+SRCS=	nvmecontrol.c devlist.c firmware.c identify.c logpage.c	\
+	perftest.c reset.c nvme_util.c
+MAN=	nvmecontrol.8
+
+.PATH:	${.CURDIR}/../../sys/dev/nvme
+
+.include <bsd.prog.mk>


Property changes on: trunk/sbin/nvmecontrol/Makefile
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sbin/nvmecontrol/devlist.c
===================================================================
--- trunk/sbin/nvmecontrol/devlist.c	                        (rev 0)
+++ trunk/sbin/nvmecontrol/devlist.c	2018-04-25 23:38:10 UTC (rev 9819)
@@ -0,0 +1,117 @@
+/* $MidnightBSD$ */
+/*-
+ * 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: stable/9/sbin/nvmecontrol/devlist.c 265558 2014-05-07 16:40:44Z jimharris $");
+
+#include <sys/param.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "nvmecontrol.h"
+
+static void
+devlist_usage(void)
+{
+	fprintf(stderr, "usage:\n");
+	fprintf(stderr, DEVLIST_USAGE);
+	exit(1);
+}
+
+static inline uint32_t
+ns_get_sector_size(struct nvme_namespace_data *nsdata)
+{
+
+	return (1 << nsdata->lbaf[nsdata->flbas.format].lbads);
+}
+
+void
+devlist(int argc, char *argv[])
+{
+	struct nvme_controller_data	cdata;
+	struct nvme_namespace_data	nsdata;
+	char				name[64];
+	uint8_t				mn[64];
+	uint32_t			i;
+	int				ch, ctrlr, fd, found, ret;
+
+	while ((ch = getopt(argc, argv, "")) != -1) {
+		switch ((char)ch) {
+		default:
+			devlist_usage();
+		}
+	}
+
+	ctrlr = -1;
+	found = 0;
+
+	while (1) {
+		ctrlr++;
+		sprintf(name, "%s%d", NVME_CTRLR_PREFIX, ctrlr);
+
+		ret = open_dev(name, &fd, 0, 0);
+
+		if (ret != 0) {
+			if (ret == EACCES) {
+				warnx("could not open "_PATH_DEV"%s\n", name);
+				continue;
+			} else
+				break;
+		}
+
+		found++;
+		read_controller_data(fd, &cdata);
+		nvme_strvis(mn, cdata.mn, sizeof(mn), NVME_MODEL_NUMBER_LENGTH);
+		printf("%6s: %s\n", name, mn);
+
+		for (i = 0; i < cdata.nn; i++) {
+			sprintf(name, "%s%d%s%d", NVME_CTRLR_PREFIX, ctrlr,
+			    NVME_NS_PREFIX, i+1);
+			read_namespace_data(fd, i+1, &nsdata);
+			printf("  %10s (%lldMB)\n",
+				name,
+				nsdata.nsze *
+				(long long)ns_get_sector_size(&nsdata) /
+				1024 / 1024);
+		}
+
+		close(fd);
+	}
+
+	if (found == 0)
+		printf("No NVMe controllers found.\n");
+
+	exit(1);
+}


Property changes on: trunk/sbin/nvmecontrol/devlist.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sbin/nvmecontrol/firmware.c
===================================================================
--- trunk/sbin/nvmecontrol/firmware.c	                        (rev 0)
+++ trunk/sbin/nvmecontrol/firmware.c	2018-04-25 23:38:10 UTC (rev 9819)
@@ -0,0 +1,323 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2013 EMC Corp.
+ * All rights reserved.
+ *
+ * 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: stable/9/sbin/nvmecontrol/firmware.c 265557 2014-05-07 16:37:04Z jimharris $");
+
+#include <sys/param.h>
+#include <sys/ioccom.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "nvmecontrol.h"
+
+static int
+slot_has_valid_firmware(int fd, int slot)
+{
+	struct nvme_firmware_page	fw;
+	int				has_fw = false;
+
+	read_logpage(fd, NVME_LOG_FIRMWARE_SLOT,
+	    NVME_GLOBAL_NAMESPACE_TAG, &fw, sizeof(fw));
+
+	if (fw.revision[slot-1] != 0LLU)
+		has_fw = true;
+
+	return (has_fw);
+}
+
+static void
+read_image_file(char *path, void **buf, int32_t *size)
+{
+	struct stat	sb;
+	int32_t		filesize;
+	int		fd;
+
+	*size = 0;
+	*buf = NULL;
+
+	if ((fd = open(path, O_RDONLY)) < 0)
+		err(1, "unable to open '%s'", path);
+	if (fstat(fd, &sb) < 0)
+		err(1, "unable to stat '%s'", path);
+
+	/*
+	 * The NVMe spec does not explicitly state a maximum firmware image
+	 *  size, although one can be inferred from the dword size limitation
+	 *  for the size and offset fields in the Firmware Image Download
+	 *  command.
+	 *
+	 * Technically, the max is UINT32_MAX * sizeof(uint32_t), since the
+	 *  size and offsets are specified in terms of dwords (not bytes), but
+	 *  realistically INT32_MAX is sufficient here and simplifies matters
+	 *  a bit.
+	 */
+	if (sb.st_size > INT32_MAX)
+		errx(1, "size of file '%s' is too large (%jd bytes)",
+		    path, (intmax_t)sb.st_size);
+	filesize = (int32_t)sb.st_size;
+	if ((*buf = malloc(filesize)) == NULL)
+		errx(1, "unable to malloc %d bytes", filesize);
+	if ((*size = read(fd, *buf, filesize)) < 0)
+		err(1, "error reading '%s'", path);
+	/* XXX assuming no short reads */
+	if (*size != filesize)
+		errx(1,
+		    "error reading '%s' (read %d bytes, requested %d bytes)",
+		    path, *size, filesize);
+}
+
+static void
+update_firmware(int fd, uint8_t *payload, int32_t payload_size)
+{
+	struct nvme_pt_command	pt;
+	int32_t			off, resid, size;
+	void			*chunk;
+
+	off = 0;
+	resid = payload_size;
+
+	if ((chunk = malloc(NVME_MAX_XFER_SIZE)) == NULL)
+		errx(1, "unable to malloc %d bytes", NVME_MAX_XFER_SIZE);
+
+	while (resid > 0) {
+		size = (resid >= NVME_MAX_XFER_SIZE) ?
+		    NVME_MAX_XFER_SIZE : resid;
+		memcpy(chunk, payload + off, size);
+
+		memset(&pt, 0, sizeof(pt));
+		pt.cmd.opc = NVME_OPC_FIRMWARE_IMAGE_DOWNLOAD;
+		pt.cmd.cdw10 = (size / sizeof(uint32_t)) - 1;
+		pt.cmd.cdw11 = (off / sizeof(uint32_t));
+		pt.buf = chunk;
+		pt.len = size;
+		pt.is_read = 0;
+
+		if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
+			err(1, "firmware download request failed");
+
+		if (nvme_completion_is_error(&pt.cpl))
+			errx(1, "firmware download request returned error");
+
+		resid -= size;
+		off += size;
+	}
+}
+
+static int
+activate_firmware(int fd, int slot, int activate_action)
+{
+	struct nvme_pt_command	pt;
+
+	memset(&pt, 0, sizeof(pt));
+	pt.cmd.opc = NVME_OPC_FIRMWARE_ACTIVATE;
+	pt.cmd.cdw10 = (activate_action << 3) | slot;
+	pt.is_read = 0;
+
+	if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
+		err(1, "firmware activate request failed");
+
+	if (pt.cpl.status.sct == NVME_SCT_COMMAND_SPECIFIC &&
+	    pt.cpl.status.sc == NVME_SC_FIRMWARE_REQUIRES_RESET)
+		return 1;
+
+	if (nvme_completion_is_error(&pt.cpl))
+		errx(1, "firmware activate request returned error");
+
+	return 0;
+}
+
+static void
+firmware_usage(void)
+{
+	fprintf(stderr, "usage:\n");
+	fprintf(stderr, FIRMWARE_USAGE);
+	exit(1);
+}
+
+void
+firmware(int argc, char *argv[])
+{
+	int				fd = -1, slot = 0;
+	int				a_flag, s_flag, f_flag;
+	int				activate_action, reboot_required;
+	char				ch, *p, *image = NULL;
+	char				*controller = NULL, prompt[64];
+	void				*buf = NULL;
+	int32_t				size = 0;
+	struct nvme_controller_data	cdata;
+
+	a_flag = s_flag = f_flag = false;
+
+	while ((ch = getopt(argc, argv, "af:s:")) != -1) {
+		switch (ch) {
+		case 'a':
+			a_flag = true;
+			break;
+		case 's':
+			slot = strtol(optarg, &p, 0);
+			if (p != NULL && *p != '\0') {
+				fprintf(stderr,
+				    "\"%s\" not valid slot.\n",
+				    optarg);
+				firmware_usage();
+			} else if (slot == 0) {
+				fprintf(stderr,
+				    "0 is not a valid slot number. "
+				    "Slot numbers start at 1.\n");
+				firmware_usage();
+			} else if (slot > 7) {
+				fprintf(stderr,
+				    "Slot number %s specified which is "
+				    "greater than max allowed slot number of "
+				    "7.\n", optarg);
+				firmware_usage();
+			}
+			s_flag = true;
+			break;
+		case 'f':
+			image = optarg;
+			f_flag = true;
+			break;
+		}
+	}
+
+	/* Check that a controller (and not a namespace) was specified. */
+	if (optind >= argc || strstr(argv[optind], NVME_NS_PREFIX) != NULL)
+		firmware_usage();
+
+	if (!f_flag && !a_flag) {
+		fprintf(stderr,
+		    "Neither a replace ([-f path_to_firmware]) nor "
+		    "activate ([-a]) firmware image action\n"
+		    "was specified.\n");
+		firmware_usage();
+	}
+
+	if (!f_flag && a_flag && slot == 0) {
+		fprintf(stderr,
+		    "Slot number to activate not specified.\n");
+		firmware_usage();
+	}
+
+	controller = argv[optind];
+	open_dev(controller, &fd, 1, 1);
+	read_controller_data(fd, &cdata);
+
+	if (cdata.oacs.firmware == 0)
+		errx(1,
+		    "controller does not support firmware activate/download");
+
+	if (f_flag && slot == 1 && cdata.frmw.slot1_ro)
+		errx(1, "slot %d is marked as read only", slot);
+
+	if (slot > cdata.frmw.num_slots)
+		errx(1,
+		    "slot %d specified but controller only supports %d slots",
+		    slot, cdata.frmw.num_slots);
+
+	if (a_flag && !f_flag && !slot_has_valid_firmware(fd, slot))
+		errx(1,
+		    "slot %d does not contain valid firmware,\n"
+		    "try 'nvmecontrol logpage -p 3 %s' to get a list "
+		    "of available images\n",
+		    slot, controller);
+
+	if (f_flag)
+		read_image_file(image, &buf, &size);
+
+	if (f_flag && a_flag)
+		printf("You are about to download and activate "
+		       "firmware image (%s) to controller %s.\n"
+		       "This may damage your controller and/or "
+		       "overwrite an existing firmware image.\n",
+		       image, controller);
+	else if (a_flag)
+		printf("You are about to activate a new firmware "
+		       "image on controller %s.\n"
+		       "This may damage your controller.\n",
+		       controller);
+	else if (f_flag)
+		printf("You are about to download firmware image "
+		       "(%s) to controller %s.\n"
+		       "This may damage your controller and/or "
+		       "overwrite an existing firmware image.\n",
+		       image, controller);
+
+	printf("Are you sure you want to continue? (yes/no) ");
+	while (1) {
+		fgets(prompt, sizeof(prompt), stdin);
+		if (strncasecmp(prompt, "yes", 3) == 0)
+			break;
+		if (strncasecmp(prompt, "no", 2) == 0)
+			exit(1);
+		printf("Please answer \"yes\" or \"no\". ");
+	}
+
+	if (f_flag) {
+		update_firmware(fd, buf, size);
+		if (a_flag)
+			activate_action = NVME_AA_REPLACE_ACTIVATE;
+		else
+			activate_action = NVME_AA_REPLACE_NO_ACTIVATE;
+	} else {
+		activate_action = NVME_AA_ACTIVATE;
+	}
+
+	reboot_required = activate_firmware(fd, slot, activate_action);
+
+	if (a_flag) {
+		if (reboot_required) {
+			printf("New firmware image activated but requires "
+			       "conventional reset (i.e. reboot) to "
+			       "complete activation.\n");
+		} else {
+			printf("New firmware image activated and will take "
+			       "effect after next controller reset.\n"
+			       "Controller reset can be initiated via "
+			       "'nvmecontrol reset %s'\n",
+			       controller);
+		}
+	}
+
+	close(fd);
+	exit(0);
+}


Property changes on: trunk/sbin/nvmecontrol/firmware.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sbin/nvmecontrol/identify.c
===================================================================
--- trunk/sbin/nvmecontrol/identify.c	                        (rev 0)
+++ trunk/sbin/nvmecontrol/identify.c	2018-04-25 23:38:10 UTC (rev 9819)
@@ -0,0 +1,285 @@
+/* $MidnightBSD$ */
+/*-
+ * 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 <ctype.h>
+#include <err.h>
+#include <fcntl.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "nvmecontrol.h"
+
+static void
+print_controller(struct nvme_controller_data *cdata)
+{
+	uint8_t str[128];
+
+	printf("Controller Capabilities/Features\n");
+	printf("================================\n");
+	printf("Vendor ID:                  %04x\n", cdata->vid);
+	printf("Subsystem Vendor ID:        %04x\n", cdata->ssvid);
+	nvme_strvis(str, cdata->sn, sizeof(str), NVME_SERIAL_NUMBER_LENGTH);
+	printf("Serial Number:              %s\n", str);
+	nvme_strvis(str, cdata->mn, sizeof(str), NVME_MODEL_NUMBER_LENGTH);
+	printf("Model Number:               %s\n", str);
+	nvme_strvis(str, cdata->fr, sizeof(str), NVME_FIRMWARE_REVISION_LENGTH);
+	printf("Firmware Version:           %s\n", str);
+	printf("Recommended Arb Burst:      %d\n", cdata->rab);
+	printf("IEEE OUI Identifier:        %02x %02x %02x\n",
+		cdata->ieee[0], cdata->ieee[1], cdata->ieee[2]);
+	printf("Multi-Interface Cap:        %02x\n", cdata->mic);
+	/* TODO: Use CAP.MPSMIN to determine true memory page size. */
+	printf("Max Data Transfer Size:     ");
+	if (cdata->mdts == 0)
+		printf("Unlimited\n");
+	else
+		printf("%d\n", PAGE_SIZE * (1 << cdata->mdts));
+	printf("\n");
+
+	printf("Admin Command Set Attributes\n");
+	printf("============================\n");
+	printf("Security Send/Receive:       %s\n",
+		cdata->oacs.security ? "Supported" : "Not Supported");
+	printf("Format NVM:                  %s\n",
+		cdata->oacs.format ? "Supported" : "Not Supported");
+	printf("Firmware Activate/Download:  %s\n",
+		cdata->oacs.firmware ? "Supported" : "Not Supported");
+	printf("Abort Command Limit:         %d\n", cdata->acl+1);
+	printf("Async Event Request Limit:   %d\n", cdata->aerl+1);
+	printf("Number of Firmware Slots:    ");
+	if (cdata->oacs.firmware != 0)
+		printf("%d\n", cdata->frmw.num_slots);
+	else
+		printf("N/A\n");
+	printf("Firmware Slot 1 Read-Only:   ");
+	if (cdata->oacs.firmware != 0)
+		printf("%s\n", cdata->frmw.slot1_ro ? "Yes" : "No");
+	else
+		printf("N/A\n");
+	printf("Per-Namespace SMART Log:     %s\n",
+		cdata->lpa.ns_smart ? "Yes" : "No");
+	printf("Error Log Page Entries:      %d\n", cdata->elpe+1);
+	printf("Number of Power States:      %d\n", cdata->npss+1);
+	printf("\n");
+
+	printf("NVM Command Set Attributes\n");
+	printf("==========================\n");
+	printf("Submission Queue Entry Size\n");
+	printf("  Max:                       %d\n", 1 << cdata->sqes.max);
+	printf("  Min:                       %d\n", 1 << cdata->sqes.min);
+	printf("Completion Queue Entry Size\n");
+	printf("  Max:                       %d\n", 1 << cdata->cqes.max);
+	printf("  Min:                       %d\n", 1 << cdata->cqes.min);
+	printf("Number of Namespaces:        %d\n", cdata->nn);
+	printf("Compare Command:             %s\n",
+		cdata->oncs.compare ? "Supported" : "Not Supported");
+	printf("Write Uncorrectable Command: %s\n",
+		cdata->oncs.write_unc ? "Supported" : "Not Supported");
+	printf("Dataset Management Command:  %s\n",
+		cdata->oncs.dsm ? "Supported" : "Not Supported");
+	printf("Volatile Write Cache:        %s\n",
+		cdata->vwc.present ? "Present" : "Not Present");
+}
+
+static void
+print_namespace(struct nvme_namespace_data *nsdata)
+{
+	uint32_t	i;
+
+	printf("Size (in LBAs):              %lld (%lldM)\n",
+		(long long)nsdata->nsze,
+		(long long)nsdata->nsze / 1024 / 1024);
+	printf("Capacity (in LBAs):          %lld (%lldM)\n",
+		(long long)nsdata->ncap,
+		(long long)nsdata->ncap / 1024 / 1024);
+	printf("Utilization (in LBAs):       %lld (%lldM)\n",
+		(long long)nsdata->nuse,
+		(long long)nsdata->nuse / 1024 / 1024);
+	printf("Thin Provisioning:           %s\n",
+		nsdata->nsfeat.thin_prov ? "Supported" : "Not Supported");
+	printf("Number of LBA Formats:       %d\n", nsdata->nlbaf+1);
+	printf("Current LBA Format:          LBA Format #%02d\n",
+		nsdata->flbas.format);
+	for (i = 0; i <= nsdata->nlbaf; i++)
+		printf("LBA Format #%02d: Data Size: %5d  Metadata Size: %5d\n",
+		    i, 1 << nsdata->lbaf[i].lbads, nsdata->lbaf[i].ms);
+}
+
+static void
+identify_usage(void)
+{
+	fprintf(stderr, "usage:\n");
+	fprintf(stderr, IDENTIFY_USAGE);
+	exit(1);
+}
+
+static void
+identify_ctrlr(int argc, char *argv[])
+{
+	struct nvme_controller_data	cdata;
+	int				ch, fd, hexflag = 0, hexlength;
+	int				verboseflag = 0;
+
+	while ((ch = getopt(argc, argv, "vx")) != -1) {
+		switch ((char)ch) {
+		case 'v':
+			verboseflag = 1;
+			break;
+		case 'x':
+			hexflag = 1;
+			break;
+		default:
+			identify_usage();
+		}
+	}
+
+	/* Check that a controller was specified. */
+	if (optind >= argc)
+		identify_usage();
+
+	open_dev(argv[optind], &fd, 1, 1);
+	read_controller_data(fd, &cdata);
+	close(fd);
+
+	if (hexflag == 1) {
+		if (verboseflag == 1)
+			hexlength = sizeof(struct nvme_controller_data);
+		else
+			hexlength = offsetof(struct nvme_controller_data,
+			    reserved5);
+		print_hex(&cdata, hexlength);
+		exit(0);
+	}
+
+	if (verboseflag == 1) {
+		fprintf(stderr, "-v not currently supported without -x\n");
+		identify_usage();
+	}
+
+	print_controller(&cdata);
+	exit(0);
+}
+
+static void
+identify_ns(int argc, char *argv[])
+{
+	struct nvme_namespace_data	nsdata;
+	char				path[64];
+	int				ch, fd, hexflag = 0, hexlength, nsid;
+	int				verboseflag = 0;
+
+	while ((ch = getopt(argc, argv, "vx")) != -1) {
+		switch ((char)ch) {
+		case 'v':
+			verboseflag = 1;
+			break;
+		case 'x':
+			hexflag = 1;
+			break;
+		default:
+			identify_usage();
+		}
+	}
+
+	/* Check that a namespace was specified. */
+	if (optind >= argc)
+		identify_usage();
+
+	/*
+	 * Check if the specified device node exists before continuing.
+	 *  This is a cleaner check for cases where the correct controller
+	 *  is specified, but an invalid namespace on that controller.
+	 */
+	open_dev(argv[optind], &fd, 1, 1);
+	close(fd);
+
+	/*
+	 * We send IDENTIFY commands to the controller, not the namespace,
+	 *  since it is an admin cmd.  The namespace ID will be specified in
+	 *  the IDENTIFY command itself.  So parse the namespace's device node
+	 *  string to get the controller substring and namespace ID.
+	 */
+	parse_ns_str(argv[optind], path, &nsid);
+	open_dev(path, &fd, 1, 1);
+	read_namespace_data(fd, nsid, &nsdata);
+	close(fd);
+
+	if (hexflag == 1) {
+		if (verboseflag == 1)
+			hexlength = sizeof(struct nvme_namespace_data);
+		else
+			hexlength = offsetof(struct nvme_namespace_data,
+			    reserved6);
+		print_hex(&nsdata, hexlength);
+		exit(0);
+	}
+
+	if (verboseflag == 1) {
+		fprintf(stderr, "-v not currently supported without -x\n");
+		identify_usage();
+	}
+
+	print_namespace(&nsdata);
+	exit(0);
+}
+
+void
+identify(int argc, char *argv[])
+{
+	char	*target;
+
+	if (argc < 2)
+		identify_usage();
+
+	while (getopt(argc, argv, "vx") != -1) ;
+
+	/* Check that a controller or namespace was specified. */
+	if (optind >= argc)
+		identify_usage();
+
+	target = argv[optind];
+
+	optreset = 1;
+	optind = 1;
+
+	/*
+	 * If device node contains "ns", we consider it a namespace,
+	 *  otherwise, consider it a controller.
+	 */
+	if (strstr(target, NVME_NS_PREFIX) == NULL)
+		identify_ctrlr(argc, argv);
+	else
+		identify_ns(argc, argv);
+}


Property changes on: trunk/sbin/nvmecontrol/identify.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sbin/nvmecontrol/logpage.c
===================================================================
--- trunk/sbin/nvmecontrol/logpage.c	                        (rev 0)
+++ trunk/sbin/nvmecontrol/logpage.c	2018-04-25 23:38:10 UTC (rev 9819)
@@ -0,0 +1,358 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2013 EMC Corp.
+ * All rights reserved.
+ *
+ * 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 <ctype.h>
+#include <err.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "nvmecontrol.h"
+
+#define DEFAULT_SIZE	(4096)
+#define MAX_FW_SLOTS	(7)
+
+typedef void (*print_fn_t)(void *buf, uint32_t size);
+
+static void *
+get_log_buffer(uint32_t size)
+{
+	void	*buf;
+
+	if ((buf = malloc(size)) == NULL)
+		errx(1, "unable to malloc %u bytes", size);
+
+	memset(buf, 0, size);
+	return (buf);
+}
+
+void
+read_logpage(int fd, uint8_t log_page, int nsid, void *payload, 
+    uint32_t payload_size)
+{
+	struct nvme_pt_command	pt;
+
+	memset(&pt, 0, sizeof(pt));
+	pt.cmd.opc = NVME_OPC_GET_LOG_PAGE;
+	pt.cmd.nsid = nsid;
+	pt.cmd.cdw10 = ((payload_size/sizeof(uint32_t)) - 1) << 16;
+	pt.cmd.cdw10 |= log_page;
+	pt.buf = payload;
+	pt.len = payload_size;
+	pt.is_read = 1;
+
+	if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
+		err(1, "get log page request failed");
+
+	if (nvme_completion_is_error(&pt.cpl))
+		errx(1, "get log page request returned error");
+}
+
+static void
+print_log_error(void *buf, uint32_t size)
+{
+	int					i, nentries;
+	struct nvme_error_information_entry	*entry = buf;
+	struct nvme_status			*status;
+
+	printf("Error Information Log\n");
+	printf("=====================\n");
+
+	if (entry->error_count == 0) {
+		printf("No error entries found\n");
+		return;
+	}
+
+	nentries = size/sizeof(struct nvme_error_information_entry);
+	for (i = 0; i < nentries; i++, entry++) {
+		if (entry->error_count == 0)
+			break;
+
+		status = &entry->status;
+		printf("Entry %02d\n", i + 1);
+		printf("=========\n");
+		printf(" Error count:          %ju\n", entry->error_count);
+		printf(" Submission queue ID:  %u\n", entry->sqid);
+		printf(" Command ID:           %u\n", entry->cid);
+		/* TODO: Export nvme_status_string structures from kernel? */
+		printf(" Status:\n");
+		printf("  Phase tag:           %d\n", status->p);
+		printf("  Status code:         %d\n", status->sc);
+		printf("  Status code type:    %d\n", status->sct);
+		printf("  More:                %d\n", status->m);
+		printf("  DNR:                 %d\n", status->dnr);
+		printf(" Error location:       %u\n", entry->error_location);
+		printf(" LBA:                  %ju\n", entry->lba);
+		printf(" Namespace ID:         %u\n", entry->nsid);
+		printf(" Vendor specific info: %u\n", entry->vendor_specific);
+	}
+}
+
+static void
+print_log_health(void *buf, uint32_t size __unused)
+{
+	struct nvme_health_information_page *health = buf;
+
+	printf("SMART/Health Information Log\n");
+	printf("============================\n");
+
+	printf("Critical Warning State:         0x%02x\n",
+	    health->critical_warning.raw);
+	printf(" Available spare:               %d\n",
+	    health->critical_warning.bits.available_spare);
+	printf(" Temperature:                   %d\n",
+	    health->critical_warning.bits.temperature);
+	printf(" Device reliability:            %d\n",
+	    health->critical_warning.bits.device_reliability);
+	printf(" Read only:                     %d\n",
+	    health->critical_warning.bits.read_only);
+	printf(" Volatile memory backup:        %d\n",
+	    health->critical_warning.bits.volatile_memory_backup);
+	printf("Temperature:                    %u K, %2.2f C, %3.2f F\n",
+	    health->temperature,
+	    (float)health->temperature - (float)273.15,
+	    ((float)health->temperature * (float)9/5) - (float)459.67);
+	printf("Available spare:                %u\n",
+	    health->available_spare);
+	printf("Available spare threshold:      %u\n",
+	    health->available_spare_threshold);
+	printf("Percentage used:                %u\n",
+	    health->percentage_used);
+
+	/* 
+	 * TODO: These are pretty ugly in hex. Is there a library that 
+	 *	 will convert 128-bit unsigned values to decimal?
+	 */
+	printf("Data units (512 byte) read:     0x%016jx%016jx\n",
+	    health->data_units_read[1],
+	    health->data_units_read[0]);
+	printf("Data units (512 byte) written:  0x%016jx%016jx\n",
+	    health->data_units_written[1],
+	    health->data_units_written[0]);
+	printf("Host read commands:             0x%016jx%016jx\n",
+	    health->host_read_commands[1],
+	    health->host_read_commands[0]);
+	printf("Host write commands:            0x%016jx%016jx\n",
+	    health->host_write_commands[1],
+	    health->host_write_commands[0]);
+	printf("Controller busy time (minutes): 0x%016jx%016jx\n",
+	    health->controller_busy_time[1],
+	    health->controller_busy_time[0]);
+	printf("Power cycles:                   0x%016jx%016jx\n",
+	    health->power_cycles[1],
+	    health->power_cycles[0]);
+	printf("Power on hours:                 0x%016jx%016jx\n",
+	    health->power_on_hours[1],
+	    health->power_on_hours[0]);
+	printf("Unsafe shutdowns:               0x%016jx%016jx\n",
+	    health->unsafe_shutdowns[1],
+	    health->unsafe_shutdowns[0]);
+	printf("Media errors:                   0x%016jx%016jx\n",
+	    health->media_errors[1],
+	    health->media_errors[0]);
+	printf("No. error info log entries:     0x%016jx%016jx\n",
+	    health->num_error_info_log_entries[1],
+	    health->num_error_info_log_entries[0]);
+}
+
+static void
+print_log_firmware(void *buf, uint32_t size __unused)
+{
+	int				i;
+	const char			*status;
+	struct nvme_firmware_page	*fw = buf;
+
+	printf("Firmware Slot Log\n");
+	printf("=================\n");
+
+	for (i = 0; i < MAX_FW_SLOTS; i++) {
+		printf("Slot %d: ", i + 1);
+		if (fw->afi.slot == i + 1)
+			status = "  Active";
+		else
+			status = "Inactive";
+
+		if (fw->revision[i] == 0LLU)
+			printf("Empty\n");
+		else
+			if (isprint(*(char *)&fw->revision[i]))
+				printf("[%s] %.8s\n", status,
+				    (char *)&fw->revision[i]);
+			else
+				printf("[%s] %016jx\n", status,
+				    fw->revision[i]);
+	}
+}
+
+static struct logpage_function {
+	uint8_t		log_page;
+	print_fn_t	fn;
+} logfuncs[] = {
+	{NVME_LOG_ERROR,		print_log_error		},
+	{NVME_LOG_HEALTH_INFORMATION,	print_log_health	},
+	{NVME_LOG_FIRMWARE_SLOT,	print_log_firmware	},
+	{0,				NULL			},
+};
+
+static void
+logpage_usage(void)
+{
+	fprintf(stderr, "usage:\n");
+	fprintf(stderr, LOGPAGE_USAGE);
+	exit(1);
+}
+
+void
+logpage(int argc, char *argv[])
+{
+	int				fd, nsid;
+	int				log_page = 0, pageflag = false;
+	int				hexflag = false, ns_specified;
+	char				ch, *p;
+	char				cname[64];
+	uint32_t			size;
+	void				*buf;
+	struct logpage_function		*f;
+	struct nvme_controller_data	cdata;
+	print_fn_t			print_fn;
+
+	while ((ch = getopt(argc, argv, "p:x")) != -1) {
+		switch (ch) {
+		case 'p':
+			/* TODO: Add human-readable ASCII page IDs */
+			log_page = strtol(optarg, &p, 0);
+			if (p != NULL && *p != '\0') {
+				fprintf(stderr,
+				    "\"%s\" not valid log page id.\n",
+				    optarg);
+				logpage_usage();
+			/* TODO: Define valid log page id ranges in nvme.h? */
+			} else if (log_page == 0 ||
+				   (log_page >= 0x04 && log_page <= 0x7F) ||
+				   (log_page >= 0x80 && log_page <= 0xBF)) {
+				fprintf(stderr,
+				    "\"%s\" not valid log page id.\n",
+				    optarg);
+				logpage_usage();
+			}
+			pageflag = true;
+			break;
+		case 'x':
+			hexflag = true;
+			break;
+		}
+	}
+
+	if (!pageflag) {
+		printf("Missing page_id (-p).\n");
+		logpage_usage();
+	}
+
+	/* Check that a controller and/or namespace was specified. */
+	if (optind >= argc)
+		logpage_usage();
+
+	if (strstr(argv[optind], NVME_NS_PREFIX) != NULL) {
+		ns_specified = true;
+		parse_ns_str(argv[optind], cname, &nsid);
+		open_dev(cname, &fd, 1, 1);
+	} else {
+		ns_specified = false;
+		nsid = NVME_GLOBAL_NAMESPACE_TAG;
+		open_dev(argv[optind], &fd, 1, 1);
+	}
+
+	/*
+	 * The log page attribtues indicate whether or not the controller
+	 * supports the SMART/Health information log page on a per
+	 * namespace basis.
+	 */
+	if (ns_specified) {
+		if (log_page != NVME_LOG_HEALTH_INFORMATION)
+			errx(1, "log page %d valid only at controller level",
+			    log_page);
+		read_controller_data(fd, &cdata);
+		if (cdata.lpa.ns_smart == 0)
+			errx(1,
+			    "controller does not support per namespace "
+			    "smart/health information");
+	}
+
+	print_fn = print_hex;
+	if (!hexflag) {
+		/*
+		 * See if there is a pretty print function for the
+		 *  specified log page.  If one isn't found, we
+		 *  just revert to the default (print_hex).
+		 */
+		f = logfuncs;
+		while (f->log_page > 0) {
+			if (log_page == f->log_page) {
+				print_fn = f->fn;
+				break;
+			}
+			f++;
+		}
+	}
+
+	/* Read the log page */
+	switch (log_page) {
+	case NVME_LOG_ERROR:
+		size = sizeof(struct nvme_error_information_entry);
+		size *= (cdata.elpe + 1);
+		break;
+	case NVME_LOG_HEALTH_INFORMATION:
+		size = sizeof(struct nvme_health_information_page);
+		break;
+	case NVME_LOG_FIRMWARE_SLOT:
+		size = sizeof(struct nvme_firmware_page);
+		break;
+	default:
+		size = DEFAULT_SIZE;
+		break;
+	}
+
+	buf = get_log_buffer(size);
+	read_logpage(fd, log_page, nsid, buf, size);
+	print_fn(buf, size);
+
+	close(fd);
+	exit(0);
+}


Property changes on: trunk/sbin/nvmecontrol/logpage.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sbin/nvmecontrol/nvmecontrol.8
===================================================================
--- trunk/sbin/nvmecontrol/nvmecontrol.8	                        (rev 0)
+++ trunk/sbin/nvmecontrol/nvmecontrol.8	2018-04-25 23:38:10 UTC (rev 9819)
@@ -0,0 +1,131 @@
+.\" $MidnightBSD$
+.\"
+.\" Copyright (c) 2012 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,
+.\"    without modification.
+.\" 2. Redistributions in binary form must reproduce at minimum a disclaimer
+.\"    substantially similar to the "NO WARRANTY" disclaimer below
+.\"    ("Disclaimer") and any redistribution must be conditioned upon
+.\"    including a substantially similar Disclaimer requirement for further
+.\"    binary redistribution.
+.\"
+.\" NO WARRANTY
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+.\" HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+.\"
+.\" nvmecontrol man page.
+.\"
+.\" Author: Jim Harris <jimharris at FreeBSD.org>
+.\"
+.\" $FreeBSD$
+.\"
+.Dd March 26, 2013
+.Dt NVMECONTROL 8
+.Os
+.Sh NAME
+.Nm nvmecontrol
+.Nd NVM Express control utility
+.Sh SYNOPSIS
+.Nm
+.Ic devlist
+.Nm
+.Ic identify
+.Op Fl v
+.Op Fl x
+.Aq device id
+.Nm
+.Ic perftest
+.Aq Fl n Ar num_threads
+.Aq Fl o Ar read|write
+.Op Fl p
+.Aq Fl s Ar size_in_bytes
+.Aq Fl t Ar time_in_sec
+.Aq namespace id
+.Nm
+.Ic reset
+.Aq controller id
+.Nm
+.Ic logpage
+.Aq Fl p Ar page_id
+.Op Fl x
+.Aq device id
+.Aq namespace id
+.Nm
+.Ic firmware
+.Op Fl s Ar slot
+.Op Fl f Ar path_to_firmware
+.Op Fl a
+.Aq device id
+.Sh DESCRIPTION
+NVM Express (NVMe) is a storage protocol standard, for SSDs and other
+high-speed storage devices over PCI Express.
+.Sh EXAMPLES
+.Dl nvmecontrol devlist
+.Pp
+Display a list of NVMe controllers and namespaces along with their device nodes.
+.Pp
+.Dl nvmecontrol identify nvme0
+.Pp
+Display a human-readable summary of the nvme0 IDENTIFY_CONTROLLER data.
+.Pp
+.Dl nvmecontrol identify -x -v nvme0ns1
+.Pp
+Display a hexadecimal dump of the nvme0 IDENTIFY_NAMESPACE data for namespace
+1.
+.Pp
+.Dl nvmecontrol perftest -n 32 -o read -s 512 -t 30 nvme0ns1
+.Pp
+Run a performance test on nvme0ns1 using 32 kernel threads for 30 seconds.  Each
+thread will issue a single 512 byte read command.  Results are printed to
+stdout when 30 seconds expires.
+.Pp
+.Dl nvmecontrol reset nvme0
+.Pp
+Perform a controller-level reset of the nvme0 controller.
+.Pp
+.Dl nvmecontrol logpage -p 1 nvme0
+.Pp
+Display a human-readable summary of the nvme0 controller's Error Information Log.
+Log pages defined by the NVMe specification include Error Information Log (ID=1),
+SMART/Health Information Log (ID=2), and Firmware Slot Log (ID=3).
+.Pp
+.Dl nvmecontrol logpage -p 1 -x nvme0
+.Pp
+Display a hexidecimal dump of the nvme0 controller's Error Information Log.
+.Pp
+.Dl nvmecontrol firmware -s 2 -f /tmp/nvme_firmware nvme0
+.Pp
+Download the firmware image contained in "/tmp/nvme_firmware" to slot 2 of the
+nvme0 controller, but do not activate the image.
+.Pp
+.Dl nvmecontrol firmware -s 4 -a nvme0
+.Pp
+Activate the firmware in slot 4 of the nvme0 controller on the next reset.
+.Pp
+.Dl nvmecontrol firmware -s 7 -f /tmp/nvme_firmware -a nvme0
+.Pp
+Download the firmware image contained in "/tmp/nvme_firmware" to slot 7 of the
+nvme0 controller and activate it on the next reset.
+.Sh AUTHORS
+.An -nosplit
+.Nm
+was developed by Intel and originally written by
+.An Jim Harris Aq jimharris at FreeBSD.org .
+.Pp
+This man page was written by
+.An Jim Harris Aq jimharris at FreeBSD.org .


Property changes on: trunk/sbin/nvmecontrol/nvmecontrol.8
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sbin/nvmecontrol/nvmecontrol.c
===================================================================
--- trunk/sbin/nvmecontrol/nvmecontrol.c	                        (rev 0)
+++ trunk/sbin/nvmecontrol/nvmecontrol.c	2018-04-25 23:38:10 UTC (rev 9819)
@@ -0,0 +1,236 @@
+/* $MidnightBSD$ */
+/*-
+ * 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 <sys/stat.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "nvmecontrol.h"
+
+typedef void (*nvme_fn_t)(int argc, char *argv[]);
+
+static struct nvme_function {
+	const char	*name;
+	nvme_fn_t	fn;
+	const char	*usage;
+} funcs[] = {
+	{"devlist",	devlist,	DEVLIST_USAGE},
+	{"identify",	identify,	IDENTIFY_USAGE},
+	{"perftest",	perftest,	PERFTEST_USAGE},
+	{"reset",	reset,		RESET_USAGE},
+	{"logpage",	logpage,	LOGPAGE_USAGE},
+	{"firmware",	firmware,	FIRMWARE_USAGE},
+	{NULL,		NULL,		NULL},
+};
+
+static void
+usage(void)
+{
+	struct nvme_function *f;
+
+	f = funcs;
+	fprintf(stderr, "usage:\n");
+	while (f->name != NULL) {
+		fprintf(stderr, "%s", f->usage);
+		f++;
+	}
+	exit(1);
+}
+
+static void
+print_bytes(void *data, uint32_t length)
+{
+	uint32_t	i, j;
+	uint8_t		*p, *end;
+
+	end = (uint8_t *)data + length;
+
+	for (i = 0; i < length; i++) {
+		p = (uint8_t *)data + (i*16);
+		printf("%03x: ", i*16);
+		for (j = 0; j < 16 && p < end; j++)
+			printf("%02x ", *p++);
+		if (p >= end)
+			break;
+		printf("\n");
+	}
+	printf("\n");
+}
+
+static void
+print_dwords(void *data, uint32_t length)
+{
+	uint32_t	*p;
+	uint32_t	i, j;
+
+	p = (uint32_t *)data;
+	length /= sizeof(uint32_t);
+
+	for (i = 0; i < length; i+=8) {
+		printf("%03x: ", i*4);
+		for (j = 0; j < 8; j++)
+			printf("%08x ", p[i+j]);
+		printf("\n");
+	}
+
+	printf("\n");
+}
+
+void
+print_hex(void *data, uint32_t length)
+{
+	if (length >= sizeof(uint32_t) || length % sizeof(uint32_t) == 0)
+		print_dwords(data, length);
+	else
+		print_bytes(data, length);
+}
+
+void
+read_controller_data(int fd, struct nvme_controller_data *cdata)
+{
+	struct nvme_pt_command	pt;
+
+	memset(&pt, 0, sizeof(pt));
+	pt.cmd.opc = NVME_OPC_IDENTIFY;
+	pt.cmd.cdw10 = 1;
+	pt.buf = cdata;
+	pt.len = sizeof(*cdata);
+	pt.is_read = 1;
+
+	if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
+		err(1, "identify request failed");
+
+	if (nvme_completion_is_error(&pt.cpl))
+		errx(1, "identify request returned error");
+}
+
+void
+read_namespace_data(int fd, int nsid, struct nvme_namespace_data *nsdata)
+{
+	struct nvme_pt_command	pt;
+
+	memset(&pt, 0, sizeof(pt));
+	pt.cmd.opc = NVME_OPC_IDENTIFY;
+	pt.cmd.nsid = nsid;
+	pt.buf = nsdata;
+	pt.len = sizeof(*nsdata);
+	pt.is_read = 1;
+
+	if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
+		err(1, "identify request failed");
+
+	if (nvme_completion_is_error(&pt.cpl))
+		errx(1, "identify request returned error");
+}
+
+int
+open_dev(const char *str, int *fd, int show_error, int exit_on_error)
+{
+	char		full_path[64];
+
+	if (!strnstr(str, NVME_CTRLR_PREFIX, strlen(NVME_CTRLR_PREFIX))) {
+		if (show_error)
+			warnx("controller/namespace ids must begin with '%s'",
+			    NVME_CTRLR_PREFIX);
+		if (exit_on_error)
+			exit(1);
+		else
+			return (EINVAL);
+	}
+
+	snprintf(full_path, sizeof(full_path), _PATH_DEV"%s", str);
+	*fd = open(full_path, O_RDWR);
+	if (*fd < 0) {
+		if (show_error)
+			warn("could not open %s", full_path);
+		if (exit_on_error)
+			exit(1);
+		else
+			return (errno);
+	}
+
+	return (0);
+}
+
+void
+parse_ns_str(const char *ns_str, char *ctrlr_str, int *nsid)
+{
+	char	*nsloc;
+
+	/*
+	 * Pull the namespace id from the string. +2 skips past the "ns" part
+	 *  of the string.  Don't search past 10 characters into the string,
+	 *  otherwise we know it is malformed.
+	 */
+	nsloc = strnstr(ns_str, NVME_NS_PREFIX, 10);
+	if (nsloc != NULL)
+		*nsid = strtol(nsloc + 2, NULL, 10);
+	if (nsloc == NULL || (*nsid == 0 && errno != 0))
+		errx(1, "invalid namespace ID '%s'", ns_str);
+
+	/*
+	 * The controller string will include only the nvmX part of the
+	 *  nvmeXnsY string.
+	 */
+	snprintf(ctrlr_str, nsloc - ns_str + 1, "%s", ns_str);
+}
+
+int
+main(int argc, char *argv[])
+{
+	struct nvme_function *f;
+
+	if (argc < 2)
+		usage();
+
+	f = funcs;
+	while (f->name != NULL) {
+		if (strcmp(argv[1], f->name) == 0)
+			f->fn(argc-1, &argv[1]);
+		f++;
+	}
+
+	usage();
+
+	return (0);
+}
+


Property changes on: trunk/sbin/nvmecontrol/nvmecontrol.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sbin/nvmecontrol/nvmecontrol.h
===================================================================
--- trunk/sbin/nvmecontrol/nvmecontrol.h	                        (rev 0)
+++ trunk/sbin/nvmecontrol/nvmecontrol.h	2018-04-25 23:38:10 UTC (rev 9819)
@@ -0,0 +1,75 @@
+/* $MidnightBSD$ */
+/*-
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef __NVMECONTROL_H__
+#define __NVMECONTROL_H__
+
+#include <dev/nvme/nvme.h>
+
+#define NVME_CTRLR_PREFIX	"nvme"
+#define NVME_NS_PREFIX		"ns"
+
+#define DEVLIST_USAGE							       \
+"       nvmecontrol devlist\n"
+
+#define IDENTIFY_USAGE							       \
+"       nvmecontrol identify [-x [-v]] <controller id|namespace id>\n"
+
+#define PERFTEST_USAGE							       \
+"       nvmecontrol perftest <-n num_threads> <-o read|write>\n"	       \
+"                            <-s size_in_bytes> <-t time_in_seconds>\n"	       \
+"                            <-i intr|wait> [-f refthread] [-p]\n"	       \
+"                            <namespace id>\n"
+
+#define RESET_USAGE							       \
+"       nvmecontrol reset <controller id>\n"
+
+#define LOGPAGE_USAGE							       \
+"       nvmecontrol logpage <-p page_id> [-x] <controller id|namespace id>\n"  \
+
+#define FIRMWARE_USAGE							       \
+"       nvmecontrol firmware [-s slot] [-f path_to_firmware] [-a] <controller id>\n"
+
+void devlist(int argc, char *argv[]);
+void identify(int argc, char *argv[]);
+void perftest(int argc, char *argv[]);
+void reset(int argc, char *argv[]);
+void logpage(int argc, char *argv[]);
+void firmware(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);
+void read_controller_data(int fd, struct nvme_controller_data *cdata);
+void read_namespace_data(int fd, int nsid, struct nvme_namespace_data *nsdata);
+void print_hex(void *data, uint32_t length);
+void read_logpage(int fd, uint8_t log_page, int nsid, void *payload,
+    uint32_t payload_size);
+
+#endif
+


Property changes on: trunk/sbin/nvmecontrol/nvmecontrol.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sbin/nvmecontrol/perftest.c
===================================================================
--- trunk/sbin/nvmecontrol/perftest.c	                        (rev 0)
+++ trunk/sbin/nvmecontrol/perftest.c	2018-04-25 23:38:10 UTC (rev 9819)
@@ -0,0 +1,177 @@
+/* $MidnightBSD$ */
+/*-
+ * 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: stable/9/sbin/nvmecontrol/perftest.c 257708 2013-11-05 15:56:15Z jimharris $");
+
+#include <sys/param.h>
+#include <sys/ioccom.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "nvmecontrol.h"
+
+static void
+print_perftest(struct nvme_io_test *io_test, bool perthread)
+{
+	uint64_t	io_completed = 0, iops, mbps;
+	uint32_t	i;
+
+	for (i = 0; i < io_test->num_threads; i++)
+		io_completed += io_test->io_completed[i];
+
+	iops = io_completed/io_test->time;
+	mbps = iops * io_test->size / (1024*1024);
+
+	printf("Threads: %2d Size: %6d %5s Time: %3d IO/s: %7ju MB/s: %4ju\n",
+	    io_test->num_threads, io_test->size,
+	    io_test->opc == NVME_OPC_READ ? "READ" : "WRITE",
+	    io_test->time, (uintmax_t)iops, (uintmax_t)mbps);
+
+	if (perthread)
+		for (i = 0; i < io_test->num_threads; i++)
+			printf("\t%3d: %8ju IO/s\n", i,
+			    (uintmax_t)io_test->io_completed[i]/io_test->time);
+}
+
+static void
+perftest_usage(void)
+{
+	fprintf(stderr, "usage:\n");
+	fprintf(stderr, PERFTEST_USAGE);
+	exit(1);
+}
+
+void
+perftest(int argc, char *argv[])
+{
+	struct nvme_io_test		io_test;
+	int				fd;
+	char				ch;
+	char				*p;
+	u_long				ioctl_cmd = NVME_IO_TEST;
+	bool				nflag, oflag, sflag, tflag;
+	int				perthread = 0;
+
+	nflag = oflag = sflag = tflag = false;
+
+	memset(&io_test, 0, sizeof(io_test));
+
+	while ((ch = getopt(argc, argv, "f:i:n:o:ps:t:")) != -1) {
+		switch (ch) {
+		case 'f':
+			if (!strcmp(optarg, "refthread"))
+				io_test.flags |= NVME_TEST_FLAG_REFTHREAD;
+			break;
+		case 'i':
+			if (!strcmp(optarg, "bio") ||
+			    !strcmp(optarg, "wait"))
+				ioctl_cmd = NVME_BIO_TEST;
+			else if (!strcmp(optarg, "io") ||
+				 !strcmp(optarg, "intr"))
+				ioctl_cmd = NVME_IO_TEST;
+			break;
+		case 'n':
+			nflag = true;
+			io_test.num_threads = strtoul(optarg, &p, 0);
+			if (p != NULL && *p != '\0') {
+				fprintf(stderr,
+				    "\"%s\" not valid number of threads.\n",
+				    optarg);
+				perftest_usage();
+			} else if (io_test.num_threads == 0 ||
+				   io_test.num_threads > 128) {
+				fprintf(stderr,
+				    "\"%s\" not valid number of threads.\n",
+				    optarg);
+				perftest_usage();
+			}
+			break;
+		case 'o':
+			oflag = true;
+			if (!strcmp(optarg, "read") || !strcmp(optarg, "READ"))
+				io_test.opc = NVME_OPC_READ;
+			else if (!strcmp(optarg, "write") ||
+				 !strcmp(optarg, "WRITE"))
+				io_test.opc = NVME_OPC_WRITE;
+			else {
+				fprintf(stderr, "\"%s\" not valid opcode.\n",
+				    optarg);
+				perftest_usage();
+			}
+			break;
+		case 'p':
+			perthread = 1;
+			break;
+		case 's':
+			sflag = true;
+			io_test.size = strtoul(optarg, &p, 0);
+			if (p == NULL || *p == '\0' || toupper(*p) == 'B') {
+				// do nothing
+			} else if (toupper(*p) == 'K') {
+				io_test.size *= 1024;
+			} else if (toupper(*p) == 'M') {
+				io_test.size *= 1024 * 1024;
+			} else {
+				fprintf(stderr, "\"%s\" not valid size.\n",
+				    optarg);
+				perftest_usage();
+			}
+			break;
+		case 't':
+			tflag = true;
+			io_test.time = strtoul(optarg, &p, 0);
+			if (p != NULL && *p != '\0') {
+				fprintf(stderr,
+				    "\"%s\" not valid time duration.\n",
+				    optarg);
+				perftest_usage();
+			}
+			break;
+		}
+	}
+
+	if (!nflag || !oflag || !sflag || !tflag || optind >= argc)
+		perftest_usage();
+
+	open_dev(argv[optind], &fd, 1, 1);
+	if (ioctl(fd, ioctl_cmd, &io_test) < 0)
+		err(1, "ioctl NVME_IO_TEST failed");
+
+	close(fd);
+	print_perftest(&io_test, perthread);
+	exit(0);
+}


Property changes on: trunk/sbin/nvmecontrol/perftest.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sbin/nvmecontrol/reset.c
===================================================================
--- trunk/sbin/nvmecontrol/reset.c	                        (rev 0)
+++ trunk/sbin/nvmecontrol/reset.c	2018-04-25 23:38:10 UTC (rev 9819)
@@ -0,0 +1,71 @@
+/* $MidnightBSD$ */
+/*-
+ * 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>
+
+#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"
+
+static void
+reset_usage(void)
+{
+	fprintf(stderr, "usage:\n");
+	fprintf(stderr, RESET_USAGE);
+	exit(1);
+}
+
+void
+reset(int argc, char *argv[])
+{
+	int	ch, fd;
+
+	while ((ch = getopt(argc, argv, "")) != -1) {
+		switch ((char)ch) {
+		default:
+			reset_usage();
+		}
+	}
+
+	/* Check that a controller was specified. */
+	if (optind >= argc)
+		reset_usage();
+
+	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);
+}


Property changes on: trunk/sbin/nvmecontrol/reset.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property


More information about the Midnightbsd-cvs mailing list