Page MenuHomeFreeBSD

D32700.id97609.diff
No OneTemporary

D32700.id97609.diff

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

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)

Event Timeline