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