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,1032 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (C) 2021 Wanpeng Qian + * + * 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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_GET_SEL(x) \ + (((x) >> NVME_FEAT_GET_SEL_SHIFT) & \ + NVME_FEAT_GET_SEL_MASK) +#define NVME_FEAT_GET_FID(x) \ + (((x) >> NVME_FEAT_GET_FID_SHIFT) & \ + NVME_FEAT_GET_FID_MASK) + +#define NVME_FEAT_SET_SV_SHIFT (31) +#define NVME_FEAT_SET_SV_MASK (0x1) +#define NVME_FEAT_SET_FID_SHIFT (0) +#define NVME_FEAT_SET_FID_MASK (0xFF) + +#define NVME_FEAT_SET_SV(x) \ + (((x) >> NVME_FEAT_SET_SV_SHIFT) & \ + NVME_FEAT_SET_SV_MASK) +#define NVME_FEAT_SET_FID(x) \ + (((x) >> NVME_FEAT_SET_FID_SHIFT) & \ + NVME_FEAT_SET_FID_MASK) + +#define NVME_FEAT_ARBITRATION_HPW_SHIFT (24) +#define NVME_FEAT_ARBITRATION_HPW_MASK (0xFF) +#define NVME_FEAT_ARBITRATION_MPW_SHIFT (16) +#define NVME_FEAT_ARBITRATION_MPW_MASK (0xFF) +#define NVME_FEAT_ARBITRATION_LPW_SHIFT (8) +#define NVME_FEAT_ARBITRATION_LPW_MASK (0xFF) +#define NVME_FEAT_ARBITRATION_AB_SHIFT (0) +#define NVME_FEAT_ARBITRATION_AB_MASK (0x7) + +#define NVME_FEAT_ARBITRATION_HPW(x) \ + (((x) >> NVME_FEAT_ARBITRATION_HPW_SHIFT) & \ + NVME_FEAT_ARBITRATION_HPW_MASK) +#define NVME_FEAT_ARBITRATION_MPW(x) \ + (((x) >> NVME_FEAT_ARBITRATION_MPW_SHIFT) & \ + NVME_FEAT_ARBITRATION_MPW_MASK) +#define NVME_FEAT_ARBITRATION_LPW(x) \ + (((x) >> NVME_FEAT_ARBITRATION_LPW_SHIFT) & \ + NVME_FEAT_ARBITRATION_LPW_MASK) +#define NVME_FEAT_ARBITRATION_AB(x) \ + (((x) >> NVME_FEAT_ARBITRATION_AB_SHIFT) & \ + NVME_FEAT_ARBITRATION_AB_MASK) + +#define NVME_FEAT_POWER_MANAGEMENT_WH_SHIFT (5) +#define NVME_FEAT_POWER_MANAGEMENT_WH_MASK (0x7) +#define NVME_FEAT_POWER_MANAGEMENT_PS_SHIFT (0) +#define NVME_FEAT_POWER_MANAGEMENT_PS_MASK (0x1F) + +#define NVME_FEAT_POWER_MANAGEMENT_WH(x) \ + (((x) >> NVME_FEAT_POWER_MANAGEMENT_WH_SHIFT) & \ + NVME_FEAT_POWER_MANAGEMENT_WH_MASK) +#define NVME_FEAT_POWER_MANAGEMENT_PS(x) \ + (((x) >> NVME_FEAT_POWER_MANAGEMENT_PS_SHIFT) & \ + NVME_FEAT_POWER_MANAGEMENT_PS_MASK) + +#define NVME_FEAT_LBA_RANGE_TYPE_NUM_SHIFT (0) +#define NVME_FEAT_LBA_RANGE_TYPE_NUM_MASK (0x3F) + +#define NVME_FEAT_LBA_RANGE_TYPE_NUM(x) \ + (((x) >> NVME_FEAT_LBA_RANGE_TYPE_NUM_SHIFT) & \ + NVME_FEAT_LBA_RANGE_TYPE_NUM_MASK) + +#define NVME_FEAT_TEMPERATURE_THRESHOLD_THSEL_SHIFT (20) +#define NVME_FEAT_TEMPERATURE_THRESHOLD_THSEL_MASK (0x3) +#define NVME_FEAT_TEMPERATURE_THRESHOLD_TMPSEL_SHIFT (16) +#define NVME_FEAT_TEMPERATURE_THRESHOLD_TMPSEL_MASK (0xF) +#define NVME_FEAT_TEMPERATURE_THRESHOLD_TMPTH_SHIFT (0) +#define NVME_FEAT_TEMPERATURE_THRESHOLD_TMPTH_MASK (0xFFFF) + +#define NVME_FEAT_TEMPERATURE_THRESHOLD_THSEL(x) \ + (((x) >> NVME_FEAT_TEMPERATURE_THRESHOLD_THSEL_SHIFT) & \ + NVME_FEAT_TEMPERATURE_THRESHOLD_THSEL_MASK) +#define NVME_FEAT_TEMPERATURE_THRESHOLD_TMPSEL(x) \ + (((x) >> NVME_FEAT_TEMPERATURE_THRESHOLD_TMPSEL_SHIFT) & \ + NVME_FEAT_TEMPERATURE_THRESHOLD_TMPSEL_MASK) +#define NVME_FEAT_TEMPERATURE_THRESHOLD_TMPTH(x) \ + (((x) >> NVME_FEAT_TEMPERATURE_THRESHOLD_TMPTH_SHIFT) & \ + NVME_FEAT_TEMPERATURE_THRESHOLD_TMPTH_MASK) + +#define NVME_FEAT_ERROR_RECOVERY_DULBE_SHIFT (16) +#define NVME_FEAT_ERROR_RECOVERY_DULBE_MASK (0x1) +#define NVME_FEAT_ERROR_RECOVERY_TLER_SHIFT (0) +#define NVME_FEAT_ERROR_RECOVERY_TLER_MASK (0xFF) + +#define NVME_FEAT_ERROR_RECOVERY_DULBE(x) \ + (((x) >> NVME_FEAT_ERROR_RECOVERY_DULBE_SHIFT) & \ + NVME_FEAT_ERROR_RECOVERY_DULBE_MASK) +#define NVME_FEAT_ERROR_RECOVERY_TLER(x) \ + (((x) >> NVME_FEAT_ERROR_RECOVERY_TLER_SHIFT) & \ + NVME_FEAT_ERROR_RECOVERY_TLER_MASK) + +#define NVME_FEAT_VOLATILE_WRITE_CACHE_WCE_SHIFT (0) +#define NVME_FEAT_VOLATILE_WRITE_CACHE_WCE_MASK (0x1) + +#define NVME_FEAT_VOLATILE_WRITE_CACHE_WCE(x) \ + (((x) >> NVME_FEAT_VOLATILE_WRITE_CACHE_WCE_SHIFT) & \ + NVME_FEAT_VOLATILE_WRITE_CACHE_WCE_MASK) + +#define NVME_FEAT_NUMBER_OF_QUEUES_NCQR_SHIFT (16) +#define NVME_FEAT_NUMBER_OF_QUEUES_NCQR_MASK (0xFFFF) +#define NVME_FEAT_NUMBER_OF_QUEUES_NSQR_SHIFT (0) +#define NVME_FEAT_NUMBER_OF_QUEUES_NSQR_MASK (0xFFFF) +#define NVME_FEAT_NUMBER_OF_QUEUES_NCQA_SHIFT (16) +#define NVME_FEAT_NUMBER_OF_QUEUES_NCQA_MASK (0xFFFF) +#define NVME_FEAT_NUMBER_OF_QUEUES_NSQA_SHIFT (0) +#define NVME_FEAT_NUMBER_OF_QUEUES_NSQA_MASK (0xFFFF) + +#define NVME_FEAT_NUMBER_OF_QUEUES_NCQR(x) \ + (((x) >> NVME_FEAT_NUMBER_OF_QUEUES_NCQR_SHIFT) & \ + NVME_FEAT_NUMBER_OF_QUEUES_NCQR_MASK) +#define NVME_FEAT_NUMBER_OF_QUEUES_NSQR(x) \ + (((x) >> NVME_FEAT_NUMBER_OF_QUEUES_NSQR_SHIFT) & \ + NVME_FEAT_NUMBER_OF_QUEUES_NSQR_MASK) +#define NVME_FEAT_NUMBER_OF_QUEUES_NCQA(x) \ + (((x) >> NVME_FEAT_NUMBER_OF_QUEUES_NCQA_SHIFT) & \ + NVME_FEAT_NUMBER_OF_QUEUES_NCQA_MASK) +#define NVME_FEAT_NUMBER_OF_QUEUES_NSQA(x) \ + (((x) >> NVME_FEAT_NUMBER_OF_QUEUES_NSQA_SHIFT) & \ + NVME_FEAT_NUMBER_OF_QUEUES_NSQA_MASK) + +#define NVME_FEAT_INTERRUPT_COALESCING_TIME_SHIFT (8) +#define NVME_FEAT_INTERRUPT_COALESCING_TIME_MASK (0xFF) +#define NVME_FEAT_INTERRUPT_COALESCING_THR_SHIFT (0) +#define NVME_FEAT_INTERRUPT_COALESCING_THR_MASK (0xFF) + +#define NVME_FEAT_INTERRUPT_COALESCING_TIME(x) \ + (((x) >> NVME_FEAT_INTERRUPT_COALESCING_TIME_SHIFT) & \ + NVME_FEAT_INTERRUPT_COALESCING_TIME_MASK) +#define NVME_FEAT_INTERRUPT_COALESCING_THR(x) \ + (((x) >> NVME_FEAT_INTERRUPT_COALESCING_THR_SHIFT) & \ + NVME_FEAT_INTERRUPT_COALESCING_THR_MASK) + +#define NVME_FEAT_INTERRUPT_VECTOR_CONFIGURATION_CD_SHIFT (16) +#define NVME_FEAT_INTERRUPT_VECTOR_CONFIGURATION_CD_MASK (0x1) +#define NVME_FEAT_INTERRUPT_VECTOR_CONFIGURATION_IV_SHIFT (0) +#define NVME_FEAT_INTERRUPT_VECTOR_CONFIGURATION_IV_MASK (0xFF) + +#define NVME_FEAT_INTERRUPT_VECTOR_CONFIGURATION_CD(x) \ + (((x) >> NVME_FEAT_INTERRUPT_VECTOR_CONFIGURATION_CD_SHIFT) & \ + NVME_FEAT_INTERRUPT_VECTOR_CONFIGURATION_CD_MASK) +#define NVME_FEAT_INTERRUPT_VECTOR_CONFIGURATION_IV(x) \ + (((x) >> NVME_FEAT_INTERRUPT_VECTOR_CONFIGURATION_IV_SHIFT) & \ + NVME_FEAT_INTERRUPT_VECTOR_CONFIGURATION_IV_MASK) + +#define NVME_FEAT_WRITE_ATOMICITY_DN_SHIFT (0) +#define NVME_FEAT_WRITE_ATOMICITY_DN_MASK (0x1) + +#define NVME_FEAT_WRITE_ATOMICITY_DN(x) \ + (((x) >> NVME_FEAT_WRITE_ATOMICITY_DN_SHIFT) & \ + NVME_FEAT_WRITE_ATOMICITY_DN_MASK) + +#define NVME_FEAT_ASYNC_EVENT_CONFIGURATION_TLN_SHIFT (10) +#define NVME_FEAT_ASYNC_EVENT_CONFIGURATION_TLN_MASK (0x1) +#define NVME_FEAT_ASYNC_EVENT_CONFIGURATION_FAN_SHIFT (9) +#define NVME_FEAT_ASYNC_EVENT_CONFIGURATION_FAN_MASK (0x1) +#define NVME_FEAT_ASYNC_EVENT_CONFIGURATION_NAN_SHIFT (8) +#define NVME_FEAT_ASYNC_EVENT_CONFIGURATION_NAN_MASK (0x1) +#define NVME_FEAT_ASYNC_EVENT_CONFIGURATION_HCW_SHIFT (0) +#define NVME_FEAT_ASYNC_EVENT_CONFIGURATION_HCW_MASK (0xFF) + +#define NVME_FEAT_ASYNC_EVENT_CONFIGURATION_TLN(x) \ + (((x) >> NVME_FEAT_ASYNC_EVENT_CONFIGURATION_TLN_SHIFT) & \ + NVME_FEAT_ASYNC_EVENT_CONFIGURATION_TLN_MASK) +#define NVME_FEAT_ASYNC_EVENT_CONFIGURATION_FAN(x) \ + (((x) >> NVME_FEAT_ASYNC_EVENT_CONFIGURATION_FAN_SHIFT) & \ + NVME_FEAT_ASYNC_EVENT_CONFIGURATION_FAN_MASK) +#define NVME_FEAT_ASYNC_EVENT_CONFIGURATION_NAN(x) \ + (((x) >> NVME_FEAT_ASYNC_EVENT_CONFIGURATION_NAN_SHIFT) & \ + NVME_FEAT_ASYNC_EVENT_CONFIGURATION_NAN_MASK) +#define NVME_FEAT_ASYNC_EVENT_CONFIGURATION_HCW(x) \ + (((x) >> NVME_FEAT_ASYNC_EVENT_CONFIGURATION_HCW_SHIFT) & \ + NVME_FEAT_ASYNC_EVENT_CONFIGURATION_HCW_MASK) + +#define NVME_FEAT_AUTONOMOUS_POWER_STATE_TRANSITION_APSTE_SHIFT (0) +#define NVME_FEAT_AUTONOMOUS_POWER_STATE_TRANSITION_APSTE_MASK (0x1) + +#define NVME_FEAT_AUTONOMOUS_POWER_STATE_TRANSITION_APSTE(x) \ + (((x) >> NVME_FEAT_AUTONOMOUS_POWER_STATE_TRANSITION_APSTE_SHIFT) & \ + NVME_FEAT_AUTONOMOUS_POWER_STATE_TRANSITION_APSTE_MASK) + +#define NVME_FEAT_HOST_MEMORY_BUFFER_MR_SHIFT (1) +#define NVME_FEAT_HOST_MEMORY_BUFFER_MR_MASK (0x1) +#define NVME_FEAT_HOST_MEMORY_BUFFER_EHM_SHIFT (0) +#define NVME_FEAT_HOST_MEMORY_BUFFER_EHM_MASK (0x1) +#define NVME_FEAT_HOST_MEMORY_BUFFER_HSIZE_SHIFT (0) +#define NVME_FEAT_HOST_MEMORY_BUFFER_HSIZE_MASK (0xFFFF) +#define NVME_FEAT_HOST_MEMORY_BUFFER_HMDLLA_SHIFT (4) +#define NVME_FEAT_HOST_MEMORY_BUFFER_HMDLLA_MASK (0xFFF) +#define NVME_FEAT_HOST_MEMORY_BUFFER_HMDLUA_SHIFT (0) +#define NVME_FEAT_HOST_MEMORY_BUFFER_HMDLUA_MASK (0xFFFF) +#define NVME_FEAT_HOST_MEMORY_BUFFER_HMDLEC_SHIFT (0) +#define NVME_FEAT_HOST_MEMORY_BUFFER_HMDLEC_MASK (0xFFFF) + +#define NVME_FEAT_HOST_MEMORY_BUFFER_MR(x) \ + (((x) >> NVME_FEAT_HOST_MEMORY_BUFFER_MR_SHIFT) & \ + NVME_FEAT_HOST_MEMORY_BUFFER_MR_MASK) +#define NVME_FEAT_HOST_MEMORY_BUFFER_EHM(x) \ + (((x) >> NVME_FEAT_HOST_MEMORY_BUFFER_EHM_SHIFT) & \ + NVME_FEAT_HOST_MEMORY_BUFFER_EHM_MASK) +#define NVME_FEAT_HOST_MEMORY_BUFFER_HSIZE(x) \ + (((x) >> NVME_FEAT_HOST_MEMORY_BUFFER_HSIZE_SHIFT) & \ + NVME_FEAT_HOST_MEMORY_BUFFER_HSIZE_MASK) +#define NVME_FEAT_HOST_MEMORY_BUFFER_HMDLLA(x) \ + (((x) >> NVME_FEAT_HOST_MEMORY_BUFFER_HMDLLA_SHIFT) & \ + NVME_FEAT_HOST_MEMORY_BUFFER_HMDLLA_MASK) +#define NVME_FEAT_HOST_MEMORY_BUFFER_HMDLUA(x) \ + (((x) >> NVME_FEAT_HOST_MEMORY_BUFFER_HMDLUA_SHIFT) & \ + NVME_FEAT_HOST_MEMORY_BUFFER_HMDLUA_MASK) +#define NVME_FEAT_HOST_MEMORY_BUFFER_HMDLEC(x) \ + (((x) >> NVME_FEAT_HOST_MEMORY_BUFFER_HMDLEC_SHIFT) & \ + NVME_FEAT_HOST_MEMORY_BUFFER_HMDLEC_MASK) + +#define NVME_FEAT_TIMESTAMP_TS_SHIFT (0x0) +#define NVME_FEAT_TIMESTAMP_TS_MASK (0x3F) + +#define NVME_FEAT_TIMESTAMP_TS(x) \ + (((x) >> NVME_FEAT_TIMESTAMP_TS_SHIFT) & \ + NVME_FEAT_TIMESTAMP_TS_MASK) + +#define NVME_FEAT_KEEP_ALIVE_TIMER_KATO_SHIFT (0x0) +#define NVME_FEAT_KEEP_ALIVE_TIMER_KATO_MASK (0xFFFF) + +#define NVME_FEAT_KEEP_ALIVE_TIMER_KATO(x) \ + (((x) >> NVME_FEAT_KEEP_ALIVE_TIMER_KATO_SHIFT) & \ + NVME_FEAT_KEEP_ALIVE_TIMER_KATO_MASK) + +#define NVME_FEAT_HOST_CONTROLLED_THERMAL_MGMT_TMT1_SHIFT (16) +#define NVME_FEAT_HOST_CONTROLLED_THERMAL_MGMT_TMT1_MASK (0xFF) +#define NVME_FEAT_HOST_CONTROLLED_THERMAL_MGMT_TMT2_SHIFT (0) +#define NVME_FEAT_HOST_CONTROLLED_THERMAL_MGMT_TMT2_MASK (0xFF) + +#define NVME_FEAT_HOST_CONTROLLED_THERMAL_MGMT_TMT1(x) \ + (((x) >> NVME_FEAT_HOST_CONTROLLED_THERMAL_MGMT_TMT1_SHIFT) & \ + NVME_FEAT_HOST_CONTROLLED_THERMAL_MGMT_TMT1_MASK) +#define NVME_FEAT_HOST_CONTROLLED_THERMAL_MGMT_TMT2(x) \ + (((x) >> NVME_FEAT_HOST_CONTROLLED_THERMAL_MGMT_TMT2_SHIFT) & \ + NVME_FEAT_HOST_CONTROLLED_THERMAL_MGMT_TMT2_MASK) + +#define NVME_FEAT_NON_OP_POWER_STATE_CONFIG_NOPPME_SHIFT (0) +#define NVME_FEAT_NON_OP_POWER_STATE_CONFIG_NOPPME_MASK (0x1) + +#define NVME_FEAT_NON_OP_POWER_STATE_CONFIG_NOPPME(x) \ + (((x) >> NVME_FEAT_NON_OP_POWER_STATE_CONFIG_NOPPME_SHIFT) & \ + NVME_FEAT_NON_OP_POWER_STATE_CONFIG_NOPPME_MASK) + +#define NVME_FEAT_SOFTWARE_PROGRESS_MARKER_PBSLC_SHIFT (0) +#define NVME_FEAT_SOFTWARE_PROGRESS_MARKER_PBSLC_MASK (0xFF) + +#define NVME_FEAT_SOFTWARE_PROGRESS_MARKER_PBSLC(x) \ + (((x) >> NVME_FEAT_SOFTWARE_PROGRESS_MARKER_PBSLC_SHIFT) & \ + NVME_FEAT_SOFTWARE_PROGRESS_MARKER_PBSLC_MASK) + +#define NVME_FEAT_HOST_IDENTIFIER_EXHID_SHIFT (0) +#define NVME_FEAT_HOST_IDENTIFIER_EXHID_MASK (0x1) + +#define NVME_FEAT_HOST_IDENTIFIER_EXHID(x) \ + (((x) >> NVME_FEAT_HOST_IDENTIFIER_EXHID_SHIFT) & \ + NVME_FEAT_HOST_IDENTIFIER_EXHID_MASK) + +#define NVME_FEAT_RESERVATION_NOTIFICATION_MASK_RESPRE_SHIFT (3) +#define NVME_FEAT_RESERVATION_NOTIFICATION_MASK_RESPRE_MASK (0x1) +#define NVME_FEAT_RESERVATION_NOTIFICATION_MASK_RESREL_SHIFT (2) +#define NVME_FEAT_RESERVATION_NOTIFICATION_MASK_RESREL_MASK (0x1) +#define NVME_FEAT_RESERVATION_NOTIFICATION_MASK_REGPRE_SHIFT (1) +#define NVME_FEAT_RESERVATION_NOTIFICATION_MASK_REGPRE_MASK (0x1) + +#define NVME_FEAT_RESERVATION_NOTIFICATION_MASK_RESPRE(x) \ + (((x) >> NVME_FEAT_RESERVATION_NOTIFICATION_MASK_RESPRE_SHIFT) & \ + NVME_FEAT_RESERVATION_NOTIFICATION_MASK_RESPRE_MASK) +#define NVME_FEAT_RESERVATION_NOTIFICATION_MASK_RESREL(x) \ + (((x) >> NVME_FEAT_RESERVATION_NOTIFICATION_MASK_RESREL_SHIFT) & \ + NVME_FEAT_RESERVATION_NOTIFICATION_MASK_RESREL_MASK) +#define NVME_FEAT_RESERVATION_NOTIFICATION_MASK_REGPRE(x) \ + (((x) >> NVME_FEAT_RESERVATION_NOTIFICATION_MASK_REGPRE_SHIFT) & \ + NVME_FEAT_RESERVATION_NOTIFICATION_MASK_REGPRE_MASK) + +#define NVME_FEAT_RESERVATION_PERSISTENCE_PTPL_SHIFT (0) +#define NVME_FEAT_RESERVATION_PERSISTENCE_PTPL_MASK (0x1) + +#define NVME_FEAT_RESERVATION_PERSISTENCE_PTPL(x) \ + (((x) >> NVME_FEAT_RESERVATION_PERSISTENCE_PTPL_SHIFT) & \ + NVME_FEAT_RESERVATION_PERSISTENCE_PTPL_MASK) + +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] = "General Purpose", + [1] = "Filesystem", + [2] = "RAID", + [3] = "Cache", + [4] = "Page / swap file", +}; +static uint32_t lba_range_type_name_res_max = + nitems(lba_range_type_name_res); + +struct summary_data { + uint8_t fid; + uint8_t sel; + uint32_t cdw11; +}; + +struct nvme_lba_range_type { + uint8_t type; + uint8_t attribute; + uint8_t reserved1[14]; + uint64_t slba; + uint64_t nlb; + uint8_t guid[16]; + uint8_t reserved2[16]; +} __packed __aligned(4); + +static const struct summary_data feature_summary_list[] = { + { NVME_FEAT_ARBITRATION, 0x0, 0x0 }, + { NVME_FEAT_POWER_MANAGEMENT, 0x0, 0x0 }, + { NVME_FEAT_TEMPERATURE_THRESHOLD, 0x0, 0x0 }, + { NVME_FEAT_ERROR_RECOVERY, 0x0, 0x0 }, + { NVME_FEAT_NUMBER_OF_QUEUES, 0x0, 0x0 }, + { NVME_FEAT_INTERRUPT_COALESCING, 0x0, 0x0 }, + { NVME_FEAT_INTERRUPT_VECTOR_CONFIGURATION, 0x0, 0x0 }, + { NVME_FEAT_WRITE_ATOMICITY, 0x0, 0x0 }, + { NVME_FEAT_ASYNC_EVENT_CONFIGURATION, 0x0, 0x0 }, +}; +static uint32_t feature_summary_list_max = nitems(feature_summary_list); + +static struct cmd feature_cmd = { + .name = "feature", + .fn = feature, + .descr = "Get Feature & Set Feature for specified device", + .ctx_size = 0, + .opts = NULL, + .args = NULL, +}; + +CMD_COMMAND(feature_cmd); + +static struct get_options { + uint8_t fid; + uint8_t sel; + uint32_t cdw11; + bool binary; + const char *dev; +} get_opt = { + .fid = NONE8, + .sel = 0, + .cdw11 = 0, + .binary = false, + .dev = NULL, +}; + +static const struct opts get_opts[] = { + OPT("fid", 'f', arg_uint8, get_opt, fid, + "feature id (required)"), + OPT("sel", 's', arg_uint8, get_opt, sel, + "[0-3]current/default/saved/supported"), + OPT("binary", 'b', arg_none, get_opt, binary, + "print result binary"), + OPT("cdw11", '1', arg_uint32, get_opt, cdw11, + "dword 11 value"), + OPT_END +}; + +static const struct args get_args[] = { + { arg_string, &get_opt.dev, "controller-id" }, + { arg_none, NULL, NULL }, +}; + +static struct cmd get_cmd = { + .name = "get", + .fn = feature_get, + .descr = "Get Feature for specified device", + .ctx_size = sizeof(get_opt), + .opts = get_opts, + .args = get_args, +}; + +CMD_SUBCOMMAND(feature_cmd, get_cmd); + +static struct set_options { + uint8_t fid; + bool save; + uint32_t cdw11; + uint32_t cdw12; + uint32_t cdw13; + uint32_t cdw14; + uint32_t cdw15; + const char *datafile; + const char *dev; +} set_opt = { + .fid = NONE8, + .save = false, + .cdw11 = 0, + .cdw12 = 0, + .cdw13 = 0, + .cdw14 = 0, + .cdw15 = 0, + .datafile = NULL, + .dev = NULL, +}; + +static const struct opts set_opts[] = { + OPT("fid", 'f', arg_uint8, set_opt, fid, + "feature id (required)"), + OPT("save", 's', arg_none, set_opt, save, + "the controller shall save the attribute"), + OPT("cdw11", '1', arg_uint32, set_opt, cdw11, + "dword 11 value"), + OPT("cdw12", '2', arg_uint32, set_opt, cdw12, + "dword 12 value"), + OPT("cdw13", '3', arg_uint32, set_opt, cdw13, + "dword 13 value"), + OPT("cdw14", '4', arg_uint32, set_opt, cdw14, + "dword 14 value"), + OPT("cdw15", '5', arg_uint32, set_opt, cdw15, + "dword 15 value"), + OPT("datafile", 'f', arg_path, set_opt, datafile, + "data file for some special features."), + OPT_END +}; + +static const struct args set_args[] = { + { arg_string, &set_opt.dev, "controller-id" }, + { arg_none, NULL, NULL }, +}; + +static struct cmd set_cmd = { + .name = "set", + .fn = feature_set, + .descr = "Set Feature for specified device", + .ctx_size = sizeof(set_opt), + .opts = set_opts, + .args = set_args, +}; + +CMD_SUBCOMMAND(feature_cmd, set_cmd); + +static struct summary_options { + const char *dev; +} summary_opt = { + .dev = NULL, +}; + +static const struct args summary_args[] = { + { arg_string, &summary_opt.dev, "controller-id" }, + { arg_none, NULL, NULL }, +}; + +static struct cmd summary_cmd = { + .name = "summary", + .fn = feature_summary, + .descr = "Show Feature summary for specified device", + .ctx_size = sizeof(summary_opt), + .opts = NULL, + .args = summary_args, +}; + +CMD_SUBCOMMAND(feature_cmd, summary_cmd); + +static void +print_feature_arbitration(uint32_t cdw0) +{ + + printf(" Arbitration Burst (AB): "); + if ((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(NVME_FEAT_ARBITRATION_LPW(cdw0))); + printf(" Medium Priority Weight (MPW): %d\n", + ONE_BASED(NVME_FEAT_ARBITRATION_MPW(cdw0))); + printf(" High Priority Weight (HPW): %d\n", + ONE_BASED(NVME_FEAT_ARBITRATION_HPW(cdw0))); +} + +static void +print_feature_power_management(uint32_t cdw0) +{ + + printf(" Workload Hint (WH): %#x\n", + NVME_FEAT_POWER_MANAGEMENT_WH(cdw0)); + printf(" Power State (PS): %#x\n", + NVME_FEAT_POWER_MANAGEMENT_PS(cdw0)); +} + +static void +print_feature_lba_range_type(uint32_t cdw0 __unused, void *buf, size_t len) +{ + struct nvme_lba_range_type *lba = (struct nvme_lba_range_type*)buf; + size_t num; + size_t i, j; + uint8_t idx; + + num = ONE_BASED(NVME_FEAT_LBA_RANGE_TYPE_NUM(cdw0)); + + if (num > len / sizeof(struct nvme_lba_range_type)) + num = len / sizeof(struct nvme_lba_range_type); + + for (i = 0; i < num; i++) { + if (1 == 0 ) + printf("IDX\tTYPE\tSLBA\tNLB\tGUID\n"); + if (idx > lba_range_type_name_res_max) + idx = 0; + printf("0x%zx %s", i, lba_range_type_name_res[idx]); + printf("\t0x%lx\t0x%lx\t", lba->slba, lba->nlb); + for (j = 0; j < sizeof(lba->guid); j++) + printf("%02x", lba->guid[j]); + printf("\n"); + lba++; + } +} + +static void +print_feature_temperature_threshold(uint32_t cdw0) +{ + + printf(" Temperature Threshold (TMPTH): "); + print_temp(NVME_FEAT_TEMPERATURE_THRESHOLD_TMPTH(cdw0)); +} + +static void +print_feature_error_recovery(uint32_t cdw0) +{ + + printf(" Deallocated or Unwritten Logical Block Error Enable (DULBE): %d\n", + NVME_FEAT_ERROR_RECOVERY_DULBE(cdw0)); + printf(" Time Limited Error Recovery (TLER): %d of 100ms\n", + NVME_FEAT_ERROR_RECOVERY_TLER(cdw0)); +} + +static void +print_feature_volatile_write_cache(uint32_t cdw0) +{ + + printf(" Volatile Write Cache Enable (WCE): %d\n", + NVME_FEAT_VOLATILE_WRITE_CACHE_WCE(cdw0)); +} + +static void +print_feature_number_of_queues(uint32_t cdw0) +{ + + printf(" Number of I/O Completion Queues Allocated (NCQA): %d\n", + ONE_BASED(NVME_FEAT_NUMBER_OF_QUEUES_NCQA(cdw0))); + printf(" Number of I/O Submission Queues Allocated (NSQA): %d\n", + ONE_BASED(NVME_FEAT_NUMBER_OF_QUEUES_NSQA(cdw0))); +} + +static void +print_feature_interrupt_coalescing(uint32_t cdw0) +{ + + printf(" Aggregation Time (TIME): %d\n", + NVME_FEAT_INTERRUPT_COALESCING_TIME(cdw0)); + printf(" Aggregation Threshold (THR): %d\n", + NVME_FEAT_INTERRUPT_COALESCING_THR(cdw0)); +} + +static void +print_feature_interrupt_vector_configuration(uint32_t cdw0) +{ + + printf(" Coalescing Disable (CD): %d\n", + NVME_FEAT_INTERRUPT_VECTOR_CONFIGURATION_CD(cdw0)); + printf(" Interrupt Vector (IV): %d\n", + NVME_FEAT_INTERRUPT_VECTOR_CONFIGURATION_IV(cdw0)); +} + +static void +print_feature_write_atomicity(uint32_t cdw0) +{ + + printf(" Disable Normal (DN): %d\n", + NVME_FEAT_WRITE_ATOMICITY_DN(cdw0)); +} + +static void +print_feature_async_event_configuration(uint32_t cdw0) +{ + + printf(" Telemetry Log Notices: %d\n", + NVME_FEAT_ASYNC_EVENT_CONFIGURATION_TLN(cdw0)); + printf(" Firmware Activation Notices: %d\n", + NVME_FEAT_ASYNC_EVENT_CONFIGURATION_FAN(cdw0)); + printf(" Namespace Attribute Notices: %d\n", + NVME_FEAT_ASYNC_EVENT_CONFIGURATION_NAN(cdw0)); + printf(" SMART / Health Critical Warnings: 0x%x\n", + NVME_FEAT_ASYNC_EVENT_CONFIGURATION_TLN(cdw0)); +} + +static void +print_feature_autonomous_power_state_transition(uint32_t cdw0) +{ + printf(" Autonomous Power State Transition Enable (APSTE): %d\n", + NVME_FEAT_AUTONOMOUS_POWER_STATE_TRANSITION_APSTE(cdw0)); +} + +static void +print_feature_timestamp(uint32_t cdw0) +{ + + printf(" Timestamp: %d\n", + NVME_FEAT_TIMESTAMP_TS(cdw0)); +} + +static void +print_feature_keep_alive_timer(uint32_t cdw0) +{ + + printf(" Keep Alive Timeout (KATO): %d\n", + NVME_FEAT_KEEP_ALIVE_TIMER_KATO(cdw0)); +} + +static void +print_feature_host_memory_buffer(uint32_t cdw0) +{ + + printf(" Memory Return (MR): %d\n", + NVME_FEAT_HOST_MEMORY_BUFFER_MR(cdw0)); + printf(" Enable Host Memory (EHM): %d\n", + NVME_FEAT_HOST_MEMORY_BUFFER_EHM(cdw0)); +} + +static void +print_feature_host_controlled_thermal_mgmt(uint32_t cdw0) +{ + + printf(" Thermal Management Temperature 1 (TMT1): %d\n", + NVME_FEAT_HOST_CONTROLLED_THERMAL_MGMT_TMT1(cdw0)); + printf(" Thermal Management Temperature 2 (TMT2): %d\n", + NVME_FEAT_HOST_CONTROLLED_THERMAL_MGMT_TMT2(cdw0)); +} +static void +print_feature_non_op_power_state_config(uint32_t cdw0) +{ + + printf(" Non-Operational Power State Permissive Mode Enable (NOPPME): %d\n", + NVME_FEAT_NON_OP_POWER_STATE_CONFIG_NOPPME(cdw0)); +} + +static void +output_human(const uint8_t fid, uint32_t cdw0, void *buf, size_t len) +{ + + switch (fid) { + case NVME_FEAT_ARBITRATION: + print_feature_arbitration(cdw0); + break; + case NVME_FEAT_POWER_MANAGEMENT: + print_feature_power_management(cdw0); + break; + case NVME_FEAT_LBA_RANGE_TYPE: + print_feature_lba_range_type(cdw0, buf, len); + break; + case NVME_FEAT_TEMPERATURE_THRESHOLD: + print_feature_temperature_threshold(cdw0); + break; + case NVME_FEAT_ERROR_RECOVERY: + print_feature_error_recovery(cdw0); + break; + case NVME_FEAT_VOLATILE_WRITE_CACHE: + print_feature_volatile_write_cache(cdw0); + break; + case NVME_FEAT_NUMBER_OF_QUEUES: + print_feature_number_of_queues(cdw0); + break; + case NVME_FEAT_INTERRUPT_COALESCING: + print_feature_interrupt_coalescing(cdw0); + break; + case NVME_FEAT_INTERRUPT_VECTOR_CONFIGURATION: + print_feature_interrupt_vector_configuration(cdw0); + break; + case NVME_FEAT_WRITE_ATOMICITY: + print_feature_write_atomicity(cdw0); + break; + case NVME_FEAT_ASYNC_EVENT_CONFIGURATION: + print_feature_async_event_configuration(cdw0); + break; + case NVME_FEAT_AUTONOMOUS_POWER_STATE_TRANSITION: + print_feature_autonomous_power_state_transition(cdw0); + break; + case NVME_FEAT_HOST_MEMORY_BUFFER: + print_feature_host_memory_buffer(cdw0); + break; + case NVME_FEAT_TIMESTAMP: + print_feature_timestamp(cdw0); + break; + case NVME_FEAT_KEEP_ALIVE_TIMER: + print_feature_keep_alive_timer(cdw0); + break; + case NVME_FEAT_HOST_CONTROLLED_THERMAL_MGMT: + print_feature_host_controlled_thermal_mgmt(cdw0); + break; + case NVME_FEAT_NON_OP_POWER_STATE_CONFIG: + print_feature_non_op_power_state_config(cdw0); + break; + default: + printf(" cdw0 = 0x%#08x\n", cdw0); + break; + } +} + +static void +output_binary(const uint8_t fid __unused, uint32_t cdw0, void *buf __unused, size_t len __unused) +{ + uint32_t i; + + printf("cdw0 = "); + for(i = 0; i < sizeof(cdw0) * 2; i++) { + printf("%s", bits[(cdw0 >> i*4) & 0x0F]); + printf(" "); + } + printf("\n"); +} + +static void +read_data_file(const char *path, void **buf, int32_t *size) +{ + struct stat sb; + int32_t filesize; + int fd; + + *size = 0; + *buf = NULL; + + if ((fd = open(path, O_RDONLY)) < 0) + err(EX_NOINPUT, "unable to open '%s'", path); + if (fstat(fd, &sb) < 0) + err(EX_NOINPUT, "unable to stat '%s'", path); + + if (sb.st_size > INT32_MAX) + errx(EX_USAGE, "size of file '%s' is too large (%jd bytes)", + path, (intmax_t)sb.st_size); + filesize = (int32_t)sb.st_size; + if ((*buf = malloc(filesize)) == NULL) + errx(EX_OSERR, "unable to malloc %d bytes", filesize); + if ((*size = read(fd, *buf, filesize)) < 0) + err(EX_IOERR, "error reading '%s'", path); + /* XXX assuming no short reads */ + if (*size != filesize) + errx(EX_IOERR, + "error reading '%s' (read %d bytes, requested %d bytes)", + path, *size, filesize); + close(fd); +} + +static void +feature_get(const struct cmd *f, int argc, char *argv[]) +{ + struct nvme_pt_command pt; + int fd; + uint8_t *buf = NULL; + uint32_t size = 0; + + if (arg_parse(argc, argv, f)) + return; + + if (get_opt.fid == NONE8) { + fprintf(stderr, + "feature id not specified\n"); + arg_help(argc, argv, f); + } + if (get_opt.sel > 0x3) { + fprintf(stderr, + "select value over range\n"); + arg_help(argc, argv, f); + } + + open_dev(get_opt.dev, &fd, 1, 1); + + if (get_opt.sel >= sel_name_res_max) + errx(EX_IOERR, "invalid select value"); + + if (get_opt.fid == NVME_FEAT_LBA_RANGE_TYPE){ + size = 4096; + if ((buf = malloc(size)) == NULL) + errx(EX_OSERR, "unable to malloc %d bytes", size); + memset(buf, 0, size); + } + + memset(&pt, 0, sizeof(pt)); + pt.cmd.opc = NVME_OPC_GET_FEATURES; + pt.cmd.cdw10 = htole32(NVME_FEAT_GET_SEL(get_opt.sel)); + pt.cmd.cdw11 = htole32(get_opt.cdw11); + pt.buf = buf; + pt.len = size; + pt.is_read = 1; + + if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) + err(EX_IOERR, "passthrough request failed"); + + printf("%s(0x%x), %s value\n", + (get_opt.fid < feature_name_res_max ? feature_name_res[get_opt.fid] : "\0"), get_opt.fid, + sel_name_res[get_opt.sel]); + + if (nvme_completion_is_error(&pt.cpl)) { + 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"); + } + + if ( get_opt.binary ) + output_binary(get_opt.fid, pt.cpl.cdw0, buf, sizeof(buf)); + else + output_human(get_opt.fid, pt.cpl.cdw0, buf, sizeof(buf)); + + close(fd); + exit(0); +} + +static void +feature_set(const struct cmd *f, int argc, char *argv[]) +{ + struct nvme_pt_command pt; + int fd; + void *buf = NULL; + int32_t size = 0; + + if (arg_parse(argc, argv, f)) + return; + + if (set_opt.fid == NONE8) { + fprintf(stderr, + "feature id not specified\n"); + arg_help(argc, argv, f); + } + + if (set_opt.datafile) + read_data_file(set_opt.datafile, &buf, &size); + + if (set_opt.fid == NVME_FEAT_LBA_RANGE_TYPE && + ( size > 4096 || size % 64 != 0)) { + errx(EX_USAGE, "data size of file '%s' is too large (%d bytes) or not align to 64 bytes", + set_opt.datafile, size); + } + + open_dev(set_opt.dev, &fd, 1, 1); + + memset(&pt, 0, sizeof(pt)); + pt.cmd.opc = NVME_OPC_SET_FEATURES; + pt.cmd.cdw10 = htole32(NVME_FEAT_SET_SV(set_opt.fid)); + pt.cmd.cdw11 = htole32(set_opt.cdw11); + pt.cmd.cdw12 = htole32(set_opt.cdw12); + pt.cmd.cdw13 = htole32(set_opt.cdw13); + pt.cmd.cdw14 = htole32(set_opt.cdw14); + pt.cmd.cdw15 = htole32(set_opt.cdw15); + pt.buf = buf; + pt.len = size; + + pt.is_read = 0; + + if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) + err(EX_IOERR, "passthrough request failed"); + + if (nvme_completion_is_error(&pt.cpl)) { + 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(NVME_FEAT_GET_SEL(fid)); + pt.cmd.cdw11 = htole32(cdw11); + pt.buf = NULL; + pt.len = 0; + pt.is_read = 1; + + if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) + continue; + + printf("%s(0x%x), %s value\n", + (fid < feature_name_res_max ? feature_name_res[fid] : "\0"), fid, + sel_name_res[sel]); + + if (nvme_completion_is_error(&pt.cpl)) + continue; + + cdw0 = pt.cpl.cdw0; + output_human(fid, cdw0, NULL, 0); + } + + close(fd); + exit(0); +} + +static void +feature(const struct cmd *nf __unused, int argc, char *argv[]) +{ + + cmd_dispatch(argc, argv, &feature_cmd); +} Index: sbin/nvmecontrol/nvmecontrol.h =================================================================== --- sbin/nvmecontrol/nvmecontrol.h +++ sbin/nvmecontrol/nvmecontrol.h @@ -64,6 +64,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[]) {