Commit a36785df authored by Dennis Maisenbacher's avatar Dennis Maisenbacher Committed by Tomasz Zawadzki
Browse files

nvmf: Add ZNS specific identify functions for NVMe-oF ZNS support



In order to connect to a zoned SPDK NVMe-oF target the ZNS specific
identify functions must be implemented and the supported ZNS opcodes
must be set accordingly.

Implementing ZNS specific identify functions to return the 'I/O Command
Set specific Identify Namespace data structure (CNS 05h)'
(`spdk_nvmf_ns_identify_iocs_specific`) and 'I/O Command Set specific
Identify Controller data structure (CNS 06h)'
(`spdk_nvmf_ctrlr_identify_iocs_specific`).

Those functions return a null filled data structure for any I/O Command
Set other than ZNS.

Signed-off-by: default avatarDennis Maisenbacher <dennis.maisenbacher@wdc.com>
Change-Id: I6b9529ce0a86400afb01d4e09cbdb3e5c3a68514
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/16044


Reviewed-by: default avatarJim Harris <james.r.harris@intel.com>
Reviewed-by: default avatarAleksey Marchuk <alexeymar@nvidia.com>
Reviewed-by: default avatarShuhei Matsumoto <smatsumoto@nvidia.com>
Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
parent 102d266d
Loading
Loading
Loading
Loading
+36 −0
Original line number Diff line number Diff line
@@ -25,6 +25,42 @@ enum spdk_nvmf_request_exec_status {
int spdk_nvmf_ctrlr_identify_ctrlr(struct spdk_nvmf_ctrlr *ctrlr,
				   struct spdk_nvme_ctrlr_data *cdata);

/**
 * Fills the I/O Command Set specific Identify Namespace data structure (CNS
 * 05h)
 *
 * \param ctrlr The NVMe-oF controller
 * \param cmd The NVMe command
 * \param rsp The NVMe command completion
 * \param nsdata The filled in I/O command set specific identify namespace
 * attributes
 * \param nsdata_size The size of nsdata
 * \return \ref spdk_nvmf_request_exec_status
 */
int spdk_nvmf_ns_identify_iocs_specific(struct spdk_nvmf_ctrlr *ctrlr,
					struct spdk_nvme_cmd *cmd,
					struct spdk_nvme_cpl *rsp,
					void *nsdata,
					size_t nsdata_size);

/**
 * Fills the I/O Command Set specific Identify Controller data structure (CNS
 * 06h)
 *
 * \param ctrlr The NVMe-oF controller
 * \param cmd The NVMe command
 * \param rsp The NVMe command completion
 * \param cdata The filled in I/O command set specific identify controller
 * attributes
 * \param cdata_size The size of cdata
 * \return \ref spdk_nvmf_request_exec_status
 */
int spdk_nvmf_ctrlr_identify_iocs_specific(struct spdk_nvmf_ctrlr *ctrlr,
		struct spdk_nvme_cmd *cmd,
		struct spdk_nvme_cpl *rsp,
		void *cdata,
		size_t cdata_size);

/**
 * Fills the identify namespace attributes for the specified controller
 *
+146 −3
Original line number Diff line number Diff line
@@ -9,6 +9,8 @@
#include "nvmf_internal.h"
#include "transport.h"

#include "spdk/bdev.h"
#include "spdk/bdev_zone.h"
#include "spdk/bit_array.h"
#include "spdk/endian.h"
#include "spdk/thread.h"
@@ -371,6 +373,21 @@ nvmf_ctrlr_cdata_init(struct spdk_nvmf_transport *transport, struct spdk_nvmf_su
	}
}

static bool
nvmf_subsys_has_multi_iocs(struct spdk_nvmf_subsystem *subsystem)
{
	struct spdk_nvmf_ns *ns;
	uint32_t i;

	for (i = 0; i < subsystem->max_nsid; i++) {
		ns = subsystem->ns[i];
		if (ns && ns->bdev && spdk_bdev_is_zoned(ns->bdev)) {
			return true;
		}
	}
	return false;
}

static struct spdk_nvmf_ctrlr *
nvmf_ctrlr_create(struct spdk_nvmf_subsystem *subsystem,
		  struct spdk_nvmf_request *req,
@@ -380,6 +397,7 @@ nvmf_ctrlr_create(struct spdk_nvmf_subsystem *subsystem,
	struct spdk_nvmf_ctrlr *ctrlr;
	struct spdk_nvmf_transport *transport = req->qpair->transport;
	struct spdk_nvme_transport_id listen_trid = {};
	bool subsys_has_multi_iocs = false;

	ctrlr = calloc(1, sizeof(*ctrlr));
	if (ctrlr == NULL) {
@@ -477,7 +495,14 @@ nvmf_ctrlr_create(struct spdk_nvmf_subsystem *subsystem,
	/* ready timeout - 500 msec units */
	ctrlr->vcprop.cap.bits.to = NVMF_CTRLR_RESET_SHN_TIMEOUT_IN_MS / 500;
	ctrlr->vcprop.cap.bits.dstrd = 0; /* fixed to 0 for NVMe-oF */
	subsys_has_multi_iocs = nvmf_subsys_has_multi_iocs(subsystem);
	if (subsys_has_multi_iocs) {
		ctrlr->vcprop.cap.bits.css =
			SPDK_NVME_CAP_CSS_IOCS; /* One or more I/O command sets supported */
	} else {
		ctrlr->vcprop.cap.bits.css = SPDK_NVME_CAP_CSS_NVM; /* NVM command set */
	}

	ctrlr->vcprop.cap.bits.mpsmin = 0; /* 2 ^ (12 + mpsmin) == 4k */
	ctrlr->vcprop.cap.bits.mpsmax = 0; /* 2 ^ (12 + mpsmax) == 4k */

@@ -488,6 +513,10 @@ nvmf_ctrlr_create(struct spdk_nvmf_subsystem *subsystem,

	ctrlr->vcprop.cc.raw = 0;
	ctrlr->vcprop.cc.bits.en = 0; /* Init controller disabled */
	if (subsys_has_multi_iocs) {
		ctrlr->vcprop.cc.bits.css =
			SPDK_NVME_CC_CSS_IOCS; /* All supported I/O Command Sets */
	}

	ctrlr->vcprop.csts.raw = 0;
	ctrlr->vcprop.csts.bits.rdy = 0; /* Init controller as not ready */
@@ -1238,9 +1267,12 @@ nvmf_prop_set_cc(struct spdk_nvmf_ctrlr *ctrlr, uint32_t value)
	}

	if (diff.bits.css) {
		if (cc.bits.css > SPDK_NVME_CC_CSS_IOCS) {
			SPDK_ERRLOG("I/O Command Set Selected (CSS) 0x%x not supported!\n", cc.bits.css);
			return false;
		}
		diff.bits.css = 0;
	}

	if (diff.raw != 0) {
		/* Print an error message, but don't fail the command in this case.
@@ -2812,6 +2844,108 @@ spdk_nvmf_ctrlr_identify_ctrlr(struct spdk_nvmf_ctrlr *ctrlr, struct spdk_nvme_c
	return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE;
}

static int
nvmf_ns_identify_iocs_zns(struct spdk_nvmf_ns *ns,
			  struct spdk_nvme_cmd *cmd,
			  struct spdk_nvme_cpl *rsp,
			  struct spdk_nvme_zns_ns_data *nsdata_zns)
{
	nsdata_zns->zoc.variable_zone_capacity = 0;
	nsdata_zns->zoc.zone_active_excursions = 0;
	nsdata_zns->ozcs.read_across_zone_boundaries = 1;
	/* Underflowing the zero based mar and mor bdev helper results in the correct
	   value of FFFFFFFFh. */
	nsdata_zns->mar = spdk_bdev_get_max_active_zones(ns->bdev) - 1;
	nsdata_zns->mor = spdk_bdev_get_max_open_zones(ns->bdev) - 1;
	nsdata_zns->rrl = 0;
	nsdata_zns->frl = 0;
	nsdata_zns->lbafe[0].zsze = spdk_bdev_get_zone_size(ns->bdev);

	rsp->status.sct = SPDK_NVME_SCT_GENERIC;
	rsp->status.sc = SPDK_NVME_SC_SUCCESS;
	return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE;
}

int
spdk_nvmf_ns_identify_iocs_specific(struct spdk_nvmf_ctrlr *ctrlr,
				    struct spdk_nvme_cmd *cmd,
				    struct spdk_nvme_cpl *rsp,
				    void *nsdata,
				    size_t nsdata_size)
{
	uint8_t csi = cmd->cdw11_bits.identify.csi;
	struct spdk_nvmf_subsystem *subsystem = ctrlr->subsys;
	struct spdk_nvmf_ns *ns = _nvmf_subsystem_get_ns_safe(subsystem, cmd->nsid, rsp);

	memset(nsdata, 0, nsdata_size);

	if (ns == NULL) {
		rsp->status.sct = SPDK_NVME_SCT_GENERIC;
		rsp->status.sc = SPDK_NVME_SC_INVALID_NAMESPACE_OR_FORMAT;
		return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE;
	}

	switch (csi) {
	case SPDK_NVME_CSI_ZNS:
		return nvmf_ns_identify_iocs_zns(ns, cmd, rsp, nsdata);
	default:
		break;
	}

	SPDK_DEBUGLOG(nvmf,
		      "Returning zero filled struct for the iocs specific ns "
		      "identify command and CSI 0x%02x\n",
		      csi);
	rsp->status.sct = SPDK_NVME_SCT_GENERIC;
	rsp->status.sc = SPDK_NVME_SC_SUCCESS;
	return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE;
}

static int
nvmf_ctrlr_identify_iocs_zns(struct spdk_nvmf_ctrlr *ctrlr,
			     struct spdk_nvme_cmd *cmd,
			     struct spdk_nvme_cpl *rsp,
			     struct spdk_nvme_zns_ctrlr_data *cdata_zns)
{
	/* The unit of max_zone_append_size_kib is KiB.
	The unit of zasl is the minimum memory page size
	(2 ^ (12 + CAP.MPSMIN) KiB)
	and is reported as a power of two (2^n). */
	cdata_zns->zasl = spdk_u64log2(ctrlr->subsys->max_zone_append_size_kib >>
				       (12 + ctrlr->vcprop.cap.bits.mpsmin));

	rsp->status.sct = SPDK_NVME_SCT_GENERIC;
	rsp->status.sc = SPDK_NVME_SC_SUCCESS;
	return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE;
}

int
spdk_nvmf_ctrlr_identify_iocs_specific(struct spdk_nvmf_ctrlr *ctrlr,
				       struct spdk_nvme_cmd *cmd,
				       struct spdk_nvme_cpl *rsp,
				       void *cdata,
				       size_t cdata_size)
{
	uint8_t csi = cmd->cdw11_bits.identify.csi;

	memset(cdata, 0, cdata_size);

	switch (csi) {
	case SPDK_NVME_CSI_ZNS:
		return nvmf_ctrlr_identify_iocs_zns(ctrlr, cmd, rsp, cdata);
	default:
		break;
	}

	SPDK_DEBUGLOG(nvmf,
		      "Returning zero filled struct for the iocs specific ctrlr "
		      "identify command and CSI 0x%02x\n",
		      csi);
	rsp->status.sct = SPDK_NVME_SCT_GENERIC;
	rsp->status.sc = SPDK_NVME_SC_SUCCESS;
	return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE;
}

static int
nvmf_ctrlr_identify_active_ns_list(struct spdk_nvmf_subsystem *subsystem,
				   struct spdk_nvme_cmd *cmd,
@@ -2900,6 +3034,7 @@ nvmf_ctrlr_identify_ns_id_descriptor_list(
	ADD_ID_DESC(SPDK_NVME_NIDT_EUI64, ns->opts.eui64, sizeof(ns->opts.eui64));
	ADD_ID_DESC(SPDK_NVME_NIDT_NGUID, ns->opts.nguid, sizeof(ns->opts.nguid));
	ADD_ID_DESC(SPDK_NVME_NIDT_UUID, &ns->opts.uuid, sizeof(ns->opts.uuid));
	ADD_ID_DESC(SPDK_NVME_NIDT_CSI, &ns->csi, sizeof(uint8_t));

	/*
	 * The list is automatically 0-terminated, both in the temporary buffer
@@ -2946,6 +3081,8 @@ nvmf_ctrlr_identify(struct spdk_nvmf_request *req)
	 */
	_init_copy_iovs_ctx(&copy_ctx, req->iov, req->iovcnt);

	SPDK_DEBUGLOG(nvmf, "Received identify command with CNS 0x%02x\n", cns);

	switch (cns) {
	case SPDK_NVME_IDENTIFY_NS:
		ret = spdk_nvmf_ctrlr_identify_ns(ctrlr, cmd, rsp, (void *)&tmpbuf);
@@ -2960,6 +3097,12 @@ nvmf_ctrlr_identify(struct spdk_nvmf_request *req)
		ret = nvmf_ctrlr_identify_ns_id_descriptor_list(subsystem, cmd, rsp,
				tmpbuf, req->length);
		break;
	case SPDK_NVME_IDENTIFY_NS_IOCS:
		ret = spdk_nvmf_ns_identify_iocs_specific(ctrlr, cmd, rsp, (void *)&tmpbuf, req->length);
		break;
	case SPDK_NVME_IDENTIFY_CTRLR_IOCS:
		ret = spdk_nvmf_ctrlr_identify_iocs_specific(ctrlr, cmd, rsp, (void *)&tmpbuf, req->length);
		break;
	default:
		goto invalid_cns;
	}
+6 −0
Original line number Diff line number Diff line
@@ -165,6 +165,8 @@ struct spdk_nvmf_ns {
	bool ptpl_activated;
	/* ZCOPY supported on bdev device */
	bool zcopy;
	/* Command Set Identifier */
	enum spdk_nvme_csi csi;
};

/*
@@ -263,6 +265,10 @@ struct spdk_nvmf_subsystem {
	bool						destroying;
	bool						async_destroy;

	/* Zoned storage related fields */
	bool						zone_append_supported;
	uint64_t					max_zone_append_size_kib;

	struct spdk_nvmf_tgt				*tgt;

	/* Array of pointers to namespaces of size max_nsid indexed by nsid - 1 */
+2 −0
Original line number Diff line number Diff line
@@ -84,6 +84,7 @@

	# public functions in nvmf_cmd.h
	spdk_nvmf_ctrlr_identify_ctrlr;
	spdk_nvmf_ctrlr_identify_iocs_specific;
	spdk_nvmf_ctrlr_identify_ns;
	spdk_nvmf_set_custom_admin_cmd_hdlr;
	spdk_nvmf_set_passthru_admin_cmd;
@@ -96,6 +97,7 @@
	spdk_nvmf_request_get_response;
	spdk_nvmf_request_get_req_to_abort;
	spdk_nvmf_bdev_ctrlr_abort_cmd;
	spdk_nvmf_ns_identify_iocs_specific;

	# public functions in nvmf_transport.h
	spdk_nvmf_transport_register;
+36 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@
#include "spdk/json.h"
#include "spdk/file.h"
#include "spdk/bit_array.h"
#include "spdk/bdev.h"

#define __SPDK_BDEV_MODULE_ONLY
#include "spdk/bdev_module.h"
@@ -405,6 +406,19 @@ _nvmf_subsystem_destroy(struct spdk_nvmf_subsystem *subsystem)
	return 0;
}

static struct spdk_nvmf_ns *
_nvmf_subsystem_get_first_zoned_ns(struct spdk_nvmf_subsystem *subsystem)
{
	struct spdk_nvmf_ns *ns = spdk_nvmf_subsystem_get_first_ns(subsystem);
	while (ns != NULL) {
		if (ns->csi == SPDK_NVME_CSI_ZNS) {
			return ns;
		}
		ns = spdk_nvmf_subsystem_get_next_ns(subsystem, ns);
	}
	return NULL;
}

int
spdk_nvmf_subsystem_destroy(struct spdk_nvmf_subsystem *subsystem, nvmf_subsystem_destroy_cb cpl_cb,
			    void *cpl_cb_arg)
@@ -1578,6 +1592,8 @@ spdk_nvmf_subsystem_add_ns_ext(struct spdk_nvmf_subsystem *subsystem, const char
	struct spdk_nvmf_ns *ns;
	struct spdk_nvmf_reservation_info info = {0};
	int rc;
	bool zone_append_supported;
	uint64_t max_zone_append_size_kib;

	if (!(subsystem->state == SPDK_NVMF_SUBSYSTEM_INACTIVE ||
	      subsystem->state == SPDK_NVMF_SUBSYSTEM_PAUSED)) {
@@ -1680,6 +1696,26 @@ spdk_nvmf_subsystem_add_ns_ext(struct spdk_nvmf_subsystem *subsystem, const char
		memcpy(opts.nguid, spdk_bdev_get_uuid(ns->bdev), sizeof(opts.nguid));
	}

	if (spdk_bdev_is_zoned(ns->bdev)) {
		SPDK_DEBUGLOG(nvmf, "The added namespace is backed by a zoned block device.\n");
		ns->csi = SPDK_NVME_CSI_ZNS;

		zone_append_supported = spdk_bdev_io_type_supported(ns->bdev,
					SPDK_BDEV_IO_TYPE_ZONE_APPEND);
		max_zone_append_size_kib = spdk_bdev_get_max_zone_append_size(
						   ns->bdev) * spdk_bdev_get_block_size(ns->bdev);

		if (_nvmf_subsystem_get_first_zoned_ns(subsystem) != NULL &&
		    (subsystem->zone_append_supported != zone_append_supported ||
		     subsystem->max_zone_append_size_kib != max_zone_append_size_kib)) {
			SPDK_ERRLOG("Namespaces with different zone append support or different zone append size are not allowed.\n");
			goto err_ns_reservation_restore;
		}

		subsystem->zone_append_supported = zone_append_supported;
		subsystem->max_zone_append_size_kib = max_zone_append_size_kib;
	}

	ns->opts = opts;
	ns->subsystem = subsystem;
	subsystem->ns[opts.nsid - 1] = ns;
Loading