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 /*
18 * nvmeadm output formatting for ofmt based rendering
19 */
20
21 #include <strings.h>
22 #include <sys/sysmacros.h>
23 #include <err.h>
24
25 #include "nvmeadm.h"
26
27 typedef struct {
28 uint32_t nb_flag;
29 const char *nb_str;
30 } nvmeadm_bitstr_t;
31
32 static boolean_t
nvmeadm_bits_to_str(uint32_t val,const nvmeadm_bitstr_t * strs,size_t nstrs,char * buf,size_t buflen)33 nvmeadm_bits_to_str(uint32_t val, const nvmeadm_bitstr_t *strs, size_t nstrs,
34 char *buf, size_t buflen)
35 {
36 boolean_t comma = B_FALSE;
37
38 buf[0] = '\0';
39 for (size_t i = 0; i < nstrs; i++) {
40 if ((val & strs[i].nb_flag) != strs[i].nb_flag)
41 continue;
42 if (comma && strlcat(buf, ",", buflen) >= buflen)
43 return (B_FALSE);
44 if (strlcat(buf, strs[i].nb_str, buflen) >= buflen)
45 return (B_FALSE);
46 comma = true;
47 }
48
49 if (buf[0] == '\0') {
50 if (strlcat(buf, "--", buflen) >= buflen)
51 return (B_FALSE);
52 }
53
54 return (B_TRUE);
55 }
56
57 typedef enum nvme_list_ofmt_field {
58 NVME_LIST_MODEL,
59 NVME_LIST_SERIAL,
60 NVME_LIST_FWREV,
61 NVME_LIST_VERSION,
62 NVME_LIST_SIZE,
63 NVME_LIST_CAPACITY,
64 NVME_LIST_USED,
65 NVME_LIST_INSTANCE,
66 NVME_LIST_NAMESPACE,
67 NVME_LIST_DISK,
68 NVME_LIST_UNALLOC,
69 NVME_LIST_NS_STATE,
70 NVME_LIST_CTRLPATH,
71 NVME_LIST_NS_FORMAT,
72 NVME_LIST_NS_FMTID,
73 NVME_LIST_NS_FMTDS,
74 NVME_LIST_NS_FMTMS,
75 NVME_LIST_LOC_LOC,
76 NVME_LIST_LOC_CTLAP
77 } nvme_list_ofmt_field_t;
78
79 static boolean_t
nvmeadm_list_common_ofmt_cb(ofmt_arg_t * ofmt_arg,char * buf,uint_t buflen)80 nvmeadm_list_common_ofmt_cb(ofmt_arg_t *ofmt_arg, char *buf, uint_t buflen)
81 {
82 nvmeadm_list_ofmt_arg_t *list = ofmt_arg->ofmt_cbarg;
83 nvme_ctrl_info_t *ctrl = list->nloa_ctrl;
84 const nvme_version_t *vers;
85 char *path;
86 size_t ret;
87
88 switch (ofmt_arg->ofmt_id) {
89 case NVME_LIST_MODEL:
90 ret = strlcpy(buf, nvme_ctrl_info_model(ctrl), buflen);
91 break;
92 case NVME_LIST_SERIAL:
93 ret = strlcpy(buf, nvme_ctrl_info_serial(ctrl), buflen);
94 break;
95 case NVME_LIST_FWREV:
96 ret = strlcpy(buf, nvme_ctrl_info_fwrev(ctrl), buflen);
97 break;
98 case NVME_LIST_VERSION:
99 vers = nvme_ctrl_info_version(ctrl);
100 ret = snprintf(buf, buflen, "%u.%u", vers->v_major,
101 vers->v_minor);
102 break;
103 case NVME_LIST_INSTANCE:
104 ret = strlcpy(buf, list->nloa_name, buflen);
105 break;
106 case NVME_LIST_CTRLPATH:
107 if (list->nloa_dip == DI_NODE_NIL) {
108 return (B_FALSE);
109 }
110
111 path = di_devfs_path(list->nloa_dip);
112 if (path == NULL) {
113 return (B_FALSE);
114 }
115 ret = strlcat(buf, path, buflen);
116 di_devfs_path_free(path);
117 break;
118 default:
119 warnx("internal programmer error: encountered unknown ofmt "
120 "argument id 0x%x", ofmt_arg->ofmt_id);
121 abort();
122 }
123 if (ret >= buflen) {
124 return (B_FALSE);
125 }
126 return (B_TRUE);
127 }
128
129 static boolean_t
nvmeadm_list_ctrl_ofmt_cb(ofmt_arg_t * ofmt_arg,char * buf,uint_t buflen)130 nvmeadm_list_ctrl_ofmt_cb(ofmt_arg_t *ofmt_arg, char *buf, uint_t buflen)
131 {
132 nvmeadm_list_ofmt_arg_t *list = ofmt_arg->ofmt_cbarg;
133 nvme_ctrl_info_t *ctrl = list->nloa_ctrl;
134 nvme_uint128_t u128;
135 size_t ret;
136
137 switch (ofmt_arg->ofmt_id) {
138 case NVME_LIST_CAPACITY:
139 if (nvme_ctrl_info_cap(ctrl, &u128)) {
140 ret = nvme_snprint_uint128(buf, buflen, u128, 0, 0);
141 } else {
142 return (B_FALSE);
143 }
144 break;
145 case NVME_LIST_UNALLOC:
146 if (nvme_ctrl_info_unalloc_cap(ctrl, &u128)) {
147 ret = nvme_snprint_uint128(buf, buflen, u128, 0, 0);
148 } else {
149 return (B_FALSE);
150 }
151 break;
152 case NVME_LIST_LOC_LOC:
153 if (list->nloa_loc != NULL) {
154 ret = strlcpy(buf, list->nloa_loc, buflen);
155 } else {
156 ret = strlcpy(buf, "-", buflen);
157 }
158 break;
159 case NVME_LIST_LOC_CTLAP:
160 if (list->nloa_ap != NULL) {
161 ret = strlcpy(buf, list->nloa_ap, buflen);
162 } else {
163 ret = strlcpy(buf, "-", buflen);
164 }
165 break;
166 default:
167 warnx("internal programmer error: encountered unknown ofmt "
168 "argument id 0x%x", ofmt_arg->ofmt_id);
169 abort();
170 }
171
172 if (ret >= buflen) {
173 return (B_FALSE);
174 }
175 return (B_TRUE);
176 }
177
178 static boolean_t
nvmeadm_list_nsid_ofmt_cb(ofmt_arg_t * ofmt_arg,char * buf,uint_t buflen)179 nvmeadm_list_nsid_ofmt_cb(ofmt_arg_t *ofmt_arg, char *buf, uint_t buflen)
180 {
181 nvmeadm_list_ofmt_arg_t *list = ofmt_arg->ofmt_cbarg;
182 nvme_ns_info_t *ns = list->nloa_ns;
183 const nvme_nvm_lba_fmt_t *fmt = NULL;
184 const nvme_ns_disc_level_t level = nvme_ns_info_level(ns);
185 uint64_t val;
186 size_t ret;
187
188 (void) nvme_ns_info_curformat(ns, &fmt);
189
190 switch (ofmt_arg->ofmt_id) {
191 case NVME_LIST_NAMESPACE:
192 ret = snprintf(buf, buflen, "%u", nvme_ns_info_nsid(ns));
193 break;
194 case NVME_LIST_DISK:
195 if (list->nloa_disk != NULL) {
196 ret = strlcpy(buf, list->nloa_disk, buflen);
197 } else {
198 return (B_FALSE);
199 }
200 break;
201 case NVME_LIST_SIZE:
202 if (nvme_ns_info_size(ns, &val) && fmt != NULL) {
203 val *= nvme_nvm_lba_fmt_data_size(fmt);
204 ret = snprintf(buf, buflen, "%" PRIu64, val);
205 } else {
206 return (B_FALSE);
207 }
208 break;
209 case NVME_LIST_CAPACITY:
210 if (nvme_ns_info_size(ns, &val) && fmt != NULL) {
211 val *= nvme_nvm_lba_fmt_data_size(fmt);
212 ret = snprintf(buf, buflen, "%" PRIu64, val);
213 } else {
214 return (B_FALSE);
215 }
216 break;
217 case NVME_LIST_USED:
218 if (nvme_ns_info_size(ns, &val) && fmt != NULL) {
219 val *= nvme_nvm_lba_fmt_data_size(fmt);
220 ret = snprintf(buf, buflen, "%" PRIu64, val);
221 } else {
222 return (B_FALSE);
223 }
224 break;
225 case NVME_LIST_NS_STATE:
226 ret = strlcpy(buf, list->nloa_state, buflen);
227 break;
228 case NVME_LIST_NS_FORMAT:
229 if (fmt != NULL) {
230 ret = snprintf(buf, buflen, "%u+%u",
231 nvme_nvm_lba_fmt_data_size(fmt),
232 nvme_nvm_lba_fmt_meta_size(fmt));
233 } else if (level < NVME_NS_DISC_F_ACTIVE) {
234 ret = strlcpy(buf, "-", buflen);
235 } else {
236 return (B_FALSE);
237 }
238 break;
239 case NVME_LIST_NS_FMTID:
240 if (fmt != NULL) {
241 ret = snprintf(buf, buflen, "%u",
242 nvme_nvm_lba_fmt_id(fmt));
243 } else if (level < NVME_NS_DISC_F_ACTIVE) {
244 ret = strlcpy(buf, "-", buflen);
245 } else {
246 return (B_FALSE);
247 }
248 break;
249 case NVME_LIST_NS_FMTDS:
250 if (fmt != NULL) {
251 ret = snprintf(buf, buflen, "%u",
252 nvme_nvm_lba_fmt_data_size(fmt));
253 } else if (level < NVME_NS_DISC_F_ACTIVE) {
254 ret = strlcpy(buf, "-", buflen);
255 } else {
256 return (B_FALSE);
257 }
258 break;
259 case NVME_LIST_NS_FMTMS:
260 if (fmt != NULL) {
261 ret = snprintf(buf, buflen, "%u",
262 nvme_nvm_lba_fmt_meta_size(fmt));
263 } else if (level < NVME_NS_DISC_F_ACTIVE) {
264 ret = strlcpy(buf, "-", buflen);
265 } else {
266 return (B_FALSE);
267 }
268 break;
269 default:
270 warnx("internal programmer error: encountered unknown ofmt "
271 "argument id 0x%x", ofmt_arg->ofmt_id);
272 abort();
273 }
274
275 if (ret >= buflen) {
276 return (B_FALSE);
277 }
278 return (B_TRUE);
279 }
280
281 const ofmt_field_t nvmeadm_list_ctrl_ofmt[] = {
282 { "MODEL", 30, NVME_LIST_MODEL, nvmeadm_list_common_ofmt_cb },
283 { "SERIAL", 30, NVME_LIST_SERIAL, nvmeadm_list_common_ofmt_cb },
284 { "FWREV", 10, NVME_LIST_FWREV, nvmeadm_list_common_ofmt_cb },
285 { "VERSION", 10, NVME_LIST_VERSION, nvmeadm_list_common_ofmt_cb },
286 { "CAPACITY", 15, NVME_LIST_CAPACITY, nvmeadm_list_ctrl_ofmt_cb },
287 { "INSTANCE", 10, NVME_LIST_INSTANCE, nvmeadm_list_common_ofmt_cb },
288 { "UNALLOCATED", 15, NVME_LIST_UNALLOC, nvmeadm_list_ctrl_ofmt_cb },
289 { "CTRLPATH", 30, NVME_LIST_CTRLPATH, nvmeadm_list_common_ofmt_cb },
290 { NULL, 0, 0, NULL }
291 };
292
293 const ofmt_field_t nvmeadm_list_loc_ofmt[] = {
294 { "MODEL", 30, NVME_LIST_MODEL, nvmeadm_list_common_ofmt_cb },
295 { "SERIAL", 20, NVME_LIST_SERIAL, nvmeadm_list_common_ofmt_cb },
296 { "FWREV", 10, NVME_LIST_FWREV, nvmeadm_list_common_ofmt_cb },
297 { "VERSION", 10, NVME_LIST_VERSION, nvmeadm_list_common_ofmt_cb },
298 { "CAPACITY", 15, NVME_LIST_CAPACITY, nvmeadm_list_ctrl_ofmt_cb },
299 { "INSTANCE", 10, NVME_LIST_INSTANCE, nvmeadm_list_common_ofmt_cb },
300 { "UNALLOCATED", 15, NVME_LIST_UNALLOC, nvmeadm_list_ctrl_ofmt_cb },
301 { "CTRLPATH", 30, NVME_LIST_CTRLPATH, nvmeadm_list_common_ofmt_cb },
302 { "LOCATION", 15, NVME_LIST_LOC_LOC, nvmeadm_list_ctrl_ofmt_cb },
303 { "CTLAP", 10, NVME_LIST_LOC_CTLAP, nvmeadm_list_ctrl_ofmt_cb },
304 { NULL, 0, 0, NULL }
305 };
306
307 const ofmt_field_t nvmeadm_list_nsid_ofmt[] = {
308 { "MODEL", 30, NVME_LIST_MODEL, nvmeadm_list_common_ofmt_cb },
309 { "SERIAL", 30, NVME_LIST_SERIAL, nvmeadm_list_common_ofmt_cb },
310 { "FWREV", 10, NVME_LIST_FWREV, nvmeadm_list_common_ofmt_cb },
311 { "VERSION", 10, NVME_LIST_VERSION, nvmeadm_list_common_ofmt_cb },
312 { "SIZE", 15, NVME_LIST_SIZE, nvmeadm_list_nsid_ofmt_cb },
313 { "CAPACITY", 15, NVME_LIST_CAPACITY, nvmeadm_list_nsid_ofmt_cb },
314 { "USED", 15, NVME_LIST_USED, nvmeadm_list_nsid_ofmt_cb },
315 { "INSTANCE", 10, NVME_LIST_INSTANCE, nvmeadm_list_common_ofmt_cb },
316 { "NAMESPACE", 10, NVME_LIST_NAMESPACE, nvmeadm_list_nsid_ofmt_cb },
317 { "DISK", 15, NVME_LIST_DISK, nvmeadm_list_nsid_ofmt_cb },
318 { "NS-STATE", 10, NVME_LIST_NS_STATE, nvmeadm_list_nsid_ofmt_cb },
319 { "CTRLPATH", 30, NVME_LIST_CTRLPATH, nvmeadm_list_common_ofmt_cb },
320 { "FORMAT", 12, NVME_LIST_NS_FORMAT, nvmeadm_list_nsid_ofmt_cb },
321 { "FMTID", 8, NVME_LIST_NS_FMTID, nvmeadm_list_nsid_ofmt_cb },
322 { "FMTDS", 8, NVME_LIST_NS_FMTDS, nvmeadm_list_nsid_ofmt_cb },
323 { "FMTMS", 8, NVME_LIST_NS_FMTMS, nvmeadm_list_nsid_ofmt_cb },
324 { NULL, 0, 0, NULL }
325 };
326
327 typedef enum {
328 NVME_LIST_LOGS_DEVICE,
329 NVME_LIST_LOGS_NAME,
330 NVME_LIST_LOGS_DESC,
331 NVME_LIST_LOGS_SCOPE,
332 NVME_LIST_LOGS_FIELDS,
333 NVME_LIST_LOGS_CSI,
334 NVME_LIST_LOGS_LID,
335 NVME_LIST_LOGS_SIZE,
336 NVME_LIST_LOGS_MINSIZE,
337 NVME_LIST_LOGS_IMPL,
338 NVME_LIST_LOGS_SOURCES,
339 NVME_LIST_LOGS_KIND
340 } nvme_list_logs_ofmt_field_t;
341
342 static const nvmeadm_bitstr_t nvmeadm_log_scopes[] = {
343 { NVME_LOG_SCOPE_CTRL, "controller" },
344 { NVME_LOG_SCOPE_NVM, "nvm" },
345 { NVME_LOG_SCOPE_NS, "namespace" }
346 };
347
348 static const nvmeadm_bitstr_t nvmeadm_log_fields[] = {
349 { NVME_LOG_DISC_F_NEED_LSP, "lsp" },
350 { NVME_LOG_DISC_F_NEED_LSI, "lsi" },
351 { NVME_LOG_DISC_F_NEED_RAE, "rae" }
352 };
353
354 static const nvmeadm_bitstr_t nvmeadm_log_sources[] = {
355 { NVME_LOG_DISC_S_SPEC, "spec" },
356 { NVME_LOG_DISC_S_ID_CTRL, "identify-controller" },
357 { NVME_LOG_DISC_S_DB, "internal-db" },
358 { NVME_LOG_DISC_S_CMD, "command" }
359 };
360
361 static boolean_t
nvmeadm_list_logs_ofmt_cb(ofmt_arg_t * ofmt_arg,char * buf,uint_t buflen)362 nvmeadm_list_logs_ofmt_cb(ofmt_arg_t *ofmt_arg, char *buf, uint_t buflen)
363 {
364 const nvmeadm_list_logs_ofmt_arg_t *list = ofmt_arg->ofmt_cbarg;
365 const nvme_log_disc_t *disc = list->nlloa_disc;
366 uint64_t alloc;
367 size_t ret;
368 nvme_log_size_kind_t kind;
369
370 switch (ofmt_arg->ofmt_id) {
371 case NVME_LIST_LOGS_DEVICE:
372 ret = strlcpy(buf, list->nlloa_name, buflen);
373 break;
374 case NVME_LIST_LOGS_NAME:
375 ret = strlcpy(buf, nvme_log_disc_name(disc), buflen);
376 break;
377 case NVME_LIST_LOGS_DESC:
378 ret = strlcpy(buf, nvme_log_disc_desc(disc), buflen);
379 break;
380 case NVME_LIST_LOGS_SCOPE:
381 return (nvmeadm_bits_to_str(nvme_log_disc_scopes(disc),
382 nvmeadm_log_scopes, ARRAY_SIZE(nvmeadm_log_scopes), buf,
383 buflen));
384 case NVME_LIST_LOGS_FIELDS:
385 return (nvmeadm_bits_to_str(nvme_log_disc_fields(disc),
386 nvmeadm_log_fields, ARRAY_SIZE(nvmeadm_log_fields), buf,
387 buflen));
388 break;
389 case NVME_LIST_LOGS_CSI:
390 switch (nvme_log_disc_csi(disc)) {
391 case NVME_CSI_NVM:
392 ret = strlcpy(buf, "nvm", buflen);
393 break;
394 case NVME_CSI_KV:
395 ret = strlcpy(buf, "kv", buflen);
396 break;
397 case NVME_CSI_ZNS:
398 ret = strlcpy(buf, "zns", buflen);
399 break;
400 default:
401 ret = snprintf(buf, buflen, "unknown (0x%x)",
402 nvme_log_disc_csi(disc));
403 break;
404 }
405 break;
406 case NVME_LIST_LOGS_LID:
407 ret = snprintf(buf, buflen, "0x%x", nvme_log_disc_lid(disc));
408 break;
409 case NVME_LIST_LOGS_SIZE:
410 case NVME_LIST_LOGS_MINSIZE:
411 kind = nvme_log_disc_size(disc, &alloc);
412
413 if (kind == NVME_LOG_SIZE_K_UNKNOWN) {
414 return (B_FALSE);
415 }
416
417 if (kind == NVME_LOG_SIZE_K_VAR &&
418 ofmt_arg->ofmt_id == NVME_LIST_LOGS_SIZE) {
419 return (B_FALSE);
420 }
421
422 ret = snprintf(buf, buflen, "%" PRIu64, alloc);
423 break;
424 case NVME_LIST_LOGS_IMPL:
425 ret = strlcpy(buf, nvme_log_disc_impl(disc) ? "yes" : "no",
426 buflen);
427 break;
428 case NVME_LIST_LOGS_SOURCES:
429 return (nvmeadm_bits_to_str(nvme_log_disc_sources(disc),
430 nvmeadm_log_sources, ARRAY_SIZE(nvmeadm_log_sources), buf,
431 buflen));
432 break;
433 case NVME_LIST_LOGS_KIND:
434 switch (nvme_log_disc_kind(disc)) {
435 case NVME_LOG_ID_MANDATORY:
436 ret = strlcpy(buf, "mandatory", buflen);
437 break;
438 case NVME_LOG_ID_OPTIONAL:
439 ret = strlcpy(buf, "optional", buflen);
440 break;
441 case NVME_LOG_ID_VENDOR_SPECIFIC:
442 ret = strlcpy(buf, "vendor-specific", buflen);
443 break;
444 default:
445 ret = snprintf(buf, buflen, "unknown (0x%x)",
446 nvme_log_disc_kind(disc));
447 break;
448 }
449 break;
450 default:
451 warnx("internal programmer error: encountered unknown ofmt "
452 "argument id 0x%x", ofmt_arg->ofmt_id);
453 abort();
454 }
455
456 return (ret < buflen);
457 }
458
459 const char *nvmeadm_list_logs_fields = "device,name,scope,fields,desc";
460 const char *nvmeadm_list_logs_fields_impl = "device,name,scope,impl,fields,"
461 "desc";
462 const ofmt_field_t nvmeadm_list_logs_ofmt[] = {
463 { "DEVICE", 8, NVME_LIST_LOGS_DEVICE, nvmeadm_list_logs_ofmt_cb },
464 { "NAME", 18, NVME_LIST_LOGS_NAME, nvmeadm_list_logs_ofmt_cb },
465 { "DESC", 30, NVME_LIST_LOGS_DESC, nvmeadm_list_logs_ofmt_cb },
466 { "SCOPE", 14, NVME_LIST_LOGS_SCOPE, nvmeadm_list_logs_ofmt_cb },
467 { "FIELDS", 10, NVME_LIST_LOGS_FIELDS, nvmeadm_list_logs_ofmt_cb },
468 { "CSI", 6, NVME_LIST_LOGS_CSI, nvmeadm_list_logs_ofmt_cb },
469 { "LID", 6, NVME_LIST_LOGS_LID, nvmeadm_list_logs_ofmt_cb },
470 { "SIZE", 10, NVME_LIST_LOGS_SIZE, nvmeadm_list_logs_ofmt_cb },
471 { "MINSIZE", 10, NVME_LIST_LOGS_MINSIZE, nvmeadm_list_logs_ofmt_cb },
472 { "IMPL", 6, NVME_LIST_LOGS_IMPL, nvmeadm_list_logs_ofmt_cb },
473 { "SOURCES", 20, NVME_LIST_LOGS_SOURCES, nvmeadm_list_logs_ofmt_cb },
474 { "KIND", 16, NVME_LIST_LOGS_KIND, nvmeadm_list_logs_ofmt_cb },
475 { NULL, 0, 0, NULL }
476 };
477
478 typedef enum {
479 NVME_LIST_FEATS_DEVICE,
480 NVME_LIST_FEATS_SHORT,
481 NVME_LIST_FEATS_SPEC,
482 NVME_LIST_FEATS_FID,
483 NVME_LIST_FEATS_SCOPE,
484 NVME_LIST_FEATS_KIND,
485 NVME_LIST_FEATS_CSI,
486 NVME_LIST_FEATS_FLAGS,
487 NVME_LIST_FEATS_GET_IN,
488 NVME_LIST_FEATS_SET_IN,
489 NVME_LIST_FEATS_GET_OUT,
490 NVME_LIST_FEATS_SET_OUT,
491 NVME_LIST_FEATS_DATA_LEN,
492 NVME_LIST_FEATS_IMPL
493 } nvme_list_features_ofmt_field_t;
494
495 static const nvmeadm_bitstr_t nvmeadm_feat_scopes[] = {
496 { NVME_FEAT_SCOPE_CTRL, "controller" },
497 { NVME_FEAT_SCOPE_NS, "namespace" }
498 };
499
500 static const nvmeadm_bitstr_t nvmeadm_feat_get_in[] = {
501 { NVME_GET_FEAT_F_CDW11, "cdw11" },
502 { NVME_GET_FEAT_F_DATA, "data" },
503 { NVME_GET_FEAT_F_NSID, "nsid" }
504 };
505
506 static const nvmeadm_bitstr_t nvmeadm_feat_set_in[] = {
507 { NVME_SET_FEAT_F_CDW11, "cdw11" },
508 { NVME_SET_FEAT_F_CDW12, "cdw12" },
509 { NVME_SET_FEAT_F_CDW13, "cdw13" },
510 { NVME_SET_FEAT_F_CDW14, "cdw14" },
511 { NVME_SET_FEAT_F_CDW15, "cdw15" },
512 { NVME_SET_FEAT_F_DATA, "data" },
513 { NVME_SET_FEAT_F_NSID, "nsid" }
514 };
515
516 static const nvmeadm_bitstr_t nvmeadm_feat_output[] = {
517 { NVME_FEAT_OUTPUT_CDW0, "cdw0" },
518 { NVME_FEAT_OUTPUT_DATA, "data" }
519 };
520
521 static const nvmeadm_bitstr_t nvmeadm_feat_flags[] = {
522 { NVME_FEAT_F_GET_BCAST_NSID, "get-bcastns" },
523 { NVME_FEAT_F_SET_BCAST_NSID, "set-bcastns" }
524 };
525
526 static const nvmeadm_bitstr_t nvmeadm_feat_csi[] = {
527 { NVME_FEAT_CSI_NVM, "nvm" }
528 };
529
530 static boolean_t
nvmeadm_list_features_ofmt_cb(ofmt_arg_t * ofmt_arg,char * buf,uint_t buflen)531 nvmeadm_list_features_ofmt_cb(ofmt_arg_t *ofmt_arg, char *buf, uint_t buflen)
532 {
533 const nvmeadm_list_features_ofmt_arg_t *nlfo = ofmt_arg->ofmt_cbarg;
534 const nvme_feat_disc_t *feat = nlfo->nlfoa_feat;
535 size_t ret;
536
537 switch (ofmt_arg->ofmt_id) {
538 case NVME_LIST_FEATS_DEVICE:
539 ret = strlcpy(buf, nlfo->nlfoa_name, buflen);
540 break;
541 case NVME_LIST_FEATS_SHORT:
542 ret = strlcpy(buf, nvme_feat_disc_short(feat), buflen);
543 break;
544 case NVME_LIST_FEATS_SPEC:
545 ret = strlcpy(buf, nvme_feat_disc_spec(feat), buflen);
546 break;
547 case NVME_LIST_FEATS_FID:
548 ret = snprintf(buf, buflen, "0x%x", nvme_feat_disc_fid(feat));
549 break;
550 case NVME_LIST_FEATS_SCOPE:
551 return (nvmeadm_bits_to_str(nvme_feat_disc_scope(feat),
552 nvmeadm_feat_scopes, ARRAY_SIZE(nvmeadm_feat_scopes), buf,
553 buflen));
554 case NVME_LIST_FEATS_KIND:
555 switch (nvme_feat_disc_kind(feat)) {
556 case NVME_FEAT_MANDATORY:
557 ret = strlcpy(buf, "mandatory", buflen);
558 break;
559 case NVME_FEAT_OPTIONAL:
560 ret = strlcpy(buf, "optional", buflen);
561 break;
562 case NVME_FEAT_VENDOR_SPECIFIC:
563 ret = strlcpy(buf, "vendor-specific", buflen);
564 break;
565 default:
566 ret = snprintf(buf, buflen, "unknown (0x%x)",
567 nvme_feat_disc_kind(feat));
568 break;
569 }
570 break;
571 case NVME_LIST_FEATS_CSI:
572 if (nvme_feat_disc_csi(feat) == NVME_FEAT_CSI_NONE) {
573 ret = strlcpy(buf, "none", buflen);
574 break;
575 }
576
577 return (nvmeadm_bits_to_str(nvme_feat_disc_csi(feat),
578 nvmeadm_feat_csi, ARRAY_SIZE(nvmeadm_feat_csi), buf,
579 buflen));
580 case NVME_LIST_FEATS_FLAGS:
581 return (nvmeadm_bits_to_str(nvme_feat_disc_flags(feat),
582 nvmeadm_feat_flags, ARRAY_SIZE(nvmeadm_feat_flags), buf,
583 buflen));
584 case NVME_LIST_FEATS_GET_IN:
585 return (nvmeadm_bits_to_str(nvme_feat_disc_fields_get(feat),
586 nvmeadm_feat_get_in, ARRAY_SIZE(nvmeadm_feat_get_in), buf,
587 buflen));
588 case NVME_LIST_FEATS_SET_IN:
589 return (nvmeadm_bits_to_str(nvme_feat_disc_fields_set(feat),
590 nvmeadm_feat_set_in, ARRAY_SIZE(nvmeadm_feat_set_in), buf,
591 buflen));
592 case NVME_LIST_FEATS_GET_OUT:
593 return (nvmeadm_bits_to_str(nvme_feat_disc_output_get(feat),
594 nvmeadm_feat_output, ARRAY_SIZE(nvmeadm_feat_output), buf,
595 buflen));
596 case NVME_LIST_FEATS_SET_OUT:
597 return (nvmeadm_bits_to_str(nvme_feat_disc_output_set(feat),
598 nvmeadm_feat_output, ARRAY_SIZE(nvmeadm_feat_output), buf,
599 buflen));
600 case NVME_LIST_FEATS_DATA_LEN:
601 if (nvme_feat_disc_data_size(feat) == 0) {
602 ret = strlcpy(buf, "-", buflen);
603 } else {
604 ret = snprintf(buf, buflen, "%" PRIu64,
605 nvme_feat_disc_data_size(feat));
606 }
607 break;
608 case NVME_LIST_FEATS_IMPL:
609 switch (nvme_feat_disc_impl(feat)) {
610 case NVME_FEAT_IMPL_UNKNOWN:
611 ret = strlcpy(buf, "unknown", buflen);
612 break;
613 case NVME_FEAT_IMPL_UNSUPPORTED:
614 ret = strlcpy(buf, "no", buflen);
615 break;
616 case NVME_FEAT_IMPL_SUPPORTED:
617 ret = strlcpy(buf, "yes", buflen);
618 break;
619 default:
620 ret = snprintf(buf, buflen, "unknown (0x%x)",
621 nvme_feat_disc_impl(feat));
622 break;
623 }
624 break;
625 default:
626 warnx("internal programmer error: encountered unknown ofmt "
627 "argument id 0x%x", ofmt_arg->ofmt_id);
628 abort();
629 }
630
631 return (ret < buflen);
632 }
633
634 const char *nvmeadm_list_features_fields = "device,short,scope,impl,spec";
635 const ofmt_field_t nvmeadm_list_features_ofmt[] = {
636 { "DEVICE", 8, NVME_LIST_FEATS_DEVICE, nvmeadm_list_features_ofmt_cb },
637 { "SHORT", 14, NVME_LIST_FEATS_SHORT, nvmeadm_list_features_ofmt_cb },
638 { "SPEC", 30, NVME_LIST_FEATS_SPEC, nvmeadm_list_features_ofmt_cb },
639 { "FID", 6, NVME_LIST_FEATS_FID, nvmeadm_list_features_ofmt_cb },
640 { "SCOPE", 14, NVME_LIST_FEATS_SCOPE, nvmeadm_list_features_ofmt_cb },
641 { "KIND", 16, NVME_LIST_FEATS_KIND, nvmeadm_list_features_ofmt_cb },
642 { "CSI", 6, NVME_LIST_FEATS_CSI, nvmeadm_list_features_ofmt_cb },
643 { "FLAGS", 14, NVME_LIST_FEATS_FLAGS, nvmeadm_list_features_ofmt_cb },
644 { "GET-IN", 14, NVME_LIST_FEATS_GET_IN, nvmeadm_list_features_ofmt_cb },
645 { "SET-IN", 14, NVME_LIST_FEATS_SET_IN, nvmeadm_list_features_ofmt_cb },
646 { "GET-OUT", 14, NVME_LIST_FEATS_GET_OUT,
647 nvmeadm_list_features_ofmt_cb },
648 { "SET-OUT", 14, NVME_LIST_FEATS_SET_OUT,
649 nvmeadm_list_features_ofmt_cb },
650 { "DATALEN", 8, NVME_LIST_FEATS_DATA_LEN,
651 nvmeadm_list_features_ofmt_cb },
652 { "IMPL", 8, NVME_LIST_FEATS_IMPL, nvmeadm_list_features_ofmt_cb },
653 { NULL, 0, 0, NULL }
654 };
655