xref: /illumos-gate/usr/src/cmd/nvmeadm/nvmeadm.h (revision 0439b35b4c5b977fedef1ab5cbeff2c08150aba5)
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