Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F134774062
D32700.id98178.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
43 KB
Referenced Files
None
Subscribers
None
D32700.id98178.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,741 @@
+/*-
+ * 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 <sys/stat.h>
+
+#include <stdint.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 feature;
+static cmd_fn_t feature_get;
+static cmd_fn_t feature_set;
+static cmd_fn_t feature_summary;
+
+#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)
+
+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",
+};
+
+static const char *
+feature_name_res[] = {
+ [0] = "Reserved",
+ [NVME_FEAT_ARBITRATION] = "Command Arbitration",
+ [NVME_FEAT_POWER_MANAGEMENT] = "Power Management",
+ [NVME_FEAT_LBA_RANGE_TYPE] = "LBA Range Type",
+ [NVME_FEAT_TEMPERATURE_THRESHOLD] = "Temperature Threshold",
+ [NVME_FEAT_ERROR_RECOVERY] = "Error Recovery",
+ [NVME_FEAT_VOLATILE_WRITE_CACHE] = "Volatile Write Cache",
+ [NVME_FEAT_NUMBER_OF_QUEUES] = "Number of Queues",
+ [NVME_FEAT_INTERRUPT_COALESCING] = "Interrupt Coalescing",
+ [NVME_FEAT_INTERRUPT_VECTOR_CONFIGURATION] = "Interrupt Vector Configuration",
+ [NVME_FEAT_WRITE_ATOMICITY] = "Write Atomicity Normal",
+ [NVME_FEAT_ASYNC_EVENT_CONFIGURATION] = "Asynchronous Event Configuration",
+ [NVME_FEAT_AUTONOMOUS_POWER_STATE_TRANSITION] = "Autonomous Power State Transition",
+ [NVME_FEAT_HOST_MEMORY_BUFFER] = "Host Memory Buffer",
+ [NVME_FEAT_TIMESTAMP] = "Timestamp",
+ [NVME_FEAT_KEEP_ALIVE_TIMER] = "Keep Alive Timer",
+ [NVME_FEAT_HOST_CONTROLLED_THERMAL_MGMT] = "Host Controlled Thermal Management",
+ [NVME_FEAT_NON_OP_POWER_STATE_CONFIG] = "Non-Operational Power State Config",
+};
+static uint32_t feature_name_res_max = nitems(feature_name_res);
+
+static const char *
+sel_name_res[] = {
+ [0] = "Current",
+ [1] = "Default",
+ [2] = "Saved",
+ [3] = "Supported capabilities",
+};
+static uint32_t sel_name_res_max = nitems(sel_name_res);
+
+static const char *
+lba_range_type_name_res[] = {
+ [0] = "General Purpose",
+ [1] = "Filesystem",
+ [2] = "RAID",
+ [3] = "Cache",
+ [4] = "Page / swap file",
+};
+static uint32_t lba_range_type_name_res_max =
+ nitems(lba_range_type_name_res);
+
+struct summary_data {
+ uint8_t fid;
+ uint8_t sel;
+ uint32_t cdw11;
+};
+
+struct nvme_lba_range_type {
+ uint8_t type;
+ uint8_t attribute;
+ uint8_t reserved1[14];
+ uint64_t slba;
+ uint64_t nlb;
+ uint8_t guid[16];
+ uint8_t reserved2[16];
+} __packed __aligned(4);
+
+static const struct summary_data feature_summary_list[] = {
+ { NVME_FEAT_ARBITRATION, 0x0, 0x0 },
+ { NVME_FEAT_POWER_MANAGEMENT, 0x0, 0x0 },
+ { NVME_FEAT_TEMPERATURE_THRESHOLD, 0x0, 0x0 },
+ { NVME_FEAT_ERROR_RECOVERY, 0x0, 0x0 },
+ { NVME_FEAT_NUMBER_OF_QUEUES, 0x0, 0x0 },
+ { NVME_FEAT_INTERRUPT_COALESCING, 0x0, 0x0 },
+ { NVME_FEAT_INTERRUPT_VECTOR_CONFIGURATION, 0x0, 0x0 },
+ { NVME_FEAT_WRITE_ATOMICITY, 0x0, 0x0 },
+ { NVME_FEAT_ASYNC_EVENT_CONFIGURATION, 0x0, 0x0 },
+};
+static uint32_t feature_summary_list_max = nitems(feature_summary_list);
+
+static struct cmd feature_cmd = {
+ .name = "feature",
+ .fn = feature,
+ .descr = "Get Feature & Set Feature for specified device",
+ .ctx_size = 0,
+ .opts = NULL,
+ .args = NULL,
+};
+
+CMD_COMMAND(feature_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 = feature_get,
+ .descr = "Get Feature for specified device",
+ .ctx_size = sizeof(get_opt),
+ .opts = get_opts,
+ .args = get_args,
+};
+
+CMD_SUBCOMMAND(feature_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 *datafile;
+ const char *dev;
+} set_opt = {
+ .fid = NONE8,
+ .save = false,
+ .cdw11 = 0,
+ .cdw12 = 0,
+ .cdw13 = 0,
+ .cdw14 = 0,
+ .cdw15 = 0,
+ .datafile = NULL,
+ .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("datafile", 'f', arg_path, set_opt, datafile,
+ "data file for some special features."),
+ 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 = feature_set,
+ .descr = "Set Feature for specified device",
+ .ctx_size = sizeof(set_opt),
+ .opts = set_opts,
+ .args = set_args,
+};
+
+CMD_SUBCOMMAND(feature_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 = feature_summary,
+ .descr = "Show Feature summary for specified device",
+ .ctx_size = sizeof(summary_opt),
+ .opts = NULL,
+ .args = summary_args,
+};
+
+CMD_SUBCOMMAND(feature_cmd, summary_cmd);
+
+static void
+print_feature_arbitration(uint32_t cdw0)
+{
+
+ printf(" Arbitration Burst (AB): ");
+ if ((NVME_FEAT_ARBITRATION_AB(cdw0)) == NVME_FEAT_ARBITRATION_AB_MASK)
+ printf("no limit\n");
+ else
+ printf("%d\n", 1 << (NVME_FEAT_ARBITRATION_AB(cdw0)));
+ printf(" Low Priority Weight (LPW): %d\n",
+ ONE_BASED(NVME_FEAT_ARBITRATION_LPW(cdw0)));
+ printf(" Medium Priority Weight (MPW): %d\n",
+ ONE_BASED(NVME_FEAT_ARBITRATION_MPW(cdw0)));
+ printf(" High Priority Weight (HPW): %d\n",
+ ONE_BASED(NVME_FEAT_ARBITRATION_HPW(cdw0)));
+}
+
+static void
+print_feature_power_management(uint32_t cdw0)
+{
+
+ printf(" Workload Hint (WH): %#x\n",
+ NVME_FEAT_POWER_MANAGEMENT_WH(cdw0));
+ printf(" Power State (PS): %#x\n",
+ NVME_FEAT_POWER_MANAGEMENT_PS(cdw0));
+}
+
+static void
+print_feature_lba_range_type(uint32_t cdw0 __unused, void *buf, size_t len)
+{
+ struct nvme_lba_range_type *lba = (struct nvme_lba_range_type*)buf;
+ size_t num;
+ size_t i, j;
+ uint8_t idx;
+
+ num = ONE_BASED(NVME_FEAT_LBA_RANGE_TYPE_NUM(cdw0));
+
+ if (num > len / sizeof(struct nvme_lba_range_type))
+ num = len / sizeof(struct nvme_lba_range_type);
+
+ for (i = 0; i < num; i++) {
+ if (1 == 0 )
+ printf("IDX\tTYPE\tSLBA\tNLB\tGUID\n");
+ if (idx > lba_range_type_name_res_max)
+ idx = 0;
+ printf("0x%zx %s", i, lba_range_type_name_res[idx]);
+ printf("\t0x%lx\t0x%lx\t", lba->slba, lba->nlb);
+ for (j = 0; j < sizeof(lba->guid); j++)
+ printf("%02x", lba->guid[j]);
+ printf("\n");
+ lba++;
+ }
+}
+
+static void
+print_feature_temperature_threshold(uint32_t cdw0)
+{
+
+ printf(" Temperature Threshold (TMPTH): ");
+ print_temp(NVME_FEAT_TEMPERATURE_THRESHOLD_TMPTH(cdw0));
+}
+
+static void
+print_feature_error_recovery(uint32_t cdw0)
+{
+
+ printf(" Deallocated or Unwritten Logical Block Error Enable (DULBE): %d\n",
+ NVME_FEAT_ERROR_RECOVERY_DULBE(cdw0));
+ printf(" Time Limited Error Recovery (TLER): %d of 100ms\n",
+ NVME_FEAT_ERROR_RECOVERY_TLER(cdw0));
+}
+
+static void
+print_feature_volatile_write_cache(uint32_t cdw0)
+{
+
+ printf(" Volatile Write Cache Enable (WCE): %d\n",
+ NVME_FEAT_VOLATILE_WRITE_CACHE_WCE(cdw0));
+}
+
+static void
+print_feature_number_of_queues(uint32_t cdw0)
+{
+
+ printf(" Number of I/O Completion Queues Allocated (NCQA): %d\n",
+ ONE_BASED(NVME_FEAT_NUMBER_OF_QUEUES_NCQA(cdw0)));
+ printf(" Number of I/O Submission Queues Allocated (NSQA): %d\n",
+ ONE_BASED(NVME_FEAT_NUMBER_OF_QUEUES_NSQA(cdw0)));
+}
+
+static void
+print_feature_interrupt_coalescing(uint32_t cdw0)
+{
+
+ printf(" Aggregation Time (TIME): %d\n",
+ NVME_FEAT_INTERRUPT_COALESCING_TIME(cdw0));
+ printf(" Aggregation Threshold (THR): %d\n",
+ NVME_FEAT_INTERRUPT_COALESCING_THR(cdw0));
+}
+
+static void
+print_feature_interrupt_vector_configuration(uint32_t cdw0)
+{
+
+ printf(" Coalescing Disable (CD): %d\n",
+ NVME_FEAT_INTERRUPT_VECTOR_CONFIGURATION_CD(cdw0));
+ printf(" Interrupt Vector (IV): %d\n",
+ NVME_FEAT_INTERRUPT_VECTOR_CONFIGURATION_IV(cdw0));
+}
+
+static void
+print_feature_write_atomicity(uint32_t cdw0)
+{
+
+ printf(" Disable Normal (DN): %d\n",
+ NVME_FEAT_WRITE_ATOMICITY_DN(cdw0));
+}
+
+static void
+print_feature_async_event_configuration(uint32_t cdw0)
+{
+
+ printf(" Telemetry Log Notices: %d\n",
+ NVME_FEAT_ASYNC_EVENT_CONFIGURATION_TLN(cdw0));
+ printf(" Firmware Activation Notices: %d\n",
+ NVME_FEAT_ASYNC_EVENT_CONFIGURATION_FAN(cdw0));
+ printf(" Namespace Attribute Notices: %d\n",
+ NVME_FEAT_ASYNC_EVENT_CONFIGURATION_NAN(cdw0));
+ printf(" SMART / Health Critical Warnings: 0x%x\n",
+ NVME_FEAT_ASYNC_EVENT_CONFIGURATION_TLN(cdw0));
+}
+
+static void
+print_feature_autonomous_power_state_transition(uint32_t cdw0)
+{
+ printf(" Autonomous Power State Transition Enable (APSTE): %d\n",
+ NVME_FEAT_AUTONOMOUS_POWER_STATE_TRANSITION_APSTE(cdw0));
+}
+
+static void
+print_feature_timestamp(uint32_t cdw0)
+{
+
+ printf(" Timestamp: %d\n",
+ NVME_FEAT_TIMESTAMP_TS(cdw0));
+}
+
+static void
+print_feature_keep_alive_timer(uint32_t cdw0)
+{
+
+ printf(" Keep Alive Timeout (KATO): %d\n",
+ NVME_FEAT_KEEP_ALIVE_TIMER_KATO(cdw0));
+}
+
+static void
+print_feature_host_memory_buffer(uint32_t cdw0)
+{
+
+ printf(" Memory Return (MR): %d\n",
+ NVME_FEAT_HOST_MEMORY_BUFFER_MR(cdw0));
+ printf(" Enable Host Memory (EHM): %d\n",
+ NVME_FEAT_HOST_MEMORY_BUFFER_EHM(cdw0));
+}
+
+static void
+print_feature_host_controlled_thermal_mgmt(uint32_t cdw0)
+{
+
+ printf(" Thermal Management Temperature 1 (TMT1): %d\n",
+ NVME_FEAT_HOST_CONTROLLED_THERMAL_MGMT_TMT1(cdw0));
+ printf(" Thermal Management Temperature 2 (TMT2): %d\n",
+ NVME_FEAT_HOST_CONTROLLED_THERMAL_MGMT_TMT2(cdw0));
+}
+static void
+print_feature_non_op_power_state_config(uint32_t cdw0)
+{
+
+ printf(" Non-Operational Power State Permissive Mode Enable (NOPPME): %d\n",
+ NVME_FEAT_NON_OP_POWER_STATE_CONFIG_NOPPME(cdw0));
+}
+
+static void
+output_human(const uint8_t fid, uint32_t cdw0, void *buf, size_t len)
+{
+
+ switch (fid) {
+ case NVME_FEAT_ARBITRATION:
+ print_feature_arbitration(cdw0);
+ break;
+ case NVME_FEAT_POWER_MANAGEMENT:
+ print_feature_power_management(cdw0);
+ break;
+ case NVME_FEAT_LBA_RANGE_TYPE:
+ print_feature_lba_range_type(cdw0, buf, len);
+ break;
+ case NVME_FEAT_TEMPERATURE_THRESHOLD:
+ print_feature_temperature_threshold(cdw0);
+ break;
+ case NVME_FEAT_ERROR_RECOVERY:
+ print_feature_error_recovery(cdw0);
+ break;
+ case NVME_FEAT_VOLATILE_WRITE_CACHE:
+ print_feature_volatile_write_cache(cdw0);
+ break;
+ case NVME_FEAT_NUMBER_OF_QUEUES:
+ print_feature_number_of_queues(cdw0);
+ break;
+ case NVME_FEAT_INTERRUPT_COALESCING:
+ print_feature_interrupt_coalescing(cdw0);
+ break;
+ case NVME_FEAT_INTERRUPT_VECTOR_CONFIGURATION:
+ print_feature_interrupt_vector_configuration(cdw0);
+ break;
+ case NVME_FEAT_WRITE_ATOMICITY:
+ print_feature_write_atomicity(cdw0);
+ break;
+ case NVME_FEAT_ASYNC_EVENT_CONFIGURATION:
+ print_feature_async_event_configuration(cdw0);
+ break;
+ case NVME_FEAT_AUTONOMOUS_POWER_STATE_TRANSITION:
+ print_feature_autonomous_power_state_transition(cdw0);
+ break;
+ case NVME_FEAT_HOST_MEMORY_BUFFER:
+ print_feature_host_memory_buffer(cdw0);
+ break;
+ case NVME_FEAT_TIMESTAMP:
+ print_feature_timestamp(cdw0);
+ break;
+ case NVME_FEAT_KEEP_ALIVE_TIMER:
+ print_feature_keep_alive_timer(cdw0);
+ break;
+ case NVME_FEAT_HOST_CONTROLLED_THERMAL_MGMT:
+ print_feature_host_controlled_thermal_mgmt(cdw0);
+ break;
+ case NVME_FEAT_NON_OP_POWER_STATE_CONFIG:
+ print_feature_non_op_power_state_config(cdw0);
+ break;
+ default:
+ printf(" cdw0 = 0x%#08x\n", cdw0);
+ break;
+ }
+}
+
+static void
+output_binary(const uint8_t fid __unused, uint32_t cdw0, void *buf __unused, size_t len __unused)
+{
+ uint32_t i;
+
+ printf("cdw0 = ");
+ for(i = 0; i < sizeof(cdw0) * 2; i++) {
+ printf("%s", bits[(cdw0 >> i*4) & 0x0F]);
+ printf(" ");
+ }
+ printf("\n");
+}
+
+static void
+read_data_file(const 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(EX_NOINPUT, "unable to open '%s'", path);
+ if (fstat(fd, &sb) < 0)
+ err(EX_NOINPUT, "unable to stat '%s'", path);
+
+ if (sb.st_size > INT32_MAX)
+ errx(EX_USAGE, "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(EX_OSERR, "unable to malloc %d bytes", filesize);
+ if ((*size = read(fd, *buf, filesize)) < 0)
+ err(EX_IOERR, "error reading '%s'", path);
+ /* XXX assuming no short reads */
+ if (*size != filesize)
+ errx(EX_IOERR,
+ "error reading '%s' (read %d bytes, requested %d bytes)",
+ path, *size, filesize);
+ close(fd);
+}
+
+static void
+feature_get(const struct cmd *f, int argc, char *argv[])
+{
+ struct nvme_pt_command pt;
+ int fd;
+ uint8_t *buf = NULL;
+ uint32_t size = 0;
+
+ 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);
+
+ if (get_opt.sel >= sel_name_res_max)
+ errx(EX_IOERR, "invalid select value");
+
+ if (get_opt.fid == NVME_FEAT_LBA_RANGE_TYPE){
+ size = 4096;
+ if ((buf = malloc(size)) == NULL)
+ errx(EX_OSERR, "unable to malloc %d bytes", size);
+ memset(buf, 0, size);
+ }
+
+ memset(&pt, 0, sizeof(pt));
+ pt.cmd.opc = NVME_OPC_GET_FEATURES;
+ pt.cmd.cdw10 = htole32(NVME_FEAT_GET_SEL(get_opt.sel));
+ pt.cmd.cdw11 = htole32(get_opt.cdw11);
+ pt.buf = buf;
+ pt.len = size;
+ pt.is_read = 1;
+
+ if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
+ err(EX_IOERR, "passthrough request failed");
+
+ printf("%s(0x%x), %s value\n",
+ (get_opt.fid < feature_name_res_max ? feature_name_res[get_opt.fid] : "\0"), get_opt.fid,
+ sel_name_res[get_opt.sel]);
+
+ if (nvme_completion_is_error(&pt.cpl)) {
+ errx(EX_IOERR, "%s",
+ get_status_string(NVME_STATUS_GET_SCT(pt.cpl.status),
+ NVME_STATUS_GET_SC(pt.cpl.status)));
+ }
+
+ if ( get_opt.binary )
+ output_binary(get_opt.fid, pt.cpl.cdw0, buf, sizeof(buf));
+ else
+ output_human(get_opt.fid, pt.cpl.cdw0, buf, sizeof(buf));
+
+ close(fd);
+ exit(0);
+}
+
+static void
+feature_set(const struct cmd *f, int argc, char *argv[])
+{
+ struct nvme_pt_command pt;
+ int fd;
+ void *buf = NULL;
+ int32_t size = 0;
+
+ if (arg_parse(argc, argv, f))
+ return;
+
+ if (set_opt.fid == NONE8) {
+ fprintf(stderr,
+ "feature id not specified\n");
+ arg_help(argc, argv, f);
+ }
+
+ if (set_opt.datafile)
+ read_data_file(set_opt.datafile, &buf, &size);
+
+ if (set_opt.fid == NVME_FEAT_LBA_RANGE_TYPE &&
+ ( size > 4096 || size % 64 != 0)) {
+ errx(EX_USAGE, "data size of file '%s' is too large (%d bytes) or not align to 64 bytes",
+ set_opt.datafile, size);
+ }
+
+ open_dev(set_opt.dev, &fd, 1, 1);
+
+ memset(&pt, 0, sizeof(pt));
+ pt.cmd.opc = NVME_OPC_SET_FEATURES;
+ pt.cmd.cdw10 = htole32(NVME_FEAT_SET_SV(set_opt.fid));
+ pt.cmd.cdw11 = htole32(set_opt.cdw11);
+ pt.cmd.cdw12 = htole32(set_opt.cdw12);
+ pt.cmd.cdw13 = htole32(set_opt.cdw13);
+ pt.cmd.cdw14 = htole32(set_opt.cdw14);
+ pt.cmd.cdw15 = htole32(set_opt.cdw15);
+ pt.buf = buf;
+ pt.len = size;
+
+ pt.is_read = 0;
+
+ if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
+ err(EX_IOERR, "passthrough request failed");
+
+
+ if (nvme_completion_is_error(&pt.cpl)) {
+ errx(EX_IOERR, "%s",
+ get_status_string(NVME_STATUS_GET_SCT(pt.cpl.status),
+ NVME_STATUS_GET_SC(pt.cpl.status)));
+ }
+
+ printf("set feature success\n");
+
+ close(fd);
+ exit(0);
+}
+
+static void
+feature_summary(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 < feature_summary_list_max; i++) {
+ fid = feature_summary_list[i].fid;
+ sel = feature_summary_list[i].sel;
+ cdw11 = feature_summary_list[i].cdw11;
+
+ if (sel >= sel_name_res_max)
+ continue;
+
+ memset(&pt, 0, sizeof(pt));
+ pt.cmd.opc = NVME_OPC_GET_FEATURES;
+ pt.cmd.cdw10 = htole32(NVME_FEAT_GET_SEL(fid));
+ 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), %s value\n",
+ (fid < feature_name_res_max ? feature_name_res[fid] : "\0"), fid,
+ sel_name_res[sel]);
+
+ if (nvme_completion_is_error(&pt.cpl))
+ continue;
+
+ cdw0 = pt.cpl.cdw0;
+ output_human(fid, cdw0, NULL, 0);
+ }
+
+ close(fd);
+ exit(0);
+}
+
+static void
+feature(const struct cmd *nf __unused, int argc, char *argv[])
+{
+
+ cmd_dispatch(argc, argv, &feature_cmd);
+}
Index: sbin/nvmecontrol/nvmecontrol.h
===================================================================
--- sbin/nvmecontrol/nvmecontrol.h
+++ sbin/nvmecontrol/nvmecontrol.h
@@ -64,6 +64,8 @@
const char *kv_lookup(const struct kv_name *kv, size_t kv_count, uint32_t key);
+const char *get_status_string(uint16_t sct, uint16_t sc);
+
void logpage_register(struct logpage_function *p);
#define NVME_CTRLR_PREFIX "nvme"
#define NVME_NS_PREFIX "ns"
Index: sbin/nvmecontrol/nvmecontrol.8
===================================================================
--- sbin/nvmecontrol/nvmecontrol.8
+++ sbin/nvmecontrol/nvmecontrol.8
@@ -153,6 +153,22 @@
.Op Fl a
.Aq Ar device-id
.Nm
+.Ic feature get
+.Aq Fl f Ar feature-id
+.Op Fl s Ar select
+.Op Fl b
+.Op Fl args
+.Aq Ar device-id
+.Nm
+.Ic feature set
+.Aq Fl f Ar feature-id
+.Op Fl s Ar save
+.Op Fl args
+.Aq Ar device-id
+.Nm
+.Ic feature summay
+.Aq Ar device-id
+.Nm
.Ic format
.Op Fl f Ar fmt
.Op Fl m Ar mset
@@ -242,6 +258,80 @@
.Dv IDENTIFY_CONTROLLER
data associated with that drive.
.El
+.Ss feature
+The feature command include
+.Ic get set
+and
+.Ic summay
+sub commands
+to get and set feature for specific device.
+.El
+.Ss feature get
+The feature get command can output feature settings for specific device.
+.Bl -tag -width 6n
+.It Fl f Ar feature-id
+Feature id to get
+.It Fl s
+Select
+.Bl -tag -compact -width 6n
+.It Dv 0
+Current
+.It Dv 1
+Default
+.It Dv 2
+Saved
+.It Dv 3
+Supported capabilities
+.El
+.It Fl b
+Print binary data
+.El
+.Ss feature set
+The feature set command can set feature for specific device.
+.Bl -tag -width 8n
+.It Fl f Ar feature-id
+Feature id to set
+.It Fl s
+Specifies that the controller shall save the attribute
+so that the attribute persists through all power states and resets.
+.It Fl 1 Ar value
+32-bit value for CDW11.
+.It Fl 2 Ar value
+32-bit value for CDW12.
+.It Fl 3 Ar value
+32-bit value for CDW13.
+.It Fl 4 Ar value
+32-bit value for CDW14.
+.It Fl 5 Ar value
+32-bit value for CDW15.
+.It Fl f Ar value
+Data File for specify feature.
+.El
+.Ss feature summay
+The feature summay command will output all mandatory features
+for specific device.
+These features are:
+.Pp
+.Bl -tag -compact -width "Fid 0x00"
+.It Dv Fid 0x01
+Command Arbitration
+.It Dv Fid 0x02
+Power Management
+.It Dv Fid 0x04
+Temperature Threshold
+.It Dv Fid 0x05
+Error Recovery
+.It Dv Fid 0x07
+Number if Queues
+.It Dv Fid 0x08
+Interrupt Coalescing
+.It Dv Fid 0x09
+Interrupt Vector Configuration
+.It Dv Fid 0x0A
+Write Atomicity Normal
+.It Dv Fid 0x0B
+Asynchronous Event Configuration
+.El
.Ss logpage
The logpage command knows how to print log pages of various types.
It also knows about vendor specific log pages from hgst/wdc and intel.
Index: sbin/nvmecontrol/nvmecontrol.c
===================================================================
--- sbin/nvmecontrol/nvmecontrol.c
+++ sbin/nvmecontrol/nvmecontrol.c
@@ -176,6 +176,154 @@
*nsid = gnsid.nsid;
}
+struct nvme_status_string {
+ uint16_t sc;
+ const char * str;
+};
+
+static struct nvme_status_string generic_status[] = {
+ { NVME_SC_SUCCESS, "SUCCESS" },
+ { NVME_SC_INVALID_OPCODE, "INVALID OPCODE" },
+ { NVME_SC_INVALID_FIELD, "INVALID_FIELD" },
+ { NVME_SC_COMMAND_ID_CONFLICT, "COMMAND ID CONFLICT" },
+ { NVME_SC_DATA_TRANSFER_ERROR, "DATA TRANSFER ERROR" },
+ { NVME_SC_ABORTED_POWER_LOSS, "ABORTED - POWER LOSS" },
+ { NVME_SC_INTERNAL_DEVICE_ERROR, "INTERNAL DEVICE ERROR" },
+ { NVME_SC_ABORTED_BY_REQUEST, "ABORTED - BY REQUEST" },
+ { NVME_SC_ABORTED_SQ_DELETION, "ABORTED - SQ DELETION" },
+ { NVME_SC_ABORTED_FAILED_FUSED, "ABORTED - FAILED FUSED" },
+ { NVME_SC_ABORTED_MISSING_FUSED, "ABORTED - MISSING FUSED" },
+ { NVME_SC_INVALID_NAMESPACE_OR_FORMAT, "INVALID NAMESPACE OR FORMAT" },
+ { NVME_SC_COMMAND_SEQUENCE_ERROR, "COMMAND SEQUENCE ERROR" },
+ { NVME_SC_INVALID_SGL_SEGMENT_DESCR, "INVALID SGL SEGMENT DESCRIPTOR" },
+ { NVME_SC_INVALID_NUMBER_OF_SGL_DESCR, "INVALID NUMBER OF SGL DESCRIPTORS" },
+ { NVME_SC_DATA_SGL_LENGTH_INVALID, "DATA SGL LENGTH INVALID" },
+ { NVME_SC_METADATA_SGL_LENGTH_INVALID, "METADATA SGL LENGTH INVALID" },
+ { NVME_SC_SGL_DESCRIPTOR_TYPE_INVALID, "SGL DESCRIPTOR TYPE INVALID" },
+ { NVME_SC_INVALID_USE_OF_CMB, "INVALID USE OF CONTROLLER MEMORY BUFFER" },
+ { NVME_SC_PRP_OFFET_INVALID, "PRP OFFET INVALID" },
+ { NVME_SC_ATOMIC_WRITE_UNIT_EXCEEDED, "ATOMIC WRITE UNIT EXCEEDED" },
+ { NVME_SC_OPERATION_DENIED, "OPERATION DENIED" },
+ { NVME_SC_SGL_OFFSET_INVALID, "SGL OFFSET INVALID" },
+ { NVME_SC_HOST_ID_INCONSISTENT_FORMAT, "HOST IDENTIFIER INCONSISTENT FORMAT" },
+ { NVME_SC_KEEP_ALIVE_TIMEOUT_EXPIRED, "KEEP ALIVE TIMEOUT EXPIRED" },
+ { NVME_SC_KEEP_ALIVE_TIMEOUT_INVALID, "KEEP ALIVE TIMEOUT INVALID" },
+ { NVME_SC_ABORTED_DUE_TO_PREEMPT, "COMMAND ABORTED DUE TO PREEMPT AND ABORT" },
+ { NVME_SC_SANITIZE_FAILED, "SANITIZE FAILED" },
+ { NVME_SC_SANITIZE_IN_PROGRESS, "SANITIZE IN PROGRESS" },
+ { NVME_SC_SGL_DATA_BLOCK_GRAN_INVALID, "SGL_DATA_BLOCK_GRANULARITY_INVALID" },
+ { NVME_SC_NOT_SUPPORTED_IN_CMB, "COMMAND NOT SUPPORTED FOR QUEUE IN CMB" },
+ { NVME_SC_NAMESPACE_IS_WRITE_PROTECTED, "NAMESPACE IS WRITE PROTECTED" },
+ { NVME_SC_COMMAND_INTERRUPTED, "COMMAND INTERRUPTED" },
+ { NVME_SC_TRANSIENT_TRANSPORT_ERROR, "TRANSIENT TRANSPORT ERROR" },
+
+ { NVME_SC_LBA_OUT_OF_RANGE, "LBA OUT OF RANGE" },
+ { NVME_SC_CAPACITY_EXCEEDED, "CAPACITY EXCEEDED" },
+ { NVME_SC_NAMESPACE_NOT_READY, "NAMESPACE NOT READY" },
+ { NVME_SC_RESERVATION_CONFLICT, "RESERVATION CONFLICT" },
+ { NVME_SC_FORMAT_IN_PROGRESS, "FORMAT IN PROGRESS" },
+ { 0xFFFF, "GENERIC" }
+};
+
+static struct nvme_status_string command_specific_status[] = {
+ { NVME_SC_COMPLETION_QUEUE_INVALID, "INVALID COMPLETION QUEUE" },
+ { NVME_SC_INVALID_QUEUE_IDENTIFIER, "INVALID QUEUE IDENTIFIER" },
+ { NVME_SC_MAXIMUM_QUEUE_SIZE_EXCEEDED, "MAX QUEUE SIZE EXCEEDED" },
+ { NVME_SC_ABORT_COMMAND_LIMIT_EXCEEDED, "ABORT CMD LIMIT EXCEEDED" },
+ { NVME_SC_ASYNC_EVENT_REQUEST_LIMIT_EXCEEDED, "ASYNC LIMIT EXCEEDED" },
+ { NVME_SC_INVALID_FIRMWARE_SLOT, "INVALID FIRMWARE SLOT" },
+ { NVME_SC_INVALID_FIRMWARE_IMAGE, "INVALID FIRMWARE IMAGE" },
+ { NVME_SC_INVALID_INTERRUPT_VECTOR, "INVALID INTERRUPT VECTOR" },
+ { NVME_SC_INVALID_LOG_PAGE, "INVALID LOG PAGE" },
+ { NVME_SC_INVALID_FORMAT, "INVALID FORMAT" },
+ { NVME_SC_FIRMWARE_REQUIRES_RESET, "FIRMWARE REQUIRES RESET" },
+ { NVME_SC_INVALID_QUEUE_DELETION, "INVALID QUEUE DELETION" },
+ { NVME_SC_FEATURE_NOT_SAVEABLE, "FEATURE IDENTIFIER NOT SAVEABLE" },
+ { NVME_SC_FEATURE_NOT_CHANGEABLE, "FEATURE NOT CHANGEABLE" },
+ { NVME_SC_FEATURE_NOT_NS_SPECIFIC, "FEATURE NOT NAMESPACE SPECIFIC" },
+ { NVME_SC_FW_ACT_REQUIRES_NVMS_RESET, "FIRMWARE ACTIVATION REQUIRES NVM SUBSYSTEM RESET" },
+ { NVME_SC_FW_ACT_REQUIRES_RESET, "FIRMWARE ACTIVATION REQUIRES RESET" },
+ { NVME_SC_FW_ACT_REQUIRES_TIME, "FIRMWARE ACTIVATION REQUIRES MAXIMUM TIME VIOLATION" },
+ { NVME_SC_FW_ACT_PROHIBITED, "FIRMWARE ACTIVATION PROHIBITED" },
+ { NVME_SC_OVERLAPPING_RANGE, "OVERLAPPING RANGE" },
+ { NVME_SC_NS_INSUFFICIENT_CAPACITY, "NAMESPACE INSUFFICIENT CAPACITY" },
+ { NVME_SC_NS_ID_UNAVAILABLE, "NAMESPACE IDENTIFIER UNAVAILABLE" },
+ { NVME_SC_NS_ALREADY_ATTACHED, "NAMESPACE ALREADY ATTACHED" },
+ { NVME_SC_NS_IS_PRIVATE, "NAMESPACE IS PRIVATE" },
+ { NVME_SC_NS_NOT_ATTACHED, "NS NOT ATTACHED" },
+ { NVME_SC_THIN_PROV_NOT_SUPPORTED, "THIN PROVISIONING NOT SUPPORTED" },
+ { NVME_SC_CTRLR_LIST_INVALID, "CONTROLLER LIST INVALID" },
+ { NVME_SC_SELF_TEST_IN_PROGRESS, "DEVICE SELF-TEST IN PROGRESS" },
+ { NVME_SC_BOOT_PART_WRITE_PROHIB, "BOOT PARTITION WRITE PROHIBITED" },
+ { NVME_SC_INVALID_CTRLR_ID, "INVALID CONTROLLER IDENTIFIER" },
+ { NVME_SC_INVALID_SEC_CTRLR_STATE, "INVALID SECONDARY CONTROLLER STATE" },
+ { NVME_SC_INVALID_NUM_OF_CTRLR_RESRC, "INVALID NUMBER OF CONTROLLER RESOURCES" },
+ { NVME_SC_INVALID_RESOURCE_ID, "INVALID RESOURCE IDENTIFIER" },
+ { NVME_SC_SANITIZE_PROHIBITED_WPMRE, "SANITIZE PROHIBITED WRITE PERSISTENT MEMORY REGION ENABLED" },
+ { NVME_SC_ANA_GROUP_ID_INVALID, "ANA GROUP IDENTIFIED INVALID" },
+ { NVME_SC_ANA_ATTACH_FAILED, "ANA ATTACH FAILED" },
+
+ { NVME_SC_CONFLICTING_ATTRIBUTES, "CONFLICTING ATTRIBUTES" },
+ { NVME_SC_INVALID_PROTECTION_INFO, "INVALID PROTECTION INFO" },
+ { NVME_SC_ATTEMPTED_WRITE_TO_RO_PAGE, "WRITE TO RO PAGE" },
+ { 0xFFFF, "COMMAND SPECIFIC" }
+};
+
+static struct nvme_status_string media_error_status[] = {
+ { NVME_SC_WRITE_FAULTS, "WRITE FAULTS" },
+ { NVME_SC_UNRECOVERED_READ_ERROR, "UNRECOVERED READ ERROR" },
+ { NVME_SC_GUARD_CHECK_ERROR, "GUARD CHECK ERROR" },
+ { NVME_SC_APPLICATION_TAG_CHECK_ERROR, "APPLICATION TAG CHECK ERROR" },
+ { NVME_SC_REFERENCE_TAG_CHECK_ERROR, "REFERENCE TAG CHECK ERROR" },
+ { NVME_SC_COMPARE_FAILURE, "COMPARE FAILURE" },
+ { NVME_SC_ACCESS_DENIED, "ACCESS DENIED" },
+ { NVME_SC_DEALLOCATED_OR_UNWRITTEN, "DEALLOCATED OR UNWRITTEN LOGICAL BLOCK" },
+ { 0xFFFF, "MEDIA ERROR" }
+};
+
+static struct nvme_status_string path_related_status[] = {
+ { NVME_SC_INTERNAL_PATH_ERROR, "INTERNAL PATH ERROR" },
+ { NVME_SC_ASYMMETRIC_ACCESS_PERSISTENT_LOSS, "ASYMMETRIC ACCESS PERSISTENT LOSS" },
+ { NVME_SC_ASYMMETRIC_ACCESS_INACCESSIBLE, "ASYMMETRIC ACCESS INACCESSIBLE" },
+ { NVME_SC_ASYMMETRIC_ACCESS_TRANSITION, "ASYMMETRIC ACCESS TRANSITION" },
+ { NVME_SC_CONTROLLER_PATHING_ERROR, "CONTROLLER PATHING ERROR" },
+ { NVME_SC_HOST_PATHING_ERROR, "HOST PATHING ERROR" },
+ { NVME_SC_COMMAND_ABOTHED_BY_HOST, "COMMAND ABOTHED BY HOST" },
+ { 0xFFFF, "PATH RELATED" },
+};
+
+const char *
+get_status_string(uint16_t sct, uint16_t sc)
+{
+ struct nvme_status_string *entry;
+
+ switch (sct) {
+ case NVME_SCT_GENERIC:
+ entry = generic_status;
+ break;
+ case NVME_SCT_COMMAND_SPECIFIC:
+ entry = command_specific_status;
+ break;
+ case NVME_SCT_MEDIA_ERROR:
+ entry = media_error_status;
+ break;
+ case NVME_SCT_PATH_RELATED:
+ entry = path_related_status;
+ break;
+ case NVME_SCT_VENDOR_SPECIFIC:
+ return ("VENDOR SPECIFIC");
+ default:
+ return ("RESERVED");
+ }
+
+ while (entry->sc != 0xFFFF) {
+ if (entry->sc == sc)
+ return (entry->str);
+ entry++;
+ }
+ return (entry->str);
+}
+
int
main(int argc, char *argv[])
{
Index: sys/dev/nvme/nvme.h
===================================================================
--- sys/dev/nvme/nvme.h
+++ sys/dev/nvme/nvme.h
@@ -533,6 +533,316 @@
#define NVME_SS_PAGE_SSTAT_GDE_SHIFT (8)
#define NVME_SS_PAGE_SSTAT_GDE_MASK (0x1)
+/* Features */
+/* Get Features */
+#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_GET_SEL(x) \
+ (((x) >> NVME_FEAT_GET_SEL_SHIFT) & \
+ NVME_FEAT_GET_SEL_MASK)
+#define NVME_FEAT_GET_FID(x) \
+ (((x) >> NVME_FEAT_GET_FID_SHIFT) & \
+ NVME_FEAT_GET_FID_MASK)
+
+/* Set Features */
+#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_SET_SV(x) \
+ (((x) >> NVME_FEAT_SET_SV_SHIFT) & \
+ NVME_FEAT_SET_SV_MASK)
+#define NVME_FEAT_SET_FID(x) \
+ (((x) >> NVME_FEAT_SET_FID_SHIFT) & \
+ NVME_FEAT_SET_FID_MASK)
+
+/* Arbitration */
+#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_ARBITRATION_HPW(x) \
+ (((x) >> NVME_FEAT_ARBITRATION_HPW_SHIFT) & \
+ NVME_FEAT_ARBITRATION_HPW_MASK)
+#define NVME_FEAT_ARBITRATION_MPW(x) \
+ (((x) >> NVME_FEAT_ARBITRATION_MPW_SHIFT) & \
+ NVME_FEAT_ARBITRATION_MPW_MASK)
+#define NVME_FEAT_ARBITRATION_LPW(x) \
+ (((x) >> NVME_FEAT_ARBITRATION_LPW_SHIFT) & \
+ NVME_FEAT_ARBITRATION_LPW_MASK)
+#define NVME_FEAT_ARBITRATION_AB(x) \
+ (((x) >> NVME_FEAT_ARBITRATION_AB_SHIFT) & \
+ NVME_FEAT_ARBITRATION_AB_MASK)
+
+/* Power Management */
+#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_POWER_MANAGEMENT_WH(x) \
+ (((x) >> NVME_FEAT_POWER_MANAGEMENT_WH_SHIFT) & \
+ NVME_FEAT_POWER_MANAGEMENT_WH_MASK)
+#define NVME_FEAT_POWER_MANAGEMENT_PS(x) \
+ (((x) >> NVME_FEAT_POWER_MANAGEMENT_PS_SHIFT) & \
+ NVME_FEAT_POWER_MANAGEMENT_PS_MASK)
+
+/* LBA Range Type */
+#define NVME_FEAT_LBA_RANGE_TYPE_NUM_SHIFT (0)
+#define NVME_FEAT_LBA_RANGE_TYPE_NUM_MASK (0x3F)
+
+#define NVME_FEAT_LBA_RANGE_TYPE_NUM(x) \
+ (((x) >> NVME_FEAT_LBA_RANGE_TYPE_NUM_SHIFT) & \
+ NVME_FEAT_LBA_RANGE_TYPE_NUM_MASK)
+
+/* Temperature Threshold */
+#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 (0xF)
+#define NVME_FEAT_TEMPERATURE_THRESHOLD_TMPTH_SHIFT (0)
+#define NVME_FEAT_TEMPERATURE_THRESHOLD_TMPTH_MASK (0xFFFF)
+
+#define NVME_FEAT_TEMPERATURE_THRESHOLD_THSEL(x) \
+ (((x) >> NVME_FEAT_TEMPERATURE_THRESHOLD_THSEL_SHIFT) & \
+ NVME_FEAT_TEMPERATURE_THRESHOLD_THSEL_MASK)
+#define NVME_FEAT_TEMPERATURE_THRESHOLD_TMPSEL(x) \
+ (((x) >> NVME_FEAT_TEMPERATURE_THRESHOLD_TMPSEL_SHIFT) & \
+ NVME_FEAT_TEMPERATURE_THRESHOLD_TMPSEL_MASK)
+#define NVME_FEAT_TEMPERATURE_THRESHOLD_TMPTH(x) \
+ (((x) >> NVME_FEAT_TEMPERATURE_THRESHOLD_TMPTH_SHIFT) & \
+ NVME_FEAT_TEMPERATURE_THRESHOLD_TMPTH_MASK)
+
+/* Error Recovery */
+#define NVME_FEAT_ERROR_RECOVERY_DULBE_SHIFT (16)
+#define NVME_FEAT_ERROR_RECOVERY_DULBE_MASK (0x1)
+#define NVME_FEAT_ERROR_RECOVERY_TLER_SHIFT (0)
+#define NVME_FEAT_ERROR_RECOVERY_TLER_MASK (0xFF)
+
+#define NVME_FEAT_ERROR_RECOVERY_DULBE(x) \
+ (((x) >> NVME_FEAT_ERROR_RECOVERY_DULBE_SHIFT) & \
+ NVME_FEAT_ERROR_RECOVERY_DULBE_MASK)
+#define NVME_FEAT_ERROR_RECOVERY_TLER(x) \
+ (((x) >> NVME_FEAT_ERROR_RECOVERY_TLER_SHIFT) & \
+ NVME_FEAT_ERROR_RECOVERY_TLER_MASK)
+
+/* Volatile Write Cache */
+#define NVME_FEAT_VOLATILE_WRITE_CACHE_WCE_SHIFT (0)
+#define NVME_FEAT_VOLATILE_WRITE_CACHE_WCE_MASK (0x1)
+
+#define NVME_FEAT_VOLATILE_WRITE_CACHE_WCE(x) \
+ (((x) >> NVME_FEAT_VOLATILE_WRITE_CACHE_WCE_SHIFT) & \
+ NVME_FEAT_VOLATILE_WRITE_CACHE_WCE_MASK)
+
+/* Number of Queues */
+#define NVME_FEAT_NUMBER_OF_QUEUES_NCQR_SHIFT (16)
+#define NVME_FEAT_NUMBER_OF_QUEUES_NCQR_MASK (0xFFFF)
+#define NVME_FEAT_NUMBER_OF_QUEUES_NSQR_SHIFT (0)
+#define NVME_FEAT_NUMBER_OF_QUEUES_NSQR_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)
+
+#define NVME_FEAT_NUMBER_OF_QUEUES_NCQR(x) \
+ (((x) >> NVME_FEAT_NUMBER_OF_QUEUES_NCQR_SHIFT) & \
+ NVME_FEAT_NUMBER_OF_QUEUES_NCQR_MASK)
+#define NVME_FEAT_NUMBER_OF_QUEUES_NSQR(x) \
+ (((x) >> NVME_FEAT_NUMBER_OF_QUEUES_NSQR_SHIFT) & \
+ NVME_FEAT_NUMBER_OF_QUEUES_NSQR_MASK)
+#define NVME_FEAT_NUMBER_OF_QUEUES_NCQA(x) \
+ (((x) >> NVME_FEAT_NUMBER_OF_QUEUES_NCQA_SHIFT) & \
+ NVME_FEAT_NUMBER_OF_QUEUES_NCQA_MASK)
+#define NVME_FEAT_NUMBER_OF_QUEUES_NSQA(x) \
+ (((x) >> NVME_FEAT_NUMBER_OF_QUEUES_NSQA_SHIFT) & \
+ NVME_FEAT_NUMBER_OF_QUEUES_NSQA_MASK)
+
+/* Interrupt Coalescing */
+#define NVME_FEAT_INTERRUPT_COALESCING_TIME_SHIFT (8)
+#define NVME_FEAT_INTERRUPT_COALESCING_TIME_MASK (0xFF)
+#define NVME_FEAT_INTERRUPT_COALESCING_THR_SHIFT (0)
+#define NVME_FEAT_INTERRUPT_COALESCING_THR_MASK (0xFF)
+
+#define NVME_FEAT_INTERRUPT_COALESCING_TIME(x) \
+ (((x) >> NVME_FEAT_INTERRUPT_COALESCING_TIME_SHIFT) & \
+ NVME_FEAT_INTERRUPT_COALESCING_TIME_MASK)
+#define NVME_FEAT_INTERRUPT_COALESCING_THR(x) \
+ (((x) >> NVME_FEAT_INTERRUPT_COALESCING_THR_SHIFT) & \
+ NVME_FEAT_INTERRUPT_COALESCING_THR_MASK)
+
+/* Interrupt Vector Configuration */
+#define NVME_FEAT_INTERRUPT_VECTOR_CONFIGURATION_CD_SHIFT (16)
+#define NVME_FEAT_INTERRUPT_VECTOR_CONFIGURATION_CD_MASK (0x1)
+#define NVME_FEAT_INTERRUPT_VECTOR_CONFIGURATION_IV_SHIFT (0)
+#define NVME_FEAT_INTERRUPT_VECTOR_CONFIGURATION_IV_MASK (0xFF)
+
+#define NVME_FEAT_INTERRUPT_VECTOR_CONFIGURATION_CD(x) \
+ (((x) >> NVME_FEAT_INTERRUPT_VECTOR_CONFIGURATION_CD_SHIFT) & \
+ NVME_FEAT_INTERRUPT_VECTOR_CONFIGURATION_CD_MASK)
+#define NVME_FEAT_INTERRUPT_VECTOR_CONFIGURATION_IV(x) \
+ (((x) >> NVME_FEAT_INTERRUPT_VECTOR_CONFIGURATION_IV_SHIFT) & \
+ NVME_FEAT_INTERRUPT_VECTOR_CONFIGURATION_IV_MASK)
+
+/* Write Atomicity Normal */
+#define NVME_FEAT_WRITE_ATOMICITY_DN_SHIFT (0)
+#define NVME_FEAT_WRITE_ATOMICITY_DN_MASK (0x1)
+
+#define NVME_FEAT_WRITE_ATOMICITY_DN(x) \
+ (((x) >> NVME_FEAT_WRITE_ATOMICITY_DN_SHIFT) & \
+ NVME_FEAT_WRITE_ATOMICITY_DN_MASK)
+
+/* Asynchronous Event Configuration */
+#define NVME_FEAT_ASYNC_EVENT_CONFIGURATION_TLN_SHIFT (10)
+#define NVME_FEAT_ASYNC_EVENT_CONFIGURATION_TLN_MASK (0x1)
+#define NVME_FEAT_ASYNC_EVENT_CONFIGURATION_FAN_SHIFT (9)
+#define NVME_FEAT_ASYNC_EVENT_CONFIGURATION_FAN_MASK (0x1)
+#define NVME_FEAT_ASYNC_EVENT_CONFIGURATION_NAN_SHIFT (8)
+#define NVME_FEAT_ASYNC_EVENT_CONFIGURATION_NAN_MASK (0x1)
+#define NVME_FEAT_ASYNC_EVENT_CONFIGURATION_HCW_SHIFT (0)
+#define NVME_FEAT_ASYNC_EVENT_CONFIGURATION_HCW_MASK (0xFF)
+
+#define NVME_FEAT_ASYNC_EVENT_CONFIGURATION_TLN(x) \
+ (((x) >> NVME_FEAT_ASYNC_EVENT_CONFIGURATION_TLN_SHIFT) & \
+ NVME_FEAT_ASYNC_EVENT_CONFIGURATION_TLN_MASK)
+#define NVME_FEAT_ASYNC_EVENT_CONFIGURATION_FAN(x) \
+ (((x) >> NVME_FEAT_ASYNC_EVENT_CONFIGURATION_FAN_SHIFT) & \
+ NVME_FEAT_ASYNC_EVENT_CONFIGURATION_FAN_MASK)
+#define NVME_FEAT_ASYNC_EVENT_CONFIGURATION_NAN(x) \
+ (((x) >> NVME_FEAT_ASYNC_EVENT_CONFIGURATION_NAN_SHIFT) & \
+ NVME_FEAT_ASYNC_EVENT_CONFIGURATION_NAN_MASK)
+#define NVME_FEAT_ASYNC_EVENT_CONFIGURATION_HCW(x) \
+ (((x) >> NVME_FEAT_ASYNC_EVENT_CONFIGURATION_HCW_SHIFT) & \
+ NVME_FEAT_ASYNC_EVENT_CONFIGURATION_HCW_MASK)
+
+/* Autonomous Power State Transition */
+#define NVME_FEAT_AUTONOMOUS_POWER_STATE_TRANSITION_APSTE_SHIFT (0)
+#define NVME_FEAT_AUTONOMOUS_POWER_STATE_TRANSITION_APSTE_MASK (0x1)
+
+#define NVME_FEAT_AUTONOMOUS_POWER_STATE_TRANSITION_APSTE(x) \
+ (((x) >> NVME_FEAT_AUTONOMOUS_POWER_STATE_TRANSITION_APSTE_SHIFT) & \
+ NVME_FEAT_AUTONOMOUS_POWER_STATE_TRANSITION_APSTE_MASK)
+
+/* Host Memory Buffer */
+#define NVME_FEAT_HOST_MEMORY_BUFFER_MR_SHIFT (1)
+#define NVME_FEAT_HOST_MEMORY_BUFFER_MR_MASK (0x1)
+#define NVME_FEAT_HOST_MEMORY_BUFFER_EHM_SHIFT (0)
+#define NVME_FEAT_HOST_MEMORY_BUFFER_EHM_MASK (0x1)
+#define NVME_FEAT_HOST_MEMORY_BUFFER_HSIZE_SHIFT (0)
+#define NVME_FEAT_HOST_MEMORY_BUFFER_HSIZE_MASK (0xFFFF)
+#define NVME_FEAT_HOST_MEMORY_BUFFER_HMDLLA_SHIFT (4)
+#define NVME_FEAT_HOST_MEMORY_BUFFER_HMDLLA_MASK (0xFFF)
+#define NVME_FEAT_HOST_MEMORY_BUFFER_HMDLUA_SHIFT (0)
+#define NVME_FEAT_HOST_MEMORY_BUFFER_HMDLUA_MASK (0xFFFF)
+#define NVME_FEAT_HOST_MEMORY_BUFFER_HMDLEC_SHIFT (0)
+#define NVME_FEAT_HOST_MEMORY_BUFFER_HMDLEC_MASK (0xFFFF)
+
+#define NVME_FEAT_HOST_MEMORY_BUFFER_MR(x) \
+ (((x) >> NVME_FEAT_HOST_MEMORY_BUFFER_MR_SHIFT) & \
+ NVME_FEAT_HOST_MEMORY_BUFFER_MR_MASK)
+#define NVME_FEAT_HOST_MEMORY_BUFFER_EHM(x) \
+ (((x) >> NVME_FEAT_HOST_MEMORY_BUFFER_EHM_SHIFT) & \
+ NVME_FEAT_HOST_MEMORY_BUFFER_EHM_MASK)
+#define NVME_FEAT_HOST_MEMORY_BUFFER_HSIZE(x) \
+ (((x) >> NVME_FEAT_HOST_MEMORY_BUFFER_HSIZE_SHIFT) & \
+ NVME_FEAT_HOST_MEMORY_BUFFER_HSIZE_MASK)
+#define NVME_FEAT_HOST_MEMORY_BUFFER_HMDLLA(x) \
+ (((x) >> NVME_FEAT_HOST_MEMORY_BUFFER_HMDLLA_SHIFT) & \
+ NVME_FEAT_HOST_MEMORY_BUFFER_HMDLLA_MASK)
+#define NVME_FEAT_HOST_MEMORY_BUFFER_HMDLUA(x) \
+ (((x) >> NVME_FEAT_HOST_MEMORY_BUFFER_HMDLUA_SHIFT) & \
+ NVME_FEAT_HOST_MEMORY_BUFFER_HMDLUA_MASK)
+#define NVME_FEAT_HOST_MEMORY_BUFFER_HMDLEC(x) \
+ (((x) >> NVME_FEAT_HOST_MEMORY_BUFFER_HMDLEC_SHIFT) & \
+ NVME_FEAT_HOST_MEMORY_BUFFER_HMDLEC_MASK)
+
+/* Timestamp */
+#define NVME_FEAT_TIMESTAMP_TS_SHIFT (0x0)
+#define NVME_FEAT_TIMESTAMP_TS_MASK (0x3F)
+
+#define NVME_FEAT_TIMESTAMP_TS(x) \
+ (((x) >> NVME_FEAT_TIMESTAMP_TS_SHIFT) & \
+ NVME_FEAT_TIMESTAMP_TS_MASK)
+
+/* Keep Alive Timer */
+#define NVME_FEAT_KEEP_ALIVE_TIMER_KATO_SHIFT (0x0)
+#define NVME_FEAT_KEEP_ALIVE_TIMER_KATO_MASK (0xFFFF)
+
+#define NVME_FEAT_KEEP_ALIVE_TIMER_KATO(x) \
+ (((x) >> NVME_FEAT_KEEP_ALIVE_TIMER_KATO_SHIFT) & \
+ NVME_FEAT_KEEP_ALIVE_TIMER_KATO_MASK)
+
+/* Host Controlled Thermal Management */
+#define NVME_FEAT_HOST_CONTROLLED_THERMAL_MGMT_TMT1_SHIFT (16)
+#define NVME_FEAT_HOST_CONTROLLED_THERMAL_MGMT_TMT1_MASK (0xFF)
+#define NVME_FEAT_HOST_CONTROLLED_THERMAL_MGMT_TMT2_SHIFT (0)
+#define NVME_FEAT_HOST_CONTROLLED_THERMAL_MGMT_TMT2_MASK (0xFF)
+
+#define NVME_FEAT_HOST_CONTROLLED_THERMAL_MGMT_TMT1(x) \
+ (((x) >> NVME_FEAT_HOST_CONTROLLED_THERMAL_MGMT_TMT1_SHIFT) & \
+ NVME_FEAT_HOST_CONTROLLED_THERMAL_MGMT_TMT1_MASK)
+#define NVME_FEAT_HOST_CONTROLLED_THERMAL_MGMT_TMT2(x) \
+ (((x) >> NVME_FEAT_HOST_CONTROLLED_THERMAL_MGMT_TMT2_SHIFT) & \
+ NVME_FEAT_HOST_CONTROLLED_THERMAL_MGMT_TMT2_MASK)
+
+/* Non-Operational Power State Config */
+#define NVME_FEAT_NON_OP_POWER_STATE_CONFIG_NOPPME_SHIFT (0)
+#define NVME_FEAT_NON_OP_POWER_STATE_CONFIG_NOPPME_MASK (0x1)
+
+#define NVME_FEAT_NON_OP_POWER_STATE_CONFIG_NOPPME(x) \
+ (((x) >> NVME_FEAT_NON_OP_POWER_STATE_CONFIG_NOPPME_SHIFT) & \
+ NVME_FEAT_NON_OP_POWER_STATE_CONFIG_NOPPME_MASK)
+
+/* Software Progress Marker */
+#define NVME_FEAT_SOFTWARE_PROGRESS_MARKER_PBSLC_SHIFT (0)
+#define NVME_FEAT_SOFTWARE_PROGRESS_MARKER_PBSLC_MASK (0xFF)
+
+#define NVME_FEAT_SOFTWARE_PROGRESS_MARKER_PBSLC(x) \
+ (((x) >> NVME_FEAT_SOFTWARE_PROGRESS_MARKER_PBSLC_SHIFT) & \
+ NVME_FEAT_SOFTWARE_PROGRESS_MARKER_PBSLC_MASK)
+
+/* Host Identifier */
+#define NVME_FEAT_HOST_IDENTIFIER_EXHID_SHIFT (0)
+#define NVME_FEAT_HOST_IDENTIFIER_EXHID_MASK (0x1)
+
+#define NVME_FEAT_HOST_IDENTIFIER_EXHID(x) \
+ (((x) >> NVME_FEAT_HOST_IDENTIFIER_EXHID_SHIFT) & \
+ NVME_FEAT_HOST_IDENTIFIER_EXHID_MASK)
+
+/* Reservation Notification Mask */
+#define NVME_FEAT_RESERVATION_NOTIFICATION_MASK_RESPRE_SHIFT (3)
+#define NVME_FEAT_RESERVATION_NOTIFICATION_MASK_RESPRE_MASK (0x1)
+#define NVME_FEAT_RESERVATION_NOTIFICATION_MASK_RESREL_SHIFT (2)
+#define NVME_FEAT_RESERVATION_NOTIFICATION_MASK_RESREL_MASK (0x1)
+#define NVME_FEAT_RESERVATION_NOTIFICATION_MASK_REGPRE_SHIFT (1)
+#define NVME_FEAT_RESERVATION_NOTIFICATION_MASK_REGPRE_MASK (0x1)
+
+#define NVME_FEAT_RESERVATION_NOTIFICATION_MASK_RESPRE(x) \
+ (((x) >> NVME_FEAT_RESERVATION_NOTIFICATION_MASK_RESPRE_SHIFT) & \
+ NVME_FEAT_RESERVATION_NOTIFICATION_MASK_RESPRE_MASK)
+#define NVME_FEAT_RESERVATION_NOTIFICATION_MASK_RESREL(x) \
+ (((x) >> NVME_FEAT_RESERVATION_NOTIFICATION_MASK_RESREL_SHIFT) & \
+ NVME_FEAT_RESERVATION_NOTIFICATION_MASK_RESREL_MASK)
+#define NVME_FEAT_RESERVATION_NOTIFICATION_MASK_REGPRE(x) \
+ (((x) >> NVME_FEAT_RESERVATION_NOTIFICATION_MASK_REGPRE_SHIFT) & \
+ NVME_FEAT_RESERVATION_NOTIFICATION_MASK_REGPRE_MASK)
+
+/* Reservation Persistence */
+#define NVME_FEAT_RESERVATION_PERSISTENCE_PTPL_SHIFT (0)
+#define NVME_FEAT_RESERVATION_PERSISTENCE_PTPL_MASK (0x1)
+
+#define NVME_FEAT_RESERVATION_PERSISTENCE_PTPL(x) \
+ (((x) >> NVME_FEAT_RESERVATION_PERSISTENCE_PTPL_SHIFT) & \
+ NVME_FEAT_RESERVATION_PERSISTENCE_PTPL_MASK)
+
/* CC register SHN field values */
enum shn_value {
NVME_SHN_NORMAL = 0x1,
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Wed, Nov 5, 1:27 PM (17 h, 8 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
24839124
Default Alt Text
D32700.id98178.diff (43 KB)
Attached To
Mode
D32700: nvmecontrol: Implement Get/Set Feature for nvmecontrol
Attached
Detach File
Event Timeline
Log In to Comment