1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2026 Oxide Computer Company 14 * Copyright 2022 Tintri by DDN, Inc. All rights reserved. 15 */ 16 17 #ifndef _NVMEADM_H 18 #define _NVMEADM_H 19 20 #include <stdio.h> 21 #include <libdevinfo.h> 22 #include <libnvme.h> 23 #include <nvme_common.h> 24 #include <nvme_reg.h> 25 #include <ofmt.h> 26 27 #ifdef __cplusplus 28 extern "C" { 29 #endif 30 31 extern int verbose; 32 extern int debug; 33 34 /* Common structures */ 35 typedef struct nvme_process_arg nvme_process_arg_t; 36 typedef struct nvmeadm_feature nvmeadm_feature_t; 37 typedef struct nvmeadm_cmd nvmeadm_cmd_t; 38 39 typedef enum { 40 /* 41 * Indicates a command that is allowed to run on multiple controllers. 42 */ 43 NVMEADM_C_MULTI = 1 << 0, 44 /* 45 * Indicates a command that requires exclusive access to the device. 46 */ 47 NVMEADM_C_EXCL = 1 << 1, 48 /* 49 * Indicates a command that does not run on a controller and therefore 50 * processing should not assume this. 51 */ 52 NVMEADM_C_NOCTRL = 1 << 2 53 } nvmeadm_cmd_flags_t; 54 55 /* 56 * General command structure 57 */ 58 struct nvmeadm_cmd { 59 const char *c_name; 60 const char *c_desc; 61 const char *c_flagdesc; 62 const char *c_fielddesc; 63 int (*c_func)(const nvme_process_arg_t *); 64 void (*c_usage)(const char *); 65 void (*c_optparse)(nvme_process_arg_t *); 66 nvmeadm_cmd_flags_t c_flags; 67 }; 68 69 /* 70 * This is used to represent information for getting and printing specific 71 * features. 72 */ 73 struct nvmeadm_feature { 74 uint8_t f_feature; 75 boolean_t (*f_get)(const nvme_process_arg_t *, const nvme_feat_disc_t *, 76 const nvmeadm_feature_t *); 77 void (*f_print)(uint32_t, void *, size_t, const nvme_identify_ctrl_t *, 78 const nvme_version_t *); 79 }; 80 81 struct nvme_process_arg { 82 nvme_t *npa_nvme; 83 nvme_ctrl_t *npa_ctrl; 84 nvme_ns_t *npa_ns; 85 nvme_ctrl_info_t *npa_ctrl_info; 86 nvme_ns_info_t *npa_ns_info; 87 int npa_argc; 88 char **npa_argv; 89 char *npa_name; 90 const char *npa_ctrl_name; 91 boolean_t npa_excl; 92 uint32_t npa_cmdflags; 93 const nvmeadm_cmd_t *npa_cmd; 94 const nvme_identify_ctrl_t *npa_idctl; 95 const nvme_version_t *npa_version; 96 ofmt_handle_t npa_ofmt; 97 void *npa_cmd_arg; 98 }; 99 100 /* 101 * Command-specific arguments 102 */ 103 typedef struct { 104 boolean_t nll_unimpl; 105 nvme_log_disc_scope_t nll_scope; 106 uint32_t nll_nprint; 107 int nll_nfilts; 108 char *const *nll_filts; 109 boolean_t *nll_used; 110 } nvmeadm_list_logs_t; 111 112 typedef struct { 113 boolean_t nf_unimpl; 114 uint32_t nf_nprint; 115 uint32_t nf_nfilts; 116 char *const *nf_filts; 117 boolean_t *nf_used; 118 } nvmeadm_features_t; 119 120 typedef struct { 121 boolean_t ncn_use_flbas; 122 nvme_csi_t ncn_csi; 123 uint64_t ncn_size; 124 uint64_t ncn_cap; 125 uint32_t ncn_lba; 126 uint32_t ncn_nmic; 127 } nvmeadm_create_ns_t; 128 129 typedef struct { 130 const char *ngl_output; 131 bool ngl_hex; 132 } nvmeadm_get_logpage_t; 133 134 /* Version checking */ 135 extern boolean_t nvme_version_check(const nvme_process_arg_t *, 136 const nvme_version_t *); 137 138 /* printing functions */ 139 extern int nvme_strlen(const char *, int); 140 extern void nvme_print(int, const char *, int, const char *, ...); 141 extern int nvme_snprint_uint128(char *, size_t, nvme_uint128_t, int, int); 142 extern void nvme_print_ctrl_summary(nvme_ctrl_info_t *); 143 extern void nvme_print_nsid_summary(nvme_ns_info_t *); 144 extern void nvme_print_identify_ctrl(const nvme_identify_ctrl_t *, uint32_t, 145 const nvme_version_t *); 146 extern void nvme_print_identify_nsid(const nvme_identify_nsid_t *, 147 const nvme_version_t *); 148 extern void nvme_print_identify_nsid_list(const char *, 149 const nvme_identify_nsid_list_t *); 150 extern void nvme_print_identify_nsid_desc(void *); 151 extern void nvme_print_identify_ctrl_list(const char *, 152 const nvme_identify_ctrl_list_t *); 153 extern void nvme_print_error_log(int, const nvme_error_log_entry_t *, 154 const nvme_version_t *); 155 extern void nvme_print_health_log(const nvme_health_log_t *, 156 const nvme_identify_ctrl_t *, 157 const nvme_version_t *); 158 extern void nvme_print_fwslot_log(const nvme_fwslot_log_t *, 159 const nvme_identify_ctrl_t *); 160 161 extern void nvme_print_feat_unknown(nvme_feat_output_t, uint32_t, void *, 162 size_t); 163 extern void nvme_print_feat_arbitration(uint32_t, void *, size_t, 164 const nvme_identify_ctrl_t *, const nvme_version_t *); 165 extern void nvme_print_feat_power_mgmt(uint32_t, void *, size_t, 166 const nvme_identify_ctrl_t *, const nvme_version_t *); 167 extern void nvme_print_feat_lba_range(uint32_t, void *, size_t, 168 const nvme_identify_ctrl_t *, const nvme_version_t *); 169 extern void nvme_print_feat_temperature(uint32_t, void *, size_t, 170 const nvme_identify_ctrl_t *, const nvme_version_t *); 171 extern void nvme_print_feat_error(uint32_t, void *, size_t, 172 const nvme_identify_ctrl_t *, const nvme_version_t *); 173 extern void nvme_print_feat_write_cache(uint32_t, void *, size_t, 174 const nvme_identify_ctrl_t *, const nvme_version_t *); 175 extern void nvme_print_feat_nqueues(uint32_t, void *, size_t, 176 const nvme_identify_ctrl_t *, const nvme_version_t *); 177 extern void nvme_print_feat_intr_coal(uint32_t, void *, size_t, 178 const nvme_identify_ctrl_t *, const nvme_version_t *); 179 extern void nvme_print_feat_intr_vect(uint32_t, void *, size_t, 180 const nvme_identify_ctrl_t *, const nvme_version_t *); 181 extern void nvme_print_feat_write_atom(uint32_t, void *, size_t, 182 const nvme_identify_ctrl_t *, const nvme_version_t *); 183 extern void nvme_print_feat_async_event(uint32_t, void *, size_t, 184 const nvme_identify_ctrl_t *, const nvme_version_t *); 185 extern void nvme_print_feat_auto_pst(uint32_t, void *, size_t, 186 const nvme_identify_ctrl_t *, const nvme_version_t *); 187 extern void nvme_print_feat_progress(uint32_t, void *, size_t, 188 const nvme_identify_ctrl_t *, const nvme_version_t *); 189 extern void nvme_print_feat_host_behavior(uint32_t, void *, size_t, 190 const nvme_identify_ctrl_t *, const nvme_version_t *); 191 192 extern void nvmeadm_dump_hex(const uint8_t *, size_t); 193 194 /* 195 * ofmt related 196 */ 197 typedef struct { 198 const char *nloa_name; 199 di_node_t nloa_dip; 200 nvme_ctrl_info_t *nloa_ctrl; 201 nvme_ns_info_t *nloa_ns; 202 const char *nloa_disk; 203 const char *nloa_state; 204 } nvmeadm_list_ofmt_arg_t; 205 206 extern const ofmt_field_t nvmeadm_list_ctrl_ofmt[]; 207 extern const ofmt_field_t nvmeadm_list_nsid_ofmt[]; 208 209 typedef struct { 210 const char *nlloa_name; 211 const nvme_log_disc_t *nlloa_disc; 212 } nvmeadm_list_logs_ofmt_arg_t; 213 214 extern const char *nvmeadm_list_logs_fields; 215 extern const char *nvmeadm_list_logs_fields_impl; 216 extern const ofmt_field_t nvmeadm_list_logs_ofmt[]; 217 218 typedef struct { 219 const char *nlfoa_name; 220 const nvme_feat_disc_t *nlfoa_feat; 221 } nvmeadm_list_features_ofmt_arg_t; 222 223 extern const char *nvmeadm_list_features_fields; 224 extern const ofmt_field_t nvmeadm_list_features_ofmt[]; 225 226 /* 227 * Log pages that have special handling. 228 */ 229 extern int do_get_logpage_telemetry(const nvme_process_arg_t *, 230 const nvme_log_disc_t *, nvme_log_req_t *); 231 232 /* 233 * Warning and error cases. The default nvmeadm ones assume a libnvme related 234 * issue. Most errors are on the nvme_ctrl_t, which are the versions without any 235 * args. The ones that operate on the nvme_t handle have hdl in the name. 236 */ 237 extern void nvmeadm_warn(const nvme_process_arg_t *, const char *, 238 ...) __PRINTFLIKE(2); 239 extern void nvmeadm_fatal(const nvme_process_arg_t *, const char *, 240 ...) __PRINTFLIKE(2) __NORETURN; 241 extern void nvmeadm_hdl_warn(const nvme_process_arg_t *, const char *, 242 ...) __PRINTFLIKE(2); 243 extern void nvmeadm_hdl_fatal(const nvme_process_arg_t *, const char *, 244 ...) __PRINTFLIKE(2) __NORETURN; 245 246 /* 247 * Namespace Management Commands 248 */ 249 extern int do_create_ns(const nvme_process_arg_t *); 250 extern void optparse_create_ns(nvme_process_arg_t *); 251 extern void usage_create_ns(const char *); 252 253 extern int do_delete_ns(const nvme_process_arg_t *); 254 extern void usage_delete_ns(const char *); 255 256 extern int do_attach_ns(const nvme_process_arg_t *); 257 extern void usage_attach_ns(const char *); 258 259 extern int do_detach_ns(const nvme_process_arg_t *); 260 extern void usage_detach_ns(const char *); 261 262 /* 263 * Physical Eye Commands 264 */ 265 extern int do_measure_phyeye_cmd(const nvme_process_arg_t *); 266 extern void optparse_measure_phyeye_cmd(nvme_process_arg_t *); 267 extern void usage_measure_phyeye_cmd(const char *); 268 extern int do_report_phyeye_cmd(const nvme_process_arg_t *); 269 extern void optparse_report_phyeye_cmd(nvme_process_arg_t *); 270 extern void usage_report_phyeye_cmd(const char *); 271 272 /* 273 * Locking functions 274 */ 275 extern void nvmeadm_excl(const nvme_process_arg_t *, nvme_lock_level_t); 276 277 /* 278 * Vendor specific commands. 279 * 280 * All vendor commands must first call nvmeadm_vuc_validate() which will 281 * validate that a given vendor unique command is useable by the device and then 282 * proceed to take any necessary locks that the command suggests. 283 */ 284 extern nvme_vuc_disc_t *nvmeadm_vuc_init(const nvme_process_arg_t *, 285 const char *); 286 extern void nvmeadm_vuc_fini(const nvme_process_arg_t *, nvme_vuc_disc_t *); 287 extern int do_vendor_cmd(const nvme_process_arg_t *); 288 extern void optparse_vendor_cmd(nvme_process_arg_t *); 289 extern void usage_vendor_cmd(const char *); 290 291 extern int do_wdc_e6dump(const nvme_process_arg_t *); 292 extern void optparse_wdc_e6dump(nvme_process_arg_t *); 293 extern void usage_wdc_e6dump(const char *); 294 295 extern int do_wdc_resize(const nvme_process_arg_t *); 296 extern void optparse_wdc_resize(nvme_process_arg_t *); 297 extern void usage_wdc_resize(const char *); 298 299 extern int do_wdc_clear_assert(const nvme_process_arg_t *); 300 extern void usage_wdc_clear_assert(const char *); 301 302 extern int do_wdc_inject_assert(const nvme_process_arg_t *); 303 extern void usage_wdc_inject_assert(const char *); 304 305 extern int do_sandisk_hwrev(const nvme_process_arg_t *); 306 extern void usage_sandisk_hwrev(const char *); 307 308 extern int do_sandisk_pcieye(const nvme_process_arg_t *); 309 extern void optparse_sandisk_pcieye(nvme_process_arg_t *); 310 extern void usage_sandisk_pcieye(const char *); 311 312 /* 313 * This is an arbitrary maximum that we use for what we expect the likely size 314 * of a log page may end up being. We use 128 MiB as a rough upper bound for 315 * what we'll mmap. This is a somewhat arbitrary value, but if we end up having 316 * a larger file, then we'll want to be more conscious of memory and probably 317 * read in a file in a buffer over time instead of mmap. 318 */ 319 #define NVMEADM_MAX_MMAP (1ULL << 27) 320 321 /* 322 * Field slicing and dicing. This is logic that is similar to pcieadm's 323 * show-cfgspace which allows us to select specific fields based on the short 324 * name of the log from the spec. 325 */ 326 typedef struct { 327 const char *nff_str; 328 size_t nff_len; 329 bool nff_used; 330 } nvmeadm_field_filt_t; 331 332 typedef enum nvmeadm_field_type_t { 333 /* 334 * Print as a raw hexadecimal value. The optional addend may be set to 335 * modify the value. 336 */ 337 NVMEADM_FT_HEX, 338 /* 339 * A number that should take the same shift as above, but have a 340 * particular unscaled unit applied. 341 */ 342 NVMEADM_FT_UNIT, 343 /* 344 * The raw value maps to a string of some kind. 345 */ 346 NVMEADM_FT_STRMAP, 347 /* 348 * Treat as a power of 2 number of bytes. Raw value is the full hex 349 * value. Otherwise this should be humanized. 350 */ 351 NVMEADM_FT_BYTES, 352 /* 353 * Indicates that this is a nested structure with a series of bitfields 354 * that we should print. 355 */ 356 NVMEADM_FT_BITS, 357 /* 358 * Indicate that there are a series of fields inside of this. Similar in 359 * spirit to BITS above, but generally meant to be used to help separate 360 * stuff which can be a little weirder such as the OCP telemetry string 361 * log or the various extended SMART items. Containers are only included 362 * in human readable output and are not part of the machine parsable 363 * output as they have no value. 364 */ 365 NVMEADM_FT_CONTAINER, 366 /* 367 * Indicates that this field is a normalized percentage. Note, this may 368 * result in a value > 100%. 369 */ 370 NVMEADM_FT_PERCENT, 371 /* 372 * A 16-byte style UUID. 373 */ 374 NVMEADM_FT_GUID, 375 /* 376 * A series of characters that are supposed to be ASCII strings. The 377 * ASCIIZ says that these are NUL padded where as ASCII 378 * is probably space padded. Either way padding is not guaranteed. 379 */ 380 NVMEADM_FT_ASCII, 381 NVMEADM_FT_ASCIIZ 382 } nvmeadm_field_type_t; 383 384 typedef struct { 385 uint8_t nfa_shift; 386 int64_t nfa_addend; 387 const char *nfa_unit; 388 } nvmeadm_field_addend_t; 389 390 typedef struct nvmeadm_field_bit nvmeadm_field_bit_t; 391 struct nvmeadm_field_bit { 392 uint8_t nfb_lowbit; 393 uint8_t nfb_hibit; 394 const char *nfb_short; 395 const char *nfb_desc; 396 uint8_t nfb_rev; 397 uint8_t nfb_maxrev; 398 const nvme_version_t *nfb_vers; 399 nvmeadm_field_type_t nfb_type; 400 /* 401 * Enough space for up to an 8-bit fields worth of values 402 * (though we expect most to be sparse). 403 */ 404 const char *nfb_strs[128]; 405 const nvmeadm_field_bit_t *nfb_bits; 406 size_t nfb_nbits; 407 nvmeadm_field_addend_t nfb_addend; 408 }; 409 410 typedef struct nvmeadm_field nvmeadm_field_t; 411 struct nvmeadm_field { 412 uint32_t nf_off; 413 uint32_t nf_len; 414 const char *nf_short; 415 const char *nf_desc; 416 uint32_t nf_rev; 417 uint32_t nf_maxrev; 418 const nvme_version_t *nf_vers; 419 nvmeadm_field_type_t nf_type; 420 /* 421 * Enough space for up to an 8-bit fields worth of values 422 * (though we expect most to be sparse). 423 */ 424 const char *nf_strs[128]; 425 const nvmeadm_field_bit_t *nf_bits; 426 size_t nf_nbits; 427 nvmeadm_field_addend_t nf_addend; 428 const nvmeadm_field_t *nf_fields; 429 size_t nf_nfields; 430 }; 431 432 typedef struct nvmeadm_field_print { 433 /* 434 * fp_header provides a header when printing this data. In general, 435 * 'fp_header' should only be used if we are breaking up a single log 436 * page or similar into multiple disjoint tables. This is used when 437 * there's a header for a log page and then a variable set of body 438 * entries (e.g. the PHY Eye Measurement). 439 * 440 * This header is paired with a 'base' string that corresponds to the 441 * short name for this region of the file. This should be set in fp_base 442 * and is required if fp_header is set. 443 */ 444 const char *fp_header; 445 /* 446 * Optional field revision and NVMe version information. If this is 447 * present, the field will be skipped if the object revision or the 448 * controller version is not sufficient. If this is against a file then 449 * the version checks are ignored by default. 450 */ 451 uint32_t fp_rev; 452 const nvme_version_t *fp_vers; 453 /* 454 * These are the set of fields to actually print. 455 */ 456 const nvmeadm_field_t *fp_fields; 457 size_t fp_nfields; 458 /* 459 * This represents the initial portion of the 'short' path. This will be 460 * prepended to all the different fields in here. This may be NULL if 461 * there is nothing here. When it is NULL, the header should be as well. 462 */ 463 const char *fp_base; 464 /* 465 * The data pointer and its corresponding length of valid data. Note, 466 * fp_off is a logical offset to be added. There is no relationship 467 * assumed between the data pointer and the fp_off. When a field is 468 * processed its embedded offset is always relative to the start of 469 * data. fp_off exists when manually driving so when a data pointer 470 * points to the start of some region that is offset, e.g. a pointer to 471 * the start of some variable length data after a header, then the 472 * logical offset in the overall structure can still be applied when 473 * telling the user about offsets. 474 */ 475 const void *fp_data; 476 size_t fp_dlen; 477 size_t fp_off; 478 /* 479 * Filters that are checked against. 480 */ 481 size_t fp_nfilts; 482 nvmeadm_field_filt_t *fp_filts; 483 ofmt_handle_t fp_ofmt; 484 /* 485 * Internal data used for indentation purposes. 486 */ 487 uint32_t fp_indent; 488 } nvmeadm_field_print_t; 489 490 /* 491 * Functions and data to reach the field printing logic. 492 */ 493 extern const ofmt_field_t nvmeadm_field_ofmt[]; 494 extern void nvmeadm_field_print(nvmeadm_field_print_t *); 495 496 /* 497 * This is the internal function used by log processing code to reach the 498 * filtering / ofmt log formatting logic. 499 */ 500 typedef enum { 501 /* 502 * Indicates that this is the first time that a log page name is being 503 * checked. If it isn't found, then we should warn about it. This'll 504 * result in the command failing. This is mean to be used by 505 * print-logpage. 506 */ 507 NVMEADM_LFF_CHECK_NAME = 1 << 0 508 } nvmeadm_log_field_flag_t; 509 extern bool nvmeadm_log_page_fields(const nvme_process_arg_t *, const char *, 510 const void *, size_t, nvmeadm_field_filt_t *, size_t, 511 nvmeadm_log_field_flag_t); 512 513 /* 514 * Convenience macros to set a field type and consistent members. This should be 515 * used in the implementation of field information. 516 */ 517 #define NVMEADM_F_BITS(bits) \ 518 .nf_type = NVMEADM_FT_BITS, \ 519 .nf_bits = bits, \ 520 .nf_nbits = ARRAY_SIZE(bits) 521 #define NVMEADM_FB_BITS(bits) \ 522 .nfb_type = NVMEADM_FT_BITS, \ 523 .nfb_bits = bits, \ 524 .nfb_nbits = ARRAY_SIZE(bits) 525 #define NVMEADM_F_FIELDS(f) \ 526 .nf_type = NVMEADM_FT_CONTAINER, \ 527 .nf_fields = f, \ 528 .nf_nfields = ARRAY_SIZE(f) 529 530 /* 531 * Defined field structures. 532 */ 533 typedef struct { 534 const char *nlfi_log; 535 const nvmeadm_field_t *const nlfi_fields; 536 const size_t nlfi_nfields; 537 const size_t nlfi_min; 538 /* 539 * Return the revision of the log field. Callers are guaranteed that at 540 * least nlfi_min byte are already present, 541 */ 542 uint32_t (*nlfi_getrev)(const void *, size_t len); 543 /* 544 * Run the process of walking through the log data and providing field 545 * callbacks. This should be used for logs that have a fixed header and 546 * variable contents. 547 */ 548 bool (*nlfi_drive)(nvmeadm_field_print_t *, const void *, size_t); 549 } nvmeadm_log_field_info_t; 550 551 extern const nvmeadm_log_field_info_t suplog_field_info; 552 extern const nvmeadm_log_field_info_t supcmd_field_info; 553 extern const nvmeadm_log_field_info_t supmicmd_field_info; 554 extern const nvmeadm_log_field_info_t supfeat_field_info; 555 extern const nvmeadm_log_field_info_t phyeye_field_info; 556 extern const nvmeadm_log_field_info_t kioxia_vul_extsmart_field_info; 557 extern const nvmeadm_log_field_info_t micron_vul_extsmart_field_info; 558 extern const nvmeadm_log_field_info_t ocp_vul_smart_field_info; 559 extern const nvmeadm_log_field_info_t ocp_vul_errrec_field_info; 560 extern const nvmeadm_log_field_info_t ocp_vul_devcap_field_info; 561 extern const nvmeadm_log_field_info_t ocp_vul_unsup_field_info; 562 extern const nvmeadm_log_field_info_t ocp_vul_telstr_field_info; 563 extern const nvmeadm_log_field_info_t solidigm_vul_power_field_info; 564 extern const nvmeadm_log_field_info_t solidigm_vul_temp_field_info; 565 extern const nvmeadm_log_field_info_t wdc_vul_cusmart_field_info; 566 extern const nvmeadm_log_field_info_t wdc_vul_eol_field_info; 567 extern const nvmeadm_log_field_info_t wdc_vul_power_field_info; 568 569 #ifdef __cplusplus 570 } 571 #endif 572 573 #endif /* _NVMEADM_H */ 574