1e4cc4004SRobert Mustacchi /*
2e4cc4004SRobert Mustacchi  * This file and its contents are supplied under the terms of the
3e4cc4004SRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
4e4cc4004SRobert Mustacchi  * You may only use this file in accordance with the terms of version
5e4cc4004SRobert Mustacchi  * 1.0 of the CDDL.
6e4cc4004SRobert Mustacchi  *
7e4cc4004SRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
8e4cc4004SRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
9e4cc4004SRobert Mustacchi  * http://www.illumos.org/license/CDDL.
10e4cc4004SRobert Mustacchi  */
11e4cc4004SRobert Mustacchi 
12e4cc4004SRobert Mustacchi /*
13533affcbSRobert Mustacchi  * Copyright 2024 Oxide Computer Company
14b3266bebSHans Rosenfeld  * Copyright 2022 Tintri by DDN, Inc. All rights reserved.
15e4cc4004SRobert Mustacchi  */
16e4cc4004SRobert Mustacchi 
17e4cc4004SRobert Mustacchi /*
18e4cc4004SRobert Mustacchi  * nvmeadm output formatting for ofmt based rendering
19e4cc4004SRobert Mustacchi  */
20e4cc4004SRobert Mustacchi 
21e4cc4004SRobert Mustacchi #include <strings.h>
22533affcbSRobert Mustacchi #include <sys/sysmacros.h>
23533affcbSRobert Mustacchi #include <err.h>
24e4cc4004SRobert Mustacchi 
25e4cc4004SRobert Mustacchi #include "nvmeadm.h"
26e4cc4004SRobert Mustacchi 
27533affcbSRobert Mustacchi typedef struct {
28533affcbSRobert Mustacchi 	uint32_t	nb_flag;
29533affcbSRobert Mustacchi 	const char	*nb_str;
30533affcbSRobert Mustacchi } nvmeadm_bitstr_t;
31533affcbSRobert Mustacchi 
32533affcbSRobert Mustacchi static boolean_t
nvmeadm_bits_to_str(uint32_t val,const nvmeadm_bitstr_t * strs,size_t nstrs,char * buf,size_t buflen)33533affcbSRobert Mustacchi nvmeadm_bits_to_str(uint32_t val, const nvmeadm_bitstr_t *strs, size_t nstrs,
34533affcbSRobert Mustacchi     char *buf, size_t buflen)
35533affcbSRobert Mustacchi {
36533affcbSRobert Mustacchi 	boolean_t comma = B_FALSE;
37533affcbSRobert Mustacchi 
38533affcbSRobert Mustacchi 	buf[0] = '\0';
39533affcbSRobert Mustacchi 	for (size_t i = 0; i < nstrs; i++) {
40533affcbSRobert Mustacchi 		if ((val & strs[i].nb_flag) != strs[i].nb_flag)
41533affcbSRobert Mustacchi 			continue;
42533affcbSRobert Mustacchi 		if (comma && strlcat(buf, ",", buflen) >= buflen)
43533affcbSRobert Mustacchi 			return (B_FALSE);
44533affcbSRobert Mustacchi 		if (strlcat(buf, strs[i].nb_str, buflen) >= buflen)
45533affcbSRobert Mustacchi 			return (B_FALSE);
46533affcbSRobert Mustacchi 		comma = true;
47533affcbSRobert Mustacchi 	}
48533affcbSRobert Mustacchi 
49533affcbSRobert Mustacchi 	if (buf[0] == '\0') {
50533affcbSRobert Mustacchi 		if (strlcat(buf, "--", buflen) >= buflen)
51533affcbSRobert Mustacchi 			return (B_FALSE);
52533affcbSRobert Mustacchi 	}
53533affcbSRobert Mustacchi 
54533affcbSRobert Mustacchi 	return (B_TRUE);
55533affcbSRobert Mustacchi }
56533affcbSRobert Mustacchi 
57e4cc4004SRobert Mustacchi typedef enum nvme_list_ofmt_field {
58e4cc4004SRobert Mustacchi 	NVME_LIST_MODEL,
59e4cc4004SRobert Mustacchi 	NVME_LIST_SERIAL,
60e4cc4004SRobert Mustacchi 	NVME_LIST_FWREV,
61e4cc4004SRobert Mustacchi 	NVME_LIST_VERSION,
62e4cc4004SRobert Mustacchi 	NVME_LIST_SIZE,
63e4cc4004SRobert Mustacchi 	NVME_LIST_CAPACITY,
64e4cc4004SRobert Mustacchi 	NVME_LIST_USED,
65e4cc4004SRobert Mustacchi 	NVME_LIST_INSTANCE,
66e4cc4004SRobert Mustacchi 	NVME_LIST_NAMESPACE,
67b3266bebSHans Rosenfeld 	NVME_LIST_DISK,
68b3266bebSHans Rosenfeld 	NVME_LIST_UNALLOC,
69e4cc4004SRobert Mustacchi } nvme_list_ofmt_field_t;
70e4cc4004SRobert Mustacchi 
71e4cc4004SRobert Mustacchi static boolean_t
nvmeadm_list_common_ofmt_cb(ofmt_arg_t * ofmt_arg,char * buf,uint_t buflen)72533affcbSRobert Mustacchi nvmeadm_list_common_ofmt_cb(ofmt_arg_t *ofmt_arg, char *buf, uint_t buflen)
73e4cc4004SRobert Mustacchi {
74533affcbSRobert Mustacchi 	nvmeadm_list_ofmt_arg_t *list = ofmt_arg->ofmt_cbarg;
75533affcbSRobert Mustacchi 	nvme_ctrl_info_t *ctrl = list->nloa_ctrl;
76533affcbSRobert Mustacchi 	const nvme_version_t *vers;
77e4cc4004SRobert Mustacchi 	size_t ret;
78e4cc4004SRobert Mustacchi 
79e4cc4004SRobert Mustacchi 	switch (ofmt_arg->ofmt_id) {
80e4cc4004SRobert Mustacchi 	case NVME_LIST_MODEL:
81533affcbSRobert Mustacchi 		ret = strlcpy(buf, nvme_ctrl_info_model(ctrl), buflen);
82e4cc4004SRobert Mustacchi 		break;
83e4cc4004SRobert Mustacchi 	case NVME_LIST_SERIAL:
84533affcbSRobert Mustacchi 		ret = strlcpy(buf, nvme_ctrl_info_serial(ctrl), buflen);
85e4cc4004SRobert Mustacchi 		break;
86e4cc4004SRobert Mustacchi 	case NVME_LIST_FWREV:
87533affcbSRobert Mustacchi 		ret = strlcpy(buf, nvme_ctrl_info_fwrev(ctrl), buflen);
88e4cc4004SRobert Mustacchi 		break;
89e4cc4004SRobert Mustacchi 	case NVME_LIST_VERSION:
90533affcbSRobert Mustacchi 		vers = nvme_ctrl_info_version(ctrl);
91533affcbSRobert Mustacchi 		ret = snprintf(buf, buflen, "%u.%u", vers->v_major,
92533affcbSRobert Mustacchi 		    vers->v_minor);
93e4cc4004SRobert Mustacchi 		break;
94e4cc4004SRobert Mustacchi 	case NVME_LIST_INSTANCE:
95533affcbSRobert Mustacchi 		ret = strlcpy(buf, list->nloa_name, buflen);
96e4cc4004SRobert Mustacchi 		break;
97b3266bebSHans Rosenfeld 	default:
98533affcbSRobert Mustacchi 		warnx("internal programmer error: encountered unknown ofmt "
99533affcbSRobert Mustacchi 		    "argument id 0x%x", ofmt_arg->ofmt_id);
100b3266bebSHans Rosenfeld 		abort();
101b3266bebSHans Rosenfeld 	}
102b3266bebSHans Rosenfeld 	if (ret >= buflen) {
103b3266bebSHans Rosenfeld 		return (B_FALSE);
104b3266bebSHans Rosenfeld 	}
105b3266bebSHans Rosenfeld 	return (B_TRUE);
106b3266bebSHans Rosenfeld }
107b3266bebSHans Rosenfeld 
108b3266bebSHans Rosenfeld static boolean_t
nvmeadm_list_ctrl_ofmt_cb(ofmt_arg_t * ofmt_arg,char * buf,uint_t buflen)109533affcbSRobert Mustacchi nvmeadm_list_ctrl_ofmt_cb(ofmt_arg_t *ofmt_arg, char *buf, uint_t buflen)
110b3266bebSHans Rosenfeld {
111533affcbSRobert Mustacchi 	nvmeadm_list_ofmt_arg_t *list = ofmt_arg->ofmt_cbarg;
112533affcbSRobert Mustacchi 	nvme_ctrl_info_t *ctrl = list->nloa_ctrl;
113533affcbSRobert Mustacchi 	nvme_uint128_t u128;
114b3266bebSHans Rosenfeld 	size_t ret;
115b3266bebSHans Rosenfeld 
116b3266bebSHans Rosenfeld 	switch (ofmt_arg->ofmt_id) {
117b3266bebSHans Rosenfeld 	case NVME_LIST_CAPACITY:
118533affcbSRobert Mustacchi 		if (nvme_ctrl_info_cap(ctrl, &u128)) {
119533affcbSRobert Mustacchi 			ret = nvme_snprint_uint128(buf, buflen, u128, 0, 0);
120533affcbSRobert Mustacchi 		} else {
121533affcbSRobert Mustacchi 			return (B_FALSE);
122533affcbSRobert Mustacchi 		}
123b3266bebSHans Rosenfeld 		break;
124b3266bebSHans Rosenfeld 	case NVME_LIST_UNALLOC:
125533affcbSRobert Mustacchi 		if (nvme_ctrl_info_unalloc_cap(ctrl, &u128)) {
126533affcbSRobert Mustacchi 			ret = nvme_snprint_uint128(buf, buflen, u128, 0, 0);
127533affcbSRobert Mustacchi 		} else {
128533affcbSRobert Mustacchi 			return (B_FALSE);
129533affcbSRobert Mustacchi 		}
130b3266bebSHans Rosenfeld 		break;
131b3266bebSHans Rosenfeld 	default:
132533affcbSRobert Mustacchi 		warnx("internal programmer error: encountered unknown ofmt "
133533affcbSRobert Mustacchi 		    "argument id 0x%x", ofmt_arg->ofmt_id);
134b3266bebSHans Rosenfeld 		abort();
135b3266bebSHans Rosenfeld 	}
136b3266bebSHans Rosenfeld 
137b3266bebSHans Rosenfeld 	if (ret >= buflen) {
138b3266bebSHans Rosenfeld 		return (B_FALSE);
139b3266bebSHans Rosenfeld 	}
140b3266bebSHans Rosenfeld 	return (B_TRUE);
141b3266bebSHans Rosenfeld }
142b3266bebSHans Rosenfeld 
143b3266bebSHans Rosenfeld static boolean_t
nvmeadm_list_nsid_ofmt_cb(ofmt_arg_t * ofmt_arg,char * buf,uint_t buflen)144533affcbSRobert Mustacchi nvmeadm_list_nsid_ofmt_cb(ofmt_arg_t *ofmt_arg, char *buf, uint_t buflen)
145b3266bebSHans Rosenfeld {
146533affcbSRobert Mustacchi 	nvmeadm_list_ofmt_arg_t *list = ofmt_arg->ofmt_cbarg;
147533affcbSRobert Mustacchi 	nvme_ns_info_t *ns = list->nloa_ns;
148533affcbSRobert Mustacchi 	const nvme_nvm_lba_fmt_t *fmt = NULL;
149b3266bebSHans Rosenfeld 	uint64_t val;
150b3266bebSHans Rosenfeld 	size_t ret;
151b3266bebSHans Rosenfeld 
152533affcbSRobert Mustacchi 
153533affcbSRobert Mustacchi 	(void) nvme_ns_info_curformat(ns, &fmt);
154b3266bebSHans Rosenfeld 
155b3266bebSHans Rosenfeld 	switch (ofmt_arg->ofmt_id) {
156e4cc4004SRobert Mustacchi 	case NVME_LIST_NAMESPACE:
157533affcbSRobert Mustacchi 		ret = snprintf(buf, buflen, "%u", nvme_ns_info_nsid(ns));
158e4cc4004SRobert Mustacchi 		break;
159e4cc4004SRobert Mustacchi 	case NVME_LIST_DISK:
160533affcbSRobert Mustacchi 		if (list->nloa_disk != NULL) {
161533affcbSRobert Mustacchi 			ret = strlcpy(buf, list->nloa_disk, buflen);
162e4cc4004SRobert Mustacchi 		} else {
163533affcbSRobert Mustacchi 			return (B_FALSE);
164e4cc4004SRobert Mustacchi 		}
165e4cc4004SRobert Mustacchi 		break;
166e4cc4004SRobert Mustacchi 	case NVME_LIST_SIZE:
167533affcbSRobert Mustacchi 		if (nvme_ns_info_size(ns, &val) && fmt != NULL) {
168533affcbSRobert Mustacchi 			val *= nvme_nvm_lba_fmt_data_size(fmt);
169533affcbSRobert Mustacchi 			ret = snprintf(buf, buflen, "%" PRIu64, val);
170533affcbSRobert Mustacchi 		} else {
171533affcbSRobert Mustacchi 			return (B_FALSE);
172533affcbSRobert Mustacchi 		}
173e4cc4004SRobert Mustacchi 		break;
174e4cc4004SRobert Mustacchi 	case NVME_LIST_CAPACITY:
175533affcbSRobert Mustacchi 		if (nvme_ns_info_size(ns, &val) && fmt != NULL) {
176533affcbSRobert Mustacchi 			val *= nvme_nvm_lba_fmt_data_size(fmt);
177533affcbSRobert Mustacchi 			ret = snprintf(buf, buflen, "%" PRIu64, val);
178533affcbSRobert Mustacchi 		} else {
179533affcbSRobert Mustacchi 			return (B_FALSE);
180533affcbSRobert Mustacchi 		}
181e4cc4004SRobert Mustacchi 		break;
182e4cc4004SRobert Mustacchi 	case NVME_LIST_USED:
183533affcbSRobert Mustacchi 		if (nvme_ns_info_size(ns, &val) && fmt != NULL) {
184533affcbSRobert Mustacchi 			val *= nvme_nvm_lba_fmt_data_size(fmt);
185533affcbSRobert Mustacchi 			ret = snprintf(buf, buflen, "%" PRIu64, val);
186533affcbSRobert Mustacchi 		} else {
187533affcbSRobert Mustacchi 			return (B_FALSE);
188533affcbSRobert Mustacchi 		}
189e4cc4004SRobert Mustacchi 		break;
190e4cc4004SRobert Mustacchi 	default:
191533affcbSRobert Mustacchi 		warnx("internal programmer error: encountered unknown ofmt "
192533affcbSRobert Mustacchi 		    "argument id 0x%x", ofmt_arg->ofmt_id);
193e4cc4004SRobert Mustacchi 		abort();
194e4cc4004SRobert Mustacchi 	}
195e4cc4004SRobert Mustacchi 
196e4cc4004SRobert Mustacchi 	if (ret >= buflen) {
197e4cc4004SRobert Mustacchi 		return (B_FALSE);
198e4cc4004SRobert Mustacchi 	}
199e4cc4004SRobert Mustacchi 	return (B_TRUE);
200e4cc4004SRobert Mustacchi }
201e4cc4004SRobert Mustacchi 
202533affcbSRobert Mustacchi const ofmt_field_t nvmeadm_list_ctrl_ofmt[] = {
203533affcbSRobert Mustacchi 	{ "MODEL", 30, NVME_LIST_MODEL, nvmeadm_list_common_ofmt_cb },
204533affcbSRobert Mustacchi 	{ "SERIAL", 30, NVME_LIST_SERIAL, nvmeadm_list_common_ofmt_cb },
205533affcbSRobert Mustacchi 	{ "FWREV", 10, NVME_LIST_FWREV, nvmeadm_list_common_ofmt_cb },
206533affcbSRobert Mustacchi 	{ "VERSION", 10, NVME_LIST_VERSION, nvmeadm_list_common_ofmt_cb },
207533affcbSRobert Mustacchi 	{ "CAPACITY", 15, NVME_LIST_CAPACITY, nvmeadm_list_ctrl_ofmt_cb },
208533affcbSRobert Mustacchi 	{ "INSTANCE", 10, NVME_LIST_INSTANCE, nvmeadm_list_common_ofmt_cb },
209533affcbSRobert Mustacchi 	{ "UNALLOCATED", 15, NVME_LIST_UNALLOC, nvmeadm_list_ctrl_ofmt_cb },
210b3266bebSHans Rosenfeld 	{ NULL, 0, 0, NULL }
211b3266bebSHans Rosenfeld };
212b3266bebSHans Rosenfeld 
213533affcbSRobert Mustacchi const ofmt_field_t nvmeadm_list_nsid_ofmt[] = {
214533affcbSRobert Mustacchi 	{ "MODEL", 30, NVME_LIST_MODEL, nvmeadm_list_common_ofmt_cb },
215533affcbSRobert Mustacchi 	{ "SERIAL", 30, NVME_LIST_SERIAL, nvmeadm_list_common_ofmt_cb },
216533affcbSRobert Mustacchi 	{ "FWREV", 10, NVME_LIST_FWREV, nvmeadm_list_common_ofmt_cb },
217533affcbSRobert Mustacchi 	{ "VERSION", 10, NVME_LIST_VERSION, nvmeadm_list_common_ofmt_cb },
218533affcbSRobert Mustacchi 	{ "SIZE", 15, NVME_LIST_SIZE, nvmeadm_list_nsid_ofmt_cb },
219533affcbSRobert Mustacchi 	{ "CAPACITY", 15, NVME_LIST_CAPACITY, nvmeadm_list_nsid_ofmt_cb },
220533affcbSRobert Mustacchi 	{ "USED", 15, NVME_LIST_USED, nvmeadm_list_nsid_ofmt_cb },
221533affcbSRobert Mustacchi 	{ "INSTANCE", 10, NVME_LIST_INSTANCE, nvmeadm_list_common_ofmt_cb },
222533affcbSRobert Mustacchi 	{ "NAMESPACE", 10, NVME_LIST_NAMESPACE, nvmeadm_list_nsid_ofmt_cb },
223533affcbSRobert Mustacchi 	{ "DISK", 15, NVME_LIST_DISK, nvmeadm_list_nsid_ofmt_cb },
224533affcbSRobert Mustacchi 	{ NULL, 0, 0, NULL }
225533affcbSRobert Mustacchi };
226533affcbSRobert Mustacchi 
227533affcbSRobert Mustacchi typedef enum {
228533affcbSRobert Mustacchi 	NVME_LIST_LOGS_DEVICE,
229533affcbSRobert Mustacchi 	NVME_LIST_LOGS_NAME,
230533affcbSRobert Mustacchi 	NVME_LIST_LOGS_DESC,
231533affcbSRobert Mustacchi 	NVME_LIST_LOGS_SCOPE,
232533affcbSRobert Mustacchi 	NVME_LIST_LOGS_FIELDS,
233533affcbSRobert Mustacchi 	NVME_LIST_LOGS_CSI,
234533affcbSRobert Mustacchi 	NVME_LIST_LOGS_LID,
235533affcbSRobert Mustacchi 	NVME_LIST_LOGS_SIZE,
236533affcbSRobert Mustacchi 	NVME_LIST_LOGS_MINSIZE,
237533affcbSRobert Mustacchi 	NVME_LIST_LOGS_IMPL,
238533affcbSRobert Mustacchi 	NVME_LIST_LOGS_SOURCES,
239533affcbSRobert Mustacchi 	NVME_LIST_LOGS_KIND
240533affcbSRobert Mustacchi } nvme_list_logs_ofmt_field_t;
241533affcbSRobert Mustacchi 
242533affcbSRobert Mustacchi static const nvmeadm_bitstr_t nvmeadm_log_scopes[] = {
243533affcbSRobert Mustacchi 	{ NVME_LOG_SCOPE_CTRL, "controller" },
244533affcbSRobert Mustacchi 	{ NVME_LOG_SCOPE_NVM, "nvm" },
245533affcbSRobert Mustacchi 	{ NVME_LOG_SCOPE_NS, "namespace" }
246533affcbSRobert Mustacchi };
247533affcbSRobert Mustacchi 
248533affcbSRobert Mustacchi static const nvmeadm_bitstr_t nvmeadm_log_fields[] = {
249533affcbSRobert Mustacchi 	{ NVME_LOG_DISC_F_NEED_LSP, "lsp" },
250533affcbSRobert Mustacchi 	{ NVME_LOG_DISC_F_NEED_LSI, "lsi" },
251533affcbSRobert Mustacchi 	{ NVME_LOG_DISC_F_NEED_RAE, "rae" }
252533affcbSRobert Mustacchi };
253533affcbSRobert Mustacchi 
254533affcbSRobert Mustacchi static const nvmeadm_bitstr_t nvmeadm_log_sources[] = {
255533affcbSRobert Mustacchi 	{ NVME_LOG_DISC_S_SPEC, "spec" },
256533affcbSRobert Mustacchi 	{ NVME_LOG_DISC_S_ID_CTRL, "identify-controller" },
257533affcbSRobert Mustacchi 	{ NVME_LOG_DISC_S_DB, "internal-db" },
258533affcbSRobert Mustacchi 	{ NVME_LOG_DISC_S_CMD, "command" }
259533affcbSRobert Mustacchi };
260533affcbSRobert Mustacchi 
261533affcbSRobert Mustacchi static boolean_t
nvmeadm_list_logs_ofmt_cb(ofmt_arg_t * ofmt_arg,char * buf,uint_t buflen)262533affcbSRobert Mustacchi nvmeadm_list_logs_ofmt_cb(ofmt_arg_t *ofmt_arg, char *buf, uint_t buflen)
263533affcbSRobert Mustacchi {
264533affcbSRobert Mustacchi 	const nvmeadm_list_logs_ofmt_arg_t *list = ofmt_arg->ofmt_cbarg;
265533affcbSRobert Mustacchi 	const nvme_log_disc_t *disc = list->nlloa_disc;
266533affcbSRobert Mustacchi 	uint64_t alloc;
267533affcbSRobert Mustacchi 	size_t ret;
268533affcbSRobert Mustacchi 	nvme_log_size_kind_t kind;
269533affcbSRobert Mustacchi 
270533affcbSRobert Mustacchi 	switch (ofmt_arg->ofmt_id) {
271533affcbSRobert Mustacchi 	case NVME_LIST_LOGS_DEVICE:
272533affcbSRobert Mustacchi 		ret = strlcpy(buf, list->nlloa_name, buflen);
273533affcbSRobert Mustacchi 		break;
274533affcbSRobert Mustacchi 	case NVME_LIST_LOGS_NAME:
275533affcbSRobert Mustacchi 		ret = strlcpy(buf, nvme_log_disc_name(disc), buflen);
276533affcbSRobert Mustacchi 		break;
277533affcbSRobert Mustacchi 	case NVME_LIST_LOGS_DESC:
278533affcbSRobert Mustacchi 		ret = strlcpy(buf, nvme_log_disc_desc(disc), buflen);
279533affcbSRobert Mustacchi 		break;
280533affcbSRobert Mustacchi 	case NVME_LIST_LOGS_SCOPE:
281533affcbSRobert Mustacchi 		return (nvmeadm_bits_to_str(nvme_log_disc_scopes(disc),
282533affcbSRobert Mustacchi 		    nvmeadm_log_scopes, ARRAY_SIZE(nvmeadm_log_scopes), buf,
283533affcbSRobert Mustacchi 		    buflen));
284533affcbSRobert Mustacchi 	case NVME_LIST_LOGS_FIELDS:
285533affcbSRobert Mustacchi 		return (nvmeadm_bits_to_str(nvme_log_disc_fields(disc),
286533affcbSRobert Mustacchi 		    nvmeadm_log_fields, ARRAY_SIZE(nvmeadm_log_fields), buf,
287533affcbSRobert Mustacchi 		    buflen));
288533affcbSRobert Mustacchi 		break;
289533affcbSRobert Mustacchi 	case NVME_LIST_LOGS_CSI:
290533affcbSRobert Mustacchi 		switch (nvme_log_disc_csi(disc)) {
291533affcbSRobert Mustacchi 		case NVME_CSI_NVM:
292533affcbSRobert Mustacchi 			ret = strlcpy(buf, "nvm", buflen);
293533affcbSRobert Mustacchi 			break;
294533affcbSRobert Mustacchi 		case NVME_CSI_KV:
295533affcbSRobert Mustacchi 			ret = strlcpy(buf, "kv", buflen);
296533affcbSRobert Mustacchi 			break;
297533affcbSRobert Mustacchi 		case NVME_CSI_ZNS:
298533affcbSRobert Mustacchi 			ret = strlcpy(buf, "zns", buflen);
299533affcbSRobert Mustacchi 			break;
300533affcbSRobert Mustacchi 		default:
301533affcbSRobert Mustacchi 			ret = snprintf(buf, buflen, "unknown (0x%x)",
302533affcbSRobert Mustacchi 			    nvme_log_disc_csi(disc));
303533affcbSRobert Mustacchi 			break;
304533affcbSRobert Mustacchi 		}
305533affcbSRobert Mustacchi 		break;
306533affcbSRobert Mustacchi 	case NVME_LIST_LOGS_LID:
307533affcbSRobert Mustacchi 		ret = snprintf(buf, buflen, "0x%x", nvme_log_disc_lid(disc));
308533affcbSRobert Mustacchi 		break;
309533affcbSRobert Mustacchi 	case NVME_LIST_LOGS_SIZE:
310533affcbSRobert Mustacchi 	case NVME_LIST_LOGS_MINSIZE:
311533affcbSRobert Mustacchi 		kind = nvme_log_disc_size(disc, &alloc);
312533affcbSRobert Mustacchi 
313533affcbSRobert Mustacchi 		if (kind == NVME_LOG_SIZE_K_UNKNOWN) {
314533affcbSRobert Mustacchi 			return (B_FALSE);
315533affcbSRobert Mustacchi 		}
316533affcbSRobert Mustacchi 
317533affcbSRobert Mustacchi 		if (kind == NVME_LOG_SIZE_K_VAR &&
318533affcbSRobert Mustacchi 		    ofmt_arg->ofmt_id == NVME_LIST_LOGS_SIZE) {
319533affcbSRobert Mustacchi 			return (B_FALSE);
320533affcbSRobert Mustacchi 		}
321533affcbSRobert Mustacchi 
322533affcbSRobert Mustacchi 		ret = snprintf(buf, buflen, "%" PRIu64, alloc);
323533affcbSRobert Mustacchi 		break;
324533affcbSRobert Mustacchi 	case NVME_LIST_LOGS_IMPL:
325*046911ebSRobert Mustacchi 		ret = strlcpy(buf, nvme_log_disc_impl(disc) ? "yes" : "no",
326533affcbSRobert Mustacchi 		    buflen);
327533affcbSRobert Mustacchi 		break;
328533affcbSRobert Mustacchi 	case NVME_LIST_LOGS_SOURCES:
329533affcbSRobert Mustacchi 		return (nvmeadm_bits_to_str(nvme_log_disc_sources(disc),
330533affcbSRobert Mustacchi 		    nvmeadm_log_sources, ARRAY_SIZE(nvmeadm_log_sources), buf,
331533affcbSRobert Mustacchi 		    buflen));
332533affcbSRobert Mustacchi 		break;
333533affcbSRobert Mustacchi 	case NVME_LIST_LOGS_KIND:
334533affcbSRobert Mustacchi 		switch (nvme_log_disc_kind(disc)) {
335533affcbSRobert Mustacchi 		case NVME_LOG_ID_MANDATORY:
336533affcbSRobert Mustacchi 			ret = strlcpy(buf, "mandatory", buflen);
337533affcbSRobert Mustacchi 			break;
338533affcbSRobert Mustacchi 		case NVME_LOG_ID_OPTIONAL:
339533affcbSRobert Mustacchi 			ret = strlcpy(buf, "optional", buflen);
340533affcbSRobert Mustacchi 			break;
341533affcbSRobert Mustacchi 		case NVME_LOG_ID_VENDOR_SPECIFIC:
342533affcbSRobert Mustacchi 			ret = strlcpy(buf, "vendor-specific", buflen);
343533affcbSRobert Mustacchi 			break;
344533affcbSRobert Mustacchi 		default:
345533affcbSRobert Mustacchi 			ret = snprintf(buf, buflen, "unknown (0x%x)",
346533affcbSRobert Mustacchi 			    nvme_log_disc_kind(disc));
347533affcbSRobert Mustacchi 			break;
348533affcbSRobert Mustacchi 		}
349533affcbSRobert Mustacchi 		break;
350533affcbSRobert Mustacchi 	default:
351533affcbSRobert Mustacchi 		warnx("internal programmer error: encountered unknown ofmt "
352533affcbSRobert Mustacchi 		    "argument id 0x%x", ofmt_arg->ofmt_id);
353533affcbSRobert Mustacchi 		abort();
354533affcbSRobert Mustacchi 	}
355533affcbSRobert Mustacchi 
356533affcbSRobert Mustacchi 	return (ret < buflen);
357533affcbSRobert Mustacchi }
358533affcbSRobert Mustacchi 
359533affcbSRobert Mustacchi const char *nvmeadm_list_logs_fields = "device,name,scope,fields,desc";
360533affcbSRobert Mustacchi const char *nvmeadm_list_logs_fields_impl = "device,name,scope,impl,fields,"
361533affcbSRobert Mustacchi 	"desc";
362533affcbSRobert Mustacchi const ofmt_field_t nvmeadm_list_logs_ofmt[] = {
363533affcbSRobert Mustacchi 	{ "DEVICE", 8, NVME_LIST_LOGS_DEVICE, nvmeadm_list_logs_ofmt_cb },
3646a5dded7SRobert Mustacchi 	{ "NAME", 18, NVME_LIST_LOGS_NAME, nvmeadm_list_logs_ofmt_cb },
365533affcbSRobert Mustacchi 	{ "DESC", 30, NVME_LIST_LOGS_DESC, nvmeadm_list_logs_ofmt_cb },
366533affcbSRobert Mustacchi 	{ "SCOPE", 14, NVME_LIST_LOGS_SCOPE, nvmeadm_list_logs_ofmt_cb },
367533affcbSRobert Mustacchi 	{ "FIELDS", 10, NVME_LIST_LOGS_FIELDS, nvmeadm_list_logs_ofmt_cb },
368533affcbSRobert Mustacchi 	{ "CSI", 6, NVME_LIST_LOGS_CSI, nvmeadm_list_logs_ofmt_cb },
369533affcbSRobert Mustacchi 	{ "LID", 6, NVME_LIST_LOGS_LID, nvmeadm_list_logs_ofmt_cb },
370533affcbSRobert Mustacchi 	{ "SIZE", 10, NVME_LIST_LOGS_SIZE, nvmeadm_list_logs_ofmt_cb },
371533affcbSRobert Mustacchi 	{ "MINSIZE", 10, NVME_LIST_LOGS_MINSIZE, nvmeadm_list_logs_ofmt_cb },
372533affcbSRobert Mustacchi 	{ "IMPL", 6, NVME_LIST_LOGS_IMPL, nvmeadm_list_logs_ofmt_cb },
373533affcbSRobert Mustacchi 	{ "SOURCES", 20, NVME_LIST_LOGS_SOURCES, nvmeadm_list_logs_ofmt_cb },
374533affcbSRobert Mustacchi 	{ "KIND", 16, NVME_LIST_LOGS_KIND, nvmeadm_list_logs_ofmt_cb },
375533affcbSRobert Mustacchi 	{ NULL, 0, 0, NULL }
376533affcbSRobert Mustacchi };
377533affcbSRobert Mustacchi 
378533affcbSRobert Mustacchi typedef enum {
379533affcbSRobert Mustacchi 	NVME_LIST_FEATS_DEVICE,
380533affcbSRobert Mustacchi 	NVME_LIST_FEATS_SHORT,
381533affcbSRobert Mustacchi 	NVME_LIST_FEATS_SPEC,
382533affcbSRobert Mustacchi 	NVME_LIST_FEATS_FID,
383533affcbSRobert Mustacchi 	NVME_LIST_FEATS_SCOPE,
384533affcbSRobert Mustacchi 	NVME_LIST_FEATS_KIND,
385533affcbSRobert Mustacchi 	NVME_LIST_FEATS_CSI,
386533affcbSRobert Mustacchi 	NVME_LIST_FEATS_FLAGS,
387533affcbSRobert Mustacchi 	NVME_LIST_FEATS_GET_IN,
388533affcbSRobert Mustacchi 	NVME_LIST_FEATS_SET_IN,
389533affcbSRobert Mustacchi 	NVME_LIST_FEATS_GET_OUT,
390533affcbSRobert Mustacchi 	NVME_LIST_FEATS_SET_OUT,
391533affcbSRobert Mustacchi 	NVME_LIST_FEATS_DATA_LEN,
392533affcbSRobert Mustacchi 	NVME_LIST_FEATS_IMPL
393533affcbSRobert Mustacchi } nvme_list_features_ofmt_field_t;
394533affcbSRobert Mustacchi 
395533affcbSRobert Mustacchi static const nvmeadm_bitstr_t nvmeadm_feat_scopes[] = {
396533affcbSRobert Mustacchi 	{ NVME_FEAT_SCOPE_CTRL, "controller" },
397533affcbSRobert Mustacchi 	{ NVME_FEAT_SCOPE_NS, "namespace" }
398533affcbSRobert Mustacchi };
399533affcbSRobert Mustacchi 
400533affcbSRobert Mustacchi static const nvmeadm_bitstr_t nvmeadm_feat_get_in[] = {
401533affcbSRobert Mustacchi 	{ NVME_GET_FEAT_F_CDW11, "cdw11" },
402533affcbSRobert Mustacchi 	{ NVME_GET_FEAT_F_DATA, "data" },
403533affcbSRobert Mustacchi 	{ NVME_GET_FEAT_F_NSID, "nsid" }
404533affcbSRobert Mustacchi };
405533affcbSRobert Mustacchi 
406533affcbSRobert Mustacchi static const nvmeadm_bitstr_t nvmeadm_feat_set_in[] = {
407533affcbSRobert Mustacchi 	{ NVME_SET_FEAT_F_CDW11, "cdw11" },
408533affcbSRobert Mustacchi 	{ NVME_SET_FEAT_F_CDW12, "cdw12" },
409533affcbSRobert Mustacchi 	{ NVME_SET_FEAT_F_CDW13, "cdw13" },
410533affcbSRobert Mustacchi 	{ NVME_SET_FEAT_F_CDW14, "cdw14" },
411533affcbSRobert Mustacchi 	{ NVME_SET_FEAT_F_CDW15, "cdw15" },
412533affcbSRobert Mustacchi 	{ NVME_SET_FEAT_F_DATA, "data" },
413533affcbSRobert Mustacchi 	{ NVME_SET_FEAT_F_NSID, "nsid" }
414533affcbSRobert Mustacchi };
415533affcbSRobert Mustacchi 
416533affcbSRobert Mustacchi static const nvmeadm_bitstr_t nvmeadm_feat_output[] = {
417533affcbSRobert Mustacchi 	{ NVME_FEAT_OUTPUT_CDW0, "cdw0" },
418533affcbSRobert Mustacchi 	{ NVME_FEAT_OUTPUT_DATA, "data" }
419533affcbSRobert Mustacchi };
420533affcbSRobert Mustacchi 
421533affcbSRobert Mustacchi static const nvmeadm_bitstr_t nvmeadm_feat_flags[] = {
422533affcbSRobert Mustacchi 	{ NVME_FEAT_F_GET_BCAST_NSID, "get-bcastns" },
423533affcbSRobert Mustacchi 	{ NVME_FEAT_F_SET_BCAST_NSID, "set-bcastns" }
424533affcbSRobert Mustacchi };
425533affcbSRobert Mustacchi 
426533affcbSRobert Mustacchi static const nvmeadm_bitstr_t nvmeadm_feat_csi[] = {
427533affcbSRobert Mustacchi 	{ NVME_FEAT_CSI_NVM, "nvm" }
428533affcbSRobert Mustacchi };
429533affcbSRobert Mustacchi 
430533affcbSRobert Mustacchi static boolean_t
nvmeadm_list_features_ofmt_cb(ofmt_arg_t * ofmt_arg,char * buf,uint_t buflen)431533affcbSRobert Mustacchi nvmeadm_list_features_ofmt_cb(ofmt_arg_t *ofmt_arg, char *buf, uint_t buflen)
432533affcbSRobert Mustacchi {
433533affcbSRobert Mustacchi 	const nvmeadm_list_features_ofmt_arg_t *nlfo = ofmt_arg->ofmt_cbarg;
434533affcbSRobert Mustacchi 	const nvme_feat_disc_t *feat = nlfo->nlfoa_feat;
435533affcbSRobert Mustacchi 	size_t ret;
436533affcbSRobert Mustacchi 
437533affcbSRobert Mustacchi 	switch (ofmt_arg->ofmt_id) {
438533affcbSRobert Mustacchi 	case NVME_LIST_FEATS_DEVICE:
439533affcbSRobert Mustacchi 		ret = strlcpy(buf, nlfo->nlfoa_name, buflen);
440533affcbSRobert Mustacchi 		break;
441533affcbSRobert Mustacchi 	case NVME_LIST_FEATS_SHORT:
442533affcbSRobert Mustacchi 		ret = strlcpy(buf, nvme_feat_disc_short(feat), buflen);
443533affcbSRobert Mustacchi 		break;
444533affcbSRobert Mustacchi 	case NVME_LIST_FEATS_SPEC:
445533affcbSRobert Mustacchi 		ret = strlcpy(buf, nvme_feat_disc_spec(feat), buflen);
446533affcbSRobert Mustacchi 		break;
447533affcbSRobert Mustacchi 	case NVME_LIST_FEATS_FID:
448533affcbSRobert Mustacchi 		ret = snprintf(buf, buflen, "0x%x", nvme_feat_disc_fid(feat));
449533affcbSRobert Mustacchi 		break;
450533affcbSRobert Mustacchi 	case NVME_LIST_FEATS_SCOPE:
451533affcbSRobert Mustacchi 		return (nvmeadm_bits_to_str(nvme_feat_disc_scope(feat),
452533affcbSRobert Mustacchi 		    nvmeadm_feat_scopes, ARRAY_SIZE(nvmeadm_feat_scopes), buf,
453533affcbSRobert Mustacchi 		    buflen));
454533affcbSRobert Mustacchi 	case NVME_LIST_FEATS_KIND:
455533affcbSRobert Mustacchi 		switch (nvme_feat_disc_kind(feat)) {
456533affcbSRobert Mustacchi 		case NVME_FEAT_MANDATORY:
457533affcbSRobert Mustacchi 			ret = strlcpy(buf, "mandatory", buflen);
458533affcbSRobert Mustacchi 			break;
459533affcbSRobert Mustacchi 		case NVME_FEAT_OPTIONAL:
460533affcbSRobert Mustacchi 			ret = strlcpy(buf, "optional", buflen);
461533affcbSRobert Mustacchi 			break;
462533affcbSRobert Mustacchi 		case NVME_FEAT_VENDOR_SPECIFIC:
463533affcbSRobert Mustacchi 			ret = strlcpy(buf, "vendor-specific", buflen);
464533affcbSRobert Mustacchi 			break;
465533affcbSRobert Mustacchi 		default:
466533affcbSRobert Mustacchi 			ret = snprintf(buf, buflen, "unknown (0x%x)",
467533affcbSRobert Mustacchi 			    nvme_feat_disc_kind(feat));
468533affcbSRobert Mustacchi 			break;
469533affcbSRobert Mustacchi 		}
470533affcbSRobert Mustacchi 		break;
471533affcbSRobert Mustacchi 	case NVME_LIST_FEATS_CSI:
472533affcbSRobert Mustacchi 		if (nvme_feat_disc_csi(feat) == NVME_FEAT_CSI_NONE) {
473533affcbSRobert Mustacchi 			ret = strlcpy(buf, "none", buflen);
474533affcbSRobert Mustacchi 			break;
475533affcbSRobert Mustacchi 		}
476533affcbSRobert Mustacchi 
477533affcbSRobert Mustacchi 		return (nvmeadm_bits_to_str(nvme_feat_disc_csi(feat),
478533affcbSRobert Mustacchi 		    nvmeadm_feat_csi, ARRAY_SIZE(nvmeadm_feat_csi), buf,
479533affcbSRobert Mustacchi 		    buflen));
480533affcbSRobert Mustacchi 	case NVME_LIST_FEATS_FLAGS:
481533affcbSRobert Mustacchi 		return (nvmeadm_bits_to_str(nvme_feat_disc_flags(feat),
482533affcbSRobert Mustacchi 		    nvmeadm_feat_flags, ARRAY_SIZE(nvmeadm_feat_flags), buf,
483533affcbSRobert Mustacchi 		    buflen));
484533affcbSRobert Mustacchi 	case NVME_LIST_FEATS_GET_IN:
485533affcbSRobert Mustacchi 		return (nvmeadm_bits_to_str(nvme_feat_disc_fields_get(feat),
486533affcbSRobert Mustacchi 		    nvmeadm_feat_get_in, ARRAY_SIZE(nvmeadm_feat_get_in), buf,
487533affcbSRobert Mustacchi 		    buflen));
488533affcbSRobert Mustacchi 	case NVME_LIST_FEATS_SET_IN:
489533affcbSRobert Mustacchi 		return (nvmeadm_bits_to_str(nvme_feat_disc_fields_set(feat),
490533affcbSRobert Mustacchi 		    nvmeadm_feat_set_in, ARRAY_SIZE(nvmeadm_feat_set_in), buf,
491533affcbSRobert Mustacchi 		    buflen));
492533affcbSRobert Mustacchi 	case NVME_LIST_FEATS_GET_OUT:
493533affcbSRobert Mustacchi 		return (nvmeadm_bits_to_str(nvme_feat_disc_output_get(feat),
494533affcbSRobert Mustacchi 		    nvmeadm_feat_output, ARRAY_SIZE(nvmeadm_feat_output), buf,
495533affcbSRobert Mustacchi 		    buflen));
496533affcbSRobert Mustacchi 	case NVME_LIST_FEATS_SET_OUT:
497533affcbSRobert Mustacchi 		return (nvmeadm_bits_to_str(nvme_feat_disc_output_set(feat),
498533affcbSRobert Mustacchi 		    nvmeadm_feat_output, ARRAY_SIZE(nvmeadm_feat_output), buf,
499533affcbSRobert Mustacchi 		    buflen));
500533affcbSRobert Mustacchi 	case NVME_LIST_FEATS_DATA_LEN:
501533affcbSRobert Mustacchi 		if (nvme_feat_disc_data_size(feat) == 0) {
502533affcbSRobert Mustacchi 			ret = strlcpy(buf, "-", buflen);
503533affcbSRobert Mustacchi 		} else {
504533affcbSRobert Mustacchi 			ret = snprintf(buf, buflen, "%" PRIu64,
505533affcbSRobert Mustacchi 			    nvme_feat_disc_data_size(feat));
506533affcbSRobert Mustacchi 		}
507533affcbSRobert Mustacchi 		break;
508533affcbSRobert Mustacchi 	case NVME_LIST_FEATS_IMPL:
509533affcbSRobert Mustacchi 		switch (nvme_feat_disc_impl(feat)) {
510533affcbSRobert Mustacchi 		case NVME_FEAT_IMPL_UNKNOWN:
511533affcbSRobert Mustacchi 			ret = strlcpy(buf, "unknown", buflen);
512533affcbSRobert Mustacchi 			break;
513533affcbSRobert Mustacchi 		case NVME_FEAT_IMPL_UNSUPPORTED:
514533affcbSRobert Mustacchi 			ret = strlcpy(buf, "no", buflen);
515533affcbSRobert Mustacchi 			break;
516533affcbSRobert Mustacchi 		case NVME_FEAT_IMPL_SUPPORTED:
517533affcbSRobert Mustacchi 			ret = strlcpy(buf, "yes", buflen);
518533affcbSRobert Mustacchi 			break;
519533affcbSRobert Mustacchi 		default:
520533affcbSRobert Mustacchi 			ret = snprintf(buf, buflen, "unknown (0x%x)",
521533affcbSRobert Mustacchi 			    nvme_feat_disc_impl(feat));
522533affcbSRobert Mustacchi 			break;
523533affcbSRobert Mustacchi 		}
524533affcbSRobert Mustacchi 		break;
525533affcbSRobert Mustacchi 	default:
526533affcbSRobert Mustacchi 		warnx("internal programmer error: encountered unknown ofmt "
527533affcbSRobert Mustacchi 		    "argument id 0x%x", ofmt_arg->ofmt_id);
528533affcbSRobert Mustacchi 		abort();
529533affcbSRobert Mustacchi 	}
530533affcbSRobert Mustacchi 
531533affcbSRobert Mustacchi 	return (ret < buflen);
532533affcbSRobert Mustacchi }
533533affcbSRobert Mustacchi 
534533affcbSRobert Mustacchi const char *nvmeadm_list_features_fields = "device,short,scope,impl,spec";
535533affcbSRobert Mustacchi const ofmt_field_t nvmeadm_list_features_ofmt[] = {
536533affcbSRobert Mustacchi 	{ "DEVICE", 8, NVME_LIST_FEATS_DEVICE, nvmeadm_list_features_ofmt_cb },
537533affcbSRobert Mustacchi 	{ "SHORT", 14, NVME_LIST_FEATS_SHORT, nvmeadm_list_features_ofmt_cb },
538533affcbSRobert Mustacchi 	{ "SPEC", 30, NVME_LIST_FEATS_SPEC, nvmeadm_list_features_ofmt_cb },
539533affcbSRobert Mustacchi 	{ "FID", 6, NVME_LIST_FEATS_FID, nvmeadm_list_features_ofmt_cb },
540533affcbSRobert Mustacchi 	{ "SCOPE", 14, NVME_LIST_FEATS_SCOPE, nvmeadm_list_features_ofmt_cb },
541533affcbSRobert Mustacchi 	{ "KIND", 16, NVME_LIST_FEATS_KIND, nvmeadm_list_features_ofmt_cb },
542533affcbSRobert Mustacchi 	{ "CSI", 6, NVME_LIST_FEATS_CSI, nvmeadm_list_features_ofmt_cb },
543533affcbSRobert Mustacchi 	{ "FLAGS", 14, NVME_LIST_FEATS_FLAGS, nvmeadm_list_features_ofmt_cb },
544533affcbSRobert Mustacchi 	{ "GET-IN", 14, NVME_LIST_FEATS_GET_IN, nvmeadm_list_features_ofmt_cb },
545533affcbSRobert Mustacchi 	{ "SET-IN", 14, NVME_LIST_FEATS_SET_IN, nvmeadm_list_features_ofmt_cb },
546533affcbSRobert Mustacchi 	{ "GET-OUT", 14, NVME_LIST_FEATS_GET_OUT,
547533affcbSRobert Mustacchi 	    nvmeadm_list_features_ofmt_cb },
548533affcbSRobert Mustacchi 	{ "SET-OUT", 14, NVME_LIST_FEATS_SET_OUT,
549533affcbSRobert Mustacchi 	    nvmeadm_list_features_ofmt_cb },
550533affcbSRobert Mustacchi 	{ "DATALEN", 8, NVME_LIST_FEATS_DATA_LEN,
551533affcbSRobert Mustacchi 	    nvmeadm_list_features_ofmt_cb },
552533affcbSRobert Mustacchi 	{ "IMPL", 8, NVME_LIST_FEATS_IMPL, nvmeadm_list_features_ofmt_cb },
553e4cc4004SRobert Mustacchi 	{ NULL, 0, 0, NULL }
554e4cc4004SRobert Mustacchi };
555