xref: /spdk/app/spdk_nvme_identify/identify.c (revision 57fd99b91e71a4baa5543e19ff83958dc99d4dac)
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright (C) 2015 Intel Corporation. All rights reserved.
3  *   Copyright (c) 2020 Mellanox Technologies LTD. All rights reserved.
4  */
5 
6 #include "spdk/stdinc.h"
7 
8 #include "spdk/endian.h"
9 #include "spdk/log.h"
10 #include "spdk/nvme.h"
11 #include "spdk/vmd.h"
12 #include "spdk/nvme_ocssd.h"
13 #include "spdk/nvme_zns.h"
14 #include "spdk/env.h"
15 #include "spdk/nvme_intel.h"
16 #include "spdk/nvmf_spec.h"
17 #include "spdk/pci_ids.h"
18 #include "spdk/string.h"
19 #include "spdk/util.h"
20 #include "spdk/uuid.h"
21 #include "spdk/sock.h"
22 
23 #define MAX_DISCOVERY_LOG_ENTRIES	((uint64_t)1000)
24 
25 #define NUM_CHUNK_INFO_ENTRIES		8
26 #define MAX_OCSSD_PU			128
27 #define MAX_ZONE_DESC_ENTRIES		8
28 
29 #define FDP_LOG_PAGE_SIZE		4096
30 
31 static int outstanding_commands;
32 
33 struct feature {
34 	uint32_t result;
35 	bool valid;
36 };
37 
38 static struct feature features[256] = {};
39 
40 static struct spdk_nvme_error_information_entry error_page[256];
41 
42 static struct spdk_nvme_health_information_page health_page;
43 
44 static struct spdk_nvme_firmware_page firmware_page;
45 
46 static struct spdk_nvme_ana_page *g_ana_log_page;
47 
48 static struct spdk_nvme_ana_group_descriptor *g_copied_ana_desc;
49 
50 static size_t g_ana_log_page_size;
51 
52 static size_t g_fdp_cfg_log_page_size;
53 
54 static size_t g_fdp_ruhu_log_page_size;
55 
56 static size_t g_fdp_events_log_page_size;
57 
58 static struct spdk_nvme_fdp_stats_log_page g_fdp_stats_log_page;
59 
60 static struct spdk_nvme_fdp_cfg_log_page *g_fdp_cfg_log_page;
61 
62 static struct spdk_nvme_fdp_ruhu_log_page *g_fdp_ruhu_log_page;
63 
64 static struct spdk_nvme_fdp_events_log_page *g_fdp_events_log_page;
65 
66 static struct spdk_nvme_cmds_and_effect_log_page cmd_effects_log_page;
67 
68 static struct spdk_nvme_intel_smart_information_page intel_smart_page;
69 
70 static struct spdk_nvme_intel_temperature_page intel_temperature_page;
71 
72 static struct spdk_nvme_intel_marketing_description_page intel_md_page;
73 
74 static struct spdk_nvmf_discovery_log_page *g_discovery_page;
75 static size_t g_discovery_page_size;
76 static uint64_t g_discovery_page_numrec;
77 
78 static struct spdk_ocssd_geometry_data geometry_data;
79 
80 static struct spdk_ocssd_chunk_information_entry *g_ocssd_chunk_info_page;
81 
82 static int64_t g_zone_report_limit = 8;
83 
84 static bool g_hex_dump = false;
85 
86 static int g_shm_id = -1;
87 
88 static int g_dpdk_mem = 0;
89 
90 static bool g_dpdk_mem_single_seg = false;
91 
92 static int g_main_core = 0;
93 
94 static char g_core_mask[20] = "0x1";
95 
96 static struct spdk_nvme_transport_id g_trid;
97 static char g_hostnqn[SPDK_NVMF_NQN_MAX_LEN + 1];
98 
99 static int g_controllers_found = 0;
100 
101 static bool g_vmd = false;
102 
103 static bool g_ocssd_verbose = false;
104 
105 static struct spdk_nvme_detach_ctx *g_detach_ctx = NULL;
106 
107 static const char *g_iova_mode;
108 
109 static void
110 hex_dump(const void *data, size_t size)
111 {
112 	size_t offset = 0, i;
113 	const uint8_t *bytes = data;
114 
115 	while (size) {
116 		printf("%08zX:", offset);
117 
118 		for (i = 0; i < 16; i++) {
119 			if (i == 8) {
120 				printf("-");
121 			} else {
122 				printf(" ");
123 			}
124 
125 			if (i < size) {
126 				printf("%02X", bytes[offset + i]);
127 			} else {
128 				printf("  ");
129 			}
130 		}
131 
132 		printf("  ");
133 
134 		for (i = 0; i < 16; i++) {
135 			if (i < size) {
136 				if (bytes[offset + i] > 0x20 && bytes[offset + i] < 0x7F) {
137 					printf("%c", bytes[offset + i]);
138 				} else {
139 					printf(".");
140 				}
141 			}
142 		}
143 
144 		printf("\n");
145 
146 		offset += 16;
147 		if (size > 16) {
148 			size -= 16;
149 		} else {
150 			break;
151 		}
152 	}
153 }
154 
155 static void
156 get_feature_completion(void *cb_arg, const struct spdk_nvme_cpl *cpl)
157 {
158 	struct feature *feature = cb_arg;
159 	int fid = feature - features;
160 
161 	if (spdk_nvme_cpl_is_error(cpl)) {
162 		printf("get_feature(0x%02X) failed\n", fid);
163 	} else {
164 		feature->result = cpl->cdw0;
165 		feature->valid = true;
166 	}
167 	outstanding_commands--;
168 }
169 
170 static void
171 get_log_page_completion(void *cb_arg, const struct spdk_nvme_cpl *cpl)
172 {
173 	if (spdk_nvme_cpl_is_error(cpl)) {
174 		printf("get log page failed\n");
175 	}
176 	outstanding_commands--;
177 }
178 
179 static void
180 get_ocssd_geometry_completion(void *cb_arg, const struct spdk_nvme_cpl *cpl)
181 {
182 	if (spdk_nvme_cpl_is_error(cpl)) {
183 		printf("get ocssd geometry failed\n");
184 	}
185 	outstanding_commands--;
186 }
187 
188 static void
189 get_zns_zone_report_completion(void *cb_arg, const struct spdk_nvme_cpl *cpl)
190 {
191 	if (spdk_nvme_cpl_is_error(cpl)) {
192 		printf("get zns zone report failed\n");
193 	}
194 
195 	outstanding_commands--;
196 }
197 
198 static int
199 get_feature(struct spdk_nvme_ctrlr *ctrlr, uint8_t fid, uint32_t cdw11, uint32_t nsid)
200 {
201 	struct spdk_nvme_cmd cmd = {};
202 	struct feature *feature = &features[fid];
203 
204 	feature->valid = false;
205 
206 	cmd.opc = SPDK_NVME_OPC_GET_FEATURES;
207 	cmd.cdw10_bits.get_features.fid = fid;
208 	cmd.cdw11 = cdw11;
209 	cmd.nsid = nsid;
210 
211 	return spdk_nvme_ctrlr_cmd_admin_raw(ctrlr, &cmd, NULL, 0, get_feature_completion, feature);
212 }
213 
214 static void
215 get_features(struct spdk_nvme_ctrlr *ctrlr, uint8_t *features_to_get, size_t num_features,
216 	     uint32_t nsid)
217 {
218 	size_t i;
219 	uint32_t cdw11;
220 
221 	/* Submit only one GET FEATURES at a time. There is a known issue #1799
222 	 * with Google Cloud Platform NVMe SSDs that do not handle overlapped
223 	 * GET FEATURES commands correctly.
224 	 */
225 	outstanding_commands = 0;
226 	for (i = 0; i < num_features; i++) {
227 		cdw11 = 0;
228 		if (!spdk_nvme_ctrlr_is_ocssd_supported(ctrlr) &&
229 		    features_to_get[i] == SPDK_OCSSD_FEAT_MEDIA_FEEDBACK) {
230 			continue;
231 		}
232 		if (features_to_get[i] == SPDK_NVME_FEAT_FDP) {
233 			const struct spdk_nvme_ctrlr_data *cdata = spdk_nvme_ctrlr_get_data(ctrlr);
234 			struct spdk_nvme_ns *ns = spdk_nvme_ctrlr_get_ns(ctrlr, nsid);
235 			const struct spdk_nvme_ns_data *nsdata = spdk_nvme_ns_get_data(ns);
236 
237 			if (!cdata->ctratt.bits.fdps) {
238 				continue;
239 			} else {
240 				cdw11 = nsdata->endgid;
241 				/* Endurance group scope */
242 				nsid = 0;
243 			}
244 		}
245 		if (get_feature(ctrlr, features_to_get[i], cdw11, nsid) == 0) {
246 			outstanding_commands++;
247 		} else {
248 			printf("get_feature(0x%02X) failed to submit command\n", features_to_get[i]);
249 		}
250 
251 		while (outstanding_commands) {
252 			spdk_nvme_ctrlr_process_admin_completions(ctrlr);
253 		}
254 	}
255 
256 }
257 
258 static void
259 get_ctrlr_features(struct spdk_nvme_ctrlr *ctrlr)
260 {
261 	uint8_t features_to_get[] = {
262 		SPDK_NVME_FEAT_ARBITRATION,
263 		SPDK_NVME_FEAT_POWER_MANAGEMENT,
264 		SPDK_NVME_FEAT_TEMPERATURE_THRESHOLD,
265 		SPDK_NVME_FEAT_NUMBER_OF_QUEUES,
266 		SPDK_OCSSD_FEAT_MEDIA_FEEDBACK,
267 	};
268 
269 	get_features(ctrlr, features_to_get, SPDK_COUNTOF(features_to_get), 0);
270 }
271 
272 static void
273 get_ns_features(struct spdk_nvme_ctrlr *ctrlr, uint32_t nsid)
274 {
275 	uint8_t features_to_get[] = {
276 		SPDK_NVME_FEAT_ERROR_RECOVERY,
277 		SPDK_NVME_FEAT_FDP,
278 	};
279 
280 	get_features(ctrlr, features_to_get, SPDK_COUNTOF(features_to_get), nsid);
281 }
282 
283 static int
284 get_error_log_page(struct spdk_nvme_ctrlr *ctrlr)
285 {
286 	const struct spdk_nvme_ctrlr_data *cdata;
287 
288 	cdata = spdk_nvme_ctrlr_get_data(ctrlr);
289 
290 	if (spdk_nvme_ctrlr_cmd_get_log_page(ctrlr, SPDK_NVME_LOG_ERROR,
291 					     SPDK_NVME_GLOBAL_NS_TAG, error_page,
292 					     sizeof(*error_page) * (cdata->elpe + 1),
293 					     0,
294 					     get_log_page_completion, NULL)) {
295 		printf("spdk_nvme_ctrlr_cmd_get_log_page() failed\n");
296 		exit(1);
297 	}
298 
299 	return 0;
300 }
301 
302 static int
303 get_health_log_page(struct spdk_nvme_ctrlr *ctrlr)
304 {
305 	if (spdk_nvme_ctrlr_cmd_get_log_page(ctrlr, SPDK_NVME_LOG_HEALTH_INFORMATION,
306 					     SPDK_NVME_GLOBAL_NS_TAG, &health_page, sizeof(health_page), 0, get_log_page_completion, NULL)) {
307 		printf("spdk_nvme_ctrlr_cmd_get_log_page() failed\n");
308 		exit(1);
309 	}
310 
311 	return 0;
312 }
313 
314 static int
315 get_firmware_log_page(struct spdk_nvme_ctrlr *ctrlr)
316 {
317 	if (spdk_nvme_ctrlr_cmd_get_log_page(ctrlr, SPDK_NVME_LOG_FIRMWARE_SLOT,
318 					     SPDK_NVME_GLOBAL_NS_TAG, &firmware_page, sizeof(firmware_page), 0, get_log_page_completion, NULL)) {
319 		printf("spdk_nvme_ctrlr_cmd_get_log_page() failed\n");
320 		exit(1);
321 	}
322 
323 	return 0;
324 }
325 
326 static int
327 get_ana_log_page(struct spdk_nvme_ctrlr *ctrlr)
328 {
329 	if (spdk_nvme_ctrlr_cmd_get_log_page(ctrlr, SPDK_NVME_LOG_ASYMMETRIC_NAMESPACE_ACCESS,
330 					     SPDK_NVME_GLOBAL_NS_TAG, g_ana_log_page, g_ana_log_page_size, 0,
331 					     get_log_page_completion, NULL)) {
332 		printf("spdk_nvme_ctrlr_cmd_get_log_page() failed\n");
333 		exit(1);
334 	}
335 
336 	return 0;
337 }
338 
339 static int
340 get_cmd_effects_log_page(struct spdk_nvme_ctrlr *ctrlr)
341 {
342 	if (spdk_nvme_ctrlr_cmd_get_log_page(ctrlr, SPDK_NVME_LOG_COMMAND_EFFECTS_LOG,
343 					     SPDK_NVME_GLOBAL_NS_TAG, &cmd_effects_log_page, sizeof(cmd_effects_log_page), 0,
344 					     get_log_page_completion, NULL)) {
345 		printf("spdk_nvme_ctrlr_cmd_get_log_page() failed\n");
346 		exit(1);
347 	}
348 
349 	return 0;
350 }
351 
352 static int
353 get_intel_smart_log_page(struct spdk_nvme_ctrlr *ctrlr)
354 {
355 	if (spdk_nvme_ctrlr_cmd_get_log_page(ctrlr, SPDK_NVME_INTEL_LOG_SMART, SPDK_NVME_GLOBAL_NS_TAG,
356 					     &intel_smart_page, sizeof(intel_smart_page), 0, get_log_page_completion, NULL)) {
357 		printf("spdk_nvme_ctrlr_cmd_get_log_page() failed\n");
358 		exit(1);
359 	}
360 
361 	return 0;
362 }
363 
364 static int
365 get_intel_temperature_log_page(struct spdk_nvme_ctrlr *ctrlr)
366 {
367 	if (spdk_nvme_ctrlr_cmd_get_log_page(ctrlr, SPDK_NVME_INTEL_LOG_TEMPERATURE,
368 					     SPDK_NVME_GLOBAL_NS_TAG, &intel_temperature_page, sizeof(intel_temperature_page), 0,
369 					     get_log_page_completion, NULL)) {
370 		printf("spdk_nvme_ctrlr_cmd_get_log_page() failed\n");
371 		exit(1);
372 	}
373 	return 0;
374 }
375 
376 static int
377 get_intel_md_log_page(struct spdk_nvme_ctrlr *ctrlr)
378 {
379 	if (spdk_nvme_ctrlr_cmd_get_log_page(ctrlr, SPDK_NVME_INTEL_MARKETING_DESCRIPTION,
380 					     SPDK_NVME_GLOBAL_NS_TAG, &intel_md_page, sizeof(intel_md_page), 0,
381 					     get_log_page_completion, NULL)) {
382 		printf("spdk_nvme_ctrlr_cmd_get_log_page() failed\n");
383 		exit(1);
384 	}
385 	return 0;
386 }
387 
388 static void
389 get_discovery_log_page_cb(void *ctx, int rc, const struct spdk_nvme_cpl *cpl,
390 			  struct spdk_nvmf_discovery_log_page *log_page)
391 {
392 	if (rc || spdk_nvme_cpl_is_error(cpl)) {
393 		printf("get discovery log page failed\n");
394 		exit(1);
395 	}
396 
397 	g_discovery_page = log_page;
398 	g_discovery_page_numrec = from_le64(&log_page->numrec);
399 	g_discovery_page_size = sizeof(struct spdk_nvmf_discovery_log_page);
400 	g_discovery_page_size += g_discovery_page_numrec *
401 				 sizeof(struct spdk_nvmf_discovery_log_page_entry);
402 	outstanding_commands--;
403 }
404 
405 static int
406 get_discovery_log_page(struct spdk_nvme_ctrlr *ctrlr)
407 {
408 	return spdk_nvme_ctrlr_get_discovery_log_page(ctrlr, get_discovery_log_page_cb, NULL);
409 }
410 
411 static void
412 get_log_pages(struct spdk_nvme_ctrlr *ctrlr)
413 {
414 	const struct spdk_nvme_ctrlr_data *cdata;
415 	outstanding_commands = 0;
416 	bool is_discovery = spdk_nvme_ctrlr_is_discovery(ctrlr);
417 	uint32_t nsid, active_ns_count = 0;
418 
419 	cdata = spdk_nvme_ctrlr_get_data(ctrlr);
420 
421 	if (!is_discovery) {
422 		/*
423 		 * Only attempt to retrieve the following log pages
424 		 * when the NVM subsystem that's being targeted is
425 		 * NOT the Discovery Controller which only fields
426 		 * a Discovery Log Page.
427 		 */
428 		if (get_error_log_page(ctrlr) == 0) {
429 			outstanding_commands++;
430 		} else {
431 			printf("Get Error Log Page failed\n");
432 		}
433 
434 		if (get_health_log_page(ctrlr) == 0) {
435 			outstanding_commands++;
436 		} else {
437 			printf("Get Log Page (SMART/health) failed\n");
438 		}
439 
440 		if (get_firmware_log_page(ctrlr) == 0) {
441 			outstanding_commands++;
442 		} else {
443 			printf("Get Log Page (Firmware Slot Information) failed\n");
444 		}
445 	}
446 
447 	if (spdk_nvme_ctrlr_is_log_page_supported(ctrlr, SPDK_NVME_LOG_ASYMMETRIC_NAMESPACE_ACCESS)) {
448 		for (nsid = spdk_nvme_ctrlr_get_first_active_ns(ctrlr);
449 		     nsid != 0; nsid = spdk_nvme_ctrlr_get_next_active_ns(ctrlr, nsid)) {
450 			active_ns_count++;
451 		}
452 
453 		/* We always set RGO (Return Groups Only) to 0 in this tool, an ANA group
454 		 * descriptor is returned only if that ANA group contains namespaces
455 		 * that are attached to the controller processing the command, and
456 		 * namespaces attached to the controller shall be members of an ANA group.
457 		 * Hence the following size should be enough.
458 		 */
459 		g_ana_log_page_size = sizeof(struct spdk_nvme_ana_page) + cdata->nanagrpid *
460 				      sizeof(struct spdk_nvme_ana_group_descriptor) + active_ns_count *
461 				      sizeof(uint32_t);
462 		g_ana_log_page = calloc(1, g_ana_log_page_size);
463 		if (g_ana_log_page == NULL) {
464 			exit(1);
465 		}
466 		g_copied_ana_desc = calloc(1, g_ana_log_page_size);
467 		if (g_copied_ana_desc == NULL) {
468 			exit(1);
469 		}
470 		if (get_ana_log_page(ctrlr) == 0) {
471 			outstanding_commands++;
472 		} else {
473 			printf("Get Log Page (Asymmetric Namespace Access) failed\n");
474 		}
475 	}
476 	if (cdata->lpa.celp) {
477 		if (get_cmd_effects_log_page(ctrlr) == 0) {
478 			outstanding_commands++;
479 		} else {
480 			printf("Get Log Page (Commands Supported and Effects) failed\n");
481 		}
482 	}
483 
484 	if (cdata->vid == SPDK_PCI_VID_INTEL) {
485 		if (spdk_nvme_ctrlr_is_log_page_supported(ctrlr, SPDK_NVME_INTEL_LOG_SMART)) {
486 			if (get_intel_smart_log_page(ctrlr) == 0) {
487 				outstanding_commands++;
488 			} else {
489 				printf("Get Log Page (Intel SMART/health) failed\n");
490 			}
491 		}
492 		if (spdk_nvme_ctrlr_is_log_page_supported(ctrlr, SPDK_NVME_INTEL_LOG_TEMPERATURE)) {
493 			if (get_intel_temperature_log_page(ctrlr) == 0) {
494 				outstanding_commands++;
495 			} else {
496 				printf("Get Log Page (Intel temperature) failed\n");
497 			}
498 		}
499 		if (spdk_nvme_ctrlr_is_log_page_supported(ctrlr, SPDK_NVME_INTEL_MARKETING_DESCRIPTION)) {
500 			if (get_intel_md_log_page(ctrlr) == 0) {
501 				outstanding_commands++;
502 			} else {
503 				printf("Get Log Page (Intel Marketing Description) failed\n");
504 			}
505 		}
506 
507 	}
508 
509 	if (is_discovery && (get_discovery_log_page(ctrlr) == 0)) {
510 		outstanding_commands++;
511 	}
512 
513 	while (outstanding_commands) {
514 		spdk_nvme_ctrlr_process_admin_completions(ctrlr);
515 	}
516 }
517 
518 static int
519 get_fdp_cfg_log_page(struct spdk_nvme_ns *ns)
520 {
521 	struct spdk_nvme_ctrlr *ctrlr = spdk_nvme_ns_get_ctrlr(ns);
522 	const struct spdk_nvme_ns_data *nsdata = spdk_nvme_ns_get_data(ns);
523 
524 	outstanding_commands = 0;
525 
526 	g_fdp_cfg_log_page_size = sizeof(struct spdk_nvme_fdp_cfg_log_page);
527 	g_fdp_cfg_log_page = calloc(1, g_fdp_cfg_log_page_size);
528 	if (!g_fdp_cfg_log_page) {
529 		printf("FDP config log page allocation failed!\n");
530 		return -1;
531 	}
532 
533 	/* Fetch the FDP configurations log page header */
534 	if (spdk_nvme_ctrlr_cmd_get_log_page_ext(ctrlr, SPDK_NVME_LOG_FDP_CONFIGURATIONS, 0,
535 			g_fdp_cfg_log_page, g_fdp_cfg_log_page_size, 0, 0, (nsdata->endgid << 16),
536 			0, get_log_page_completion, NULL) == 0) {
537 		outstanding_commands++;
538 	} else {
539 		printf("spdk_nvme_ctrlr_cmd_get_log_page_ext(FDP config) failed\n");
540 		free(g_fdp_cfg_log_page);
541 		return -1;
542 	}
543 
544 	while (outstanding_commands) {
545 		spdk_nvme_ctrlr_process_admin_completions(ctrlr);
546 	}
547 
548 	g_fdp_cfg_log_page_size = g_fdp_cfg_log_page->size;
549 	g_fdp_cfg_log_page = realloc(g_fdp_cfg_log_page, g_fdp_cfg_log_page_size);
550 	if (!g_fdp_cfg_log_page) {
551 		printf("FDP config log page reallocation failed!\n");
552 		return -1;
553 	}
554 
555 	/* Fetch the FDP configurations log page */
556 	if (spdk_nvme_ctrlr_cmd_get_log_page_ext(ctrlr, SPDK_NVME_LOG_FDP_CONFIGURATIONS, 0,
557 			g_fdp_cfg_log_page, g_fdp_cfg_log_page_size, 0, 0, (nsdata->endgid << 16),
558 			0, get_log_page_completion, NULL) == 0) {
559 		outstanding_commands++;
560 	} else {
561 		printf("spdk_nvme_ctrlr_cmd_get_log_page_ext(FDP config) failed\n");
562 		free(g_fdp_cfg_log_page);
563 		return -1;
564 	}
565 
566 	while (outstanding_commands) {
567 		spdk_nvme_ctrlr_process_admin_completions(ctrlr);
568 	}
569 
570 	return 0;
571 }
572 
573 static int
574 get_fdp_ruhu_log_page(struct spdk_nvme_ns *ns)
575 {
576 	struct spdk_nvme_ctrlr *ctrlr = spdk_nvme_ns_get_ctrlr(ns);
577 	const struct spdk_nvme_ns_data *nsdata = spdk_nvme_ns_get_data(ns);
578 
579 	outstanding_commands = 0;
580 
581 	g_fdp_ruhu_log_page_size = sizeof(struct spdk_nvme_fdp_ruhu_log_page);
582 	g_fdp_ruhu_log_page = calloc(1, g_fdp_ruhu_log_page_size);
583 	if (!g_fdp_ruhu_log_page) {
584 		printf("FDP RUH usage log page allocation failed!\n");
585 		return -1;
586 	}
587 
588 	/* Fetch the reclaim unit handle usage log page header */
589 	if (spdk_nvme_ctrlr_cmd_get_log_page_ext(ctrlr, SPDK_NVME_LOG_RECLAIM_UNIT_HANDLE_USAGE, 0,
590 			g_fdp_ruhu_log_page, g_fdp_ruhu_log_page_size, 0, 0, (nsdata->endgid << 16),
591 			0, get_log_page_completion, NULL) == 0) {
592 		outstanding_commands++;
593 	} else {
594 		printf("spdk_nvme_ctrlr_cmd_get_log_page_ext(RUH usage) failed\n");
595 		free(g_fdp_ruhu_log_page);
596 		return -1;
597 	}
598 
599 	while (outstanding_commands) {
600 		spdk_nvme_ctrlr_process_admin_completions(ctrlr);
601 	}
602 
603 	g_fdp_ruhu_log_page_size += g_fdp_ruhu_log_page->nruh *
604 				    sizeof(struct spdk_nvme_fdp_ruhu_descriptor);
605 	g_fdp_ruhu_log_page = realloc(g_fdp_ruhu_log_page, g_fdp_ruhu_log_page_size);
606 	if (!g_fdp_ruhu_log_page) {
607 		printf("FDP RUH usage log page reallocation failed!\n");
608 		return -1;
609 	}
610 
611 	/* Fetch the reclaim unit handle usage log page */
612 	if (spdk_nvme_ctrlr_cmd_get_log_page_ext(ctrlr, SPDK_NVME_LOG_RECLAIM_UNIT_HANDLE_USAGE, 0,
613 			g_fdp_ruhu_log_page, g_fdp_ruhu_log_page_size, 0, 0, (nsdata->endgid << 16),
614 			0, get_log_page_completion, NULL) == 0) {
615 		outstanding_commands++;
616 	} else {
617 		printf("spdk_nvme_ctrlr_cmd_get_log_page_ext(RUH usage) failed\n");
618 		free(g_fdp_ruhu_log_page);
619 		return -1;
620 	}
621 
622 	while (outstanding_commands) {
623 		spdk_nvme_ctrlr_process_admin_completions(ctrlr);
624 	}
625 
626 	return 0;
627 }
628 
629 static int
630 get_fdp_stats_log_page(struct spdk_nvme_ns *ns)
631 {
632 	struct spdk_nvme_ctrlr *ctrlr = spdk_nvme_ns_get_ctrlr(ns);
633 	const struct spdk_nvme_ns_data *nsdata = spdk_nvme_ns_get_data(ns);
634 
635 	outstanding_commands = 0;
636 
637 	if (spdk_nvme_ctrlr_cmd_get_log_page_ext(ctrlr, SPDK_NVME_LOG_FDP_STATISTICS, 0,
638 			&g_fdp_stats_log_page, 64, 0, 0, (nsdata->endgid << 16), 0,
639 			get_log_page_completion, NULL) == 0) {
640 		outstanding_commands++;
641 	} else {
642 		printf("spdk_nvme_ctrlr_cmd_get_log_page_ext(FDP stats) failed\n");
643 		return -1;
644 	}
645 
646 	while (outstanding_commands) {
647 		spdk_nvme_ctrlr_process_admin_completions(ctrlr);
648 	}
649 
650 	return 0;
651 }
652 
653 static int
654 get_fdp_events_log_page(struct spdk_nvme_ns *ns)
655 {
656 	struct spdk_nvme_ctrlr *ctrlr = spdk_nvme_ns_get_ctrlr(ns);
657 	const struct spdk_nvme_ns_data *nsdata = spdk_nvme_ns_get_data(ns);
658 
659 	outstanding_commands = 0;
660 
661 	g_fdp_events_log_page_size = sizeof(struct spdk_nvme_fdp_events_log_page);
662 	g_fdp_events_log_page = calloc(1, g_fdp_events_log_page_size);
663 	if (!g_fdp_events_log_page) {
664 		printf("FDP events log page allocation failed!\n");
665 		return -1;
666 	}
667 
668 	/* Fetch the FDP events log page header */
669 	if (spdk_nvme_ctrlr_cmd_get_log_page_ext(ctrlr, SPDK_NVME_LOG_FDP_EVENTS, 0,
670 			g_fdp_events_log_page, g_fdp_events_log_page_size, 0,
671 			(SPDK_NVME_FDP_REPORT_HOST_EVENTS << 8), (nsdata->endgid << 16),
672 			0, get_log_page_completion, NULL) == 0) {
673 		outstanding_commands++;
674 	} else {
675 		printf("spdk_nvme_ctrlr_cmd_get_log_page_ext(FDP events) failed\n");
676 		free(g_fdp_events_log_page);
677 		return -1;
678 	}
679 
680 	while (outstanding_commands) {
681 		spdk_nvme_ctrlr_process_admin_completions(ctrlr);
682 	}
683 
684 	g_fdp_events_log_page_size += g_fdp_events_log_page->nevents *
685 				      sizeof(struct spdk_nvme_fdp_event);
686 	g_fdp_events_log_page = realloc(g_fdp_events_log_page, g_fdp_events_log_page_size);
687 	if (!g_fdp_events_log_page) {
688 		printf("FDP events log page reallocation failed!\n");
689 		return -1;
690 	}
691 
692 	/* Only fetch FDP events log page for host events */
693 	if (spdk_nvme_ctrlr_cmd_get_log_page_ext(ctrlr, SPDK_NVME_LOG_FDP_EVENTS, 0,
694 			g_fdp_events_log_page, g_fdp_events_log_page_size, 0,
695 			(SPDK_NVME_FDP_REPORT_HOST_EVENTS << 8), (nsdata->endgid << 16),
696 			0, get_log_page_completion, NULL) == 0) {
697 		outstanding_commands++;
698 	} else {
699 		printf("spdk_nvme_ctrlr_cmd_get_log_page_ext(FDP events) failed\n");
700 		free(g_fdp_events_log_page);
701 		return -1;
702 	}
703 
704 	while (outstanding_commands) {
705 		spdk_nvme_ctrlr_process_admin_completions(ctrlr);
706 	}
707 
708 	return 0;
709 }
710 
711 static int
712 get_ocssd_chunk_info_log_page(struct spdk_nvme_ns *ns)
713 {
714 	struct spdk_nvme_ctrlr *ctrlr = spdk_nvme_ns_get_ctrlr(ns);
715 	int nsid = spdk_nvme_ns_get_id(ns);
716 	uint32_t num_entry = geometry_data.num_grp * geometry_data.num_pu * geometry_data.num_chk;
717 	uint32_t xfer_size = spdk_nvme_ns_get_max_io_xfer_size(ns);
718 	uint32_t buf_size = 0;
719 	uint64_t buf_offset = 0;
720 	outstanding_commands = 0;
721 
722 	assert(num_entry != 0);
723 	if (!g_ocssd_verbose) {
724 		num_entry = spdk_min(num_entry, NUM_CHUNK_INFO_ENTRIES);
725 	}
726 
727 	g_ocssd_chunk_info_page = calloc(num_entry, sizeof(struct spdk_ocssd_chunk_information_entry));
728 	assert(g_ocssd_chunk_info_page != NULL);
729 
730 	buf_size = num_entry * sizeof(struct spdk_ocssd_chunk_information_entry);
731 	while (buf_size > 0) {
732 		xfer_size = spdk_min(buf_size, xfer_size);
733 		if (spdk_nvme_ctrlr_cmd_get_log_page(ctrlr, SPDK_OCSSD_LOG_CHUNK_INFO,
734 						     nsid, (void *) g_ocssd_chunk_info_page + buf_offset,
735 						     xfer_size, buf_offset, get_log_page_completion, NULL) == 0) {
736 			outstanding_commands++;
737 		} else {
738 			printf("get_ocssd_chunk_info_log_page() failed\n");
739 			return -1;
740 		}
741 
742 		buf_size -= xfer_size;
743 		buf_offset += xfer_size;
744 	}
745 
746 	while (outstanding_commands) {
747 		spdk_nvme_ctrlr_process_admin_completions(ctrlr);
748 	}
749 
750 	return 0;
751 }
752 
753 static void
754 get_ocssd_geometry(struct spdk_nvme_ns *ns, struct spdk_ocssd_geometry_data *geometry_data)
755 {
756 	struct spdk_nvme_ctrlr *ctrlr = spdk_nvme_ns_get_ctrlr(ns);
757 	int nsid = spdk_nvme_ns_get_id(ns);
758 	outstanding_commands = 0;
759 
760 	if (spdk_nvme_ocssd_ctrlr_cmd_geometry(ctrlr, nsid, geometry_data,
761 					       sizeof(*geometry_data), get_ocssd_geometry_completion, NULL)) {
762 		printf("Get OpenChannel SSD geometry failed\n");
763 		exit(1);
764 	} else {
765 		outstanding_commands++;
766 	}
767 
768 	while (outstanding_commands) {
769 		spdk_nvme_ctrlr_process_admin_completions(ctrlr);
770 	}
771 }
772 
773 static void
774 print_hex_be(const void *v, size_t size)
775 {
776 	const uint8_t *buf = v;
777 
778 	while (size--) {
779 		printf("%02X", *buf++);
780 	}
781 }
782 
783 static void
784 print_uint128_hex(uint64_t *v)
785 {
786 	unsigned long long lo = v[0], hi = v[1];
787 	if (hi) {
788 		printf("0x%llX%016llX", hi, lo);
789 	} else {
790 		printf("0x%llX", lo);
791 	}
792 }
793 
794 static void
795 print_uint128_dec(uint64_t *v)
796 {
797 	unsigned long long lo = v[0], hi = v[1];
798 	if (hi) {
799 		/* can't handle large (>64-bit) decimal values for now, so fall back to hex */
800 		print_uint128_hex(v);
801 	} else {
802 		printf("%llu", (unsigned long long)lo);
803 	}
804 }
805 
806 /* The len should be <= 8. */
807 static void
808 print_uint_var_dec(uint8_t *array, unsigned int len)
809 {
810 	uint64_t result = 0;
811 	int i = len;
812 
813 	while (i > 0) {
814 		result += (uint64_t)array[i - 1] << (8 * (i - 1));
815 		i--;
816 	}
817 	printf("%" PRIu64, result);
818 }
819 
820 /* Print ASCII string as defined by the NVMe spec */
821 static void
822 print_ascii_string(const void *buf, size_t size)
823 {
824 	const uint8_t *str = buf;
825 
826 	/* Trim trailing spaces */
827 	while (size > 0 && str[size - 1] == ' ') {
828 		size--;
829 	}
830 
831 	while (size--) {
832 		if (*str >= 0x20 && *str <= 0x7E) {
833 			printf("%c", *str);
834 		} else {
835 			printf(".");
836 		}
837 		str++;
838 	}
839 }
840 
841 /* Underline a "line" with the given marker, e.g. print_uline("=", printf(...)); */
842 static void
843 print_uline(char marker, int line_len)
844 {
845 	for (int i = 1; i < line_len; ++i) {
846 		putchar(marker);
847 	}
848 	putchar('\n');
849 }
850 
851 static void
852 print_fdp_cfg_log_page(void)
853 {
854 	uint32_t i, j;
855 	struct spdk_nvme_fdp_cfg_descriptor *cfg_desc;
856 	void *log = g_fdp_cfg_log_page->cfg_desc;
857 
858 	printf("FDP configurations log page\n");
859 	printf("===========================\n");
860 	if (g_hex_dump) {
861 		hex_dump(g_fdp_cfg_log_page, FDP_LOG_PAGE_SIZE);
862 		printf("\n");
863 	}
864 
865 	printf("Number of FDP configurations:         %u\n", g_fdp_cfg_log_page->ncfg + 1);
866 	printf("Version:                              %u\n", g_fdp_cfg_log_page->version);
867 	printf("Size:                                 %u\n", g_fdp_cfg_log_page->size);
868 
869 	for (i = 0; i <= g_fdp_cfg_log_page->ncfg; i++) {
870 		cfg_desc = log;
871 		printf("FDP Configuration Descriptor:         %u\n", i);
872 		printf("  Descriptor Size:                    %u\n", cfg_desc->ds);
873 		printf("  Reclaim Group Identifier format:    %u\n", cfg_desc->fdpa.bits.rgif);
874 		printf("  FDP Volatile Write Cache:           %s\n",
875 		       cfg_desc->fdpa.bits.fdpvwc ? "Present" : "Not Present");
876 		printf("  FDP Configuration:                  %s\n",
877 		       cfg_desc->fdpa.bits.fdpcv ? "Valid" : "Invalid");
878 		printf("  Vendor Specific Size:               %u\n", cfg_desc->vss);
879 		printf("  Number of Reclaim Groups:           %u\n", cfg_desc->nrg);
880 		printf("  Number of Recalim Unit Handles:     %u\n", cfg_desc->nruh);
881 		printf("  Max Placement Identifiers:          %u\n", cfg_desc->maxpids + 1);
882 		printf("  Number of Namespaces Suppprted:     %u\n", cfg_desc->nns);
883 		printf("  Reclaim unit Nominal Size:          %" PRIx64 " bytes\n", cfg_desc->runs);
884 		printf("  Estimated Reclaim Unit Time Limit:  ");
885 		if (cfg_desc->erutl) {
886 			printf("%u seconds\n", cfg_desc->erutl);
887 		} else {
888 			printf("Not Reported\n");
889 		}
890 		for (j = 0; j < cfg_desc->nruh; j++) {
891 			printf("    RUH Desc #%03d:          RUH Type: %s\n", j,
892 			       cfg_desc->ruh_desc[j].ruht == SPDK_NVME_FDP_RUHT_INITIALLY_ISOLATED ? "Initially Isolated" :
893 			       cfg_desc->ruh_desc[j].ruht == SPDK_NVME_FDP_RUHT_PERSISTENTLY_ISOLATED ? "Persistently Isolated" :
894 			       "Reserved");
895 		}
896 		log += cfg_desc->ds;
897 	}
898 
899 	free(g_fdp_cfg_log_page);
900 	printf("\n");
901 }
902 
903 static void
904 print_fdp_ruhu_log_page(void)
905 {
906 	uint32_t i;
907 	struct spdk_nvme_fdp_ruhu_descriptor *ruhu_desc;
908 
909 	printf("FDP reclaim unit handle usage log page\n");
910 	printf("======================================\n");
911 	if (g_hex_dump) {
912 		hex_dump(g_fdp_ruhu_log_page, FDP_LOG_PAGE_SIZE);
913 		printf("\n");
914 	}
915 
916 	printf("Number of Reclaim Unit Handles:       %u\n", g_fdp_ruhu_log_page->nruh);
917 
918 	for (i = 0; i < g_fdp_ruhu_log_page->nruh; i++) {
919 		ruhu_desc = &g_fdp_ruhu_log_page->ruhu_desc[i];
920 
921 		printf("  RUH Usage Desc #%03d:   RUH Attributes: %s\n", i,
922 		       ruhu_desc->ruha == SPDK_NVME_FDP_RUHA_UNUSED ? "Unused" :
923 		       ruhu_desc->ruha == SPDK_NVME_FDP_RUHA_HOST_SPECIFIED ? "Host Specified" :
924 		       ruhu_desc->ruha == SPDK_NVME_FDP_RUHA_CTRLR_SPECIFIED ? "Controller Specified" :
925 		       "Reserved");
926 	}
927 
928 	free(g_fdp_ruhu_log_page);
929 	printf("\n");
930 }
931 
932 static void
933 print_fdp_stats_log_page(void)
934 {
935 	printf("FDP statistics log page\n");
936 	printf("=======================\n");
937 	if (g_hex_dump) {
938 		hex_dump(&g_fdp_stats_log_page, 64);
939 		printf("\n");
940 	}
941 
942 	printf("Host bytes with metadata written:  ");
943 	print_uint128_dec(g_fdp_stats_log_page.hbmw);
944 	printf("\n");
945 	printf("Media bytes with metadata written: ");
946 	print_uint128_dec(g_fdp_stats_log_page.mbmw);
947 	printf("\n");
948 	printf("Media bytes erased:                ");
949 	print_uint128_dec(g_fdp_stats_log_page.mbe);
950 	printf("\n\n");
951 }
952 
953 static void
954 print_fdp_events_log_page(void)
955 {
956 	uint32_t i;
957 	struct spdk_nvme_fdp_event *event;
958 	struct spdk_nvme_fdp_event_media_reallocated *media_reallocated;
959 
960 	printf("FDP events log page\n");
961 	printf("===================\n");
962 	if (g_hex_dump) {
963 		hex_dump(g_fdp_events_log_page, FDP_LOG_PAGE_SIZE);
964 		printf("\n");
965 	}
966 
967 	printf("Number of FDP events:              %u\n", g_fdp_events_log_page->nevents);
968 
969 	for (i = 0; i < g_fdp_events_log_page->nevents; i++) {
970 		event = &g_fdp_events_log_page->event[i];
971 
972 		printf("FDP Event #%u:\n", i);
973 		printf("  Event Type:                      %s\n",
974 		       event->etype == SPDK_NVME_FDP_EVENT_RU_NOT_WRITTEN_CAPACITY ? "RU Not Written to Capacity" :
975 		       event->etype == SPDK_NVME_FDP_EVENT_RU_TIME_LIMIT_EXCEEDED ? "RU Time Limit Exceeded" :
976 		       event->etype == SPDK_NVME_FDP_EVENT_CTRLR_RESET_MODIFY_RUH ? "Ctrlr Reset Modified RUH's" :
977 		       event->etype == SPDK_NVME_FDP_EVENT_INVALID_PLACEMENT_ID ? "Invalid Placement Identifier" :
978 		       event->etype == SPDK_NVME_FDP_EVENT_MEDIA_REALLOCATED ? "Media Reallocated" :
979 		       event->etype == SPDK_NVME_FDP_EVENT_IMPLICIT_MODIFIED_RUH ? "Implicitly modified RUH" :
980 		       "Reserved");
981 		printf("  Placement Identifier:            %s\n",
982 		       event->fdpef.bits.piv ? "Valid" : "Invalid");
983 		printf("  NSID:                            %s\n",
984 		       event->fdpef.bits.nsidv ? "Valid" : "Invalid");
985 		printf("  Location:                        %s\n",
986 		       event->fdpef.bits.lv ? "Valid" : "Invalid");
987 		if (event->fdpef.bits.piv) {
988 			printf("  Placement Identifier:            %u\n", event->pid);
989 		} else {
990 			printf("  Placement Identifier:            Reserved\n");
991 		}
992 		printf("  Event Timestamp:                 %" PRIx64 "\n", event->timestamp);
993 		if (event->fdpef.bits.nsidv) {
994 			printf("  Namespace Identifier:            %u\n", event->nsid);
995 		} else {
996 			printf("  Namespace Identifier:            Ignore\n");
997 		}
998 
999 		if (event->etype == SPDK_NVME_FDP_EVENT_MEDIA_REALLOCATED) {
1000 			media_reallocated = (struct spdk_nvme_fdp_event_media_reallocated *)&event->event_type_specific;
1001 
1002 			printf("  LBA:                             %s\n",
1003 			       media_reallocated->sef.bits.lbav ? "Valid" : "Invalid");
1004 			printf("  Number of LBA's Moved:           %u\n", media_reallocated->nlbam);
1005 			if (media_reallocated->sef.bits.lbav) {
1006 				printf("  Logical Block Address:           %u\n", event->nsid);
1007 			} else {
1008 				printf("  Logical Block Address:           Ignore\n");
1009 			}
1010 		}
1011 
1012 		if (event->fdpef.bits.lv) {
1013 			printf("  Reclaim Group Identifier:        %u\n", event->rgid);
1014 		} else {
1015 			printf("  Reclaim Group Identifier:        Ignore\n");
1016 		}
1017 		if (event->fdpef.bits.lv) {
1018 			printf("  Reclaim Unit Handle Identifier:  %u\n", event->ruhid);
1019 		} else {
1020 			printf("  Reclaim Unit Handle Identifier:  Ignore\n");
1021 		}
1022 	}
1023 
1024 	free(g_fdp_events_log_page);
1025 	printf("\n");
1026 }
1027 
1028 static void
1029 print_ocssd_chunk_info(struct spdk_ocssd_chunk_information_entry *chk_info, int chk_num)
1030 {
1031 	int i;
1032 	char *cs_str, *ct_str;
1033 
1034 	printf("OCSSD Chunk Info Glance\n");
1035 	printf("======================\n");
1036 
1037 	for (i = 0; i < chk_num; i++) {
1038 		cs_str = chk_info[i].cs.free ? "Free" :
1039 			 chk_info[i].cs.closed ? "Closed" :
1040 			 chk_info[i].cs.open ? "Open" :
1041 			 chk_info[i].cs.offline ? "Offline" : "Unknown";
1042 		ct_str = chk_info[i].ct.seq_write ? "Sequential Write" :
1043 			 chk_info[i].ct.rnd_write ? "Random Write" : "Unknown";
1044 
1045 		printf("------------\n");
1046 		printf("Chunk index:                    %d\n", i);
1047 		printf("Chunk state:                    %s(0x%x)\n", cs_str, *(uint8_t *) & (chk_info[i].cs));
1048 		printf("Chunk type (write mode):        %s\n", ct_str);
1049 		printf("Chunk type (size_deviate):      %s\n", chk_info[i].ct.size_deviate ? "Yes" : "No");
1050 		printf("Wear-level Index:               %d\n", chk_info[i].wli);
1051 		printf("Starting LBA:                   %" PRIu64 "\n", chk_info[i].slba);
1052 		printf("Number of blocks in chunk:      %" PRIu64 "\n", chk_info[i].cnlb);
1053 		printf("Write Pointer:                  %" PRIu64 "\n", chk_info[i].wp);
1054 	}
1055 }
1056 
1057 static void
1058 print_ocssd_chunk_info_verbose(struct spdk_ocssd_chunk_information_entry *chk_info)
1059 {
1060 	uint32_t pu, chk, i;
1061 	uint32_t cnt_free, cnt_closed, cnt_open, cnt_offline;
1062 	uint32_t max_pu = spdk_min(MAX_OCSSD_PU, (geometry_data.num_grp * geometry_data.num_pu));
1063 	char cs_str[MAX_OCSSD_PU + 1], cs;
1064 
1065 	assert(chk_info != NULL);
1066 	printf("OCSSD Chunk Info Verbose\n");
1067 	printf("======================\n");
1068 
1069 	printf("%4s %-*s %3s %3s %3s %3s\n", "band", max_pu, "chunk state", "fr", "cl", "op", "of");
1070 	for (chk = 0; chk < geometry_data.num_chk; chk++) {
1071 		cnt_free = cnt_closed = cnt_open = cnt_offline = 0;
1072 		for (pu = 0; pu < max_pu; pu++) {
1073 			i = (pu * geometry_data.num_chk) + chk;
1074 			if (chk_info[i].cs.free) {
1075 				cnt_free++;
1076 				cs = 'f';
1077 			} else if (chk_info[i].cs.closed) {
1078 				cnt_closed++;
1079 				cs = 'c';
1080 			} else if (chk_info[i].cs.open) {
1081 				cnt_open++;
1082 				cs = 'o';
1083 			} else if (chk_info[i].cs.offline) {
1084 				cnt_offline++;
1085 				cs = 'l';
1086 			} else {
1087 				cs = '.';
1088 			}
1089 			cs_str[pu] = cs;
1090 		}
1091 		cs_str[pu] = 0;
1092 		printf("%4d %s %3d %3d %3d %3d\n", chk, cs_str, cnt_free, cnt_closed, cnt_open, cnt_offline);
1093 	}
1094 }
1095 
1096 static void
1097 print_ocssd_geometry(struct spdk_ocssd_geometry_data *geometry_data)
1098 {
1099 	printf("Namespace OCSSD Geometry\n");
1100 	printf("=======================\n");
1101 
1102 	if (geometry_data->mjr < 2) {
1103 		printf("Open-Channel Spec version is less than 2.0\n");
1104 		printf("OC version:             maj:%d\n", geometry_data->mjr);
1105 		return;
1106 	}
1107 
1108 	printf("OC version:                     maj:%d min:%d\n", geometry_data->mjr, geometry_data->mnr);
1109 	printf("LBA format:\n");
1110 	printf("  Group bits:                   %d\n", geometry_data->lbaf.grp_len);
1111 	printf("  PU bits:                      %d\n", geometry_data->lbaf.pu_len);
1112 	printf("  Chunk bits:                   %d\n", geometry_data->lbaf.chk_len);
1113 	printf("  Logical block bits:           %d\n", geometry_data->lbaf.lbk_len);
1114 
1115 	printf("Media and Controller Capabilities:\n");
1116 	printf("  Namespace supports Vector Chunk Copy:                 %s\n",
1117 	       geometry_data->mccap.vec_chk_cpy ? "Supported" : "Not Supported");
1118 	printf("  Namespace supports multiple resets a free chunk:      %s\n",
1119 	       geometry_data->mccap.multi_reset ? "Supported" : "Not Supported");
1120 
1121 	printf("Wear-level Index Delta Threshold:                       %d\n", geometry_data->wit);
1122 	printf("Groups (channels):              %d\n", geometry_data->num_grp);
1123 	printf("PUs (LUNs) per group:           %d\n", geometry_data->num_pu);
1124 	printf("Chunks per LUN:                 %d\n", geometry_data->num_chk);
1125 	printf("Logical blks per chunk:         %d\n", geometry_data->clba);
1126 	printf("MIN write size:                 %d\n", geometry_data->ws_min);
1127 	printf("OPT write size:                 %d\n", geometry_data->ws_opt);
1128 	printf("Cache min write size:           %d\n", geometry_data->mw_cunits);
1129 	printf("Max open chunks:                %d\n", geometry_data->maxoc);
1130 	printf("Max open chunks per PU:         %d\n", geometry_data->maxocpu);
1131 	printf("\n");
1132 }
1133 
1134 static void
1135 print_zns_zone(uint8_t *report, uint32_t index, uint32_t zdes)
1136 {
1137 	struct spdk_nvme_zns_zone_desc *desc;
1138 	uint32_t i, zds, zrs, zd_index;
1139 
1140 	zrs = sizeof(struct spdk_nvme_zns_zone_report);
1141 	zds = sizeof(struct spdk_nvme_zns_zone_desc);
1142 	zd_index = zrs + index * (zds + zdes);
1143 
1144 	desc = (struct spdk_nvme_zns_zone_desc *)(report + zd_index);
1145 
1146 	printf("ZSLBA: 0x%016"PRIx64" ZCAP: 0x%016"PRIx64" WP: 0x%016"PRIx64" ZS: ", desc->zslba,
1147 	       desc->zcap, desc->wp);
1148 	switch (desc->zs) {
1149 	case SPDK_NVME_ZONE_STATE_EMPTY:
1150 		printf("Empty");
1151 		break;
1152 	case SPDK_NVME_ZONE_STATE_IOPEN:
1153 		printf("Implicit open");
1154 		break;
1155 	case SPDK_NVME_ZONE_STATE_EOPEN:
1156 		printf("Explicit open");
1157 		break;
1158 	case SPDK_NVME_ZONE_STATE_CLOSED:
1159 		printf("Closed");
1160 		break;
1161 	case SPDK_NVME_ZONE_STATE_RONLY:
1162 		printf("Read only");
1163 		break;
1164 	case SPDK_NVME_ZONE_STATE_FULL:
1165 		printf("Full");
1166 		break;
1167 	case SPDK_NVME_ZONE_STATE_OFFLINE:
1168 		printf("Offline");
1169 		break;
1170 	default:
1171 		printf("Reserved");
1172 	}
1173 	printf(" ZT: %s ZA: %x\n", (desc->zt == SPDK_NVME_ZONE_TYPE_SEQWR) ? "SWR" : "Reserved",
1174 	       desc->za.raw);
1175 
1176 	if (!desc->za.bits.zdev) {
1177 		return;
1178 	}
1179 
1180 	for (i = 0; i < zdes; i += 8) {
1181 		printf("zone_desc_ext[%d] : 0x%"PRIx64"\n", i,
1182 		       *(uint64_t *)(report + zd_index + zds + i));
1183 	}
1184 }
1185 
1186 static void
1187 get_and_print_zns_zone_report(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair)
1188 {
1189 	const struct spdk_nvme_ns_data *nsdata;
1190 	const struct spdk_nvme_zns_ns_data *nsdata_zns;
1191 	uint8_t *report_buf;
1192 	size_t report_bufsize;
1193 	uint64_t zone_size_lba = spdk_nvme_zns_ns_get_zone_size_sectors(ns);
1194 	uint64_t total_zones = spdk_nvme_zns_ns_get_num_zones(ns);
1195 	uint64_t max_zones_per_buf, zones_to_print, i;
1196 	uint64_t nr_zones = 0;
1197 	uint64_t handled_zones = 0;
1198 	uint64_t slba = 0;
1199 	size_t zdes = 0;
1200 	uint32_t zds, zrs, format_index;
1201 	int rc = 0;
1202 
1203 	outstanding_commands = 0;
1204 
1205 	nsdata = spdk_nvme_ns_get_data(ns);
1206 	nsdata_zns = spdk_nvme_zns_ns_get_data(ns);
1207 
1208 	zrs = sizeof(struct spdk_nvme_zns_zone_report);
1209 	zds = sizeof(struct spdk_nvme_zns_zone_desc);
1210 
1211 	format_index = spdk_nvme_ns_get_format_index(nsdata);
1212 	zdes = nsdata_zns->lbafe[format_index].zdes * 64;
1213 	zones_to_print = g_zone_report_limit ? spdk_min(total_zones, (uint64_t)g_zone_report_limit) : \
1214 			 total_zones;
1215 
1216 	report_bufsize = spdk_min(zrs + zones_to_print * (zds + zdes),
1217 				  spdk_nvme_ns_get_max_io_xfer_size(ns));
1218 	report_buf = calloc(1, report_bufsize);
1219 	if (!report_buf) {
1220 		printf("Zone report allocation failed!\n");
1221 		exit(1);
1222 	}
1223 
1224 	print_uline('=', printf("NVMe ZNS Zone Report (first %zu of %zu)\n", zones_to_print, total_zones));
1225 
1226 	while (handled_zones < zones_to_print) {
1227 		memset(report_buf, 0, report_bufsize);
1228 
1229 		if (zdes) {
1230 			max_zones_per_buf = (report_bufsize - zrs) / (zds + zdes);
1231 			rc = spdk_nvme_zns_ext_report_zones(ns, qpair, report_buf, report_bufsize,
1232 							    slba, SPDK_NVME_ZRA_LIST_ALL, true,
1233 							    get_zns_zone_report_completion, NULL);
1234 		} else {
1235 			max_zones_per_buf = (report_bufsize - zrs) / zds;
1236 			rc = spdk_nvme_zns_report_zones(ns, qpair, report_buf, report_bufsize,
1237 							slba, SPDK_NVME_ZRA_LIST_ALL, true,
1238 							get_zns_zone_report_completion, NULL);
1239 		}
1240 
1241 		if (rc) {
1242 			fprintf(stderr, "Report zones failed\n");
1243 			exit(1);
1244 		} else {
1245 			outstanding_commands++;
1246 		}
1247 
1248 		while (outstanding_commands) {
1249 			spdk_nvme_qpair_process_completions(qpair, 0);
1250 		}
1251 
1252 		nr_zones = report_buf[0];
1253 		if (nr_zones > max_zones_per_buf) {
1254 			fprintf(stderr, "nr_zones too big\n");
1255 			exit(1);
1256 		}
1257 
1258 		if (!nr_zones) {
1259 			break;
1260 		}
1261 
1262 		for (i = 0; i < nr_zones && handled_zones < zones_to_print; i++) {
1263 			print_zns_zone(report_buf, i, zdes);
1264 			slba += zone_size_lba;
1265 			handled_zones++;
1266 		}
1267 		printf("\n");
1268 	}
1269 
1270 	free(report_buf);
1271 }
1272 
1273 static void
1274 print_zns_ns_data(const struct spdk_nvme_zns_ns_data *nsdata_zns)
1275 {
1276 	printf("ZNS Specific Namespace Data\n");
1277 	printf("===========================\n");
1278 	printf("Variable Zone Capacity:                %s\n",
1279 	       nsdata_zns->zoc.variable_zone_capacity ? "Yes" : "No");
1280 	printf("Zone Active Excursions:                %s\n",
1281 	       nsdata_zns->zoc.zone_active_excursions ? "Yes" : "No");
1282 	printf("Read Across Zone Boundaries:           %s\n",
1283 	       nsdata_zns->ozcs.read_across_zone_boundaries ? "Yes" : "No");
1284 	if (nsdata_zns->mar == 0xffffffff) {
1285 		printf("Max Active Resources:                  No Limit\n");
1286 	} else {
1287 		printf("Max Active Resources:                  %"PRIu32"\n",
1288 		       nsdata_zns->mar + 1);
1289 	}
1290 	if (nsdata_zns->mor == 0xffffffff) {
1291 		printf("Max Open Resources:                    No Limit\n");
1292 	} else {
1293 		printf("Max Open Resources:                    %"PRIu32"\n",
1294 		       nsdata_zns->mor + 1);
1295 	}
1296 	if (nsdata_zns->rrl == 0) {
1297 		printf("Reset Recommended Limit:               Not Reported\n");
1298 	} else {
1299 		printf("Reset Recommended Limit:               %"PRIu32" seconds\n",
1300 		       nsdata_zns->rrl);
1301 	}
1302 	if (nsdata_zns->rrl1 == 0) {
1303 		printf("Reset Recommended Limit 1:             Not Reported\n");
1304 	} else {
1305 		printf("Reset Recommended Limit 1:             %"PRIu32" seconds\n",
1306 		       nsdata_zns->rrl1);
1307 	}
1308 	if (nsdata_zns->rrl2 == 0) {
1309 		printf("Reset Recommended Limit 2:             Not Reported\n");
1310 	} else {
1311 		printf("Reset Recommended Limit 2:             %"PRIu32" seconds\n",
1312 		       nsdata_zns->rrl2);
1313 	}
1314 	if (nsdata_zns->rrl3 == 0) {
1315 		printf("Reset Recommended Limit 3:             Not Reported\n");
1316 	} else {
1317 		printf("Reset Recommended Limit 3:             %"PRIu32" seconds\n",
1318 		       nsdata_zns->rrl3);
1319 	}
1320 	if (nsdata_zns->frl == 0) {
1321 		printf("Finish Recommended Limit:              Not Reported\n");
1322 	} else {
1323 		printf("Finish Recommended Limit:              %"PRIu32" seconds\n",
1324 		       nsdata_zns->frl);
1325 	}
1326 	if (nsdata_zns->frl1 == 0) {
1327 		printf("Finish Recommended Limit 1:            Not Reported\n");
1328 	} else {
1329 		printf("Finish Recommended Limit 1:            %"PRIu32" seconds\n",
1330 		       nsdata_zns->frl1);
1331 	}
1332 	if (nsdata_zns->frl2 == 0) {
1333 		printf("Finish Recommended Limit 2:            Not Reported\n");
1334 	} else {
1335 		printf("Finish Recommended Limit 2:            %"PRIu32" seconds\n",
1336 		       nsdata_zns->frl2);
1337 	}
1338 	if (nsdata_zns->frl3 == 0) {
1339 		printf("Finish Recommended Limit 3:            Not Reported\n");
1340 	} else {
1341 		printf("Finish Recommended Limit 3:            %"PRIu32" seconds\n",
1342 		       nsdata_zns->frl3);
1343 	}
1344 	printf("\n");
1345 }
1346 
1347 static const char *
1348 pi_format_string(uint32_t pif)
1349 {
1350 	switch (pif) {
1351 	case 0:
1352 		return "16b Guard PI";
1353 	case 1:
1354 		return "32b Guard PI";
1355 	case 2:
1356 		return "64b Guard PI";
1357 	case 3:
1358 		return "Reserved";
1359 	default:
1360 		return "Unknown";
1361 	}
1362 }
1363 
1364 static void
1365 print_nvm_ns_data(const struct spdk_nvme_nvm_ns_data *nsdata_nvm,
1366 		  const struct spdk_nvme_ns_data *nsdata)
1367 {
1368 	uint32_t i;
1369 
1370 	printf("NVM Specific Namespace Data\n");
1371 	printf("===========================\n");
1372 	printf("Logical Block Storage Tag Mask:               %"PRIx64"\n", nsdata_nvm->lbstm);
1373 	printf("Protection Information Capabilities:\n");
1374 	printf("  16b Guard Protection Information Storage Tag Support:  %s\n",
1375 	       nsdata_nvm->pic._16bpists != 0 ? "Yes" : "No");
1376 	printf("  16b Guard Protection Information Storage Tag Mask:     %s\n",
1377 	       nsdata_nvm->pic._16bpistm != 0 ? "LBSTM must be all 1s" : "Any bit in LBSTM can be 0");
1378 	printf("  Storage Tag Check Read Support:                        %s\n",
1379 	       nsdata_nvm->pic.stcrs != 0 ? "Yes" : "No");
1380 
1381 	for (i = 0; i <= nsdata->nlbaf; i++) {
1382 		printf("Extended LBA Format #%02d: Storage Tag Size: %-2d, Protection Information Format: %s\n",
1383 		       i, nsdata_nvm->elbaf[i].sts, pi_format_string(nsdata_nvm->elbaf[i].pif));
1384 	}
1385 }
1386 
1387 static const char *
1388 csi_name(enum spdk_nvme_csi csi)
1389 {
1390 	switch (csi) {
1391 	case SPDK_NVME_CSI_NVM:
1392 		return "NVM";
1393 	case SPDK_NVME_CSI_KV:
1394 		return "KV";
1395 	case SPDK_NVME_CSI_ZNS:
1396 		return "ZNS";
1397 	default:
1398 		if (csi >= 0x30 && csi <= 0x3f) {
1399 			return "Vendor specific";
1400 		}
1401 		return "Unknown";
1402 	}
1403 }
1404 
1405 static void
1406 print_namespace(struct spdk_nvme_ctrlr *ctrlr, struct spdk_nvme_ns *ns)
1407 {
1408 	const struct spdk_nvme_ctrlr_data	*cdata;
1409 	const struct spdk_nvme_ns_data		*nsdata;
1410 	const struct spdk_nvme_zns_ns_data	*nsdata_zns;
1411 	const struct spdk_nvme_nvm_ns_data	*nsdata_nvm;
1412 	const struct spdk_uuid			*uuid;
1413 	uint32_t				i;
1414 	uint32_t				flags;
1415 	char					uuid_str[SPDK_UUID_STRING_LEN];
1416 	uint32_t				blocksize, format_index;
1417 	enum spdk_nvme_dealloc_logical_block_read_value	dlfeat_read_value;
1418 
1419 	cdata = spdk_nvme_ctrlr_get_data(ctrlr);
1420 	nsdata = spdk_nvme_ns_get_data(ns);
1421 	nsdata_zns = spdk_nvme_zns_ns_get_data(ns);
1422 	nsdata_nvm = spdk_nvme_nvm_ns_get_data(ns);
1423 	flags  = spdk_nvme_ns_get_flags(ns);
1424 
1425 	printf("Namespace ID:%d\n", spdk_nvme_ns_get_id(ns));
1426 
1427 	if (g_hex_dump) {
1428 		hex_dump(nsdata, sizeof(*nsdata));
1429 		printf("\n");
1430 	}
1431 
1432 	/* This function is only called for active namespaces. */
1433 	assert(spdk_nvme_ns_is_active(ns));
1434 
1435 	if (features[SPDK_NVME_FEAT_ERROR_RECOVERY].valid) {
1436 		unsigned tler = features[SPDK_NVME_FEAT_ERROR_RECOVERY].result & 0xFFFF;
1437 		printf("Error Recovery Timeout:                ");
1438 		if (tler == 0) {
1439 			printf("Unlimited\n");
1440 		} else {
1441 			printf("%u milliseconds\n", tler * 100);
1442 		}
1443 	}
1444 
1445 	printf("Command Set Identifier:                %s (%02Xh)\n",
1446 	       csi_name(spdk_nvme_ns_get_csi(ns)), spdk_nvme_ns_get_csi(ns));
1447 	printf("Deallocate:                            %s\n",
1448 	       (flags & SPDK_NVME_NS_DEALLOCATE_SUPPORTED) ? "Supported" : "Not Supported");
1449 	printf("Deallocated/Unwritten Error:           %s\n",
1450 	       nsdata->nsfeat.dealloc_or_unwritten_error ? "Supported" : "Not Supported");
1451 	dlfeat_read_value = spdk_nvme_ns_get_dealloc_logical_block_read_value(ns);
1452 	printf("Deallocated Read Value:                %s\n",
1453 	       dlfeat_read_value == SPDK_NVME_DEALLOC_READ_00 ? "All 0x00" :
1454 	       dlfeat_read_value == SPDK_NVME_DEALLOC_READ_FF ? "All 0xFF" :
1455 	       "Unknown");
1456 	printf("Deallocate in Write Zeroes:            %s\n",
1457 	       nsdata->dlfeat.bits.write_zero_deallocate ? "Supported" : "Not Supported");
1458 	printf("Deallocated Guard Field:               %s\n",
1459 	       nsdata->dlfeat.bits.guard_value ? "CRC for Read Value" : "0xFFFF");
1460 	printf("Flush:                                 %s\n",
1461 	       (flags & SPDK_NVME_NS_FLUSH_SUPPORTED) ? "Supported" : "Not Supported");
1462 	printf("Reservation:                           %s\n",
1463 	       (flags & SPDK_NVME_NS_RESERVATION_SUPPORTED) ? "Supported" : "Not Supported");
1464 	if (flags & SPDK_NVME_NS_DPS_PI_SUPPORTED) {
1465 		printf("End-to-End Data Protection:            Supported\n");
1466 		printf("Protection Type:                       Type%d\n", nsdata->dps.pit);
1467 		printf("Protection Information Transferred as: %s\n",
1468 		       nsdata->dps.md_start ? "First 8/16 Bytes" : "Last 8/16 Bytes");
1469 	}
1470 	format_index = spdk_nvme_ns_get_format_index(nsdata);
1471 	if (nsdata->lbaf[format_index].ms > 0) {
1472 		printf("Metadata Transferred as:               %s\n",
1473 		       nsdata->flbas.extended ? "Extended Data LBA" : "Separate Metadata Buffer");
1474 	}
1475 	printf("Namespace Sharing Capabilities:        %s\n",
1476 	       nsdata->nmic.can_share ? "Multiple Controllers" : "Private");
1477 	blocksize = 1 << nsdata->lbaf[format_index].lbads;
1478 	printf("Size (in LBAs):                        %lld (%lldGiB)\n",
1479 	       (long long)nsdata->nsze,
1480 	       (long long)nsdata->nsze * blocksize / 1024 / 1024 / 1024);
1481 	printf("Capacity (in LBAs):                    %lld (%lldGiB)\n",
1482 	       (long long)nsdata->ncap,
1483 	       (long long)nsdata->ncap * blocksize / 1024 / 1024 / 1024);
1484 	printf("Utilization (in LBAs):                 %lld (%lldGiB)\n",
1485 	       (long long)nsdata->nuse,
1486 	       (long long)nsdata->nuse * blocksize / 1024 / 1024 / 1024);
1487 	if (nsdata->noiob) {
1488 		printf("Optimal I/O Boundary:                  %u blocks\n", nsdata->noiob);
1489 	}
1490 	if (!spdk_mem_all_zero(nsdata->nguid, sizeof(nsdata->nguid))) {
1491 		printf("NGUID:                                 ");
1492 		print_hex_be(nsdata->nguid, sizeof(nsdata->nguid));
1493 		printf("\n");
1494 	}
1495 	if (!spdk_mem_all_zero(&nsdata->eui64, sizeof(nsdata->eui64))) {
1496 		printf("EUI64:                                 ");
1497 		print_hex_be(&nsdata->eui64, sizeof(nsdata->eui64));
1498 		printf("\n");
1499 	}
1500 	uuid = spdk_nvme_ns_get_uuid(ns);
1501 	if (uuid) {
1502 		spdk_uuid_fmt_lower(uuid_str, sizeof(uuid_str), uuid);
1503 		printf("UUID:                                  %s\n", uuid_str);
1504 	}
1505 	printf("Thin Provisioning:                     %s\n",
1506 	       nsdata->nsfeat.thin_prov ? "Supported" : "Not Supported");
1507 	printf("Per-NS Atomic Units:                   %s\n",
1508 	       nsdata->nsfeat.ns_atomic_write_unit ? "Yes" : "No");
1509 	if (nsdata->nsfeat.ns_atomic_write_unit) {
1510 		if (nsdata->nawun) {
1511 			printf("  Atomic Write Unit (Normal):          %d\n", nsdata->nawun + 1);
1512 		}
1513 
1514 		if (nsdata->nawupf) {
1515 			printf("  Atomic Write Unit (PFail):           %d\n", nsdata->nawupf + 1);
1516 		}
1517 
1518 		if (nsdata->npwg) {
1519 			printf("  Preferred Write Granularity:         %d\n", nsdata->npwg + 1);
1520 		}
1521 
1522 		if (nsdata->nacwu) {
1523 			printf("  Atomic Compare & Write Unit:         %d\n", nsdata->nacwu + 1);
1524 		}
1525 
1526 		printf("  Atomic Boundary Size (Normal):       %d\n", nsdata->nabsn);
1527 		printf("  Atomic Boundary Size (PFail):        %d\n", nsdata->nabspf);
1528 		printf("  Atomic Boundary Offset:              %d\n", nsdata->nabo);
1529 	}
1530 
1531 	if (cdata->oncs.copy) {
1532 		printf("Maximum Single Source Range Length:    %d\n", nsdata->mssrl);
1533 		printf("Maximum Copy Length:                   %d\n", nsdata->mcl);
1534 		printf("Maximum Source Range Count:            %d\n", nsdata->msrc + 1);
1535 	}
1536 
1537 	printf("NGUID/EUI64 Never Reused:              %s\n",
1538 	       nsdata->nsfeat.guid_never_reused ? "Yes" : "No");
1539 
1540 	if (cdata->cmic.ana_reporting) {
1541 		printf("ANA group ID:                          %u\n", nsdata->anagrpid);
1542 	}
1543 
1544 	printf("Namespace Write Protected:             %s\n",
1545 	       nsdata->nsattr.write_protected ? "Yes" : "No");
1546 
1547 	if (cdata->ctratt.bits.nvm_sets) {
1548 		printf("NVM set ID:                            %u\n", nsdata->nvmsetid);
1549 	}
1550 
1551 	if (cdata->ctratt.bits.endurance_groups) {
1552 		printf("Endurance group ID:                    %u\n", nsdata->endgid);
1553 	}
1554 
1555 	printf("Number of LBA Formats:                 %d\n", nsdata->nlbaf + 1);
1556 	printf("Current LBA Format:                    LBA Format #%02d\n",
1557 	       format_index);
1558 	for (i = 0; i <= nsdata->nlbaf; i++) {
1559 		printf("LBA Format #%02d: Data Size: %5d  Metadata Size: %5d\n",
1560 		       i, 1 << nsdata->lbaf[i].lbads, nsdata->lbaf[i].ms);
1561 		if (spdk_nvme_ns_get_csi(ns) == SPDK_NVME_CSI_ZNS) {
1562 			printf("LBA Format Extension #%02d: Zone Size (in LBAs): 0x%"PRIx64" Zone Descriptor Extension Size: %d bytes\n",
1563 			       i, nsdata_zns->lbafe[i].zsze, nsdata_zns->lbafe[i].zdes << 6);
1564 		}
1565 
1566 	}
1567 	printf("\n");
1568 
1569 	if (cdata->ctratt.bits.fdps) {
1570 		union spdk_nvme_feat_fdp_cdw12 fdp_res;
1571 
1572 		if (features[SPDK_NVME_FEAT_FDP].valid) {
1573 			fdp_res.raw = features[SPDK_NVME_FEAT_FDP].result;
1574 
1575 			printf("Get Feature FDP:\n");
1576 			printf("================\n");
1577 			printf("  Enabled:                 %s\n",
1578 			       fdp_res.bits.fdpe ? "Yes" : "No");
1579 			printf("  FDP configuration index: %u\n\n", fdp_res.bits.fdpci);
1580 
1581 			if (fdp_res.bits.fdpe && !get_fdp_cfg_log_page(ns)) {
1582 				print_fdp_cfg_log_page();
1583 			}
1584 			if (fdp_res.bits.fdpe && !get_fdp_ruhu_log_page(ns)) {
1585 				print_fdp_ruhu_log_page();
1586 			}
1587 			if (fdp_res.bits.fdpe && !get_fdp_stats_log_page(ns)) {
1588 				print_fdp_stats_log_page();
1589 			}
1590 			if (fdp_res.bits.fdpe && !get_fdp_events_log_page(ns)) {
1591 				print_fdp_events_log_page();
1592 			}
1593 		}
1594 	}
1595 
1596 	if (spdk_nvme_ctrlr_is_ocssd_supported(ctrlr)) {
1597 		get_ocssd_geometry(ns, &geometry_data);
1598 		print_ocssd_geometry(&geometry_data);
1599 		get_ocssd_chunk_info_log_page(ns);
1600 		if (g_ocssd_verbose) {
1601 			print_ocssd_chunk_info_verbose(g_ocssd_chunk_info_page);
1602 		} else {
1603 			print_ocssd_chunk_info(g_ocssd_chunk_info_page, NUM_CHUNK_INFO_ENTRIES);
1604 		}
1605 	} else if (spdk_nvme_ns_get_csi(ns) == SPDK_NVME_CSI_ZNS) {
1606 		struct spdk_nvme_qpair *qpair = spdk_nvme_ctrlr_alloc_io_qpair(ctrlr, NULL, 0);
1607 		if (qpair == NULL) {
1608 			printf("ERROR: spdk_nvme_ctrlr_alloc_io_qpair() failed\n");
1609 			exit(1);
1610 		}
1611 		print_zns_ns_data(nsdata_zns);
1612 		get_and_print_zns_zone_report(ns, qpair);
1613 		spdk_nvme_ctrlr_free_io_qpair(qpair);
1614 	} else if (nsdata_nvm != NULL) {
1615 		print_nvm_ns_data(nsdata_nvm, nsdata);
1616 	}
1617 }
1618 
1619 static const char *
1620 admin_opc_name(uint8_t opc)
1621 {
1622 	switch (opc) {
1623 	case SPDK_NVME_OPC_DELETE_IO_SQ:
1624 		return "Delete I/O Submission Queue";
1625 	case SPDK_NVME_OPC_CREATE_IO_SQ:
1626 		return "Create I/O Submission Queue";
1627 	case SPDK_NVME_OPC_GET_LOG_PAGE:
1628 		return "Get Log Page";
1629 	case SPDK_NVME_OPC_DELETE_IO_CQ:
1630 		return "Delete I/O Completion Queue";
1631 	case SPDK_NVME_OPC_CREATE_IO_CQ:
1632 		return "Create I/O Completion Queue";
1633 	case SPDK_NVME_OPC_IDENTIFY:
1634 		return "Identify";
1635 	case SPDK_NVME_OPC_ABORT:
1636 		return "Abort";
1637 	case SPDK_NVME_OPC_SET_FEATURES:
1638 		return "Set Features";
1639 	case SPDK_NVME_OPC_GET_FEATURES:
1640 		return "Get Features";
1641 	case SPDK_NVME_OPC_ASYNC_EVENT_REQUEST:
1642 		return "Asynchronous Event Request";
1643 	case SPDK_NVME_OPC_NS_MANAGEMENT:
1644 		return "Namespace Management";
1645 	case SPDK_NVME_OPC_FIRMWARE_COMMIT:
1646 		return "Firmware Commit";
1647 	case SPDK_NVME_OPC_FIRMWARE_IMAGE_DOWNLOAD:
1648 		return "Firmware Image Download";
1649 	case SPDK_NVME_OPC_DEVICE_SELF_TEST:
1650 		return "Device Self-test";
1651 	case SPDK_NVME_OPC_NS_ATTACHMENT:
1652 		return "Namespace Attachment";
1653 	case SPDK_NVME_OPC_KEEP_ALIVE:
1654 		return "Keep Alive";
1655 	case SPDK_NVME_OPC_DIRECTIVE_SEND:
1656 		return "Directive Send";
1657 	case SPDK_NVME_OPC_DIRECTIVE_RECEIVE:
1658 		return "Directive Receive";
1659 	case SPDK_NVME_OPC_VIRTUALIZATION_MANAGEMENT:
1660 		return "Virtualization Management";
1661 	case SPDK_NVME_OPC_NVME_MI_SEND:
1662 		return "NVMe-MI Send";
1663 	case SPDK_NVME_OPC_NVME_MI_RECEIVE:
1664 		return "NVMe-MI Receive";
1665 	case SPDK_NVME_OPC_DOORBELL_BUFFER_CONFIG:
1666 		return "Doorbell Buffer Config";
1667 	case SPDK_NVME_OPC_FORMAT_NVM:
1668 		return "Format NVM";
1669 	case SPDK_NVME_OPC_SECURITY_SEND:
1670 		return "Security Send";
1671 	case SPDK_NVME_OPC_SECURITY_RECEIVE:
1672 		return "Security Receive";
1673 	case SPDK_NVME_OPC_SANITIZE:
1674 		return "Sanitize";
1675 	default:
1676 		if (opc >= 0xC0) {
1677 			return "Vendor specific";
1678 		}
1679 		return "Unknown";
1680 	}
1681 }
1682 
1683 static const char *
1684 io_opc_name(uint8_t opc)
1685 {
1686 	switch (opc) {
1687 	case SPDK_NVME_OPC_FLUSH:
1688 		return "Flush";
1689 	case SPDK_NVME_OPC_WRITE:
1690 		return "Write";
1691 	case SPDK_NVME_OPC_READ:
1692 		return "Read";
1693 	case SPDK_NVME_OPC_WRITE_UNCORRECTABLE:
1694 		return "Write Uncorrectable";
1695 	case SPDK_NVME_OPC_COMPARE:
1696 		return "Compare";
1697 	case SPDK_NVME_OPC_WRITE_ZEROES:
1698 		return "Write Zeroes";
1699 	case SPDK_NVME_OPC_DATASET_MANAGEMENT:
1700 		return "Dataset Management";
1701 	case SPDK_NVME_OPC_RESERVATION_REGISTER:
1702 		return "Reservation Register";
1703 	case SPDK_NVME_OPC_RESERVATION_REPORT:
1704 		return "Reservation Report";
1705 	case SPDK_NVME_OPC_RESERVATION_ACQUIRE:
1706 		return "Reservation Acquire";
1707 	case SPDK_NVME_OPC_RESERVATION_RELEASE:
1708 		return "Reservation Release";
1709 	case SPDK_NVME_OPC_COPY:
1710 		return "Copy";
1711 	default:
1712 		if (opc >= 0x80) {
1713 			return "Vendor specific";
1714 		}
1715 		return "Unknown";
1716 	}
1717 }
1718 
1719 static void
1720 print_controller(struct spdk_nvme_ctrlr *ctrlr, const struct spdk_nvme_transport_id *trid,
1721 		 const struct spdk_nvme_ctrlr_opts *opts)
1722 {
1723 	const struct spdk_nvme_ctrlr_data	*cdata;
1724 	union spdk_nvme_cap_register		cap;
1725 	union spdk_nvme_vs_register		vs;
1726 	uint8_t					str[512];
1727 	uint32_t				i, j;
1728 	struct spdk_nvme_error_information_entry *error_entry;
1729 	struct spdk_pci_addr			pci_addr;
1730 	struct spdk_pci_device			*pci_dev;
1731 	struct spdk_pci_id			pci_id;
1732 	uint32_t				nsid;
1733 	uint8_t					*orig_desc;
1734 	struct spdk_nvme_ana_group_descriptor	*copied_desc;
1735 	uint32_t				desc_size, copy_len;
1736 
1737 
1738 	cap = spdk_nvme_ctrlr_get_regs_cap(ctrlr);
1739 	vs = spdk_nvme_ctrlr_get_regs_vs(ctrlr);
1740 
1741 	if (!spdk_nvme_ctrlr_is_discovery(ctrlr)) {
1742 		/*
1743 		 * Discovery Controller only supports the
1744 		 * IDENTIFY and GET_LOG_PAGE cmd set, so only
1745 		 * attempt GET_FEATURES when NOT targeting a
1746 		 * Discovery Controller.
1747 		 */
1748 		get_ctrlr_features(ctrlr);
1749 	}
1750 	get_log_pages(ctrlr);
1751 
1752 	cdata = spdk_nvme_ctrlr_get_data(ctrlr);
1753 
1754 	printf("=====================================================\n");
1755 	if (trid->trtype != SPDK_NVME_TRANSPORT_PCIE) {
1756 		printf("NVMe over Fabrics controller at %s:%s: %s\n",
1757 		       trid->traddr, trid->trsvcid, trid->subnqn);
1758 	} else {
1759 		if (spdk_pci_addr_parse(&pci_addr, trid->traddr) != 0) {
1760 			return;
1761 		}
1762 
1763 		pci_dev = spdk_nvme_ctrlr_get_pci_device(ctrlr);
1764 		if (!pci_dev) {
1765 			return;
1766 		}
1767 
1768 		pci_id = spdk_pci_device_get_id(pci_dev);
1769 
1770 		printf("NVMe Controller at %04x:%02x:%02x.%x [%04x:%04x]\n",
1771 		       pci_addr.domain, pci_addr.bus,
1772 		       pci_addr.dev, pci_addr.func,
1773 		       pci_id.vendor_id, pci_id.device_id);
1774 	}
1775 	printf("=====================================================\n");
1776 
1777 	if (g_hex_dump) {
1778 		hex_dump(cdata, sizeof(*cdata));
1779 		printf("\n");
1780 	}
1781 
1782 	printf("Controller Capabilities/Features\n");
1783 	printf("================================\n");
1784 	printf("Vendor ID:                             %04x\n", cdata->vid);
1785 	printf("Subsystem Vendor ID:                   %04x\n", cdata->ssvid);
1786 	printf("Serial Number:                         ");
1787 	print_ascii_string(cdata->sn, sizeof(cdata->sn));
1788 	printf("\n");
1789 	printf("Model Number:                          ");
1790 	print_ascii_string(cdata->mn, sizeof(cdata->mn));
1791 	printf("\n");
1792 	printf("Firmware Version:                      ");
1793 	print_ascii_string(cdata->fr, sizeof(cdata->fr));
1794 	printf("\n");
1795 	printf("Recommended Arb Burst:                 %d\n", cdata->rab);
1796 	printf("IEEE OUI Identifier:                   %02x %02x %02x\n",
1797 	       cdata->ieee[0], cdata->ieee[1], cdata->ieee[2]);
1798 	printf("Multi-path I/O\n");
1799 	printf("  May have multiple subsystem ports:   %s\n", cdata->cmic.multi_port ? "Yes" : "No");
1800 	printf("  May have multiple controllers:       %s\n", cdata->cmic.multi_ctrlr ? "Yes" : "No");
1801 	printf("  Associated with SR-IOV VF:           %s\n", cdata->cmic.sr_iov ? "Yes" : "No");
1802 	printf("Max Data Transfer Size:                ");
1803 	if (cdata->mdts == 0) {
1804 		printf("Unlimited\n");
1805 	} else {
1806 		printf("%" PRIu64 "\n", (uint64_t)1 << (12 + cap.bits.mpsmin + cdata->mdts));
1807 	}
1808 	printf("Max Number of Namespaces:              %d\n", cdata->nn);
1809 	printf("Max Number of I/O Queues:              %d\n", opts->num_io_queues);
1810 	printf("NVMe Specification Version (VS):       %u.%u", vs.bits.mjr, vs.bits.mnr);
1811 	if (vs.bits.ter) {
1812 		printf(".%u", vs.bits.ter);
1813 	}
1814 	printf("\n");
1815 	if (cdata->ver.raw != 0) {
1816 		printf("NVMe Specification Version (Identify): %u.%u", cdata->ver.bits.mjr, cdata->ver.bits.mnr);
1817 		if (cdata->ver.bits.ter) {
1818 			printf(".%u", cdata->ver.bits.ter);
1819 		}
1820 		printf("\n");
1821 	}
1822 
1823 	printf("Maximum Queue Entries:                 %u\n", cap.bits.mqes + 1);
1824 	printf("Contiguous Queues Required:            %s\n", cap.bits.cqr ? "Yes" : "No");
1825 	printf("Arbitration Mechanisms Supported\n");
1826 	printf("  Weighted Round Robin:                %s\n",
1827 	       cap.bits.ams & SPDK_NVME_CAP_AMS_WRR ? "Supported" : "Not Supported");
1828 	printf("  Vendor Specific:                     %s\n",
1829 	       cap.bits.ams & SPDK_NVME_CAP_AMS_VS ? "Supported" : "Not Supported");
1830 	printf("Reset Timeout:                         %" PRIu64 " ms\n", (uint64_t)500 * cap.bits.to);
1831 	printf("Doorbell Stride:                       %" PRIu64 " bytes\n",
1832 	       (uint64_t)1 << (2 + cap.bits.dstrd));
1833 	printf("NVM Subsystem Reset:                   %s\n",
1834 	       cap.bits.nssrs ? "Supported" : "Not Supported");
1835 	printf("Command Sets Supported\n");
1836 	printf("  NVM Command Set:                     %s\n",
1837 	       cap.bits.css & SPDK_NVME_CAP_CSS_NVM ? "Supported" : "Not Supported");
1838 	printf("Boot Partition:                        %s\n",
1839 	       cap.bits.bps ? "Supported" : "Not Supported");
1840 	printf("Memory Page Size Minimum:              %" PRIu64 " bytes\n",
1841 	       (uint64_t)1 << (12 + cap.bits.mpsmin));
1842 	printf("Memory Page Size Maximum:              %" PRIu64 " bytes\n",
1843 	       (uint64_t)1 << (12 + cap.bits.mpsmax));
1844 	printf("Persistent Memory Region:              %s\n",
1845 	       cap.bits.pmrs ? "Supported" : "Not Supported");
1846 
1847 	printf("Optional Asynchronous Events Supported\n");
1848 	printf("  Namespace Attribute Notices:         %s\n",
1849 	       cdata->oaes.ns_attribute_notices ? "Supported" : "Not Supported");
1850 	printf("  Firmware Activation Notices:         %s\n",
1851 	       cdata->oaes.fw_activation_notices ? "Supported" : "Not Supported");
1852 	printf("  ANA Change Notices:                  %s\n",
1853 	       cdata->oaes.ana_change_notices ? "Supported" : "Not Supported");
1854 	printf("  PLE Aggregate Log Change Notices:    %s\n",
1855 	       cdata->oaes.pleal_change_notices ? "Supported" : "Not Supported");
1856 	printf("  LBA Status Info Alert Notices:       %s\n",
1857 	       cdata->oaes.lba_sia_notices ? "Supported" : "Not Supported");
1858 	printf("  EGE Aggregate Log Change Notices:    %s\n",
1859 	       cdata->oaes.egealp_change_notices ? "Supported" : "Not Supported");
1860 	printf("  Normal NVM Subsystem Shutdown event: %s\n",
1861 	       cdata->oaes.nnvm_sse ? "Supported" : "Not Supported");
1862 	printf("  Zone Descriptor Change Notices:      %s\n",
1863 	       cdata->oaes.zdes_change_notices ? "Supported" : "Not Supported");
1864 	printf("  Discovery Log Change Notices:        %s\n",
1865 	       cdata->oaes.discovery_log_change_notices ? "Supported" : "Not Supported");
1866 
1867 	printf("Controller Attributes\n");
1868 	printf("  128-bit Host Identifier:             %s\n",
1869 	       cdata->ctratt.bits.host_id_exhid_supported ? "Supported" : "Not Supported");
1870 	printf("  Non-Operational Permissive Mode:     %s\n",
1871 	       cdata->ctratt.bits.non_operational_power_state_permissive_mode ? "Supported" : "Not Supported");
1872 	printf("  NVM Sets:                            %s\n",
1873 	       cdata->ctratt.bits.nvm_sets ? "Supported" : "Not Supported");
1874 	printf("  Read Recovery Levels:                %s\n",
1875 	       cdata->ctratt.bits.read_recovery_levels ? "Supported" : "Not Supported");
1876 	printf("  Endurance Groups:                    %s\n",
1877 	       cdata->ctratt.bits.endurance_groups ? "Supported" : "Not Supported");
1878 	printf("  Predictable Latency Mode:            %s\n",
1879 	       cdata->ctratt.bits.predictable_latency_mode ? "Supported" : "Not Supported");
1880 	printf("  Traffic Based Keep ALive:            %s\n",
1881 	       cdata->ctratt.bits.tbkas ? "Supported" : "Not Supported");
1882 	printf("  Namespace Granularity:               %s\n",
1883 	       cdata->ctratt.bits.namespace_granularity ? "Supported" : "Not Supported");
1884 	printf("  SQ Associations:                     %s\n",
1885 	       cdata->ctratt.bits.sq_associations ? "Supported" : "Not Supported");
1886 	printf("  UUID List:                           %s\n",
1887 	       cdata->ctratt.bits.uuid_list ? "Supported" : "Not Supported");
1888 	printf("  Multi-Domain Subsystem:              %s\n",
1889 	       cdata->ctratt.bits.mds ? "Supported" : "Not Supported");
1890 	printf("  Fixed Capacity Management:           %s\n",
1891 	       cdata->ctratt.bits.fixed_capacity_management ? "Supported" : "Not Supported");
1892 	printf("  Variable Capacity Management:        %s\n",
1893 	       cdata->ctratt.bits.variable_capacity_management ? "Supported" : "Not Supported");
1894 	printf("  Delete Endurance Group:              %s\n",
1895 	       cdata->ctratt.bits.delete_endurance_group ? "Supported" : "Not Supported");
1896 	printf("  Delete NVM Set:                      %s\n",
1897 	       cdata->ctratt.bits.delete_nvm_set ? "Supported" : "Not Supported");
1898 	printf("  Extended LBA Formats Supported:      %s\n",
1899 	       cdata->ctratt.bits.elbas ? "Supported" : "Not Supported");
1900 	printf("  Flexible Data Placement Supported:   %s\n",
1901 	       cdata->ctratt.bits.fdps ? "Supported" : "Not Supported");
1902 	printf("\n");
1903 
1904 	printf("Controller Memory Buffer Support\n");
1905 	printf("================================\n");
1906 	if (cap.bits.cmbs != 0) {
1907 		union spdk_nvme_cmbsz_register		cmbsz;
1908 		uint64_t size;
1909 
1910 		cmbsz = spdk_nvme_ctrlr_get_regs_cmbsz(ctrlr);
1911 		size = cmbsz.bits.sz;
1912 
1913 		/* Convert the size to bytes by multiplying by the granularity.
1914 		   By spec, szu is at most 6 and sz is 20 bits, so size requires
1915 		   at most 56 bits. */
1916 		size *= (0x1000 << (cmbsz.bits.szu * 4));
1917 
1918 		printf("Supported:                             Yes\n");
1919 		printf("Total Size:                            %" PRIu64 " bytes\n", size);
1920 		printf("Submission Queues in CMB:              %s\n",
1921 		       cmbsz.bits.sqs ? "Supported" : "Not Supported");
1922 		printf("Completion Queues in CMB:              %s\n",
1923 		       cmbsz.bits.cqs ? "Supported" : "Not Supported");
1924 		printf("Read data and metadata in CMB          %s\n",
1925 		       cmbsz.bits.rds ? "Supported" : "Not Supported");
1926 		printf("Write data and metadata in CMB:        %s\n",
1927 		       cmbsz.bits.wds ? "Supported" : "Not Supported");
1928 	} else {
1929 		printf("Supported:                             No\n");
1930 	}
1931 	printf("\n");
1932 
1933 	printf("Persistent Memory Region Support\n");
1934 	printf("================================\n");
1935 	if (cap.bits.pmrs != 0) {
1936 		union spdk_nvme_pmrcap_register		pmrcap;
1937 		uint64_t				pmrsz;
1938 
1939 		pmrcap = spdk_nvme_ctrlr_get_regs_pmrcap(ctrlr);
1940 		pmrsz = spdk_nvme_ctrlr_get_pmrsz(ctrlr);
1941 
1942 		printf("Supported:                             Yes\n");
1943 		printf("Total Size:                            %" PRIu64 " bytes\n", pmrsz);
1944 		printf("Read data and metadata in PMR          %s\n",
1945 		       pmrcap.bits.rds ? "Supported" : "Not Supported");
1946 		printf("Write data and metadata in PMR:        %s\n",
1947 		       pmrcap.bits.wds ? "Supported" : "Not Supported");
1948 	} else {
1949 		printf("Supported:                             No\n");
1950 	}
1951 	printf("\n");
1952 
1953 	printf("Admin Command Set Attributes\n");
1954 	printf("============================\n");
1955 	printf("Security Send/Receive:                 %s\n",
1956 	       cdata->oacs.security ? "Supported" : "Not Supported");
1957 	printf("Format NVM:                            %s\n",
1958 	       cdata->oacs.format ? "Supported" : "Not Supported");
1959 	printf("Firmware Activate/Download:            %s\n",
1960 	       cdata->oacs.firmware ? "Supported" : "Not Supported");
1961 	printf("Namespace Management:                  %s\n",
1962 	       cdata->oacs.ns_manage ? "Supported" : "Not Supported");
1963 	printf("Device Self-Test:                      %s\n",
1964 	       cdata->oacs.device_self_test ? "Supported" : "Not Supported");
1965 	printf("Directives:                            %s\n",
1966 	       cdata->oacs.directives ? "Supported" : "Not Supported");
1967 	printf("NVMe-MI:                               %s\n",
1968 	       cdata->oacs.nvme_mi ? "Supported" : "Not Supported");
1969 	printf("Virtualization Management:             %s\n",
1970 	       cdata->oacs.virtualization_management ? "Supported" : "Not Supported");
1971 	printf("Doorbell Buffer Config:                %s\n",
1972 	       cdata->oacs.doorbell_buffer_config ? "Supported" : "Not Supported");
1973 	printf("Get LBA Status Capability:             %s\n",
1974 	       cdata->oacs.get_lba_status ? "Supported" : "Not Supported");
1975 	printf("Command & Feature Lockdown Capability: %s\n",
1976 	       cdata->oacs.command_feature_lockdown ? "Supported" : "Not Supported");
1977 	printf("Abort Command Limit:                   %d\n", cdata->acl + 1);
1978 	printf("Async Event Request Limit:             %d\n", cdata->aerl + 1);
1979 	printf("Number of Firmware Slots:              ");
1980 	if (cdata->oacs.firmware != 0) {
1981 		printf("%d\n", cdata->frmw.num_slots);
1982 	} else {
1983 		printf("N/A\n");
1984 	}
1985 	printf("Firmware Slot 1 Read-Only:             ");
1986 	if (cdata->oacs.firmware != 0) {
1987 		printf("%s\n", cdata->frmw.slot1_ro ? "Yes" : "No");
1988 	} else {
1989 		printf("N/A\n");
1990 	}
1991 	printf("Firmware Activation Without Reset:     ");
1992 	if (cdata->oacs.firmware != 0) {
1993 		printf("%s\n", cdata->frmw.activation_without_reset ? "Yes" : "No");
1994 	} else {
1995 		printf("N/A\n");
1996 	}
1997 	printf("Multiple Update Detection Support:     ");
1998 	if (cdata->oacs.firmware != 0) {
1999 		printf("%s\n", cdata->frmw.multiple_update_detection ? "Yes" : "No");
2000 	} else {
2001 		printf("N/A\n");
2002 	}
2003 	if (cdata->fwug == 0x00) {
2004 		printf("Firmware Update Granularity:           No Information Provided\n");
2005 	} else if (cdata->fwug == 0xFF) {
2006 		printf("Firmware Update Granularity:           No Restriction\n");
2007 	} else {
2008 		printf("Firmware Update Granularity:           %u KiB\n",
2009 		       cdata->fwug * 4);
2010 	}
2011 	printf("Per-Namespace SMART Log:               %s\n",
2012 	       cdata->lpa.ns_smart ? "Yes" : "No");
2013 	if (cdata->cmic.ana_reporting == 0) {
2014 		printf("Asymmetric Namespace Access Log Page:  Not Supported\n");
2015 	} else {
2016 		printf("Asymmetric Namespace Access Log Page:  Supported\n");
2017 		printf("ANA Transition Time                 :  %u sec\n", cdata->anatt);
2018 		printf("\n");
2019 		printf("Asymmetric Namespace Access Capabilities\n");
2020 		printf("  ANA Optimized State               : %s\n",
2021 		       cdata->anacap.ana_optimized_state ? "Supported" : "Not Supported");
2022 		printf("  ANA Non-Optimized State           : %s\n",
2023 		       cdata->anacap.ana_non_optimized_state ? "Supported" : "Not Supported");
2024 		printf("  ANA Inaccessible State            : %s\n",
2025 		       cdata->anacap.ana_inaccessible_state ? "Supported" : "Not Supported");
2026 		printf("  ANA Persistent Loss State         : %s\n",
2027 		       cdata->anacap.ana_persistent_loss_state ? "Supported" : "Not Supported");
2028 		printf("  ANA Change State                  : %s\n",
2029 		       cdata->anacap.ana_change_state ? "Supported" : "Not Supported");
2030 		printf("  ANAGRPID is not changed           : %s\n",
2031 		       cdata->anacap.no_change_anagrpid ? "Yes" : "No");
2032 		printf("  Non-Zero ANAGRPID for NS Mgmt Cmd : %s\n",
2033 		       cdata->anacap.non_zero_anagrpid ? "Supported" : "Not Supported");
2034 		printf("\n");
2035 		printf("ANA Group Identifier Maximum        : %u\n", cdata->anagrpmax);
2036 		printf("Number of ANA Group Identifiers     : %u\n", cdata->nanagrpid);
2037 		printf("Max Number of Allowed Namespaces    : %u\n", cdata->mnan);
2038 	}
2039 	printf("Subsystem NQN:                         %s\n", cdata->subnqn);
2040 	printf("Command Effects Log Page:              %s\n",
2041 	       cdata->lpa.celp ? "Supported" : "Not Supported");
2042 	printf("Get Log Page Extended Data:            %s\n",
2043 	       cdata->lpa.edlp ? "Supported" : "Not Supported");
2044 	printf("Telemetry Log Pages:                   %s\n",
2045 	       cdata->lpa.telemetry ? "Supported" : "Not Supported");
2046 	printf("Persistent Event Log Pages:            %s\n",
2047 	       cdata->lpa.pelp ? "Supported" : "Not Supported");
2048 	printf("Supported Log Pages Log Page:          %s\n",
2049 	       cdata->lpa.lplp ? "Supported" : "May Support");
2050 	printf("Commands Supported & Effects Log Page: %s\n",
2051 	       cdata->lpa.lplp ? "Supported" : "Not Supported");
2052 	printf("Feature Identifiers & Effects Log Page:%s\n",
2053 	       cdata->lpa.lplp ? "Supported" : "May Support");
2054 	printf("NVMe-MI Commands & Effects Log Page:   %s\n",
2055 	       cdata->lpa.lplp ? "Supported" : "May Support");
2056 	printf("Data Area 4 for Telemetry Log:         %s\n",
2057 	       cdata->lpa.da4_telemetry ? "Supported" : "Not Supported");
2058 	printf("Error Log Page Entries Supported:      %d\n", cdata->elpe + 1);
2059 	if (cdata->kas == 0) {
2060 		printf("Keep Alive:                            Not Supported\n");
2061 	} else {
2062 		printf("Keep Alive:                            Supported\n");
2063 		printf("Keep Alive Granularity:                %u ms\n",
2064 		       cdata->kas * 100);
2065 	}
2066 	printf("\n");
2067 
2068 	printf("NVM Command Set Attributes\n");
2069 	printf("==========================\n");
2070 	printf("Submission Queue Entry Size\n");
2071 	printf("  Max:                       %d\n", 1 << cdata->sqes.max);
2072 	printf("  Min:                       %d\n", 1 << cdata->sqes.min);
2073 	printf("Completion Queue Entry Size\n");
2074 	printf("  Max:                       %d\n", 1 << cdata->cqes.max);
2075 	printf("  Min:                       %d\n", 1 << cdata->cqes.min);
2076 	printf("Number of Namespaces:        %d\n", cdata->nn);
2077 	printf("Compare Command:             %s\n",
2078 	       cdata->oncs.compare ? "Supported" : "Not Supported");
2079 	printf("Write Uncorrectable Command: %s\n",
2080 	       cdata->oncs.write_unc ? "Supported" : "Not Supported");
2081 	printf("Dataset Management Command:  %s\n",
2082 	       cdata->oncs.dsm ? "Supported" : "Not Supported");
2083 	printf("Write Zeroes Command:        %s\n",
2084 	       cdata->oncs.write_zeroes ? "Supported" : "Not Supported");
2085 	printf("Set Features Save Field:     %s\n",
2086 	       cdata->oncs.set_features_save ? "Supported" : "Not Supported");
2087 	printf("Reservations:                %s\n",
2088 	       cdata->oncs.reservations ? "Supported" : "Not Supported");
2089 	printf("Timestamp:                   %s\n",
2090 	       cdata->oncs.timestamp ? "Supported" : "Not Supported");
2091 	printf("Copy:                        %s\n",
2092 	       cdata->oncs.copy ? "Supported" : "Not Supported");
2093 	printf("Volatile Write Cache:        %s\n",
2094 	       cdata->vwc.present ? "Present" : "Not Present");
2095 	printf("Atomic Write Unit (Normal):  %d\n", cdata->awun + 1);
2096 	printf("Atomic Write Unit (PFail):   %d\n", cdata->awupf + 1);
2097 	printf("Atomic Compare & Write Unit: %d\n", cdata->acwu + 1);
2098 	printf("Fused Compare & Write:       %s\n",
2099 	       cdata->fuses.compare_and_write ? "Supported" : "Not Supported");
2100 	printf("Scatter-Gather List\n");
2101 	printf("  SGL Command Set:           %s\n",
2102 	       cdata->sgls.supported == SPDK_NVME_SGLS_SUPPORTED ? "Supported" :
2103 	       cdata->sgls.supported == SPDK_NVME_SGLS_SUPPORTED_DWORD_ALIGNED ? "Supported (Dword aligned)" :
2104 	       "Not Supported");
2105 	printf("  SGL Keyed:                 %s\n",
2106 	       cdata->sgls.keyed_sgl ? "Supported" : "Not Supported");
2107 	printf("  SGL Bit Bucket Descriptor: %s\n",
2108 	       cdata->sgls.bit_bucket_descriptor ? "Supported" : "Not Supported");
2109 	printf("  SGL Metadata Pointer:      %s\n",
2110 	       cdata->sgls.metadata_pointer ? "Supported" : "Not Supported");
2111 	printf("  Oversized SGL:             %s\n",
2112 	       cdata->sgls.oversized_sgl ? "Supported" : "Not Supported");
2113 	printf("  SGL Metadata Address:      %s\n",
2114 	       cdata->sgls.metadata_address ? "Supported" : "Not Supported");
2115 	printf("  SGL Offset:                %s\n",
2116 	       cdata->sgls.sgl_offset ? "Supported" : "Not Supported");
2117 	printf("  Transport SGL Data Block:  %s\n",
2118 	       cdata->sgls.transport_sgl ? "Supported" : "Not Supported");
2119 	printf("Replay Protected Memory Block:");
2120 	if (cdata->rpmbs.num_rpmb_units > 0) {
2121 		printf("  Supported\n");
2122 		printf("  Number of RPMB Units:  %d\n", cdata->rpmbs.num_rpmb_units);
2123 		printf("  Authentication Method: %s\n", cdata->rpmbs.auth_method == 0 ? "HMAC SHA-256" : "Unknown");
2124 		printf("  Total Size (in 128KB units) = %d\n", cdata->rpmbs.total_size + 1);
2125 		printf("  Access Size (in 512B units) = %d\n", cdata->rpmbs.access_size + 1);
2126 	} else {
2127 		printf("  Not Supported\n");
2128 	}
2129 	if (cdata->crdt[0]) {
2130 		printf("Command Retry Delay Time 1:  %u milliseconds\n", cdata->crdt[0] * 100);
2131 	}
2132 	if (cdata->crdt[1]) {
2133 		printf("Command Retry Delay Time 2:  %u milliseconds\n", cdata->crdt[1] * 100);
2134 	}
2135 	if (cdata->crdt[2]) {
2136 		printf("Command Retry Delay Time 3:  %u milliseconds\n", cdata->crdt[2] * 100);
2137 	}
2138 	printf("\n");
2139 
2140 	printf("Firmware Slot Information\n");
2141 	printf("=========================\n");
2142 	if (g_hex_dump) {
2143 		hex_dump(&firmware_page, sizeof(firmware_page));
2144 		printf("\n");
2145 	}
2146 	printf("Active slot:                 %u\n", firmware_page.afi.active_slot);
2147 	if (firmware_page.afi.next_reset_slot) {
2148 		printf("Next controller reset slot:  %u\n", firmware_page.afi.next_reset_slot);
2149 	}
2150 	for (i = 0; i < 7; i++) {
2151 		if (!spdk_mem_all_zero(firmware_page.revision[i], sizeof(firmware_page.revision[i]))) {
2152 			printf("Slot %u Firmware Revision:    ", i + 1);
2153 			print_ascii_string(firmware_page.revision[i], sizeof(firmware_page.revision[i]));
2154 			printf("\n");
2155 		}
2156 	}
2157 	printf("\n");
2158 
2159 	if (g_ana_log_page) {
2160 		printf("Asymmetric Namespace Access\n");
2161 		printf("===========================\n");
2162 		if (g_hex_dump) {
2163 			hex_dump(g_ana_log_page, g_ana_log_page_size);
2164 			printf("\n");
2165 		}
2166 
2167 		printf("Change Count                    : %" PRIx64 "\n", g_ana_log_page->change_count);
2168 		printf("Number of ANA Group Descriptors : %u\n", g_ana_log_page->num_ana_group_desc);
2169 
2170 		copied_desc = g_copied_ana_desc;
2171 		orig_desc = (uint8_t *)g_ana_log_page + sizeof(struct spdk_nvme_ana_page);
2172 		copy_len = g_ana_log_page_size - sizeof(struct spdk_nvme_ana_page);
2173 
2174 		for (i = 0; i < g_ana_log_page->num_ana_group_desc; i++) {
2175 			memcpy(copied_desc, orig_desc, copy_len);
2176 
2177 			printf("ANA Group Descriptor            : %u\n", i);
2178 			printf("  ANA Group ID                  : %u\n", copied_desc->ana_group_id);
2179 			printf("  Number of NSID Values         : %u\n", copied_desc->num_of_nsid);
2180 			printf("  Change Count                  : %" PRIx64 "\n", copied_desc->change_count);
2181 			printf("  ANA State                     : %u\n", copied_desc->ana_state);
2182 			for (j = 0; j < copied_desc->num_of_nsid; j++) {
2183 				printf("  Namespace Identifier          : %u\n", copied_desc->nsid[j]);
2184 			}
2185 
2186 			desc_size = sizeof(struct spdk_nvme_ana_group_descriptor) +
2187 				    copied_desc->num_of_nsid * sizeof(uint32_t);
2188 			orig_desc += desc_size;
2189 			copy_len -= desc_size;
2190 		}
2191 		free(g_ana_log_page);
2192 		free(g_copied_ana_desc);
2193 	}
2194 
2195 	printf("\n");
2196 
2197 	if (cdata->lpa.celp) {
2198 		printf("Commands Supported and Effects\n");
2199 		printf("==============================\n");
2200 
2201 		if (g_hex_dump) {
2202 			hex_dump(&cmd_effects_log_page, sizeof(cmd_effects_log_page));
2203 			printf("\n");
2204 		}
2205 
2206 		printf("Admin Commands\n");
2207 		printf("--------------\n");
2208 		for (i = 0; i < SPDK_COUNTOF(cmd_effects_log_page.admin_cmds_supported); i++) {
2209 			struct spdk_nvme_cmds_and_effect_entry *cmd = &cmd_effects_log_page.admin_cmds_supported[i];
2210 			if (cmd->csupp) {
2211 				printf("%30s (%02Xh): Supported %s%s%s%s%s\n",
2212 				       admin_opc_name(i), i,
2213 				       cmd->lbcc ? "LBA-Change " : "",
2214 				       cmd->ncc ? "NS-Cap-Change " : "",
2215 				       cmd->nic ? "NS-Inventory-Change " : "",
2216 				       cmd->ccc ? "Ctrlr-Cap-Change " : "",
2217 				       cmd->cse == 0 ? "" : cmd->cse == 1 ? "Per-NS-Exclusive" : cmd->cse == 2 ? "All-NS-Exclusive" : "");
2218 			}
2219 		}
2220 
2221 		printf("I/O Commands\n");
2222 		printf("------------\n");
2223 		for (i = 0; i < SPDK_COUNTOF(cmd_effects_log_page.io_cmds_supported); i++) {
2224 			struct spdk_nvme_cmds_and_effect_entry *cmd = &cmd_effects_log_page.io_cmds_supported[i];
2225 			if (cmd->csupp) {
2226 				printf("%30s (%02Xh): Supported %s%s%s%s%s\n",
2227 				       io_opc_name(i), i,
2228 				       cmd->lbcc ? "LBA-Change " : "",
2229 				       cmd->ncc ? "NS-Cap-Change " : "",
2230 				       cmd->nic ? "NS-Inventory-Change " : "",
2231 				       cmd->ccc ? "Ctrlr-Cap-Change " : "",
2232 				       cmd->cse == 0 ? "" : cmd->cse == 1 ? "Per-NS-Exclusive" : cmd->cse == 2 ? "All-NS-Exclusive" : "");
2233 			}
2234 		}
2235 		printf("\n");
2236 	}
2237 
2238 	printf("Error Log\n");
2239 	printf("=========\n");
2240 	for (i = 0; i <= cdata->elpe; i++) {
2241 		error_entry = &error_page[i];
2242 		if (error_entry->error_count == 0) {
2243 			continue;
2244 		}
2245 		if (i != 0) {
2246 			printf("-----------\n");
2247 		}
2248 
2249 		printf("Entry: %u\n", i);
2250 		printf("Error Count:            0x%"PRIx64"\n", error_entry->error_count);
2251 		printf("Submission Queue Id:    0x%x\n", error_entry->sqid);
2252 		printf("Command Id:             0x%x\n", error_entry->cid);
2253 		printf("Phase Bit:              %x\n", error_entry->status.p);
2254 		printf("Status Code:            0x%x\n", error_entry->status.sc);
2255 		printf("Status Code Type:       0x%x\n", error_entry->status.sct);
2256 		printf("Do Not Retry:           %x\n", error_entry->status.dnr);
2257 		printf("Error Location:         0x%x\n", error_entry->error_location);
2258 		printf("LBA:                    0x%"PRIx64"\n", error_entry->lba);
2259 		printf("Namespace:              0x%x\n", error_entry->nsid);
2260 		printf("Vendor Log Page:        0x%x\n", error_entry->vendor_specific);
2261 
2262 	}
2263 	printf("\n");
2264 
2265 	if (features[SPDK_NVME_FEAT_ARBITRATION].valid) {
2266 		uint32_t arb = features[SPDK_NVME_FEAT_ARBITRATION].result;
2267 		unsigned ab, lpw, mpw, hpw;
2268 
2269 		ab = arb & 0x7;
2270 		lpw = ((arb >> 8) & 0xFF) + 1;
2271 		mpw = ((arb >> 16) & 0xFF) + 1;
2272 		hpw = ((arb >> 24) & 0xFF) + 1;
2273 
2274 		printf("Arbitration\n");
2275 		printf("===========\n");
2276 		printf("Arbitration Burst:           ");
2277 		if (ab == 0x7) {
2278 			printf("no limit\n");
2279 		} else {
2280 			printf("%u\n", 1u << ab);
2281 		}
2282 
2283 		if (cap.bits.ams & SPDK_NVME_CAP_AMS_WRR) {
2284 			printf("Low Priority Weight:         %u\n", lpw);
2285 			printf("Medium Priority Weight:      %u\n", mpw);
2286 			printf("High Priority Weight:        %u\n", hpw);
2287 		}
2288 		printf("\n");
2289 	}
2290 
2291 	if (features[SPDK_NVME_FEAT_POWER_MANAGEMENT].valid) {
2292 		unsigned ps = features[SPDK_NVME_FEAT_POWER_MANAGEMENT].result & 0x1F;
2293 		printf("Power Management\n");
2294 		printf("================\n");
2295 		printf("Number of Power States:          %u\n", cdata->npss + 1);
2296 		printf("Current Power State:             Power State #%u\n", ps);
2297 		for (i = 0; i <= cdata->npss; i++) {
2298 			const struct spdk_nvme_power_state psd = cdata->psd[i];
2299 			printf("Power State #%u:\n", i);
2300 			if (psd.mps) {
2301 				/* MP scale is 0.0001 W */
2302 				printf("  Max Power:                    %u.%04u W\n",
2303 				       psd.mp / 10000,
2304 				       psd.mp % 10000);
2305 			} else {
2306 				/* MP scale is 0.01 W */
2307 				printf("  Max Power:                    %3u.%02u W\n",
2308 				       psd.mp / 100,
2309 				       psd.mp % 100);
2310 			}
2311 			printf("  Non-Operational State:         %s\n",
2312 			       psd.nops ? "Non-Operation" : "Operational");
2313 			printf("  Entry Latency:                 ");
2314 			if (psd.enlat) {
2315 				printf("%u microseconds\n", psd.enlat);
2316 			} else {
2317 				printf("Not Reported\n");
2318 			}
2319 			printf("  Exit Latency:                  ");
2320 			if (psd.exlat) {
2321 				printf("%u microseconds\n", psd.exlat);
2322 			} else {
2323 				printf("Not Reported\n");
2324 			}
2325 			printf("  Relative Read Throughput:      %u\n", psd.rrt);
2326 			printf("  Relative Read Latency:         %u\n", psd.rrl);
2327 			printf("  Relative Write Throughput:     %u\n", psd.rwt);
2328 			printf("  Relative Write Latency:        %u\n", psd.rwl);
2329 			printf("  Idle Power:                    ");
2330 			switch (psd.ips) {
2331 			case 1:
2332 				/* Idle Power scale is 0.0001 W */
2333 				printf("%u.%04u W\n", psd.idlp / 10000, psd.idlp % 10000);
2334 				break;
2335 			case 2:
2336 				/* Idle Power scale is 0.01 W */
2337 				printf("%u.%02u W\n", psd.idlp / 100, psd.idlp % 100);
2338 				break;
2339 			default:
2340 				printf(" Not Reported\n");
2341 			}
2342 			printf("  Active Power:                  ");
2343 			switch (psd.aps) {
2344 			case 1:
2345 				/* Active Power scale is 0.0001 W */
2346 				printf("%u.%04u W\n", psd.actp / 10000, psd.actp % 10000);
2347 				break;
2348 			case 2:
2349 				/* Active Power scale is 0.01 W */
2350 				printf("%u.%02u W\n", psd.actp / 100, psd.actp % 100);
2351 				break;
2352 			default:
2353 				printf(" Not Reported\n");
2354 			}
2355 		}
2356 		printf("Non-Operational Permissive Mode: %s\n",
2357 		       cdata->ctratt.bits.non_operational_power_state_permissive_mode ? "Supported" : "Not Supported");
2358 		printf("\n");
2359 	}
2360 
2361 	if (features[SPDK_NVME_FEAT_TEMPERATURE_THRESHOLD].valid) {
2362 		printf("Health Information\n");
2363 		printf("==================\n");
2364 
2365 		if (g_hex_dump) {
2366 			hex_dump(&health_page, sizeof(health_page));
2367 			printf("\n");
2368 		}
2369 
2370 		printf("Critical Warnings:\n");
2371 		printf("  Available Spare Space:     %s\n",
2372 		       health_page.critical_warning.bits.available_spare ? "WARNING" : "OK");
2373 		printf("  Temperature:               %s\n",
2374 		       health_page.critical_warning.bits.temperature ? "WARNING" : "OK");
2375 		printf("  Device Reliability:        %s\n",
2376 		       health_page.critical_warning.bits.device_reliability ? "WARNING" : "OK");
2377 		printf("  Read Only:                 %s\n",
2378 		       health_page.critical_warning.bits.read_only ? "Yes" : "No");
2379 		printf("  Volatile Memory Backup:    %s\n",
2380 		       health_page.critical_warning.bits.volatile_memory_backup ? "WARNING" : "OK");
2381 		printf("Current Temperature:         %u Kelvin (%d Celsius)\n",
2382 		       health_page.temperature,
2383 		       (int)health_page.temperature - 273);
2384 		printf("Temperature Threshold:       %u Kelvin (%d Celsius)\n",
2385 		       features[SPDK_NVME_FEAT_TEMPERATURE_THRESHOLD].result,
2386 		       (int)features[SPDK_NVME_FEAT_TEMPERATURE_THRESHOLD].result - 273);
2387 		printf("Available Spare:             %u%%\n", health_page.available_spare);
2388 		printf("Available Spare Threshold:   %u%%\n", health_page.available_spare_threshold);
2389 		printf("Life Percentage Used:        %u%%\n", health_page.percentage_used);
2390 		printf("Data Units Read:             ");
2391 		print_uint128_dec(health_page.data_units_read);
2392 		printf("\n");
2393 		printf("Data Units Written:          ");
2394 		print_uint128_dec(health_page.data_units_written);
2395 		printf("\n");
2396 		printf("Host Read Commands:          ");
2397 		print_uint128_dec(health_page.host_read_commands);
2398 		printf("\n");
2399 		printf("Host Write Commands:         ");
2400 		print_uint128_dec(health_page.host_write_commands);
2401 		printf("\n");
2402 		printf("Controller Busy Time:        ");
2403 		print_uint128_dec(health_page.controller_busy_time);
2404 		printf(" minutes\n");
2405 		printf("Power Cycles:                ");
2406 		print_uint128_dec(health_page.power_cycles);
2407 		printf("\n");
2408 		printf("Power On Hours:              ");
2409 		print_uint128_dec(health_page.power_on_hours);
2410 		printf(" hours\n");
2411 		printf("Unsafe Shutdowns:            ");
2412 		print_uint128_dec(health_page.unsafe_shutdowns);
2413 		printf("\n");
2414 		printf("Unrecoverable Media Errors:  ");
2415 		print_uint128_dec(health_page.media_errors);
2416 		printf("\n");
2417 		printf("Lifetime Error Log Entries:  ");
2418 		print_uint128_dec(health_page.num_error_info_log_entries);
2419 		printf("\n");
2420 		printf("Warning Temperature Time:    %u minutes\n", health_page.warning_temp_time);
2421 		printf("Critical Temperature Time:   %u minutes\n", health_page.critical_temp_time);
2422 		for (i = 0; i < 8; i++) {
2423 			if (health_page.temp_sensor[i] != 0) {
2424 				printf("Temperature Sensor %d:        %u Kelvin (%d Celsius)\n",
2425 				       i + 1, health_page.temp_sensor[i],
2426 				       (int)health_page.temp_sensor[i] - 273);
2427 			}
2428 		}
2429 		printf("\n");
2430 	}
2431 
2432 	if (features[SPDK_NVME_FEAT_NUMBER_OF_QUEUES].valid) {
2433 		uint32_t result = features[SPDK_NVME_FEAT_NUMBER_OF_QUEUES].result;
2434 
2435 		printf("Number of Queues\n");
2436 		printf("================\n");
2437 		printf("Number of I/O Submission Queues:      %u\n", (result & 0xFFFF) + 1);
2438 		printf("Number of I/O Completion Queues:      %u\n", (result & 0xFFFF0000 >> 16) + 1);
2439 		printf("\n");
2440 	}
2441 
2442 	if (features[SPDK_OCSSD_FEAT_MEDIA_FEEDBACK].valid) {
2443 		uint32_t result = features[SPDK_OCSSD_FEAT_MEDIA_FEEDBACK].result;
2444 
2445 		printf("OCSSD Media Feedback\n");
2446 		printf("=======================\n");
2447 		printf("High ECC status:                %u\n", (result & 0x1));
2448 		printf("Vector High ECC status:         %u\n", (result & 0x2 >> 1));
2449 		printf("\n");
2450 	}
2451 
2452 	if (cdata->hctma.bits.supported) {
2453 		printf("Host Controlled Thermal Management\n");
2454 		printf("==================================\n");
2455 		printf("Minimum Thermal Management Temperature:  ");
2456 		if (cdata->mntmt) {
2457 			printf("%u Kelvin (%d Celsius)\n", cdata->mntmt, (int)cdata->mntmt - 273);
2458 		} else {
2459 			printf("Not Reported\n");
2460 		}
2461 		printf("Maximum Thermal Management Temperature:   ");
2462 		if (cdata->mxtmt) {
2463 			printf("%u Kelvin (%d Celsius)\n", cdata->mxtmt, (int)cdata->mxtmt - 273);
2464 		} else {
2465 			printf("Not Reported\n");
2466 		}
2467 		printf("\n");
2468 	}
2469 
2470 	if (spdk_nvme_ctrlr_is_log_page_supported(ctrlr, SPDK_NVME_INTEL_LOG_SMART)) {
2471 		size_t i = 0;
2472 
2473 		printf("Intel Health Information\n");
2474 		printf("==================\n");
2475 		for (i = 0;
2476 		     i < SPDK_COUNTOF(intel_smart_page.attributes); i++) {
2477 			if (intel_smart_page.attributes[i].code == SPDK_NVME_INTEL_SMART_PROGRAM_FAIL_COUNT) {
2478 				printf("Program Fail Count:\n");
2479 				printf("  Normalized Value : %d\n",
2480 				       intel_smart_page.attributes[i].normalized_value);
2481 				printf("  Current Raw Value: ");
2482 				print_uint_var_dec(intel_smart_page.attributes[i].raw_value, 6);
2483 				printf("\n");
2484 			}
2485 			if (intel_smart_page.attributes[i].code == SPDK_NVME_INTEL_SMART_ERASE_FAIL_COUNT) {
2486 				printf("Erase Fail Count:\n");
2487 				printf("  Normalized Value : %d\n",
2488 				       intel_smart_page.attributes[i].normalized_value);
2489 				printf("  Current Raw Value: ");
2490 				print_uint_var_dec(intel_smart_page.attributes[i].raw_value, 6);
2491 				printf("\n");
2492 			}
2493 			if (intel_smart_page.attributes[i].code == SPDK_NVME_INTEL_SMART_WEAR_LEVELING_COUNT) {
2494 				printf("Wear Leveling Count:\n");
2495 				printf("  Normalized Value : %d\n",
2496 				       intel_smart_page.attributes[i].normalized_value);
2497 				printf("  Current Raw Value:\n");
2498 				printf("  Min: ");
2499 				print_uint_var_dec(&intel_smart_page.attributes[i].raw_value[0], 2);
2500 				printf("\n");
2501 				printf("  Max: ");
2502 				print_uint_var_dec(&intel_smart_page.attributes[i].raw_value[2], 2);
2503 				printf("\n");
2504 				printf("  Avg: ");
2505 				print_uint_var_dec(&intel_smart_page.attributes[i].raw_value[4], 2);
2506 				printf("\n");
2507 			}
2508 			if (intel_smart_page.attributes[i].code == SPDK_NVME_INTEL_SMART_E2E_ERROR_COUNT) {
2509 				printf("End to End Error Detection Count:\n");
2510 				printf("  Normalized Value : %d\n",
2511 				       intel_smart_page.attributes[i].normalized_value);
2512 				printf("  Current Raw Value: ");
2513 				print_uint_var_dec(intel_smart_page.attributes[i].raw_value, 6);
2514 				printf("\n");
2515 			}
2516 			if (intel_smart_page.attributes[i].code == SPDK_NVME_INTEL_SMART_CRC_ERROR_COUNT) {
2517 				printf("CRC Error Count:\n");
2518 				printf("  Normalized Value : %d\n",
2519 				       intel_smart_page.attributes[i].normalized_value);
2520 				printf("  Current Raw Value: ");
2521 				print_uint_var_dec(intel_smart_page.attributes[i].raw_value, 6);
2522 				printf("\n");
2523 			}
2524 			if (intel_smart_page.attributes[i].code == SPDK_NVME_INTEL_SMART_MEDIA_WEAR) {
2525 				printf("Timed Workload, Media Wear:\n");
2526 				printf("  Normalized Value : %d\n",
2527 				       intel_smart_page.attributes[i].normalized_value);
2528 				printf("  Current Raw Value: ");
2529 				print_uint_var_dec(intel_smart_page.attributes[i].raw_value, 6);
2530 				printf("\n");
2531 			}
2532 			if (intel_smart_page.attributes[i].code == SPDK_NVME_INTEL_SMART_HOST_READ_PERCENTAGE) {
2533 				printf("Timed Workload, Host Read/Write Ratio:\n");
2534 				printf("  Normalized Value : %d\n",
2535 				       intel_smart_page.attributes[i].normalized_value);
2536 				printf("  Current Raw Value: ");
2537 				print_uint_var_dec(intel_smart_page.attributes[i].raw_value, 6);
2538 				printf("%%");
2539 				printf("\n");
2540 			}
2541 			if (intel_smart_page.attributes[i].code == SPDK_NVME_INTEL_SMART_TIMER) {
2542 				printf("Timed Workload, Timer:\n");
2543 				printf("  Normalized Value : %d\n",
2544 				       intel_smart_page.attributes[i].normalized_value);
2545 				printf("  Current Raw Value: ");
2546 				print_uint_var_dec(intel_smart_page.attributes[i].raw_value, 6);
2547 				printf("\n");
2548 			}
2549 			if (intel_smart_page.attributes[i].code == SPDK_NVME_INTEL_SMART_THERMAL_THROTTLE_STATUS) {
2550 				printf("Thermal Throttle Status:\n");
2551 				printf("  Normalized Value : %d\n",
2552 				       intel_smart_page.attributes[i].normalized_value);
2553 				printf("  Current Raw Value:\n");
2554 				printf("  Percentage: %d%%\n", intel_smart_page.attributes[i].raw_value[0]);
2555 				printf("  Throttling Event Count: ");
2556 				print_uint_var_dec(&intel_smart_page.attributes[i].raw_value[1], 4);
2557 				printf("\n");
2558 			}
2559 			if (intel_smart_page.attributes[i].code == SPDK_NVME_INTEL_SMART_RETRY_BUFFER_OVERFLOW_COUNTER) {
2560 				printf("Retry Buffer Overflow Counter:\n");
2561 				printf("  Normalized Value : %d\n",
2562 				       intel_smart_page.attributes[i].normalized_value);
2563 				printf("  Current Raw Value: ");
2564 				print_uint_var_dec(intel_smart_page.attributes[i].raw_value, 6);
2565 				printf("\n");
2566 			}
2567 			if (intel_smart_page.attributes[i].code == SPDK_NVME_INTEL_SMART_PLL_LOCK_LOSS_COUNT) {
2568 				printf("PLL Lock Loss Count:\n");
2569 				printf("  Normalized Value : %d\n",
2570 				       intel_smart_page.attributes[i].normalized_value);
2571 				printf("  Current Raw Value: ");
2572 				print_uint_var_dec(intel_smart_page.attributes[i].raw_value, 6);
2573 				printf("\n");
2574 			}
2575 			if (intel_smart_page.attributes[i].code == SPDK_NVME_INTEL_SMART_NAND_BYTES_WRITTEN) {
2576 				printf("NAND Bytes Written:\n");
2577 				printf("  Normalized Value : %d\n",
2578 				       intel_smart_page.attributes[i].normalized_value);
2579 				printf("  Current Raw Value: ");
2580 				print_uint_var_dec(intel_smart_page.attributes[i].raw_value, 6);
2581 				printf("\n");
2582 			}
2583 			if (intel_smart_page.attributes[i].code == SPDK_NVME_INTEL_SMART_HOST_BYTES_WRITTEN) {
2584 				printf("Host Bytes Written:\n");
2585 				printf("  Normalized Value : %d\n",
2586 				       intel_smart_page.attributes[i].normalized_value);
2587 				printf("  Current Raw Value: ");
2588 				print_uint_var_dec(intel_smart_page.attributes[i].raw_value, 6);
2589 				printf("\n");
2590 			}
2591 		}
2592 		printf("\n");
2593 	}
2594 
2595 	if (spdk_nvme_ctrlr_is_log_page_supported(ctrlr, SPDK_NVME_INTEL_LOG_TEMPERATURE)) {
2596 		printf("Intel Temperature Information\n");
2597 		printf("==================\n");
2598 		printf("Current Temperature: %" PRIu64 "\n", intel_temperature_page.current_temperature);
2599 		printf("Overtemp shutdown Flag for last critical component temperature: %" PRIu64 "\n",
2600 		       intel_temperature_page.shutdown_flag_last);
2601 		printf("Overtemp shutdown Flag for life critical component temperature: %" PRIu64 "\n",
2602 		       intel_temperature_page.shutdown_flag_life);
2603 		printf("Highest temperature: %" PRIu64 "\n", intel_temperature_page.highest_temperature);
2604 		printf("Lowest temperature: %" PRIu64 "\n", intel_temperature_page.lowest_temperature);
2605 		printf("Specified Maximum Operating Temperature: %" PRIu64 "\n",
2606 		       intel_temperature_page.specified_max_op_temperature);
2607 		printf("Specified Minimum Operating Temperature: %" PRIu64 "\n",
2608 		       intel_temperature_page.specified_min_op_temperature);
2609 		printf("Estimated offset: %" PRId64 "\n", (int64_t)intel_temperature_page.estimated_offset);
2610 		printf("\n");
2611 		printf("\n");
2612 
2613 	}
2614 
2615 	if (spdk_nvme_ctrlr_is_log_page_supported(ctrlr, SPDK_NVME_INTEL_MARKETING_DESCRIPTION)) {
2616 		printf("Intel Marketing Information\n");
2617 		printf("==================\n");
2618 		snprintf(str, sizeof(intel_md_page.marketing_product), "%s", intel_md_page.marketing_product);
2619 		printf("Marketing Product Information:		%s\n", str);
2620 		printf("\n");
2621 		printf("\n");
2622 	}
2623 
2624 	if (spdk_nvme_zns_ctrlr_get_data(ctrlr)) {
2625 		printf("ZNS Specific Controller Data\n");
2626 		printf("============================\n");
2627 		printf("Zone Append Size Limit:      %u\n",
2628 		       spdk_nvme_zns_ctrlr_get_data(ctrlr)->zasl);
2629 		printf("\n");
2630 		printf("\n");
2631 	}
2632 
2633 	printf("Active Namespaces\n");
2634 	printf("=================\n");
2635 	for (nsid = spdk_nvme_ctrlr_get_first_active_ns(ctrlr);
2636 	     nsid != 0; nsid = spdk_nvme_ctrlr_get_next_active_ns(ctrlr, nsid)) {
2637 		get_ns_features(ctrlr, nsid);
2638 		print_namespace(ctrlr, spdk_nvme_ctrlr_get_ns(ctrlr, nsid));
2639 	}
2640 
2641 	if (g_discovery_page) {
2642 		printf("Discovery Log Page\n");
2643 		printf("==================\n");
2644 
2645 		if (g_hex_dump) {
2646 			hex_dump(g_discovery_page, g_discovery_page_size);
2647 			printf("\n");
2648 		}
2649 
2650 		printf("Generation Counter:                    %" PRIu64 "\n",
2651 		       from_le64(&g_discovery_page->genctr));
2652 		printf("Number of Records:                     %" PRIu64 "\n",
2653 		       from_le64(&g_discovery_page->numrec));
2654 		printf("Record Format:                         %" PRIu16 "\n",
2655 		       from_le16(&g_discovery_page->recfmt));
2656 		printf("\n");
2657 
2658 		for (i = 0; i < g_discovery_page_numrec; i++) {
2659 			struct spdk_nvmf_discovery_log_page_entry *entry = &g_discovery_page->entries[i];
2660 
2661 			printf("Discovery Log Entry %u\n", i);
2662 			printf("----------------------\n");
2663 			printf("Transport Type:                        %u (%s)\n",
2664 			       entry->trtype, spdk_nvme_transport_id_trtype_str(entry->trtype));
2665 			printf("Address Family:                        %u (%s)\n",
2666 			       entry->adrfam, spdk_nvme_transport_id_adrfam_str(entry->adrfam));
2667 			printf("Subsystem Type:                        %u (%s)\n",
2668 			       entry->subtype,
2669 			       entry->subtype == SPDK_NVMF_SUBTYPE_DISCOVERY ? "Referral to a discovery service" :
2670 			       entry->subtype == SPDK_NVMF_SUBTYPE_NVME ? "NVM Subsystem" :
2671 			       entry->subtype == SPDK_NVMF_SUBTYPE_DISCOVERY_CURRENT ? "Current Discovery Subsystem" :
2672 			       "Unknown");
2673 			printf("Entry Flags:\n");
2674 			printf("  Duplicate Returned Information:			%u\n",
2675 			       !!(entry->eflags & SPDK_NVMF_DISCOVERY_LOG_EFLAGS_DUPRETINFO));
2676 			printf("  Explicit Persistent Connection Support for Discovery: %u\n",
2677 			       !!(entry->eflags & SPDK_NVMF_DISCOVERY_LOG_EFLAGS_EPCSD));
2678 			printf("Transport Requirements:\n");
2679 			printf("  Secure Channel:                      %s\n",
2680 			       entry->treq.secure_channel == SPDK_NVMF_TREQ_SECURE_CHANNEL_NOT_SPECIFIED ? "Not Specified" :
2681 			       entry->treq.secure_channel == SPDK_NVMF_TREQ_SECURE_CHANNEL_REQUIRED ? "Required" :
2682 			       entry->treq.secure_channel == SPDK_NVMF_TREQ_SECURE_CHANNEL_NOT_REQUIRED ? "Not Required" :
2683 			       "Reserved");
2684 			printf("Port ID:                               %" PRIu16 " (0x%04" PRIx16 ")\n",
2685 			       from_le16(&entry->portid), from_le16(&entry->portid));
2686 			printf("Controller ID:                         %" PRIu16 " (0x%04" PRIx16 ")\n",
2687 			       from_le16(&entry->cntlid), from_le16(&entry->cntlid));
2688 			printf("Admin Max SQ Size:                     %" PRIu16 "\n",
2689 			       from_le16(&entry->asqsz));
2690 			snprintf(str, sizeof(entry->trsvcid) + 1, "%s", entry->trsvcid);
2691 			printf("Transport Service Identifier:          %s\n", str);
2692 			snprintf(str, sizeof(entry->subnqn) + 1, "%s", entry->subnqn);
2693 			printf("NVM Subsystem Qualified Name:          %s\n", str);
2694 			snprintf(str, sizeof(entry->traddr) + 1, "%s", entry->traddr);
2695 			printf("Transport Address:                     %s\n", str);
2696 
2697 			if (entry->trtype == SPDK_NVMF_TRTYPE_RDMA) {
2698 				printf("Transport Specific Address Subtype - RDMA\n");
2699 				printf("  RDMA QP Service Type:                %u (%s)\n",
2700 				       entry->tsas.rdma.rdma_qptype,
2701 				       entry->tsas.rdma.rdma_qptype == SPDK_NVMF_RDMA_QPTYPE_RELIABLE_CONNECTED ? "Reliable Connected" :
2702 				       entry->tsas.rdma.rdma_qptype == SPDK_NVMF_RDMA_QPTYPE_RELIABLE_DATAGRAM ? "Reliable Datagram" :
2703 				       "Unknown");
2704 				printf("  RDMA Provider Type:                  %u (%s)\n",
2705 				       entry->tsas.rdma.rdma_prtype,
2706 				       entry->tsas.rdma.rdma_prtype == SPDK_NVMF_RDMA_PRTYPE_NONE ? "No provider specified" :
2707 				       entry->tsas.rdma.rdma_prtype == SPDK_NVMF_RDMA_PRTYPE_IB ? "InfiniBand" :
2708 				       entry->tsas.rdma.rdma_prtype == SPDK_NVMF_RDMA_PRTYPE_ROCE ? "InfiniBand RoCE" :
2709 				       entry->tsas.rdma.rdma_prtype == SPDK_NVMF_RDMA_PRTYPE_ROCE2 ? "InfiniBand RoCE v2" :
2710 				       entry->tsas.rdma.rdma_prtype == SPDK_NVMF_RDMA_PRTYPE_IWARP ? "iWARP" :
2711 				       "Unknown");
2712 				printf("  RDMA CM Service:                     %u (%s)\n",
2713 				       entry->tsas.rdma.rdma_cms,
2714 				       entry->tsas.rdma.rdma_cms == SPDK_NVMF_RDMA_CMS_RDMA_CM ? "RDMA_CM" :
2715 				       "Unknown");
2716 				if (entry->adrfam == SPDK_NVMF_ADRFAM_IB) {
2717 					printf("  RDMA Partition Key:                  %" PRIu32 "\n",
2718 					       from_le32(&entry->tsas.rdma.rdma_pkey));
2719 				}
2720 			}
2721 		}
2722 		free(g_discovery_page);
2723 		g_discovery_page = NULL;
2724 	}
2725 }
2726 
2727 static void
2728 usage(const char *program_name)
2729 {
2730 	printf("%s [options]", program_name);
2731 	printf("\n");
2732 	printf("options:\n");
2733 	printf(" -r trid    remote NVMe over Fabrics target address\n");
2734 	printf("    Format: 'key:value [key:value] ...'\n");
2735 	printf("    Keys:\n");
2736 	printf("     trtype      Transport type (e.g. RDMA)\n");
2737 	printf("     adrfam      Address family (e.g. IPv4, IPv6)\n");
2738 	printf("     traddr      Transport address (e.g. 192.168.100.8)\n");
2739 	printf("     trsvcid     Transport service identifier (e.g. 4420)\n");
2740 	printf("     subnqn      Subsystem NQN (default: %s)\n", SPDK_NVMF_DISCOVERY_NQN);
2741 	printf("     hostnqn     Host NQN\n");
2742 	printf("    Example: -r 'trtype:RDMA adrfam:IPv4 traddr:192.168.100.8 trsvcid:4420'\n");
2743 
2744 	spdk_log_usage(stdout, "-L");
2745 
2746 	printf(" -i         shared memory group ID\n");
2747 	printf(" -p         core number in decimal to run this application which started from 0\n");
2748 	printf(" -d         DPDK huge memory size in MB\n");
2749 	printf(" -g         use single file descriptor for DPDK memory segments\n");
2750 	printf(" -v         IOVA mode ('pa' or 'va')\n");
2751 	printf(" -x         print hex dump of raw data\n");
2752 	printf(" -z         For NVMe Zoned Namespaces, dump the full zone report (-z) or the first N entries (-z N)\n");
2753 	printf(" -V         enumerate VMD\n");
2754 	printf(" -S         socket implementation, e.g. -S uring (default is posix)\n");
2755 	printf(" -H         show this usage\n");
2756 }
2757 
2758 static int
2759 parse_args(int argc, char **argv)
2760 {
2761 	int op, rc;
2762 	char *hostnqn;
2763 
2764 	spdk_nvme_trid_populate_transport(&g_trid, SPDK_NVME_TRANSPORT_PCIE);
2765 	snprintf(g_trid.subnqn, sizeof(g_trid.subnqn), "%s", SPDK_NVMF_DISCOVERY_NQN);
2766 
2767 	while ((op = getopt(argc, argv, "d:gi:op:r:v:xz::HL:S:V")) != -1) {
2768 		switch (op) {
2769 		case 'd':
2770 			g_dpdk_mem = spdk_strtol(optarg, 10);
2771 			if (g_dpdk_mem < 0) {
2772 				fprintf(stderr, "Invalid DPDK memory size\n");
2773 				return g_dpdk_mem;
2774 			}
2775 			break;
2776 		case 'g':
2777 			g_dpdk_mem_single_seg = true;
2778 			break;
2779 		case 'i':
2780 			g_shm_id = spdk_strtol(optarg, 10);
2781 			if (g_shm_id < 0) {
2782 				fprintf(stderr, "Invalid shared memory ID\n");
2783 				return g_shm_id;
2784 			}
2785 			break;
2786 		case 'o':
2787 			g_ocssd_verbose = true;
2788 			break;
2789 		case 'p':
2790 			g_main_core = spdk_strtol(optarg, 10);
2791 			if (g_main_core < 0) {
2792 				fprintf(stderr, "Invalid core number\n");
2793 				return g_main_core;
2794 			}
2795 			snprintf(g_core_mask, sizeof(g_core_mask), "0x%llx", 1ULL << g_main_core);
2796 			break;
2797 		case 'r':
2798 			if (spdk_nvme_transport_id_parse(&g_trid, optarg) != 0) {
2799 				fprintf(stderr, "Error parsing transport address\n");
2800 				return 1;
2801 			}
2802 
2803 			assert(optarg != NULL);
2804 			hostnqn = strcasestr(optarg, "hostnqn:");
2805 			if (hostnqn) {
2806 				size_t len;
2807 
2808 				hostnqn += strlen("hostnqn:");
2809 
2810 				len = strcspn(hostnqn, " \t\n");
2811 				if (len > (sizeof(g_hostnqn) - 1)) {
2812 					fprintf(stderr, "Host NQN is too long\n");
2813 					return 1;
2814 				}
2815 
2816 				memcpy(g_hostnqn, hostnqn, len);
2817 				g_hostnqn[len] = '\0';
2818 			}
2819 			break;
2820 		case 'v':
2821 			g_iova_mode = optarg;
2822 			break;
2823 		case 'x':
2824 			g_hex_dump = true;
2825 			break;
2826 		case 'z':
2827 			if (optarg == NULL && argv[optind] != NULL && argv[optind][0] != '-') {
2828 				g_zone_report_limit = spdk_strtol(argv[optind], 10);
2829 				++optind;
2830 			} else if (optarg) {
2831 				g_zone_report_limit = spdk_strtol(optarg, 10);
2832 			} else {
2833 				g_zone_report_limit = 0;
2834 			}
2835 			if (g_zone_report_limit < 0) {
2836 				fprintf(stderr, "Invalid Zone Report limit\n");
2837 				return g_zone_report_limit;
2838 			}
2839 			break;
2840 		case 'L':
2841 			rc = spdk_log_set_flag(optarg);
2842 			if (rc < 0) {
2843 				fprintf(stderr, "unknown flag\n");
2844 				usage(argv[0]);
2845 				exit(EXIT_FAILURE);
2846 			}
2847 #ifdef DEBUG
2848 			spdk_log_set_print_level(SPDK_LOG_DEBUG);
2849 #endif
2850 			break;
2851 		case 'H':
2852 			usage(argv[0]);
2853 			exit(EXIT_SUCCESS);
2854 		case 'V':
2855 			g_vmd = true;
2856 			break;
2857 		case 'S':
2858 			rc = spdk_sock_set_default_impl(optarg);
2859 			if (rc < 0) {
2860 				fprintf(stderr, "Invalid socket implementation\n");
2861 				exit(EXIT_FAILURE);
2862 			}
2863 			break;
2864 		default:
2865 			usage(argv[0]);
2866 			return 1;
2867 		}
2868 	}
2869 
2870 	return 0;
2871 }
2872 
2873 static bool
2874 probe_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid,
2875 	 struct spdk_nvme_ctrlr_opts *opts)
2876 {
2877 	memcpy(opts->hostnqn, g_hostnqn, sizeof(opts->hostnqn));
2878 	return true;
2879 }
2880 
2881 static void
2882 attach_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid,
2883 	  struct spdk_nvme_ctrlr *ctrlr, const struct spdk_nvme_ctrlr_opts *opts)
2884 {
2885 	g_controllers_found++;
2886 	print_controller(ctrlr, trid, opts);
2887 	spdk_nvme_detach_async(ctrlr, &g_detach_ctx);
2888 }
2889 
2890 int
2891 main(int argc, char **argv)
2892 {
2893 	int				rc;
2894 	struct spdk_env_opts		opts;
2895 	struct spdk_nvme_ctrlr		*ctrlr;
2896 
2897 	rc = parse_args(argc, argv);
2898 	if (rc != 0) {
2899 		return rc;
2900 	}
2901 
2902 	opts.opts_size = sizeof(opts);
2903 	spdk_env_opts_init(&opts);
2904 	opts.name = "identify";
2905 	opts.shm_id = g_shm_id;
2906 	opts.mem_size = g_dpdk_mem;
2907 	opts.mem_channel = 1;
2908 	opts.main_core = g_main_core;
2909 	opts.core_mask = g_core_mask;
2910 	opts.hugepage_single_segments = g_dpdk_mem_single_seg;
2911 	opts.iova_mode = g_iova_mode;
2912 	if (g_trid.trtype != SPDK_NVME_TRANSPORT_PCIE) {
2913 		opts.no_pci = true;
2914 	}
2915 	if (spdk_env_init(&opts) < 0) {
2916 		fprintf(stderr, "Unable to initialize SPDK env\n");
2917 		return 1;
2918 	}
2919 
2920 	if (g_vmd && spdk_vmd_init()) {
2921 		fprintf(stderr, "Failed to initialize VMD."
2922 			" Some NVMe devices can be unavailable.\n");
2923 	}
2924 
2925 	/* A specific trid is required. */
2926 	if (strlen(g_trid.traddr) != 0) {
2927 		struct spdk_nvme_ctrlr_opts opts;
2928 
2929 		spdk_nvme_ctrlr_get_default_ctrlr_opts(&opts, sizeof(opts));
2930 		if (g_hostnqn[0] != '\0') {
2931 			memcpy(opts.hostnqn, g_hostnqn, sizeof(opts.hostnqn));
2932 		}
2933 		ctrlr = spdk_nvme_connect(&g_trid, &opts, sizeof(opts));
2934 		if (!ctrlr) {
2935 			fprintf(stderr, "spdk_nvme_connect() failed\n");
2936 			rc = 1;
2937 			goto exit;
2938 		}
2939 
2940 		g_controllers_found++;
2941 		print_controller(ctrlr, &g_trid, spdk_nvme_ctrlr_get_opts(ctrlr));
2942 		spdk_nvme_detach_async(ctrlr, &g_detach_ctx);
2943 	} else if (spdk_nvme_probe(&g_trid, NULL, probe_cb, attach_cb, NULL) != 0) {
2944 		fprintf(stderr, "spdk_nvme_probe() failed\n");
2945 		rc = 1;
2946 		goto exit;
2947 	}
2948 
2949 	if (g_detach_ctx) {
2950 		spdk_nvme_detach_poll(g_detach_ctx);
2951 	}
2952 
2953 	if (g_controllers_found == 0) {
2954 		fprintf(stderr, "No NVMe controllers found.\n");
2955 	}
2956 
2957 exit:
2958 	if (g_vmd) {
2959 		spdk_vmd_fini();
2960 	}
2961 
2962 	spdk_env_fini();
2963 
2964 	return rc;
2965 }
2966