svn commit: r295062 - head/sbin/nvmecontrol

Warner Losh imp at FreeBSD.org
Sat Jan 30 06:18:39 UTC 2016


Author: imp
Date: Sat Jan 30 06:18:37 2016
New Revision: 295062
URL: https://svnweb.freebsd.org/changeset/base/295062

Log:
  Implement power command to list all power modes, find out the power
  mode we're in and to set the power mode.

Added:
  head/sbin/nvmecontrol/power.c   (contents, props changed)
Modified:
  head/sbin/nvmecontrol/Makefile
  head/sbin/nvmecontrol/nvmecontrol.8
  head/sbin/nvmecontrol/nvmecontrol.c
  head/sbin/nvmecontrol/nvmecontrol.h

Modified: head/sbin/nvmecontrol/Makefile
==============================================================================
--- head/sbin/nvmecontrol/Makefile	Sat Jan 30 06:12:03 2016	(r295061)
+++ head/sbin/nvmecontrol/Makefile	Sat Jan 30 06:18:37 2016	(r295062)
@@ -2,7 +2,7 @@
 
 PROG=	nvmecontrol
 SRCS=	nvmecontrol.c devlist.c firmware.c identify.c logpage.c	\
-	perftest.c reset.c nvme_util.c
+	perftest.c reset.c nvme_util.c power.c
 MAN=	nvmecontrol.8
 
 .PATH:	${.CURDIR}/../../sys/dev/nvme

Modified: head/sbin/nvmecontrol/nvmecontrol.8
==============================================================================
--- head/sbin/nvmecontrol/nvmecontrol.8	Sat Jan 30 06:12:03 2016	(r295061)
+++ head/sbin/nvmecontrol/nvmecontrol.8	Sat Jan 30 06:18:37 2016	(r295062)
@@ -70,6 +70,11 @@
 .Op Fl f Ar path_to_firmware
 .Op Fl a
 .Aq device id
+.Nm
+.Ic power
+.Op Fl l
+.Op Fl p power_state
+.Op fl w workload_hint
 .Sh DESCRIPTION
 NVM Express (NVMe) is a storage protocol standard, for SSDs and other
 high-speed storage devices over PCI Express.
@@ -120,6 +125,18 @@ Activate the firmware in slot 4 of the n
 .Pp
 Download the firmware image contained in "/tmp/nvme_firmware" to slot 7 of the
 nvme0 controller and activate it on the next reset.
+.Pp
+.Dl nvmecontrol power -l nvme0
+.Pp
+List all the current power modes.
+.Pp
+.Dl nvmecontrol power -p 3 nvme0
+.Pp
+Set the current power mode.
+.Pp
+.Dl nvmecontrol power nvme0
+.Pp
+Get the current power mode.
 .Sh AUTHORS
 .An -nosplit
 .Nm

Modified: head/sbin/nvmecontrol/nvmecontrol.c
==============================================================================
--- head/sbin/nvmecontrol/nvmecontrol.c	Sat Jan 30 06:12:03 2016	(r295061)
+++ head/sbin/nvmecontrol/nvmecontrol.c	Sat Jan 30 06:18:37 2016	(r295062)
@@ -58,6 +58,7 @@ static struct nvme_function {
 	{"reset",	reset,		RESET_USAGE},
 	{"logpage",	logpage,	LOGPAGE_USAGE},
 	{"firmware",	firmware,	FIRMWARE_USAGE},
+	{"power",	power,		POWER_USAGE},
 	{NULL,		NULL,		NULL},
 };
 

Modified: head/sbin/nvmecontrol/nvmecontrol.h
==============================================================================
--- head/sbin/nvmecontrol/nvmecontrol.h	Sat Jan 30 06:12:03 2016	(r295061)
+++ head/sbin/nvmecontrol/nvmecontrol.h	Sat Jan 30 06:18:37 2016	(r295062)
@@ -55,12 +55,16 @@
 #define FIRMWARE_USAGE							       \
 "       nvmecontrol firmware [-s slot] [-f path_to_firmware] [-a] <controller id>\n"
 
+#define POWER_USAGE							       \
+"       nvmecontrol power [-l] [-p new-state [-w workload-hint]] <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[]);
+void power(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);

