Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F134647267
D32700.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
39 KB
Referenced Files
None
Subscribers
None
D32700.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D32700: nvmecontrol: Implement Get/Set Feature for nvmecontrol
Attached
Detach File
Event Timeline
Log In to Comment