Page MenuHomeFreeBSD

D32700.id97992.diff
No OneTemporary

D32700.id97992.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,845 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (C) 2021 Wanpeng Qian <wanpengqian@gmail.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer,
+ * without modification, immediately at the beginning of the file.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/ioccom.h>
+
+#include <err.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+#include <unistd.h>
+
+#include "nvmecontrol.h"
+
+/* Tables for command line parsing */
+
+static cmd_fn_t 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)
+
+#define NVME_FEAT_GET_SEL_SHIFT (8)
+#define NVME_FEAT_GET_SEL_MASK (0x7)
+#define NVME_FEAT_GET_FID_SHIFT (0)
+#define NVME_FEAT_GET_FID_MASK (0xFF)
+
+#define NVME_FEAT_SET_SV_SHIFT (31)
+#define NVME_FEAT_SET_SV_MASK (0x1)
+#define NVME_FEAT_SET_FID_SHIFT (0)
+#define NVME_FEAT_SET_FID_MASK (0xFF)
+
+#define NVME_FEAT_ARBITRATION_HPW_SHIFT (24)
+#define NVME_FEAT_ARBITRATION_HPW_MASK (0xFF)
+#define NVME_FEAT_ARBITRATION_MPW_SHIFT (16)
+#define NVME_FEAT_ARBITRATION_MPW_MASK (0xFF)
+#define NVME_FEAT_ARBITRATION_LPW_SHIFT (8)
+#define NVME_FEAT_ARBITRATION_LPW_MASK (0xFF)
+#define NVME_FEAT_ARBITRATION_AB_SHIFT (0)
+#define NVME_FEAT_ARBITRATION_AB_MASK (0x7)
+
+#define NVME_FEAT_POWER_MANAGEMENT_WH_SHIFT (5)
+#define NVME_FEAT_POWER_MANAGEMENT_WH_MASK (0x7)
+#define NVME_FEAT_POWER_MANAGEMENT_PS_SHIFT (0)
+#define NVME_FEAT_POWER_MANAGEMENT_PS_MASK (0x1F)
+
+#define NVME_FEAT_LBA_RANGE_TYPE_NUM_SHIFT (0)
+#define NVME_FEAT_LBA_RANGE_TYPE_NUM_MASK (0x1F)
+
+#define NVME_FEAT_TEMPERATURE_THRESHOLD_THSEL_SHIFT (20)
+#define NVME_FEAT_TEMPERATURE_THRESHOLD_THSEL_MASK (0x3)
+#define NVME_FEAT_TEMPERATURE_THRESHOLD_TMPSEL_SHIFT (16)
+#define NVME_FEAT_TEMPERATURE_THRESHOLD_TMPSEL_MASK (0xF)
+#define NVME_FEAT_TEMPERATURE_THRESHOLD_TMPTH_SHIFT (0)
+#define NVME_FEAT_TEMPERATURE_THRESHOLD_TMPTH_MASK (0xFFFF)
+
+#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_VOLATILE_WRITE_CACHE_WCE_SHIFT (0)
+#define NVME_FEAT_VOLATILE_WRITE_CACHE_WCE_MASK (0x1)
+
+#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_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_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_WRITE_ATOMICITY_DN_SHIFT (0)
+#define NVME_FEAT_WRITE_ATOMICITY_DN_MASK (0x1)
+
+#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_AUTONOMOUS_POWER_STATE_TRANSITION_APSTE_SHIFT (0)
+#define NVME_FEAT_AUTONOMOUS_POWER_STATE_TRANSITION_APSTE_MASK (0x1)
+
+#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_TIMESTAMP_TS_SHIFT (0x0)
+#define NVME_FEAT_TIMESTAMP_TS_MASK (0x3F)
+
+#define NVME_FEAT_KEEP_ALIVE_TIMER_KATO_SHIFT (0x0)
+#define NVME_FEAT_KEEP_ALIVE_TIMER_KATO_MASK (0xFFFF)
+
+#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_NON_OP_POWER_STATE_CONFIG_NOPPME_SHIFT (0)
+#define NVME_FEAT_NON_OP_POWER_STATE_CONFIG_NOPPME_MASK (0x1)
+
+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",
+ [1] = "Command Arbitration",
+ [2] = "Power Management",
+ [3] = "LBA Range Type",
+ [4] = "Temperature Threshold",
+ [5] = "Error Recovery",
+ [6] = "Volatile Write Cache",
+ [7] = "Number of Queues",
+ [8] = "Interrupt Coalescing",
+ [9] = "Interrupt Vector Configuration",
+ [10] = "Write Atomicity Normal",
+ [11] = "Asynchronous Event Configuration",
+ [12] = "Autonomous Power State Transition",
+ [13] = "Host Memory Buffer",
+ [14] = "Timestamp",
+ [15] = "Keep Alive Timer",
+ [16] = "Host Controlled Thermal Management",
+ [17] = "Non-Operational Power State Config",
+};
+static uint32_t 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] = "Reserved",
+ [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 *dev;
+} set_opt = {
+ .fid = NONE8,
+ .save = false,
+ .cdw11 = 0,
+ .cdw12 = 0,
+ .cdw13 = 0,
+ .cdw14 = 0,
+ .cdw15 = 0,
+ .dev = NULL,
+};
+
+static const struct opts set_opts[] = {
+ OPT("fid", 'f', arg_uint8, set_opt, fid,
+ "feature id (required)"),
+ OPT("save", 's', arg_none, set_opt, save,
+ "the controller shall save the attribute"),
+ OPT("cdw11", '1', arg_uint32, set_opt, cdw11,
+ "dword 11 value"),
+ OPT("cdw12", '2', arg_uint32, set_opt, cdw12,
+ "dword 12 value"),
+ OPT("cdw13", '3', arg_uint32, set_opt, cdw13,
+ "dword 13 value"),
+ OPT("cdw14", '4', arg_uint32, set_opt, cdw14,
+ "dword 14 value"),
+ OPT("cdw15", '5', arg_uint32, set_opt, cdw15,
+ "dword 15 value"),
+ OPT_END
+};
+
+static const struct args set_args[] = {
+ { arg_string, &set_opt.dev, "controller-id" },
+ { arg_none, NULL, NULL },
+};
+
+static struct cmd set_cmd = {
+ .name = "set",
+ .fn = 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 ((cdw0 & NVME_FEAT_ARBITRATION_AB_MASK) == NVME_FEAT_ARBITRATION_AB_MASK)
+ printf("no limit\n");
+ else
+ printf("%d\n", 1 << (cdw0 & NVME_FEAT_ARBITRATION_AB_MASK));
+ printf(" Low Priority Weight (LPW): %d\n",
+ ONE_BASED((cdw0 >> NVME_FEAT_ARBITRATION_LPW_SHIFT) &
+ NVME_FEAT_ARBITRATION_LPW_MASK));
+ printf(" Medium Priority Weight (MPW): %d\n",
+ ONE_BASED((cdw0 >> NVME_FEAT_ARBITRATION_MPW_SHIFT) &
+ NVME_FEAT_ARBITRATION_MPW_MASK));
+ printf(" High Priority Weight (HPW): %d\n",
+ ONE_BASED((cdw0 >> NVME_FEAT_ARBITRATION_HPW_SHIFT) &
+ NVME_FEAT_ARBITRATION_HPW_MASK));
+}
+
+static void
+print_feature_power_management(uint32_t cdw0)
+{
+
+ printf(" Workload Hint (WH): %#x\n",
+ (cdw0 >> NVME_FEAT_POWER_MANAGEMENT_WH_SHIFT) &
+ NVME_FEAT_POWER_MANAGEMENT_WH_MASK);
+ printf(" Power State (PS): %#x\n",
+ (cdw0 >> NVME_FEAT_POWER_MANAGEMENT_PS_SHIFT) &
+ NVME_FEAT_POWER_MANAGEMENT_PS_MASK);
+}
+
+static void
+print_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((cdw0 >> NVME_FEAT_LBA_RANGE_TYPE_NUM_SHIFT) &
+ NVME_FEAT_LBA_RANGE_TYPE_NUM_MASK);
+
+ if (num > len / sizeof(struct nvme_lba_range_type))
+ num = len / sizeof(struct nvme_lba_range_type);
+
+ printf("IDX\tTYPE\tSLBA\tNLB\tGUID\n");
+ for (i = 0; i < num; i++) {
+ 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((cdw0 >> NVME_FEAT_TEMPERATURE_THRESHOLD_TMPTH_SHIFT) &
+ NVME_FEAT_TEMPERATURE_THRESHOLD_TMPTH_MASK);
+}
+
+static void
+print_feature_error_recovery(uint32_t cdw0)
+{
+
+ printf(" Deallocated or Unwritten Logical Block Error Enable (DULBE): %d\n",
+ (cdw0 >> NVME_FEAT_ERROR_RECOVERY_DULBE_SHIFT) &
+ NVME_FEAT_ERROR_RECOVERY_DULBE_MASK);
+ printf(" Time Limited Error Recovery (TLER): %d of 100ms\n",
+ (cdw0 >> NVME_FEAT_ERROR_RECOVERY_TLER_SHIFT) &
+ NVME_FEAT_ERROR_RECOVERY_TLER_MASK);
+}
+
+static void
+print_feature_volatile_write_cache(uint32_t cdw0)
+{
+
+ printf(" Volatile Write Cache Enable (WCE): %d\n",
+ (cdw0 >> NVME_FEAT_VOLATILE_WRITE_CACHE_WCE_SHIFT) &
+ NVME_FEAT_VOLATILE_WRITE_CACHE_WCE_MASK);
+}
+
+static void
+print_feature_number_of_queues(uint32_t cdw0)
+{
+
+ printf(" Number of I/O Completion Queues Allocated (NCQA): %d\n",
+ ONE_BASED((cdw0 >> NVME_FEAT_NUMBER_OF_QUEUES_NCQA_SHIFT) &
+ NVME_FEAT_NUMBER_OF_QUEUES_NCQA_MASK));
+ printf(" Number of I/O Submission Queues Allocated (NSQA): %d\n",
+ ONE_BASED((cdw0 >> NVME_FEAT_NUMBER_OF_QUEUES_NSQA_SHIFT) &
+ NVME_FEAT_NUMBER_OF_QUEUES_NSQA_MASK));
+}
+
+static void
+print_feature_interrupt_coalescing(uint32_t cdw0)
+{
+
+ printf(" Aggregation Time (TIME): %d\n",
+ (cdw0 >> NVME_FEAT_INTERRUPT_COALESCING_TIME_SHIFT) &
+ NVME_FEAT_INTERRUPT_COALESCING_TIME_MASK);
+ printf(" Aggregation Threshold (THR): %d\n",
+ (cdw0 >> NVME_FEAT_INTERRUPT_COALESCING_THR_SHIFT) &
+ NVME_FEAT_INTERRUPT_COALESCING_THR_MASK);
+}
+
+static void
+print_feature_interrupt_vector_configuration(uint32_t cdw0)
+{
+
+ printf(" Coalescing Disable (CD): %d\n",
+ (cdw0 >> NVME_FEAT_INTERRUPT_VECTOR_CONFIGURATION_CD_SHIFT) &
+ NVME_FEAT_INTERRUPT_VECTOR_CONFIGURATION_CD_MASK);
+ printf(" Interrupt Vector (IV): %d\n",
+ (cdw0 >> NVME_FEAT_INTERRUPT_VECTOR_CONFIGURATION_IV_SHIFT) &
+ NVME_FEAT_INTERRUPT_VECTOR_CONFIGURATION_IV_MASK);
+}
+
+static void
+print_feature_write_atomicity(uint32_t cdw0)
+{
+
+ printf(" Disable Normal (DN): %d\n",
+ (cdw0 >> NVME_FEAT_WRITE_ATOMICITY_DN_SHIFT) &
+ NVME_FEAT_WRITE_ATOMICITY_DN_MASK);
+}
+
+static void
+print_feature_async_event_configuration(uint32_t cdw0)
+{
+
+ printf(" Telemetry Log Notices (TLN): %d\n",
+ (cdw0 >> NVME_FEAT_ASYNC_EVENT_CONFIGURATION_TLN_SHIFT) &
+ NVME_FEAT_ASYNC_EVENT_CONFIGURATION_TLN_MASK);
+ printf(" Firmware Activation Notices (FAN): %d\n",
+ (cdw0 >> NVME_FEAT_ASYNC_EVENT_CONFIGURATION_FAN_SHIFT) &
+ NVME_FEAT_ASYNC_EVENT_CONFIGURATION_FAN_MASK);
+ printf(" Namespace Attribute Notices (NAN): %d\n",
+ (cdw0 >> NVME_FEAT_ASYNC_EVENT_CONFIGURATION_NAN_SHIFT) &
+ NVME_FEAT_ASYNC_EVENT_CONFIGURATION_NAN_MASK);
+ printf(" SMART / Health Critical Warnings (HCW): 0x%x\n",
+ (cdw0 >> NVME_FEAT_ASYNC_EVENT_CONFIGURATION_HCW_SHIFT) &
+ NVME_FEAT_ASYNC_EVENT_CONFIGURATION_HCW_MASK);
+}
+
+static void
+print_feature_autonomous_power_state_transition(uint32_t cdw0)
+{
+ printf(" Autonomous Power State Transition Enable (APSTE): %d\n",
+ (cdw0 >> NVME_FEAT_AUTONOMOUS_POWER_STATE_TRANSITION_APSTE_SHIFT) &
+ NVME_FEAT_AUTONOMOUS_POWER_STATE_TRANSITION_APSTE_MASK);
+}
+
+static void
+print_feature_timestamp(uint32_t cdw0)
+{
+
+ printf(" Timestamp: %d\n",
+ (cdw0 >> NVME_FEAT_TIMESTAMP_TS_SHIFT) &
+ NVME_FEAT_TIMESTAMP_TS_MASK);
+}
+
+static void
+print_feature_keep_alive_timer(uint32_t cdw0)
+{
+
+ printf(" Keep Alive Timeout (KATO): %d\n",
+ (cdw0 >> NVME_FEAT_KEEP_ALIVE_TIMER_KATO_SHIFT) &
+ NVME_FEAT_KEEP_ALIVE_TIMER_KATO_MASK);
+}
+
+static void
+print_feature_host_memory_buffer(uint32_t cdw0)
+{
+
+ printf(" Memory Return (MR): %d\n",
+ (cdw0 >> NVME_FEAT_HOST_MEMORY_BUFFER_MR_SHIFT) &
+ NVME_FEAT_HOST_MEMORY_BUFFER_MR_MASK);
+ printf(" Enable Host Memory (EHM): %d\n",
+ (cdw0 >> NVME_FEAT_HOST_MEMORY_BUFFER_EHM_SHIFT) &
+ NVME_FEAT_HOST_MEMORY_BUFFER_EHM_MASK);
+}
+
+static void
+print_feature_host_controlled_thermal_mgmt(uint32_t cdw0)
+{
+
+ printf(" Thermal Management Temperature 1 (TMT1): %d\n",
+ (cdw0 >> NVME_FEAT_HOST_CONTROLLED_THERMAL_MGMT_TMT1_SHIFT) &
+ NVME_FEAT_HOST_CONTROLLED_THERMAL_MGMT_TMT1_MASK);
+ printf(" Thermal Management Temperature 2 (TMT2): %d\n",
+ (cdw0 >> NVME_FEAT_HOST_CONTROLLED_THERMAL_MGMT_TMT2_SHIFT) &
+ NVME_FEAT_HOST_CONTROLLED_THERMAL_MGMT_TMT2_MASK);
+}
+static void
+print_feature_non_op_power_state_config(uint32_t cdw0)
+{
+
+ printf(" Non-Operational Power State Permissive Mode Enable (NOPPME): %d\n",
+ (cdw0 >> NVME_FEAT_NON_OP_POWER_STATE_CONFIG_NOPPME_SHIFT) &
+ NVME_FEAT_NON_OP_POWER_STATE_CONFIG_NOPPME_MASK);
+}
+
+static void
+output_human(const uint8_t fid, uint32_t cdw0, uint8_t *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
+feature_get(const struct cmd *f, int argc, char *argv[])
+{
+ struct nvme_pt_command pt;
+ uint8_t fid, sel;
+ uint32_t cdw0, cdw11;
+ int fd;
+ uint8_t buf[4096];
+
+ if (arg_parse(argc, argv, f))
+ return;
+
+ if (get_opt.fid == NONE8) {
+ fprintf(stderr,
+ "feature id not specified\n");
+ arg_help(argc, argv, f);
+ }
+ if (get_opt.sel > 0x3) {
+ fprintf(stderr,
+ "select value over range\n");
+ arg_help(argc, argv, f);
+ }
+
+ open_dev(get_opt.dev, &fd, 1, 1);
+
+ fid = get_opt.fid;
+ sel = get_opt.sel;
+ cdw11 = get_opt.cdw11;
+
+ if (sel >= sel_name_res_max)
+ errx(EX_IOERR, "invalid select value");
+
+ memset(&pt, 0, sizeof(pt));
+ pt.cmd.opc = NVME_OPC_GET_FEATURES;
+ pt.cmd.cdw10 = htole32((sel << NVME_FEAT_GET_SEL_SHIFT) |
+ (fid << NVME_FEAT_GET_FID_SHIFT));
+ pt.cmd.cdw11 = htole32(cdw11);
+ if (fid == NVME_FEAT_LBA_RANGE_TYPE){
+ memset(buf, 0, sizeof(buf));
+ pt.buf = buf;
+ pt.len = sizeof(buf);
+ } else {
+ pt.buf = NULL;
+ pt.len = 0;
+ }
+ pt.is_read = 1;
+
+ if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
+ err(EX_IOERR, "passthrough request failed");
+
+ printf("%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)) {
+ if (NVME_STATUS_GET_SCT((&pt.cpl)->status) == 0)
+ errx(EX_IOERR, "%s", nvme_gcs_to_str(NVME_STATUS_GET_SC((&pt.cpl)->status)));
+ else if (NVME_STATUS_GET_SCT((&pt.cpl)->status) == 1)
+ errx(EX_IOERR, "%s", nvme_cse_to_str(NVME_STATUS_GET_SC((&pt.cpl)->status)));
+ else
+ errx(EX_IOERR, "get feature returned error");
+ }
+
+ cdw0 = pt.cpl.cdw0;
+
+ if ( get_opt.binary )
+ output_binary(fid, cdw0, buf, sizeof(buf));
+ else
+ output_human(fid, 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;
+ uint8_t fid;
+ bool save;
+ uint32_t cdw11, cdw12, cdw13, cdw14, cdw15;
+ int fd;
+
+ if (arg_parse(argc, argv, f))
+ return;
+
+ if (set_opt.fid == NONE8) {
+ fprintf(stderr,
+ "feature id not specified\n");
+ arg_help(argc, argv, f);
+ }
+
+ fid = set_opt.fid;
+ save = set_opt.save;
+ cdw11 = set_opt.cdw11;
+ cdw12 = set_opt.cdw12;
+ cdw13 = set_opt.cdw13;
+ cdw14 = set_opt.cdw14;
+ cdw15 = set_opt.cdw15;
+
+ open_dev(set_opt.dev, &fd, 1, 1);
+
+ memset(&pt, 0, sizeof(pt));
+ pt.cmd.opc = NVME_OPC_SET_FEATURES;
+ pt.cmd.cdw10 = htole32((save << NVME_FEAT_SET_SV_SHIFT) |
+ (fid << NVME_FEAT_SET_FID_SHIFT));
+ pt.cmd.cdw11 = htole32(cdw11);
+ pt.cmd.cdw12 = htole32(cdw12);
+ pt.cmd.cdw13 = htole32(cdw13);
+ pt.cmd.cdw14 = htole32(cdw14);
+ pt.cmd.cdw15 = htole32(cdw15);
+ pt.buf = NULL;
+ pt.len = 0;
+ pt.is_read = 0;
+
+ if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
+ err(EX_IOERR, "passthrough request failed");
+
+ if (nvme_completion_is_error(&pt.cpl)) {
+ if (NVME_STATUS_GET_SCT((&pt.cpl)->status) == 0)
+ errx(EX_IOERR, "%s", nvme_gcs_to_str(NVME_STATUS_GET_SC((&pt.cpl)->status)));
+ else if (NVME_STATUS_GET_SCT((&pt.cpl)->status) == 1)
+ errx(EX_IOERR, "%s", nvme_cse_to_str(NVME_STATUS_GET_SC((&pt.cpl)->status)));
+ else
+ errx(EX_IOERR, "set feature returned error");
+ }
+
+ 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((sel << NVME_FEAT_GET_SEL_SHIFT) |
+ (fid << NVME_FEAT_GET_FID_SHIFT));
+ pt.cmd.cdw11 = htole32(cdw11);
+ pt.buf = NULL;
+ pt.len = 0;
+ pt.is_read = 1;
+
+ if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
+ continue;
+
+ printf("%s(0x%x), %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,9 @@
const char *kv_lookup(const struct kv_name *kv, size_t kv_count, uint32_t key);
+const char *nvme_gcs_to_str(uint8_t sc);
+const char *nvme_cse_to_str(uint8_t sc);
+
void logpage_register(struct logpage_function *p);
#define NVME_CTRLR_PREFIX "nvme"
#define NVME_NS_PREFIX "ns"
Index: sbin/nvmecontrol/nvmecontrol.c
===================================================================
--- sbin/nvmecontrol/nvmecontrol.c
+++ sbin/nvmecontrol/nvmecontrol.c
@@ -176,6 +176,224 @@
*nsid = gnsid.nsid;
}
+const char *
+nvme_gcs_to_str(uint8_t sc)
+{
+ const char *str;
+
+ switch (sc) {
+ case NVME_SC_SUCCESS:
+ str = "Successful Completion";
+ break;
+ case NVME_SC_INVALID_OPCODE:
+ str = "Invalid Command Opcode";
+ break;
+ case NVME_SC_INVALID_FIELD:
+ str = "Invalid Field in Command";
+ break;
+ case NVME_SC_COMMAND_ID_CONFLICT:
+ str = "Command ID Conflict";
+ break;
+ case NVME_SC_DATA_TRANSFER_ERROR:
+ str = "Data Transfer Error";
+ break;
+ case NVME_SC_ABORTED_POWER_LOSS:
+ str = "Commands Aborted due to Power Loss Notification";
+ break;
+ case NVME_SC_INTERNAL_DEVICE_ERROR:
+ str = "Internal Error";
+ break;
+ case NVME_SC_ABORTED_BY_REQUEST:
+ str = "Command Abort Requested";
+ break;
+ case NVME_SC_ABORTED_SQ_DELETION:
+ str = "Command Aborted due to SQ Deletion";
+ break;
+ case NVME_SC_ABORTED_FAILED_FUSED:
+ str = "Command Aborted due to Failed Fused Command";
+ break;
+ case NVME_SC_ABORTED_MISSING_FUSED:
+ str = "Command Aborted due to Missing Fused Command";
+ break;
+ case NVME_SC_INVALID_NAMESPACE_OR_FORMAT:
+ str = "Invalid Namespace or Format";
+ break;
+ case NVME_SC_COMMAND_SEQUENCE_ERROR:
+ str = "Command Sequence Error";
+ break;
+ case NVME_SC_INVALID_SGL_SEGMENT_DESCR:
+ str = "Invalid SGL Segment Descriptor";
+ break;
+ case NVME_SC_INVALID_NUMBER_OF_SGL_DESCR:
+ str = "Invalid Number of SGL Descriptors";
+ break;
+ case NVME_SC_DATA_SGL_LENGTH_INVALID:
+ str = "Data SGL Length Invalid";
+ break;
+ case NVME_SC_METADATA_SGL_LENGTH_INVALID:
+ str = "Metadata SGL Length Invalid";
+ break;
+ case NVME_SC_SGL_DESCRIPTOR_TYPE_INVALID:
+ str = "SGL Descriptor Type Invalid";
+ break;
+ case NVME_SC_INVALID_USE_OF_CMB:
+ str = "Invalid Use of Controller Memory Buffer";
+ break;
+ case NVME_SC_PRP_OFFET_INVALID:
+ str = "PRP Offset Invalid";
+ break;
+ case NVME_SC_ATOMIC_WRITE_UNIT_EXCEEDED:
+ str = "Atomic Write Unit Exceeded";
+ break;
+ case NVME_SC_OPERATION_DENIED:
+ str = "Operation Denied";
+ break;
+ case NVME_SC_SGL_OFFSET_INVALID:
+ str = "SGL Offset Invalid";
+ break;
+ case NVME_SC_HOST_ID_INCONSISTENT_FORMAT:
+ str = "Host Identifier Inconsistent Format";
+ break;
+ case NVME_SC_KEEP_ALIVE_TIMEOUT_EXPIRED:
+ str = "Keep Alive Timeout Expired";
+ break;
+ case NVME_SC_KEEP_ALIVE_TIMEOUT_INVALID:
+ str = "Keep Alive Timeout Invalid";
+ break;
+ case NVME_SC_ABORTED_DUE_TO_PREEMPT:
+ str = "Command Aborted due to Preempt and Abort";
+ break;
+ case NVME_SC_SANITIZE_FAILED:
+ str = "Sanitize Failed";
+ break;
+ case NVME_SC_SANITIZE_IN_PROGRESS:
+ str = "Sanitize In Progress";
+ break;
+ case NVME_SC_SGL_DATA_BLOCK_GRAN_INVALID:
+ str = "SGL Data Block Granularity Invalid";
+ break;
+ case NVME_SC_NOT_SUPPORTED_IN_CMB:
+ str = "Command Not Supported for Queue in CMB";
+ break;
+ default:
+ str = "Unknown Error";
+ }
+
+ return str;
+}
+
+const char *
+nvme_cse_to_str(uint8_t sct)
+{
+ const char *str;
+
+ switch (sct) {
+ case NVME_SC_COMPLETION_QUEUE_INVALID:
+ str = "Completion Queue Invalid";
+ break;
+ case NVME_SC_INVALID_QUEUE_IDENTIFIER:
+ str = "Invalid Queue Identifier";
+ break;
+ case NVME_SC_MAXIMUM_QUEUE_SIZE_EXCEEDED:
+ str = "Invalid Queue Size";
+ break;
+ case NVME_SC_ABORT_COMMAND_LIMIT_EXCEEDED:
+ str = "Abort Command Limit Exceeded";
+ break;
+ case NVME_SC_ASYNC_EVENT_REQUEST_LIMIT_EXCEEDED:
+ str = "Asynchronous Event Request Limit Exceeded";
+ break;
+ case NVME_SC_INVALID_FIRMWARE_SLOT:
+ str = "Invalid Firmware Slot";
+ break;
+ case NVME_SC_INVALID_FIRMWARE_IMAGE:
+ str = "Invalid Firmware Image";
+ break;
+ case NVME_SC_INVALID_INTERRUPT_VECTOR:
+ str = "Invalid Interrupt Vector";
+ break;
+ case NVME_SC_INVALID_LOG_PAGE:
+ str = "Invalid Log Page";
+ break;
+ case NVME_SC_INVALID_FORMAT:
+ str = "Invalid Format";
+ break;
+ case NVME_SC_FIRMWARE_REQUIRES_RESET:
+ str = "Firmware Activation Requires Conventional Reset";
+ break;
+ case NVME_SC_INVALID_QUEUE_DELETION:
+ str = "Invalid Queue Deletion";
+ break;
+ case NVME_SC_FEATURE_NOT_SAVEABLE:
+ str = "Feature Identifier Not Saveable";
+ break;
+ case NVME_SC_FEATURE_NOT_CHANGEABLE:
+ str = "Feature Not Changeable";
+ break;
+ case NVME_SC_FEATURE_NOT_NS_SPECIFIC:
+ str = "Feature Not Namespace Specific";
+ break;
+ case NVME_SC_FW_ACT_REQUIRES_NVMS_RESET:
+ str = "Firmware Activation Requires NVM Subsystem Reset";
+ break;
+ case NVME_SC_FW_ACT_REQUIRES_RESET:
+ str = "Firmware Activation Requires Reset";
+ break;
+ case NVME_SC_FW_ACT_REQUIRES_TIME:
+ str = "Firmware Activation Requires Maximum Time Violation";
+ break;
+ case NVME_SC_FW_ACT_PROHIBITED:
+ str = "Firmware Activation Prohibited";
+ break;
+ case NVME_SC_OVERLAPPING_RANGE:
+ str = "Overlapping Range";
+ break;
+ case NVME_SC_NS_INSUFFICIENT_CAPACITY:
+ str = "Namespace Insufficient Capacity";
+ break;
+ case NVME_SC_NS_ID_UNAVAILABLE:
+ str = "Namespace Identifier Unavailable";
+ break;
+ case NVME_SC_NS_ALREADY_ATTACHED:
+ str = "Namespace Already Attached";
+ break;
+ case NVME_SC_NS_IS_PRIVATE:
+ str = "Namespace Is Private";
+ break;
+ case NVME_SC_NS_NOT_ATTACHED:
+ str = "Namespace Not Attached";
+ break;
+ case NVME_SC_THIN_PROV_NOT_SUPPORTED:
+ str = "Thin Provisioning Not Supported";
+ break;
+ case NVME_SC_CTRLR_LIST_INVALID:
+ str = "Controller List Invalid";
+ break;
+ case NVME_SC_SELF_TEST_IN_PROGRESS:
+ str = "Device Self-test In Progress";
+ break;
+ case NVME_SC_BOOT_PART_WRITE_PROHIB:
+ str = "Boot Partition Write Prohibited";
+ break;
+ case NVME_SC_INVALID_CTRLR_ID:
+ str = "Invalid Controller Identifier";
+ break;
+ case NVME_SC_INVALID_SEC_CTRLR_STATE:
+ str = "Invalid Secondary Controller State";
+ break;
+ case NVME_SC_INVALID_NUM_OF_CTRLR_RESRC:
+ str = "Invalid Number of Controller Resources";
+ break;
+ case NVME_SC_INVALID_RESOURCE_ID:
+ str = "Invalid Resource Identifier";
+ break;
+ default:
+ str = "Unknown Error";
+ }
+
+ return str;
+}
+
int
main(int argc, char *argv[])
{

File Metadata

Mime Type
text/plain
Expires
Wed, Oct 22, 10:00 PM (8 h, 25 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
24069709
Default Alt Text
D32700.id97992.diff (31 KB)

Event Timeline