Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F152891571
D32700.id97609.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
14 KB
Referenced Files
None
Subscribers
None
D32700.id97609.diff
View Options
Index: sbin/nvmecontrol/Makefile
===================================================================
--- sbin/nvmecontrol/Makefile
+++ sbin/nvmecontrol/Makefile
@@ -10,6 +10,7 @@
SRCS+= passthru.c
SRCS+= identify_ext.c nvme_util.c nc_util.c
SRCS+= selftest.c
+SRCS+= feature.c
MAN= nvmecontrol.8
LDFLAGS+= -rdynamic
LIBADD+= util
Index: sbin/nvmecontrol/feature.c
===================================================================
--- /dev/null
+++ sbin/nvmecontrol/feature.c
@@ -0,0 +1,546 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (C) 2021 Wanpeng Qian <wanpengqian@gmail.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer,
+ * without modification, immediately at the beginning of the file.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/ioccom.h>
+
+#include <err.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+#include <unistd.h>
+
+#include "nvmecontrol.h"
+
+/* Tables for command line parsing */
+
+static cmd_fn_t feat;
+static cmd_fn_t featget;
+static cmd_fn_t featset;
+static cmd_fn_t featsummary;
+
+#define NONE8 0xffu
+#define NONE32 0xffffffffu
+#define NONE64 0xffffffffffffffffull
+#define OPT(l, s, t, opt, addr, desc) { l, s, t, &opt.addr, desc }
+#define OPT_END { NULL, 0, arg_none, NULL, NULL }
+
+/* Convert a zero-based value into a one-based value */
+#define ONE_BASED(zero) ((zero) + 1)
+/* Convert a one-based value into a zero-based value */
+#define ZERO_BASED(one) ((one) - 1)
+
+#define NVME_FEAT_GET_SEL_SHIFT (8)
+#define NVME_FEAT_GET_SEL_MASK (0x7)
+#define NVME_FEAT_GET_FID_SHIFT (0)
+#define NVME_FEAT_GET_FID_MASK (0xFF)
+
+#define NVME_FEAT_SET_SV_SHIFT (31)
+#define NVME_FEAT_SET_SV_MASK (0x1)
+#define NVME_FEAT_SET_FID_SHIFT (0)
+#define NVME_FEAT_SET_FID_MASK (0xFF)
+
+#define NVME_FEAT_ARBITRATION_HPW_SHIFT (24)
+#define NVME_FEAT_ARBITRATION_HPW_MASK (0xFF)
+#define NVME_FEAT_ARBITRATION_MPW_SHIFT (16)
+#define NVME_FEAT_ARBITRATION_MPW_MASK (0xFF)
+#define NVME_FEAT_ARBITRATION_LPW_SHIFT (8)
+#define NVME_FEAT_ARBITRATION_LPW_MASK (0xFF)
+#define NVME_FEAT_ARBITRATION_AB_SHIFT (0)
+#define NVME_FEAT_ARBITRATION_AB_MASK (0x7)
+
+#define NVME_FEAT_POWER_MANAGEMENT_WH_SHIFT (5)
+#define NVME_FEAT_POWER_MANAGEMENT_WH_MASK (0x7)
+#define NVME_FEAT_POWER_MANAGEMENT_PS_SHIFT (0)
+#define NVME_FEAT_POWER_MANAGEMENT_PS_MASK (0x1F)
+
+#define NVME_FEAT_TEMPERATURE_THRESHOLD_THSEL_SHIFT (20)
+#define NVME_FEAT_TEMPERATURE_THRESHOLD_THSEL_MASK (0x3)
+#define NVME_FEAT_TEMPERATURE_THRESHOLD_TMPSEL_SHIFT (16)
+#define NVME_FEAT_TEMPERATURE_THRESHOLD_TMPSEL_MASK (0xFF)
+#define NVME_FEAT_TEMPERATURE_THRESHOLD_TMPTH_SHIFT (0)
+#define NVME_FEAT_TEMPERATURE_THRESHOLD_TMPTH_MASK (0xFFFF)
+
+#define NVME_FEAT_NUMBER_OF_QUEUES_NCQA_SHIFT (16)
+#define NVME_FEAT_NUMBER_OF_QUEUES_NCQA_MASK (0xFFFF)
+#define NVME_FEAT_NUMBER_OF_QUEUES_NSQA_SHIFT (0)
+#define NVME_FEAT_NUMBER_OF_QUEUES_NSQA_MASK (0xFFFF)
+
+static
+const char *bits[16] = {
+ [ 0] = "0000", [ 1] = "0001", [ 2] = "0010", [ 3] = "0011",
+ [ 4] = "0100", [ 5] = "0101", [ 6] = "0110", [ 7] = "0111",
+ [ 8] = "1000", [ 9] = "1001", [10] = "1010", [11] = "1011",
+ [12] = "1100", [13] = "1101", [14] = "1110", [15] = "1111",
+};
+
+typedef void (*output_fn_t)(const uint8_t fid, uint32_t cdw0);
+
+static const char *
+feat_name_res[] = {
+ [0] = "Reserved",
+ [1] = "Command Arbitration",
+ [2] = "Power Management",
+ [3] = "LBA Range Type",
+ [4] = "Temperature Threshold",
+ [5] = "Error Recovery",
+ [6] = "Volatile Write Cache",
+ [7] = "Number of Queues",
+ [8] = "Interrupt Coalescing",
+ [9] = "Interrupt Vector Configuration",
+ [10] = "Write Atomicity Normal",
+ [11] = "Asynchronous Event Configuration",
+ [12] = "Autonomous Power State Transition",
+ [13] = "Host Memory Buffer",
+ [14] = "Timestamp",
+ [15] = "Keep Alive Timer",
+ [16] = "Host Controlled Thermal Management",
+ [17] = "Non-Operational Power State Config",
+};
+static uint32_t feat_name_res_max = nitems(feat_name_res);
+
+struct summary_data {
+ uint8_t fid;
+ uint8_t sel;
+ uint32_t cdw11;
+};
+
+static const struct summary_data feat_summary_list[] = {
+ { 0x1, 0x0, 0x0 },
+ { 0x2, 0x0, 0x0 },
+ { 0x4, 0x0, 0x0 },
+ { 0x5, 0x0, 0x0 },
+ { 0x7, 0x0, 0x0 },
+ { 0x8, 0x0, 0x0 },
+ { 0x9, 0x0, 0x0 },
+ { 0xa, 0x0, 0x0 },
+ { 0xb, 0x0, 0x0 },
+};
+static uint32_t feat_summary_list_max = nitems(feat_summary_list);
+
+static struct cmd feat_cmd = {
+ .name = "feature",
+ .fn = feat,
+ .descr = "Get Feature & Set Feature for specified device",
+ .ctx_size = 0,
+ .opts = NULL,
+ .args = NULL,
+};
+
+CMD_COMMAND(feat_cmd);
+
+static struct get_options {
+ uint8_t fid;
+ uint8_t sel;
+ uint32_t cdw11;
+ bool binary;
+ const char *dev;
+} get_opt = {
+ .fid = NONE8,
+ .sel = 0,
+ .cdw11 = 0,
+ .binary = false,
+ .dev = NULL,
+};
+
+static const struct opts get_opts[] = {
+ OPT("fid", 'f', arg_uint8, get_opt, fid,
+ "feature id (required)"),
+ OPT("sel", 's', arg_uint8, get_opt, sel,
+ "[0-3]current/default/saved/supported"),
+ OPT("binary", 'b', arg_none, get_opt, binary,
+ "print result binary"),
+ OPT("cdw11", '1', arg_uint32, get_opt, cdw11,
+ "dword 11 value"),
+ OPT_END
+};
+
+static const struct args get_args[] = {
+ { arg_string, &get_opt.dev, "controller-id" },
+ { arg_none, NULL, NULL },
+};
+
+static struct cmd get_cmd = {
+ .name = "get",
+ .fn = featget,
+ .descr = "Get Feature for specified device",
+ .ctx_size = sizeof(get_opt),
+ .opts = get_opts,
+ .args = get_args,
+};
+
+CMD_SUBCOMMAND(feat_cmd, get_cmd);
+
+static struct set_options {
+ uint8_t fid;
+ bool save;
+ uint32_t cdw11;
+ uint32_t cdw12;
+ uint32_t cdw13;
+ uint32_t cdw14;
+ uint32_t cdw15;
+ const char *dev;
+} set_opt = {
+ .fid = NONE8,
+ .save = false,
+ .cdw11 = 0,
+ .cdw12 = 0,
+ .cdw13 = 0,
+ .cdw14 = 0,
+ .cdw15 = 0,
+ .dev = NULL,
+};
+
+static const struct opts set_opts[] = {
+ OPT("fid", 'f', arg_uint8, set_opt, fid,
+ "feature id (required)"),
+ OPT("save", 's', arg_none, set_opt, save,
+ "the controller shall save the attribute"),
+ OPT("cdw11", '1', arg_uint32, set_opt, cdw11,
+ "dword 11 value"),
+ OPT("cdw12", '2', arg_uint32, set_opt, cdw12,
+ "dword 12 value"),
+ OPT("cdw13", '3', arg_uint32, set_opt, cdw13,
+ "dword 13 value"),
+ OPT("cdw14", '4', arg_uint32, set_opt, cdw14,
+ "dword 14 value"),
+ OPT("cdw15", '5', arg_uint32, set_opt, cdw15,
+ "dword 15 value"),
+ OPT_END
+};
+
+static const struct args set_args[] = {
+ { arg_string, &set_opt.dev, "controller-id" },
+ { arg_none, NULL, NULL },
+};
+
+static struct cmd set_cmd = {
+ .name = "set",
+ .fn = featset,
+ .descr = "Set Feature for specified device",
+ .ctx_size = sizeof(set_opt),
+ .opts = set_opts,
+ .args = set_args,
+};
+
+CMD_SUBCOMMAND(feat_cmd, set_cmd);
+
+static struct summary_options {
+ const char *dev;
+} summary_opt = {
+ .dev = NULL,
+};
+
+static const struct args summary_args[] = {
+ { arg_string, &summary_opt.dev, "controller-id" },
+ { arg_none, NULL, NULL },
+};
+
+static struct cmd summary_cmd = {
+ .name = "summary",
+ .fn = featsummary,
+ .descr = "Show Feature summary for specified device",
+ .ctx_size = sizeof(summary_opt),
+ .opts = NULL,
+ .args = summary_args,
+};
+
+CMD_SUBCOMMAND(feat_cmd, summary_cmd);
+
+static void
+print_feat_arbitration(uint32_t cdw0)
+{
+
+ printf(" Arbitration Burst (AB): ");
+ if ((cdw0 & NVME_FEAT_ARBITRATION_AB_MASK) == NVME_FEAT_ARBITRATION_AB_MASK)
+ printf("no limit\n");
+ else
+ printf("%d\n", 1 << (cdw0 & NVME_FEAT_ARBITRATION_AB_MASK));
+ printf(" Low Priority Weight (LPW): %d\n",
+ ONE_BASED((cdw0 >> NVME_FEAT_ARBITRATION_LPW_SHIFT) &
+ NVME_FEAT_ARBITRATION_LPW_MASK));
+ printf(" Medium Priority Weight (MPW): %d\n",
+ ONE_BASED((cdw0 >> NVME_FEAT_ARBITRATION_MPW_SHIFT) &
+ NVME_FEAT_ARBITRATION_MPW_MASK));
+ printf(" High Priority Weight (HPW): %d\n",
+ ONE_BASED((cdw0 >> NVME_FEAT_ARBITRATION_HPW_SHIFT) &
+ NVME_FEAT_ARBITRATION_HPW_MASK));
+}
+
+static void
+print_feat_power_management(uint32_t cdw0)
+{
+
+ printf(" Workload Hint (WH): %#x\n",
+ (cdw0 >> NVME_FEAT_POWER_MANAGEMENT_WH_SHIFT) &
+ NVME_FEAT_POWER_MANAGEMENT_WH_MASK);
+ printf(" Power State (PS): %#x\n",
+ (cdw0 >> NVME_FEAT_POWER_MANAGEMENT_PS_SHIFT) &
+ NVME_FEAT_POWER_MANAGEMENT_PS_MASK);
+}
+
+static void
+print_feat_temperature_threshold(uint32_t cdw0)
+{
+
+ printf(" Threshold Type Select (THSEL): %#x\n",
+ (cdw0 >> NVME_FEAT_TEMPERATURE_THRESHOLD_THSEL_SHIFT) &
+ NVME_FEAT_TEMPERATURE_THRESHOLD_THSEL_MASK);
+ printf(" Threshold Temperature Select (TMPSEL): %#x\n",
+ (cdw0 >> NVME_FEAT_TEMPERATURE_THRESHOLD_TMPSEL_SHIFT) &
+ NVME_FEAT_TEMPERATURE_THRESHOLD_TMPSEL_MASK);
+ printf(" Temperature Threshold (TMPTH): ");
+ print_temp((cdw0 >> NVME_FEAT_TEMPERATURE_THRESHOLD_TMPTH_SHIFT) &
+ NVME_FEAT_TEMPERATURE_THRESHOLD_TMPTH_MASK);
+}
+
+static void
+print_feat_number_of_queues(uint32_t cdw0)
+{
+
+ printf(" Number of I/O Completion Queues Allocated (NCQA): %d\n",
+ ONE_BASED((cdw0 >> NVME_FEAT_NUMBER_OF_QUEUES_NCQA_SHIFT) &
+ NVME_FEAT_NUMBER_OF_QUEUES_NCQA_MASK));
+ printf(" Number of I/O Submission Queues Allocated (NSQA): %d\n",
+ ONE_BASED((cdw0 >> NVME_FEAT_NUMBER_OF_QUEUES_NSQA_SHIFT) &
+ NVME_FEAT_NUMBER_OF_QUEUES_NSQA_MASK));
+}
+
+static void
+output_human(const uint8_t fid, uint32_t cdw0)
+{
+
+ switch (fid) {
+ case NVME_FEAT_ARBITRATION:
+ print_feat_arbitration(cdw0);
+ break;
+ case NVME_FEAT_POWER_MANAGEMENT:
+ print_feat_power_management(cdw0);
+ break;
+ case NVME_FEAT_TEMPERATURE_THRESHOLD:
+ print_feat_temperature_threshold(cdw0);
+ break;
+ case NVME_FEAT_NUMBER_OF_QUEUES:
+ print_feat_number_of_queues(cdw0);
+ break;
+ default:
+ printf(" cdw0 = 0x%#08x\n", cdw0);
+ break;
+ }
+}
+
+static void
+output_binary_uint4(uint8_t v){
+ printf("%s", bits[v & 0x0F]);
+}
+
+static void
+output_binary(const uint8_t fid __unused, uint32_t cdw0)
+{
+ uint32_t i;
+
+ printf("cdw0 = ");
+ for(i = 0; i < sizeof(cdw0) * 2; i++) {
+ output_binary_uint4(cdw0 >> i*4);
+ printf(" ");
+ }
+ printf("\n");
+}
+
+static void
+featget(const struct cmd *f, int argc, char *argv[])
+{
+ struct nvme_pt_command pt;
+ uint8_t fid, sel;
+ uint32_t cdw0, cdw11;
+ int fd;
+ output_fn_t output_fn;
+
+ if (arg_parse(argc, argv, f))
+ return;
+
+ if (get_opt.fid == NONE8) {
+ fprintf(stderr,
+ "feature id not specified\n");
+ arg_help(argc, argv, f);
+ }
+ if (get_opt.sel > 0x3) {
+ fprintf(stderr,
+ "select value over range\n");
+ arg_help(argc, argv, f);
+ }
+
+ open_dev(get_opt.dev, &fd, 1, 1);
+
+ fid = get_opt.fid;
+ sel = get_opt.sel;
+ cdw11 = get_opt.cdw11;
+
+ memset(&pt, 0, sizeof(pt));
+ pt.cmd.opc = NVME_OPC_GET_FEATURES;
+ pt.cmd.cdw10 = htole32((sel << NVME_FEAT_GET_SEL_SHIFT) |
+ (fid << NVME_FEAT_GET_FID_SHIFT));
+ pt.cmd.cdw11 = htole32(cdw11);
+ pt.buf = NULL;
+ pt.len = 0;
+ pt.is_read = 1;
+
+ if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
+ err(EX_IOERR, "passthrough request failed");
+
+ printf("Get Feature: %s(0x%x)\n",
+ (fid < feat_name_res_max ? feat_name_res[fid] : "\0"), fid);
+
+ if (nvme_completion_is_error(&pt.cpl))
+ errx(EX_IOERR, "get feature returned error");
+
+ cdw0 = pt.cpl.cdw0;
+
+ output_fn = output_human;
+ if ( get_opt.binary )
+ output_fn = output_binary;
+
+ output_fn(fid, cdw0);
+
+ close(fd);
+ exit(0);
+}
+
+static void
+featset(const struct cmd *f, int argc, char *argv[])
+{
+ struct nvme_pt_command pt;
+ uint8_t fid;
+ bool save;
+ uint32_t cdw11, cdw12, cdw13, cdw14, cdw15;
+ int fd;
+
+ if (arg_parse(argc, argv, f))
+ return;
+
+ if (set_opt.fid == NONE8) {
+ fprintf(stderr,
+ "feature id not specified\n");
+ arg_help(argc, argv, f);
+ }
+
+ fid = set_opt.fid;
+ save = set_opt.save;
+ cdw11 = set_opt.cdw11;
+ cdw12 = set_opt.cdw12;
+ cdw13 = set_opt.cdw13;
+ cdw14 = set_opt.cdw14;
+ cdw15 = set_opt.cdw15;
+
+ open_dev(set_opt.dev, &fd, 1, 1);
+
+ memset(&pt, 0, sizeof(pt));
+ pt.cmd.opc = NVME_OPC_SET_FEATURES;
+ pt.cmd.cdw10 = htole32((save << NVME_FEAT_SET_SV_SHIFT) |
+ (fid << NVME_FEAT_SET_FID_SHIFT));
+ pt.cmd.cdw11 = htole32(cdw11);
+ pt.cmd.cdw12 = htole32(cdw12);
+ pt.cmd.cdw13 = htole32(cdw13);
+ pt.cmd.cdw14 = htole32(cdw14);
+ pt.cmd.cdw15 = htole32(cdw15);
+ pt.buf = NULL;
+ pt.len = 0;
+ pt.is_read = 0;
+
+ if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
+ err(EX_IOERR, "passthrough request failed");
+
+ printf("Set Feature: %s(0x%x)\n",
+ (fid < feat_name_res_max ? feat_name_res[fid] : "\0"), fid);
+
+ if (nvme_completion_is_error(&pt.cpl))
+ errx(EX_IOERR, "set feature returned error");
+ else
+ printf("set feature success\n");
+
+ close(fd);
+ exit(0);
+}
+
+static void
+featsummary(const struct cmd *f, int argc, char *argv[])
+{
+ struct nvme_pt_command pt;
+ uint8_t fid, sel;
+ uint32_t cdw0, cdw11;
+ int fd;
+ uint32_t i;
+
+ if (arg_parse(argc, argv, f))
+ return;
+
+ open_dev(summary_opt.dev, &fd, 1, 1);
+
+ for(i = 0; i < feat_summary_list_max; i++) {
+ fid = feat_summary_list[i].fid;
+ sel = feat_summary_list[i].sel;
+ cdw11 = feat_summary_list[i].cdw11;
+
+ memset(&pt, 0, sizeof(pt));
+ pt.cmd.opc = NVME_OPC_GET_FEATURES;
+ pt.cmd.cdw10 = htole32((sel << NVME_FEAT_GET_SEL_SHIFT) |
+ (fid << NVME_FEAT_GET_FID_SHIFT));
+ pt.cmd.cdw11 = htole32(cdw11);
+ pt.buf = NULL;
+ pt.len = 0;
+ pt.is_read = 1;
+
+ if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
+ continue;
+
+ printf("%s(0x%x)\n",
+ (fid < feat_name_res_max ? feat_name_res[fid] : "\0"), fid);
+
+ if (nvme_completion_is_error(&pt.cpl))
+ continue;
+
+ cdw0 = pt.cpl.cdw0;
+ output_human(fid, cdw0);
+ }
+
+ close(fd);
+ exit(0);
+}
+
+static void
+feat(const struct cmd *nf __unused, int argc, char *argv[])
+{
+
+ cmd_dispatch(argc, argv, &feat_cmd);
+}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Apr 18, 8:04 PM (6 h, 53 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
31731748
Default Alt Text
D32700.id97609.diff (14 KB)
Attached To
Mode
D32700: nvmecontrol: Implement Get/Set Feature for nvmecontrol
Attached
Detach File
Event Timeline
Log In to Comment