Page MenuHomeFreeBSD

D32700.diff
No OneTemporary

D32700.diff

diff --git a/sbin/nvmecontrol/Makefile b/sbin/nvmecontrol/Makefile
--- a/sbin/nvmecontrol/Makefile
+++ b/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
diff --git a/sbin/nvmecontrol/feature.c b/sbin/nvmecontrol/feature.c
new file mode 100644
--- /dev/null
+++ b/sbin/nvmecontrol/feature.c
@@ -0,0 +1,837 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (C) 2022 Wanpeng Qian <wanpengqian@gmail.com>
+ *
+ * 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 NONE 0xffu
+#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 *
+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 type;
+ 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 {
+ bool hex;
+ uint8_t fid;
+ uint8_t type;
+ uint32_t cdw11;
+ const char *vendor;
+ const char *dev;
+} get_opt = {
+ .hex = false,
+ .fid = NONE,
+ .type = 0,
+ .cdw11 = 0,
+ .vendor = NULL,
+ .dev = NULL,
+};
+
+static const struct opts get_opts[] = {
+ OPT("hex", 'x', arg_none, get_opt, hex,
+ "print result hex"),
+ OPT("fid", 'f', arg_uint8, get_opt, fid,
+ "feature id (required)"),
+ OPT("vendor", 'v', arg_string, get_opt, vendor,
+ "Vendor specific formatting"),
+ OPT("type", 't', arg_uint8, get_opt, type,
+ "[0-3]current/default/saved/supported"),
+ 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 *vendor;
+ const char *datafile;
+ const char *dev;
+} set_opt = {
+ .fid = NONE,
+ .save = false,
+ .cdw11 = 0,
+ .cdw12 = 0,
+ .cdw13 = 0,
+ .cdw14 = 0,
+ .cdw15 = 0,
+ .vendor = NULL,
+ .datafile = NULL,
+ .dev = NULL,
+};
+
+static const struct opts set_opts[] = {
+ OPT("fid", 'f', arg_uint8, set_opt, fid,
+ "feature id (required)"),
+ OPT("vendor", 'v', arg_string, set_opt, vendor,
+ "Vendor specific formatting"),
+ 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", 'd', 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 SLIST_HEAD(,feature_function) features;
+
+static int
+feature_compare(struct feature_function *a, struct feature_function *b)
+{
+ int c;
+
+ if ((a->vendor == NULL) != (b->vendor == NULL))
+ return (a->vendor == NULL ? -1 : 1);
+ if (a->vendor != NULL) {
+ c = strcmp(a->vendor, b->vendor);
+ if (c != 0)
+ return (c);
+ }
+ return ((int)a->fid - (int)b->fid);
+}
+
+void
+feature_register(struct feature_function *p)
+{
+ struct feature_function *l, *a;
+
+ a = NULL;
+ l = SLIST_FIRST(&features);
+ while (l != NULL) {
+ if (feature_compare(l, p) > 0)
+ break;
+ a = l;
+ l = SLIST_NEXT(l, link);
+ }
+ if (a == NULL)
+ SLIST_INSERT_HEAD(&features, p, link);
+ else
+ SLIST_INSERT_AFTER(a, p, link);
+}
+
+static void
+print_feature_arbitration(uint32_t cdw0, void *buf __unused, uint32_t len __unused)
+{
+
+ printf(" Arbitration Burst (AB): ");
+ if (NVMEV(NVME_FEAT_ARBITRATION_AB, cdw0) == NVME_FEAT_ARBITRATION_AB_MASK)
+ printf("no limit\n");
+ else
+ printf("%d\n", 1 << (NVMEV(NVME_FEAT_ARBITRATION_AB, cdw0)));
+ printf(" Low Priority Weight (LPW): %d\n",
+ ONE_BASED(NVMEV(NVME_FEAT_ARBITRATION_LPW, cdw0)));
+ printf(" Medium Priority Weight (MPW): %d\n",
+ ONE_BASED(NVMEV(NVME_FEAT_ARBITRATION_MPW, cdw0)));
+ printf(" High Priority Weight (HPW): %d\n",
+ ONE_BASED(NVMEV(NVME_FEAT_ARBITRATION_HPW, cdw0)));
+}
+
+static void
+print_feature_power_management(uint32_t cdw0, void *buf __unused, uint32_t len __unused)
+{
+
+ printf(" Workload Hint (WH): %#x\n",
+ NVMEV(NVME_FEAT_POWER_MANAGEMENT_WH, cdw0));
+ printf(" Power State (PS): %#x\n",
+ NVMEV(NVME_FEAT_POWER_MANAGEMENT_PS, cdw0));
+}
+
+static void
+print_feature_lba_range_type(uint32_t cdw0 __unused, void *buf, uint32_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 = MIN(ONE_BASED(NVMEV(NVME_FEAT_LBA_RANGE_TYPE_NUM, cdw0)),
+ len / sizeof(struct nvme_lba_range_type));
+
+ for (i = 0; i < num; i++) {
+ if (i == 0)
+ printf("IDX\tTYPE\t\tSLBA\tNLB\t\tGUID\n");
+ if (idx > lba_range_type_name_res_max)
+ idx = 0;
+ printf("0x%04zx %s", i, lba_range_type_name_res[idx]);
+ printf("\t0x%lx\t0x%08lx\t", lba->slba, ONE_BASED(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, void *buf __unused, uint32_t len __unused)
+{
+
+ printf(" Temperature Threshold (TMPTH): ");
+ print_temp(NVMEV(NVME_FEAT_TEMPERATURE_THRESHOLD_TMPTH, cdw0));
+}
+
+static void
+print_feature_error_recovery(uint32_t cdw0, void *buf __unused, uint32_t len __unused)
+{
+
+ printf(" Deallocated or Unwritten Logical Block Error Enable (DULBE): %d\n",
+ NVMEV(NVME_FEAT_ERROR_RECOVERY_DULBE, cdw0));
+ printf(" Time Limited Error Recovery (TLER): %d of 100ms\n",
+ NVMEV(NVME_FEAT_ERROR_RECOVERY_TLER, cdw0));
+}
+
+static void
+print_feature_volatile_write_cache(uint32_t cdw0, void *buf __unused, uint32_t len __unused)
+{
+
+ printf(" Volatile Write Cache Enable (WCE): %d\n",
+ NVMEV(NVME_FEAT_VOLATILE_WRITE_CACHE_WCE, cdw0));
+}
+
+static void
+print_feature_number_of_queues(uint32_t cdw0, void *buf __unused, uint32_t len __unused)
+{
+
+ printf(" Number of I/O Completion Queues Allocated (NCQA): %d\n",
+ ONE_BASED(NVMEV(NVME_FEAT_NUMBER_OF_QUEUES_NCQA, cdw0)));
+ printf(" Number of I/O Submission Queues Allocated (NSQA): %d\n",
+ ONE_BASED(NVMEV(NVME_FEAT_NUMBER_OF_QUEUES_NSQA, cdw0)));
+}
+
+static void
+print_feature_interrupt_coalescing(uint32_t cdw0, void *buf __unused, uint32_t len __unused)
+{
+
+ printf(" Aggregation Time (TIME): %d\n",
+ NVMEV(NVME_FEAT_INTERRUPT_COALESCING_TIME, cdw0));
+ printf(" Aggregation Threshold (THR): %d\n",
+ NVMEV(NVME_FEAT_INTERRUPT_COALESCING_THR, cdw0));
+}
+
+static void
+print_feature_interrupt_vector_configuration(uint32_t cdw0, void *buf __unused, uint32_t len __unused)
+{
+
+ printf(" Coalescing Disable (CD): %d\n",
+ NVMEV(NVME_FEAT_INTERRUPT_VECTOR_CONFIGURATION_CD, cdw0));
+ printf(" Interrupt Vector (IV): %d\n",
+ NVMEV(NVME_FEAT_INTERRUPT_VECTOR_CONFIGURATION_IV, cdw0));
+}
+
+static void
+print_feature_write_atomicity(uint32_t cdw0, void *buf __unused, uint32_t len __unused)
+{
+
+ printf(" Disable Normal (DN): %d\n",
+ NVMEV(NVME_FEAT_WRITE_ATOMICITY_DN, cdw0));
+}
+
+static void
+print_feature_async_event_configuration(uint32_t cdw0, void *buf __unused, uint32_t len __unused)
+{
+
+ printf(" Telemetry Log Notices: %d\n",
+ NVMEV(NVME_FEAT_ASYNC_EVENT_CONFIGURATION_TLN, cdw0));
+ printf(" Firmware Activation Notices: %d\n",
+ NVMEV(NVME_FEAT_ASYNC_EVENT_CONFIGURATION_FAN, cdw0));
+ printf(" Namespace Attribute Notices: %d\n",
+ NVMEV(NVME_FEAT_ASYNC_EVENT_CONFIGURATION_NAN, cdw0));
+ printf(" SMART/Health Critical Warnings: %d\n",
+ NVMEV(NVME_FEAT_ASYNC_EVENT_CONFIGURATION_TLN, cdw0));
+}
+
+static void
+print_feature_autonomous_power_state_transition(uint32_t cdw0, void *buf __unused, uint32_t len __unused)
+{
+
+ printf(" Autonomous Power State Transition Enable (APSTE): %d\n",
+ NVMEV(NVME_FEAT_AUTONOMOUS_POWER_STATE_TRANSITION_APSTE, cdw0));
+}
+
+static void
+print_feature_timestamp(uint32_t cdw0 __unused, void *buf, uint32_t len)
+{
+ uint8_t *data = (uint8_t*)buf;
+ uint64_t milliseconds, seconds;
+ uint8_t origin;
+ bool synch;
+ uint32_t days, hours, minutes;
+
+ if (len < 8)
+ return;
+
+ origin = (data[6] >> 1) & 0x07;
+ synch = data[6] & 0x01;
+
+ memcpy((uint8_t*)&milliseconds, (uint8_t*)data, len);
+ milliseconds &= 0xffffffffffff;
+ seconds = milliseconds / 1000;
+ minutes = seconds / 60;
+ hours = minutes / 60;
+ days = hours / 24;
+
+ switch (origin) {
+ case 0x0:
+ printf(" Origin: since controller reset\n");
+ break;
+ case 0x1:
+ printf(" Origin: since last set feature\n");
+ break;
+ default:
+ printf(" Origin: reserved\n" );
+ break;
+ }
+ if (synch)
+ printf(" Synch: may not continuously.\n");
+ else
+ printf(" Synch: continuously\n");
+
+ printf(" Time elapsed: %lu ms,", milliseconds);
+ printf(" (%d days %02d:%02d:%02lu.%03lu)\n",
+ days, hours % 24, minutes % 60, seconds % 60, milliseconds % 1000);
+}
+
+static void
+print_feature_keep_alive_timer(uint32_t cdw0, void *buf __unused, uint32_t len __unused)
+{
+
+ printf(" Keep Alive Timeout (KATO): %d\n",
+ NVMEV(NVME_FEAT_KEEP_ALIVE_TIMER_KATO, cdw0));
+}
+
+static void
+print_feature_host_memory_buffer(uint32_t cdw0, void *buf __unused, uint32_t len __unused)
+{
+
+ printf(" Memory Return (MR): %d\n",
+ NVMEV(NVME_FEAT_HOST_MEMORY_BUFFER_MR, cdw0));
+ printf(" Enable Host Memory (EHM): %d\n",
+ NVMEV(NVME_FEAT_HOST_MEMORY_BUFFER_EHM, cdw0));
+}
+
+static void
+print_feature_host_controlled_thermal_mgmt(uint32_t cdw0, void *buf __unused, uint32_t len __unused)
+{
+
+ printf(" Thermal Management Temperature 1 (TMT1): %d\n",
+ NVMEV(NVME_FEAT_HOST_CONTROLLED_THERMAL_MGMT_TMT1, cdw0));
+ printf(" Thermal Management Temperature 2 (TMT2): %d\n",
+ NVMEV(NVME_FEAT_HOST_CONTROLLED_THERMAL_MGMT_TMT2, cdw0));
+}
+
+static void
+print_feature_non_op_power_state_config(uint32_t cdw0, void *buf __unused, uint32_t len __unused)
+{
+
+ printf(" Non-Operational Power State Permissive Mode Enable (NOPPME): %d\n",
+ NVMEV(NVME_FEAT_NON_OP_POWER_STATE_CONFIG_NOPPME, cdw0));
+}
+
+void
+get_feature_not_support(uint32_t cdw0 __unused, void *buf __unused, uint32_t len __unused)
+{
+
+ printf("Get for this feature is not support\n");
+}
+
+static void
+print_feat_hex(uint32_t cdw0, void *buf, uint32_t len)
+{
+
+ if (buf != NULL && len > 0)
+ print_hex(buf, len);
+ else
+ printf("0x%X\n", cdw0);
+}
+
+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_help(void)
+{
+ const struct feature_function *f;
+ const char *v;
+
+ fprintf(stderr, "\n");
+ fprintf(stderr, "%-10s %-10s %s\n", "Feature Id", "Vendor","Feature Name");
+ fprintf(stderr, "---------- ---------- ----------\n");
+ SLIST_FOREACH(f, &features, link) {
+ v = f->vendor == NULL ? "-" : f->vendor;
+ fprintf(stderr, "0x%02x %-10s %s\n", f->fid, v, f->name);
+ }
+
+ exit(EX_USAGE);
+}
+
+static void
+interpret_nvme_feature_set_status(uint8_t status)
+{
+
+ switch (status) {
+ case 0x0d:
+ printf("Feature Identifier Not Saveable\n");
+ break;
+ case 0x0e:
+ printf("Feature Not Changeable\n");
+ break;
+ case 0x0f:
+ printf("Feature Not Namespace Specific\n");
+ break;
+ case 0x14:
+ printf("Overlapping Range\n");
+ break;
+ default:
+ printf("Unknown Status Code: %u\n", status);
+ break;
+ }
+}
+
+static void
+feature_get(const struct cmd *f, int argc, char *argv[])
+{
+ struct nvme_pt_command pt;
+ int fd;
+ const struct feature_function *ff;
+ feat_print_fn_t print_fn;
+ uint8_t *buf = NULL;
+ uint32_t size = 0;
+
+ if (arg_parse(argc, argv, f))
+ return;
+ if (get_opt.vendor != NULL && strcmp(get_opt.vendor, "help") == 0)
+ feature_help();
+ if (get_opt.fid == NONE) {
+ fprintf(stderr, "Missing feature id (-f).\n");
+ arg_help(argc, argv, f);
+ }
+
+ print_fn = print_feat_hex;
+ size = 0;
+ if (!get_opt.hex) {
+ /*
+ * See if there is a pretty print function for the specified
+ * feature. If one isn't found, we just revert to the default
+ * (print_hex). If there was a vendor specified by the user, and
+ * the page is vendor specific, don't match the print function
+ * unless the vendors match.
+ */
+ SLIST_FOREACH(ff, &features, link) {
+ if (ff->vendor != NULL && get_opt.vendor != NULL &&
+ strcmp(ff->vendor, get_opt.vendor) != 0)
+ continue;
+ if (get_opt.fid != ff->fid)
+ continue;
+ if (ff->print_fn != NULL)
+ print_fn = ff->print_fn;
+ size = ff->size;
+ break;
+ }
+ }
+
+ open_dev(get_opt.dev, &fd, 1, 1);
+
+ memset(&pt, 0, sizeof(pt));
+ pt.cmd.opc = NVME_OPC_GET_FEATURES;
+ pt.cmd.cdw10 = htole32((get_opt.type << NVME_FEAT_GET_SEL_SHIFT) |
+ (get_opt.fid << NVME_FEAT_GET_FID_SHIFT));
+ 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");
+
+ if (nvme_completion_is_error(&pt.cpl))
+ errx(EX_IOERR, "get feature request returned error");
+
+ print_fn(pt.cpl.cdw0, buf, size);
+
+ close(fd);
+ exit(0);
+}
+
+static void
+feature_set(const struct cmd *f, int argc, char *argv[])
+{
+ struct nvme_pt_command pt;
+ const struct feature_function *ff;
+ int fd;
+ void *buf = NULL;
+ feat_interpret_fn_t pret_fn;
+ int32_t size = 0;
+
+ if (arg_parse(argc, argv, f))
+ return;
+ if (set_opt.vendor != NULL && strcmp(set_opt.vendor, "help") == 0)
+ feature_help();
+ if (set_opt.fid == NONE) {
+ 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);
+ }
+
+ pret_fn = NULL;
+ SLIST_FOREACH(ff, &features, link) {
+ if (ff->vendor != NULL && get_opt.vendor != NULL &&
+ strcmp(ff->vendor, set_opt.vendor) != 0)
+ continue;
+ if (set_opt.fid != ff->fid)
+ continue;
+ if (ff->pret_fn != NULL)
+ pret_fn = ff->pret_fn;
+ size = ff->size;
+ break;
+ }
+
+ open_dev(set_opt.dev, &fd, 1, 1);
+
+ memset(&pt, 0, sizeof(pt));
+ pt.cmd.opc = NVME_OPC_SET_FEATURES;
+ pt.cmd.cdw10 = htole32((set_opt.save << NVME_FEAT_SET_SV_SHIFT) |
+ (set_opt.fid << NVME_FEAT_SET_FID_SHIFT));
+ 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)) {
+ if (NVME_STATUS_GET_SCT(pt.cpl.status) == NVME_SCT_COMMAND_SPECIFIC && pret_fn) {
+ pret_fn(NVME_STATUS_GET_SC(pt.cpl.status));
+ }
+ else
+ errx(EX_IOERR, "set feature request returned error");
+ }
+ else
+ 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;
+ const struct feature_function *ff;
+ uint8_t fid, type;
+ uint32_t cdw11;
+ int fd;
+ feat_print_fn_t print_fn;
+ uint8_t *buf = NULL;
+ uint32_t i;
+ uint32_t size = 0;
+
+ 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;
+ type = feature_summary_list[i].type;
+ cdw11 = feature_summary_list[i].cdw11;
+
+ memset(&pt, 0, sizeof(pt));
+ pt.cmd.opc = NVME_OPC_GET_FEATURES;
+ pt.cmd.cdw10 = htole32((type << NVME_FEAT_GET_SEL_SHIFT) |
+ (fid << NVME_FEAT_GET_FID_SHIFT));
+ pt.cmd.cdw11 = htole32(cdw11);
+ pt.buf = buf;
+ pt.len = size;
+ pt.is_read = 1;
+
+ if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
+ continue;
+
+ if (nvme_completion_is_error(&pt.cpl))
+ continue;
+
+ print_fn = print_feat_hex;
+ SLIST_FOREACH(ff, &features, link) {
+ if (fid != ff->fid)
+ continue;
+ if (ff->print_fn != NULL)
+ print_fn = ff->print_fn;
+ size = ff->size;
+ break;
+ }
+
+ print_fn(pt.cpl.cdw0, buf, size);
+ }
+
+ close(fd);
+ exit(0);
+}
+
+static void
+feature(const struct cmd *nf __unused, int argc, char *argv[])
+{
+
+ cmd_dispatch(argc, argv, &feature_cmd);
+}
+
+NVME_FEATURE(arbitration,
+ NVME_FEAT_ARBITRATION, NULL, "Command Arbitration",
+ print_feature_arbitration, interpret_nvme_feature_set_status, 0);
+NVME_FEATURE(power_management,
+ NVME_FEAT_POWER_MANAGEMENT, NULL, "Power Management",
+ print_feature_power_management, interpret_nvme_feature_set_status, 0);
+NVME_FEATURE(lba_range_type,
+ NVME_FEAT_LBA_RANGE_TYPE, NULL, "LBA Range Type",
+ print_feature_lba_range_type, interpret_nvme_feature_set_status, 0);
+NVME_FEATURE(temperature_threshold,
+ NVME_FEAT_TEMPERATURE_THRESHOLD, NULL, "Temperature Threshold",
+ print_feature_temperature_threshold, interpret_nvme_feature_set_status, 0);
+NVME_FEATURE(error_recovery,
+ NVME_FEAT_ERROR_RECOVERY, NULL, "Error Recovery",
+ print_feature_error_recovery, interpret_nvme_feature_set_status, 0);
+NVME_FEATURE(volatile_write_cache,
+ NVME_FEAT_VOLATILE_WRITE_CACHE, NULL, "Volatile Write Cache",
+ print_feature_volatile_write_cache, interpret_nvme_feature_set_status, 0);
+NVME_FEATURE(number_of_queues,
+ NVME_FEAT_NUMBER_OF_QUEUES, NULL, "Number of Queues",
+ print_feature_number_of_queues, interpret_nvme_feature_set_status, 0);
+NVME_FEATURE(interrupt_coalescing,
+ NVME_FEAT_INTERRUPT_COALESCING, NULL, "Interrupt Coalescing",
+ print_feature_interrupt_coalescing, interpret_nvme_feature_set_status, 0);
+NVME_FEATURE(interrupt_vector_configuration,
+ NVME_FEAT_INTERRUPT_VECTOR_CONFIGURATION, NULL, "Interrupt Vector Configuration",
+ print_feature_interrupt_vector_configuration, interpret_nvme_feature_set_status, 0);
+NVME_FEATURE(write_atomicity,
+ NVME_FEAT_WRITE_ATOMICITY, NULL, "Write Atomicity Normal",
+ print_feature_write_atomicity, interpret_nvme_feature_set_status, 0);
+NVME_FEATURE(async_event_configuration,
+ NVME_FEAT_ASYNC_EVENT_CONFIGURATION, NULL, "Asynchronous Event Configuration",
+ print_feature_async_event_configuration, interpret_nvme_feature_set_status, 0);
+NVME_FEATURE(autonomous_power_state_transition,
+ NVME_FEAT_AUTONOMOUS_POWER_STATE_TRANSITION, NULL, "Autonomous Power State Transition",
+ print_feature_autonomous_power_state_transition, interpret_nvme_feature_set_status, 0);
+NVME_FEATURE(host_memory_buffer,
+ NVME_FEAT_HOST_MEMORY_BUFFER, NULL, "Host Memory Buffer",
+ print_feature_host_memory_buffer, interpret_nvme_feature_set_status, 0);
+NVME_FEATURE(timestamp,
+ NVME_FEAT_TIMESTAMP, NULL, "Timestamp",
+ print_feature_timestamp, interpret_nvme_feature_set_status, 0);
+NVME_FEATURE(keep_alive_timer,
+ NVME_FEAT_KEEP_ALIVE_TIMER, NULL, "Keep Alive Timer",
+ print_feature_keep_alive_timer, interpret_nvme_feature_set_status, 0);
+NVME_FEATURE(host_controlled_thermal_mgmt,
+ NVME_FEAT_HOST_CONTROLLED_THERMAL_MGMT, NULL, "Host Controlled Thermal Management",
+ print_feature_host_controlled_thermal_mgmt, interpret_nvme_feature_set_status, 0);
+NVME_FEATURE(non_op_power_state_config,
+ NVME_FEAT_NON_OP_POWER_STATE_CONFIG, NULL, "Non-Operational Power State Config",
+ print_feature_non_op_power_state_config, interpret_nvme_feature_set_status, 0);
diff --git a/sbin/nvmecontrol/modules/intel/intel.c b/sbin/nvmecontrol/modules/intel/intel.c
--- a/sbin/nvmecontrol/modules/intel/intel.c
+++ b/sbin/nvmecontrol/modules/intel/intel.c
@@ -181,6 +181,95 @@
}
}
+static void
+print_intel_max_lba(uint32_t cdw0, void *buf __unused, uint32_t len __unused)
+{
+
+ printf(" Max LBA: %u\n", cdw0);
+}
+
+static void
+print_intel_native_max_lba(uint32_t cdw0, void *buf __unused, uint32_t len __unused)
+{
+
+ printf(" Native Max LBA: %u\n", cdw0);
+}
+
+static void
+print_intel_power_governor_setting(uint32_t cdw0, void *buf __unused, uint32_t len __unused)
+{
+ uint8_t pg = cdw0 & 0xff; /* Power Governor */
+
+ printf(" Power Governor Setting (PGS): ");
+ switch (pg) {
+ case 0x00:
+ printf("25W(typical)\n");
+ break;
+ case 0x01:
+ printf("20W(typical)\n");
+ break;
+ case 0x02:
+ printf("10W(typical)\n");
+ break;
+ default:
+ printf("%u\n", pg);
+ break;
+ }
+}
+
+static void
+interpret_intel_max_lba(uint8_t status)
+{
+
+ switch (status) {
+ case 0xc0:
+ printf("Requested MAX LBA exceeds Available capacity\n");
+ break;
+ case 0xc1:
+ printf("Requested MAX LBA smaller than minimum allowable limit\n");
+ break;
+ case 0xc2:
+ printf("Requested MAX LBA is smaller than allocated Namespace requirements\n");
+ break;
+ default:
+ printf("Unknown Status Code: %u\n", status);
+ break;
+ }
+}
+
+static void
+interpret_intel_power_governor_setting(uint8_t status)
+{
+
+ switch (status) {
+ case 0xc0:
+ printf("Invalid Setting\n");
+ break;
+ default:
+ printf("Unknown Status Code: %u\n", status);
+ break;
+ }
+}
+
+static void
+interpret_intel_reset_timed_workload_counters(uint8_t status)
+{
+
+ switch (status) {
+ case 0xc0:
+ printf("Invalid Setting\n");
+ break;
+ default:
+ printf("Unknown Status Code: %u\n", status);
+ break;
+ }
+}
+
+#define INTEL_FEAT_MAX_LBA 0xc1
+#define INTEL_FEAT_NATIVE_MAX_LBA 0xc2
+#define INTEL_FEAT_POWER_GOVERNOR_SETTING 0xc6
+#define INTEL_FEAT_RESET_TIMED_WORKLOAD_COUNTERS 0xd5
+
NVME_LOGPAGE(intel_temp,
INTEL_LOG_TEMP_STATS, "intel", "Temperature Stats",
print_intel_temp_stats, sizeof(struct intel_log_temp_stats));
@@ -193,3 +282,15 @@
NVME_LOGPAGE(intel_smart,
INTEL_LOG_ADD_SMART, "intel", "Extra Health/SMART Data",
print_intel_add_smart, DEFAULT_SIZE);
+NVME_FEATURE(intel_max_lba,
+ INTEL_FEAT_MAX_LBA, "intel", "Max LBA",
+ print_intel_max_lba, interpret_intel_max_lba, 0);
+NVME_FEATURE(intel_native_max_lba,
+ INTEL_FEAT_NATIVE_MAX_LBA, "intel", "Native Max LBA",
+ print_intel_native_max_lba, NULL, 0);
+NVME_FEATURE(intel_power_governor_setting,
+ INTEL_FEAT_POWER_GOVERNOR_SETTING, "intel", "Power Governor Setting",
+ print_intel_power_governor_setting, interpret_intel_power_governor_setting, 0);
+NVME_FEATURE(intel_reset_timed_workload_counters,
+ INTEL_FEAT_RESET_TIMED_WORKLOAD_COUNTERS, "intel", "Reset Timed Workload Counters",
+ get_feature_not_support, interpret_intel_reset_timed_workload_counters, 0);
diff --git a/sbin/nvmecontrol/nvmecontrol.h b/sbin/nvmecontrol/nvmecontrol.h
--- a/sbin/nvmecontrol/nvmecontrol.h
+++ b/sbin/nvmecontrol/nvmecontrol.h
@@ -35,6 +35,8 @@
#include "comnd.h"
typedef void (*print_fn_t)(const struct nvme_controller_data *cdata, void *buf, uint32_t size);
+typedef void (*feat_print_fn_t)(uint32_t cdw0, void *buf, uint32_t size);
+typedef void (*feat_interpret_fn_t)(uint8_t status);
struct logpage_function {
SLIST_ENTRY(logpage_function) link;
@@ -45,6 +47,16 @@
size_t size;
};
+struct feature_function {
+ SLIST_ENTRY(feature_function) link;
+ uint8_t fid;
+ const char *vendor;
+ const char *name;
+ feat_print_fn_t print_fn;
+ feat_interpret_fn_t pret_fn;
+ size_t size;
+};
+
#define NVME_LOGPAGE(unique, lp, vend, nam, fn, sz) \
static struct logpage_function unique ## _lpf = { \
.log_page = lp, \
@@ -56,6 +68,18 @@
static void logpage_reg_##unique(void) __attribute__((constructor)); \
static void logpage_reg_##unique(void) { logpage_register(&unique##_lpf); }
+#define NVME_FEATURE(unique, id, vend, na, fnp, fni, sz) \
+ static struct feature_function unique ## _ff = { \
+ .fid = id, \
+ .vendor = vend, \
+ .name = na, \
+ .print_fn = fnp, \
+ .pret_fn = fni, \
+ .size = sz, \
+ } ; \
+ static void feature_reg_##unique(void) __attribute__((constructor)); \
+ static void feature_reg_##unique(void) { feature_register(&unique##_ff); }
+
#define DEFAULT_SIZE (4096)
struct kv_name {
uint32_t key;
@@ -65,6 +89,8 @@
const char *kv_lookup(const struct kv_name *kv, size_t kv_count, uint32_t key);
void logpage_register(struct logpage_function *p);
+void feature_register(struct feature_function *p);
+void get_feature_not_support(uint32_t cdw0, void *buf, uint32_t len);
#define NVME_CTRLR_PREFIX "nvme"
#define NVME_NS_PREFIX "ns"
diff --git a/sbin/nvmecontrol/nvmecontrol.8 b/sbin/nvmecontrol/nvmecontrol.8
--- a/sbin/nvmecontrol/nvmecontrol.8
+++ b/sbin/nvmecontrol/nvmecontrol.8
@@ -148,6 +148,29 @@
.Op Fl x
.Aq Ar namespace-id
.Nm
+.Ic feature get
+.Aq Fl f Ar feature-id
+.Op Fl v Ar vendor-string
+.Op Fl t Ar type
+.Op Fl x
+.Op Fl 1 Ar value
+.Aq Ar device-id
+.Nm
+.Ic feature set
+.Aq Fl f Ar feature-id
+.Op Fl v Ar vendor-string
+.Op Fl s Ar save
+.Op Fl 1 Ar value
+.Op Fl 2 Ar value
+.Op Fl 3 Ar value
+.Op Fl 4 Ar value
+.Op Fl 5 Ar value
+.Op Fl d Ar path_to_datafile
+.Aq Ar device-id
+.Nm
+.Ic feature summary
+.Aq Ar device-id
+.Nm
.Ic firmware
.Op Fl s Ar slot
.Op Fl f Ar path_to_firmware
@@ -250,6 +273,139 @@
.Dv IDENTIFY_CONTROLLER
data associated with that drive.
.El
+.Ss feature
+The feature command includes
+.Ic get set
+and
+.Ic summary
+sub commands
+to get and set a feature for a specific device.
+It also knows about vendor specific features.
+.Pp
+Specifying
+.Fl v
+.Ic help
+will list all valid vendors and pages within
+.Ic get
+and
+.Ic set
+sub commands.
+.Pp
+.Bl -tag -compact -width "Fid 0x00"
+.It Dv Fid 0x01
+Command Arbitration
+.It Dv Fid 0x02
+Power Management
+.It Dv Fid 0x03
+LBA Range Type
+.It Dv Fid 0x04
+Temperature Threshold
+.It Dv Fid 0x05
+Error Recovery
+.It Dv Fid 0x06
+Volatile Write Cache
+.It Dv Fid 0x07
+Number of 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
+.It Dv Fid 0x0c
+Autonomous Power State Transition
+.It Dv Fid 0x0d
+Host Memory Buffer
+.It Dv Fid 0x0e
+Timestamp
+.It Dv Fid 0x0f
+Keep Alive Timer
+.It Dv Fid 0x10
+Host Controlled Thermal Management
+.It Dv Fid 0x11
+Non-Operational Power State Config
+.It Dv Fid 0xc1
+Max LBA (Intel)
+.It Dv Fid 0xc2
+Native Max LBA (Intel)
+.It Dv Fid 0xc6
+Power Governor Setting (Intel)
+.It Dv Fid 0xd5
+Reset Timed Workload Counters (Intel)
+.El
+.Ss feature get
+The feature get command can output feature settings for specific device.
+.Bl -tag -width 8n
+.It Fl f Ar feature-id
+Feature id to get
+.It Fl v
+vendor-string
+.It Fl t
+Data type
+.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 x
+Print data as hex
+.It Fl 2 -cdw11 Ar value
+32-bit value for CDW11.
+.El
+.Ss feature set
+The feature set command can set features for specific devices.
+.Bl -tag -width 8n
+.It Fl f Ar feature-id
+Feature id to set
+.It Fl v
+vendor-string
+.It Fl s
+Requests that the controller save the attribute
+so that the attribute persists through all power states and resets.
+.It Fl 1 -cdw11 Ar value
+32-bit value for CDW11.
+.It Fl 2 -cdw12 Ar value
+32-bit value for CDW12.
+.It Fl 3 -cdw13 Ar value
+32-bit value for CDW13.
+.It Fl 4 -cdw14 Ar value
+32-bit value for CDW14.
+.It Fl 5 -cdw15 Ar value
+32-bit value for CDW15.
+.It Fl d Ar path_to_datafile
+Data file for specific features.
+.El
+.Ss feature summary
+The feature summary command will output all mandatory features
+for a 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 of 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, samsung and intel.
@@ -680,6 +836,15 @@
standard out.
Redirect it to a temporary file.
.Pp
+.Dl nvmecontrol feature get -f0x01 -t1 nvme0
+.Pp
+Get feature default value of Command Arbitration for nvme0 controller.
+.Pp
+.Dl nvmecontrol feature set -f0x04 -s -10x157 nvme0
+.Pp
+Set feature value of Temperature Threshold for nvme0 controller,
+and tell the controller to save that value.
+.Pp
.Dl nvmecontrol firmware -s 2 -f /tmp/nvme_firmware nvme0
.Pp
Download the firmware image contained in "/tmp/nvme_firmware" to slot 2 of the
diff --git a/sys/dev/nvme/nvme.h b/sys/dev/nvme/nvme.h
--- a/sys/dev/nvme/nvme.h
+++ b/sys/dev/nvme/nvme.h
@@ -566,9 +566,155 @@
#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)
+
+/* 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)
+
+/* 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)
+
+/* 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)
+
+/* LBA Range Type */
+#define NVME_FEAT_LBA_RANGE_TYPE_NUM_SHIFT (0)
+#define NVME_FEAT_LBA_RANGE_TYPE_NUM_MASK (0x3F)
+
+/* 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)
+
+/* 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)
+
+/* Volatile Write Cache */
+#define NVME_FEAT_VOLATILE_WRITE_CACHE_WCE_SHIFT (0)
+#define NVME_FEAT_VOLATILE_WRITE_CACHE_WCE_MASK (0x1)
+
+/* 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)
+
+/* 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)
+
+/* 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)
+
+/* Write Atomicity Normal */
+#define NVME_FEAT_WRITE_ATOMICITY_DN_SHIFT (0)
+#define NVME_FEAT_WRITE_ATOMICITY_DN_MASK (0x1)
+
+/* 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)
+
+/* Autonomous Power State Transition */
+#define NVME_FEAT_AUTONOMOUS_POWER_STATE_TRANSITION_APSTE_SHIFT (0)
+#define NVME_FEAT_AUTONOMOUS_POWER_STATE_TRANSITION_APSTE_MASK (0x1)
+
+/* 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)
+
+/* Timestamp */
+#define NVME_FEAT_TIMESTAMP_TS_SHIFT (0x0)
+#define NVME_FEAT_TIMESTAMP_TS_MASK (0x3F)
+
+/* Keep Alive Timer */
+#define NVME_FEAT_KEEP_ALIVE_TIMER_KATO_SHIFT (0x0)
+#define NVME_FEAT_KEEP_ALIVE_TIMER_KATO_MASK (0xFFFF)
+
+/* 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)
+
+/* 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)
+
+/* Software Progress Marker */
+#define NVME_FEAT_SOFTWARE_PROGRESS_MARKER_PBSLC_SHIFT (0)
+#define NVME_FEAT_SOFTWARE_PROGRESS_MARKER_PBSLC_MASK (0xFF)
+
+/* Host Identifier */
+#define NVME_FEAT_HOST_IDENTIFIER_EXHID_SHIFT (0)
+#define NVME_FEAT_HOST_IDENTIFIER_EXHID_MASK (0x1)
+
+/* 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)
+
+/* Reservation Persistence */
+#define NVME_FEAT_RESERVATION_PERSISTENCE_PTPL_SHIFT (0)
+#define NVME_FEAT_RESERVATION_PERSISTENCE_PTPL_MASK (0x1)
+
/* Helper macro to combine *_MASK and *_SHIFT defines */
#define NVMEB(name) (name##_MASK << name##_SHIFT)
+/* Helper macro to extract value from x */
+#define NVMEV(name, x) (((x) >> name##_SHIFT) & name##_MASK)
+
/* CC register SHN field values */
enum shn_value {
NVME_SHN_NORMAL = 0x1,

File Metadata

Mime Type
text/plain
Expires
Tue, Nov 4, 8:25 PM (7 m, 21 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
24775059
Default Alt Text
D32700.diff (39 KB)

Event Timeline