Added: head/sbin/nvmecontrol/power.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sbin/nvmecontrol/power.c	Sat Jan 30 06:18:37 2016	(r295062)
@@ -0,0 +1,185 @@
+/*-
+ * Copyright (c) 2016 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.
+ * 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 <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "nvmecontrol.h"
+
+_Static_assert(sizeof(struct nvme_power_state) == 256 / NBBY,
+	       "nvme_power_state size wrong");
+
+static void
+power_usage(void)
+{
+	fprintf(stderr, "usage:\n");
+	fprintf(stderr, POWER_USAGE);
+	exit(1);
+}
+
+static void
+power_list_one(int i, struct nvme_power_state *nps)
+{
+	int mpower, apower, ipower;
+
+	mpower = nps->mp;
+	if (nps->mps == 0)
+		mpower *= 100;
+	ipower = nps->idlp;
+	if (nps->ips == 1)
+		ipower *= 100;
+	apower = nps->actp;
+	if (nps->aps == 1)
+		apower *= 100;
+	printf("%2d: %2d.%04dW%c %3d.%03dms %3d.%03dms %2d %2d %2d %2d %2d.%04dW %2d.%04dW %d\n",
+	       i, mpower / 10000, mpower % 10000,
+	       nps->nops ? '*' : ' ', nps->enlat / 1000, nps->enlat % 1000,
+	       nps->exlat / 1000, nps->exlat % 1000, nps->rrt, nps->rrl,
+	       nps->rwt, nps->rwl, ipower / 10000, ipower % 10000,
+	       apower / 10000, apower % 10000, nps->apw);
+}
+
+static void
+power_list(struct nvme_controller_data *cdata)
+{
+	int i;
+
+	printf("\nPower States Supported: %d\n\n", cdata->npss + 1);
+	printf(" #   Max pwr  Enter Lat  Exit Lat RT RL WT WL Idle Pwr  Act Pwr Workloadd\n");
+	printf("--  --------  --------- --------- -- -- -- -- -------- -------- --\n");
+	for (i = 0; i <= cdata->npss; i++)
+		power_list_one(i, &cdata->power_state[i]);
+}
+
+static void
+power_set(int fd, int power, int workload, int perm)
+{
+	struct nvme_pt_command	pt;
+	uint32_t p;
+
+	p = perm ? (1u << 31) : 0;
+	memset(&pt, 0, sizeof(pt));
+	pt.cmd.opc = NVME_OPC_SET_FEATURES;
+	pt.cmd.cdw10 = NVME_FEAT_POWER_MANAGEMENT | p;
+	pt.cmd.cdw11 = power | (workload << 5);
+
+	if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
+		err(1, "set feature power mgmt request failed");
+
+	if (nvme_completion_is_error(&pt.cpl))
+		errx(1, "set feature power mgmt request returned error");
+}
+
+static void
+power_show(int fd)
+{
+	struct nvme_pt_command	pt;
+
+	memset(&pt, 0, sizeof(pt));
+	pt.cmd.opc = NVME_OPC_GET_FEATURES;
+	pt.cmd.cdw10 = NVME_FEAT_POWER_MANAGEMENT;
+
+	if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
+		err(1, "set feature power mgmt request failed");
+
+	if (nvme_completion_is_error(&pt.cpl))
+		errx(1, "set feature power mgmt request returned error");
+
+	printf("Current Power Mode is %d\n", pt.cpl.cdw0);
+}
+
+void
+power(int argc, char *argv[])
+{
+	struct nvme_controller_data	cdata;
+	int				ch, listflag = 0, powerflag = 0, power = 0, fd;
+	int				workload = 0;
+	char				*end;
+
+	while ((ch = getopt(argc, argv, "lp:w:")) != -1) {
+		switch ((char)ch) {
+		case 'l':
+			listflag = 1;
+			break;
+		case 'p':
+			powerflag = 1;
+			power = strtol(optarg, &end, 0);
+			if (*end != '\0') {
+				fprintf(stderr, "Invalid power state number: %s\n", optarg);
+				power_usage();
+			}
+			break;
+		case 'w':
+			workload = strtol(optarg, &end, 0);
+			if (*end != '\0') {
+				fprintf(stderr, "Invalid workload hint: %s\n", optarg);
+				power_usage();
+			}
+			break;
+		default:
+			power_usage();
+		}
+	}
+
+	/* Check that a controller was specified. */
+	if (optind >= argc)
+		power_usage();
+
+	if (listflag && powerflag) {
+		fprintf(stderr, "Can't set power and list power states\n");
+		power_usage();
+	}
+
+	open_dev(argv[optind], &fd, 1, 1);
+	read_controller_data(fd, &cdata);
+
+	if (listflag) {
+		power_list(&cdata);
+		goto out;
+	}
+
+	if (powerflag) {
+		power_set(fd, power, workload, 0);
+		goto out;
+	}
+	power_show(fd);
+
+out:
+	close(fd);
+	exit(0);
+}


More information about the svn-src-head mailing list