Commit 4629dfb5 authored by Shuhei Matsumoto's avatar Shuhei Matsumoto Committed by Tomasz Zawadzki
Browse files

nvme: Get NVM Identify Namespace Data for Extended LBA Format



If ns->csi is NVM and ctrlr->cdata.ctratt.bits.elbas is 1,
get NVM identify namespace data to handle extended LBA format.

Additionally, add a public API spdk_nvme_nvm_ns_get_data() for the
upper layer to the identify data.

Signed-off-by: default avatarShuhei Matsumoto <smatsumoto@nvidia.com>
Change-Id: Icea8127b8a4834c4efb137369f3a8bfb388cb01b
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/23621


Reviewed-by: default avatarAleksey Marchuk <alexeymar@nvidia.com>
Community-CI: Mellanox Build Bot
Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: default avatarJim Harris <jim.harris@samsung.com>
parent 60ce1414
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -2876,6 +2876,19 @@ void spdk_nvme_poll_group_free_stats(struct spdk_nvme_poll_group *group,
 */
const struct spdk_nvme_ns_data *spdk_nvme_ns_get_data(struct spdk_nvme_ns *ns);

/**
 * Get the I/O command set specific identify namespace data for NVM command set
 * as defined by the NVMe specification.
 *
 * This function is thread safe and can be called at any point while the controller
 * is attached to the SPDK NVMe driver.
 *
 * \param ns Namespace.
 *
 * \return a pointer to the identify namespace data.
 */
const struct spdk_nvme_nvm_ns_data *spdk_nvme_nvm_ns_get_data(struct spdk_nvme_ns *ns);

/**
 * Get the namespace id (index number) from the given namespace handle.
 *
+1 −1
Original line number Diff line number Diff line
@@ -7,7 +7,7 @@ SPDK_ROOT_DIR := $(abspath $(CURDIR)/../..)
include $(SPDK_ROOT_DIR)/mk/spdk.common.mk

SO_VER := 13
SO_MINOR := 0
SO_MINOR := 1

C_SRCS = nvme_ctrlr_cmd.c nvme_ctrlr.c nvme_fabric.c nvme_ns_cmd.c \
	nvme_ns.c nvme_pcie_common.c nvme_pcie.c nvme_qpair.c nvme.c \
+45 −0
Original line number Diff line number Diff line
@@ -2736,12 +2736,57 @@ nvme_ctrlr_identify_ns_zns_specific_async(struct spdk_nvme_ns *ns)
	return rc;
}

static void
nvme_ctrlr_identify_ns_nvm_specific_async_done(void *arg, const struct spdk_nvme_cpl *cpl)
{
	struct spdk_nvme_ns *ns = (struct spdk_nvme_ns *)arg;
	struct spdk_nvme_ctrlr *ctrlr = ns->ctrlr;

	if (spdk_nvme_cpl_is_error(cpl)) {
		nvme_ns_free_nvm_specific_data(ns);
		nvme_ctrlr_set_state(ctrlr, NVME_CTRLR_STATE_ERROR, NVME_TIMEOUT_INFINITE);
		return;
	}

	nvme_ctrlr_identify_namespaces_iocs_specific_next(ctrlr, ns->id);
}

static int
nvme_ctrlr_identify_ns_nvm_specific_async(struct spdk_nvme_ns *ns)
{
	struct spdk_nvme_ctrlr *ctrlr = ns->ctrlr;
	int rc;

	assert(!ns->nsdata_nvm);
	ns->nsdata_nvm = spdk_zmalloc(sizeof(*ns->nsdata_nvm), 64, NULL, SPDK_ENV_SOCKET_ID_ANY,
				      SPDK_MALLOC_SHARE);
	if (!ns->nsdata_nvm) {
		return -ENOMEM;
	}

	nvme_ctrlr_set_state(ctrlr, NVME_CTRLR_STATE_WAIT_FOR_IDENTIFY_NS_IOCS_SPECIFIC,
			     ctrlr->opts.admin_timeout_ms);
	rc = nvme_ctrlr_cmd_identify(ns->ctrlr, SPDK_NVME_IDENTIFY_NS_IOCS, 0, ns->id, ns->csi,
				     ns->nsdata_nvm, sizeof(*ns->nsdata_nvm),
				     nvme_ctrlr_identify_ns_nvm_specific_async_done, ns);
	if (rc) {
		nvme_ns_free_nvm_specific_data(ns);
	}

	return rc;
}

static int
nvme_ctrlr_identify_ns_iocs_specific_async(struct spdk_nvme_ns *ns)
{
	switch (ns->csi) {
	case SPDK_NVME_CSI_ZNS:
		return nvme_ctrlr_identify_ns_zns_specific_async(ns);
	case SPDK_NVME_CSI_NVM:
		if (ns->ctrlr->cdata.ctratt.bits.elbas) {
			return nvme_ctrlr_identify_ns_nvm_specific_async(ns);
		}
	/* fallthrough */
	default:
		/*
		 * This switch must handle all cases for which
+3 −0
Original line number Diff line number Diff line
@@ -586,6 +586,8 @@ struct spdk_nvme_ns {
	/* Zoned Namespace Command Set Specific Identify Namespace data. */
	struct spdk_nvme_zns_ns_data	*nsdata_zns;

	struct spdk_nvme_nvm_ns_data	*nsdata_nvm;

	RB_ENTRY(spdk_nvme_ns)		node;
};

