Page MenuHomeFreeBSD

D32700.id98178.diff
No OneTemporary

D32700.id98178.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,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

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)

Event Timeline