Commit 3301f821 authored by Niklas Cassel's avatar Niklas Cassel Committed by Tomasz Zawadzki
Browse files

examples/nvme/identify: print zone report excerpt for zoned namespaces



If the namespace is a zoned namespace, get and print a zone report.

Since a ZNS drive can have thousands of zones, request a zone report
containing only the first 8 zones.
The code does take a ZNS drive with less than 8 zones into account,
even though such a drive is unlikely to exist in the wild.

Signed-off-by: default avatarNiklas Cassel <niklas.cassel@wdc.com>
Change-Id: I28ecb4d7c60ab5a911d7b1faae595f43ef6706e1
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/4794


Reviewed-by: default avatarJim Harris <james.r.harris@intel.com>
Reviewed-by: default avatarShuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
Community-CI: Broadcom CI
parent 6dec7623
Loading
Loading
Loading
Loading
+95 −0
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@
#include "spdk/nvme.h"
#include "spdk/vmd.h"
#include "spdk/nvme_ocssd.h"
#include "spdk/nvme_zns.h"
#include "spdk/env.h"
#include "spdk/nvme_intel.h"
#include "spdk/nvmf_spec.h"
@@ -49,6 +50,7 @@
#define MAX_DISCOVERY_LOG_ENTRIES	((uint64_t)1000)

#define NUM_CHUNK_INFO_ENTRIES		8
#define MAX_ZONE_DESC_ENTRIES		8

static int outstanding_commands;

@@ -85,6 +87,10 @@ static struct spdk_ocssd_geometry_data geometry_data;

static struct spdk_ocssd_chunk_information_entry g_ocssd_chunk_info_page[NUM_CHUNK_INFO_ENTRIES ];

static struct spdk_nvme_zns_zone_report *g_zone_report;
static size_t g_zone_report_size;
static uint64_t g_nr_zones_requested;

static bool g_hex_dump = false;

static int g_shm_id = -1;
@@ -149,6 +155,15 @@ hex_dump(const void *data, size_t size)
	}
}

static void
exit_and_free_qpair(struct spdk_nvme_qpair *qpair)
{
	if (qpair) {
		spdk_nvme_ctrlr_free_io_qpair(qpair);
	}
	exit(1);
}

static void
get_feature_completion(void *cb_arg, const struct spdk_nvme_cpl *cpl)
{
@@ -182,6 +197,27 @@ get_ocssd_geometry_completion(void *cb_arg, const struct spdk_nvme_cpl *cpl)
	outstanding_commands--;
}

static void
get_zns_zone_report_completion(void *cb_arg, const struct spdk_nvme_cpl *cpl)
{
	struct spdk_nvme_qpair *qpair = cb_arg;

	if (spdk_nvme_cpl_is_error(cpl)) {
		printf("get zns zone report failed\n");
	}

	/*
	 * Since we requested a partial report, verify that the firmware returned the
	 * correct number of zones.
	 */
	if (g_zone_report->nr_zones != g_nr_zones_requested) {
		printf("Invalid number of zones returned: %"PRIu64" (expected: %"PRIu64")\n",
		       g_zone_report->nr_zones, g_nr_zones_requested);
		exit_and_free_qpair(qpair);
	}
	outstanding_commands--;
}

static int
get_feature(struct spdk_nvme_ctrlr *ctrlr, uint8_t fid)
{
@@ -565,6 +601,39 @@ get_ocssd_geometry(struct spdk_nvme_ns *ns, struct spdk_ocssd_geometry_data *geo
	}
}

static void
get_zns_zone_report(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair)
{
	g_nr_zones_requested = spdk_nvme_zns_ns_get_num_zones(ns);
	/*
	 * Rather than getting the whole zone report, which could contain thousands of zones,
	 * get maximum MAX_ZONE_DESC_ENTRIES, so that we don't flood stdout.
	 */
	g_nr_zones_requested = spdk_min(g_nr_zones_requested, MAX_ZONE_DESC_ENTRIES);
	outstanding_commands = 0;

	g_zone_report_size = sizeof(struct spdk_nvme_zns_zone_report) +
			     g_nr_zones_requested * sizeof(struct spdk_nvme_zns_zone_desc);
	g_zone_report = calloc(1, g_zone_report_size);
	if (g_zone_report == NULL) {
		printf("Zone report allocation failed!\n");
		exit_and_free_qpair(qpair);
	}

	if (spdk_nvme_zns_report_zones(ns, qpair, g_zone_report, g_zone_report_size,
				       0, SPDK_NVME_ZRA_LIST_ALL, true,
				       get_zns_zone_report_completion, qpair)) {
		printf("spdk_nvme_zns_report_zones() failed\n");
		exit_and_free_qpair(qpair);
	} else {
		outstanding_commands++;
	}

	while (outstanding_commands) {
		spdk_nvme_qpair_process_completions(qpair, 0);
	}
}

static void
print_hex_be(const void *v, size_t size)
{
@@ -700,6 +769,23 @@ print_ocssd_geometry(struct spdk_ocssd_geometry_data *geometry_data)
	printf("\n");
}

static void
print_zns_zone_report(void)
{
	uint64_t i;

	printf("NVMe ZNS Zone Report Glance\n");
	printf("===========================\n");

	for (i = 0; i < g_zone_report->nr_zones; i++) {
		struct spdk_nvme_zns_zone_desc *desc = &g_zone_report->descs[i];
		printf("Zone: %"PRIu64" ZSLBA: 0x%016"PRIx64" ZCAP: 0x%016"PRIx64" WP: 0x%016"PRIx64" ZS: %x ZT: %x ZA: %x\n",
		       i, desc->zslba, desc->zcap, desc->wp, desc->zs >> 4, desc->zt, desc->za);
	}
	free(g_zone_report);
	g_zone_report = NULL;
}

static void
print_namespace(struct spdk_nvme_ctrlr *ctrlr, struct spdk_nvme_ns *ns)
{
@@ -823,6 +909,15 @@ print_namespace(struct spdk_nvme_ctrlr *ctrlr, struct spdk_nvme_ns *ns)
		print_ocssd_geometry(&geometry_data);
		get_ocssd_chunk_info_log_page(ns);
		print_ocssd_chunk_info(g_ocssd_chunk_info_page, NUM_CHUNK_INFO_ENTRIES);
	} else if (spdk_nvme_ns_get_csi(ns) == SPDK_NVME_CSI_ZNS) {
		struct spdk_nvme_qpair *qpair = spdk_nvme_ctrlr_alloc_io_qpair(ctrlr, NULL, 0);
		if (qpair == NULL) {
			printf("ERROR: spdk_nvme_ctrlr_alloc_io_qpair() failed\n");
			exit(1);
		}
		get_zns_zone_report(ns, qpair);
		print_zns_zone_report();
		spdk_nvme_ctrlr_free_io_qpair(qpair);
	}
}