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