@@ -1307,6 +1309,7 @@ int nvme_ctrlr_identify_active_ns(struct spdk_nvme_ctrlr *ctrlr);
void	nvme_ns_set_identify_data(struct spdk_nvme_ns *ns);
void	nvme_ns_set_id_desc_list_data(struct spdk_nvme_ns *ns);
void	nvme_ns_free_zns_specific_data(struct spdk_nvme_ns *ns);
void	nvme_ns_free_nvm_specific_data(struct spdk_nvme_ns *ns);
void	nvme_ns_free_iocs_specific_data(struct spdk_nvme_ns *ns);
bool	nvme_ns_has_supported_iocs_specific_data(struct spdk_nvme_ns *ns);
int	nvme_ns_construct(struct spdk_nvme_ns *ns, uint32_t id,
+75 −4
Original line number Diff line number Diff line
@@ -173,12 +173,63 @@ nvme_ctrlr_identify_ns_zns_specific(struct spdk_nvme_ns *ns)
	return 0;
}

static int
nvme_ctrlr_identify_ns_nvm_specific(struct spdk_nvme_ns *ns)
{
	struct nvme_completion_poll_status *status;
	struct spdk_nvme_ctrlr *ctrlr = ns->ctrlr;
	struct spdk_nvme_nvm_ns_data *nsdata_nvm;
	int rc;

	nvme_ns_free_zns_specific_data(ns);

	nsdata_nvm = spdk_zmalloc(sizeof(*nsdata_nvm), 64, NULL, SPDK_ENV_SOCKET_ID_ANY,
				  SPDK_MALLOC_SHARE);
	if (!nsdata_nvm) {
		return -ENOMEM;
	}

	status = calloc(1, sizeof(*status));
	if (!status) {
		SPDK_ERRLOG("Failed to allocate status tracker\n");
		spdk_free(nsdata_nvm);
		return -ENOMEM;
	}

	rc = nvme_ctrlr_cmd_identify(ctrlr, SPDK_NVME_IDENTIFY_NS_IOCS, 0, ns->id, ns->csi,
				     nsdata_nvm, sizeof(*nsdata_nvm),
				     nvme_completion_poll_cb, status);
	if (rc != 0) {
		spdk_free(nsdata_nvm);
		free(status);
		return rc;
	}

	if (nvme_wait_for_completion_robust_lock(ctrlr->adminq, status, &ctrlr->ctrlr_lock)) {
		SPDK_ERRLOG("Failed to retrieve Identify IOCS Specific Namespace Data Structure\n");
		spdk_free(nsdata_nvm);
		if (!status->timed_out) {
			free(status);
		}
		return -ENXIO;
	}
	free(status);
	ns->nsdata_nvm = nsdata_nvm;

	return 0;
}

static int
nvme_ctrlr_identify_ns_iocs_specific(struct spdk_nvme_ns *ns)
{
	switch (ns->csi) {
	case SPDK_NVME_CSI_ZNS:
		return nvme_ctrlr_identify_ns_zns_specific(ns);
	case SPDK_NVME_CSI_NVM:
		if (ns->ctrlr->cdata.ctratt.bits.elbas) {
			return nvme_ctrlr_identify_ns_nvm_specific(ns);
		}
	/* fallthrough */
	default:
		/*
		 * This switch must handle all cases for which
@@ -345,6 +396,12 @@ spdk_nvme_ns_get_data(struct spdk_nvme_ns *ns)
	return _nvme_ns_get_data(ns);
}

const struct spdk_nvme_nvm_ns_data *
spdk_nvme_nvm_ns_get_data(struct spdk_nvme_ns *ns)
{
	return ns->nsdata_nvm;
}

/* We have to use the typedef in the function declaration to appease astyle. */
typedef enum spdk_nvme_dealloc_logical_block_read_value
spdk_nvme_dealloc_logical_block_read_value_t;
@@ -483,10 +540,24 @@ nvme_ns_free_zns_specific_data(struct spdk_nvme_ns *ns)
	}
}

void
nvme_ns_free_nvm_specific_data(struct spdk_nvme_ns *ns)
{
	if (!ns->id) {
		return;
	}

	if (ns->nsdata_nvm) {
		spdk_free(ns->nsdata_nvm);
		ns->nsdata_nvm = NULL;
	}
}

void
nvme_ns_free_iocs_specific_data(struct spdk_nvme_ns *ns)
{
	nvme_ns_free_zns_specific_data(ns);
	nvme_ns_free_nvm_specific_data(ns);
}

bool
@@ -494,10 +565,10 @@ nvme_ns_has_supported_iocs_specific_data(struct spdk_nvme_ns *ns)
{
	switch (ns->csi) {
	case SPDK_NVME_CSI_NVM:
		/*
		 * NVM Command Set Specific Identify Namespace data structure
		 * is currently all-zeroes, reserved for future use.
		 */
		if (ns->ctrlr->cdata.ctratt.bits.elbas) {
			return true;
		}

		return false;
	case SPDK_NVME_CSI_ZNS:
		return true;
Loading