Commit 815bf097 authored by Pawel Baldysiak's avatar Pawel Baldysiak Committed by Tomasz Zawadzki
Browse files

nvmf_tgt: Add passthru support for get_log_page admin cmd



Add handler to passthru get_log_page to underlying dev.
It is disabled by default, can be enabled by RPC.
It uses already existing generic passthru handler,
which makes sure that ctrlr-scope admin cmds are passthru
only for subsystem with single namespace.

ANA log and CHANGED_NS_LIST log pages have to be
handled by SPDK, so exclude them from passthru.

Since SPDK is not supporting passthru get/set_feature OPC to the
drive - do not expose FEATURE_IDS_EFFECTS log page as supported,
and do not passthru this log page to the drive.

Let cmd_and_effects LID to be handled by SPDK instead of
this custom handler as well. Proper handling
of this log page would be added in further patch.

In fixup for get_supported_log_pages LID -
make sure to reflect what drive supports +
what is supported by SPDK.

Change-Id: I1fe7550d5aa083fd12f2eb61869d509fff208d90
Signed-off-by: default avatarPawel Baldysiak <pawel.baldysiak@dell.com>
Reviewed-on: https://review.spdk.io/c/spdk/spdk/+/26456


Reviewed-by: default avatarJim Harris <jim.harris@nvidia.com>
Reviewed-by: default avatarAleksey Marchuk <alexeymar@nvidia.com>
Community-CI: Mellanox Build Bot
Tested-by: default avatarSPDK Automated Test System <spdkbot@gmail.com>
parent 09486eec
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -8588,6 +8588,7 @@ have been initialized.
 Name           | Optional   | Type   | Description
--------------- | ---------- | ------ | --------------------------------------------------------------------------------------------------------------
 identify_ctrlr | Optional   | bool   | If true, enables custom identify handler that reports some identify attributes from the underlying NVMe drive
 get_log_page   | Optional   | bool   | If true, enables passthru get log page command handlers for underlying NVMe drive (for non-fabrics related log pages)
 vendor_specific| Optional   | bool   | If true, enables passthru command handlers for underlying NVMe drive for vendor specific cmds (OPCs: 0xC0-0xFF)

#### Example
+1 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@

struct spdk_nvmf_admin_passthru_conf {
	bool identify_ctrlr;
	bool get_log_page;
	bool vendor_specific;
};

+2 −1
Original line number Diff line number Diff line
@@ -46,7 +46,8 @@ SPDK_RPC_REGISTER("nvmf_set_max_subsystems", rpc_nvmf_set_max_subsystems,

static const struct spdk_json_object_decoder admin_passthru_decoder[] = {
	{"identify_ctrlr", offsetof(struct spdk_nvmf_admin_passthru_conf, identify_ctrlr), spdk_json_decode_bool, true},
	{"vendor_specific", offsetof(struct spdk_nvmf_admin_passthru_conf, vendor_specific), spdk_json_decode_bool, true}
	{"get_log_page", offsetof(struct spdk_nvmf_admin_passthru_conf, get_log_page), spdk_json_decode_bool, true},
	{"vendor_specific", offsetof(struct spdk_nvmf_admin_passthru_conf, vendor_specific), spdk_json_decode_bool, true},
};

static int
+92 −0
Original line number Diff line number Diff line
@@ -56,6 +56,7 @@ struct spdk_nvmf_tgt_conf g_spdk_nvmf_tgt_conf = {
		.dhchap_dhgroups = NVMF_TGT_DEFAULT_DHGROUPS,
	},
	.admin_passthru.identify_ctrlr = false,
	.admin_passthru.get_log_page = false,
	.admin_passthru.vendor_specific = false
};

@@ -362,6 +363,63 @@ nvmf_tgt_create_target(void)
	return 0;
}

static void
get_log_page_offset_and_len(struct spdk_nvmf_request *req, size_t page_size, uint64_t *offset,
			    size_t *copy_len)
{
	struct spdk_nvme_cmd *cmd = spdk_nvmf_request_get_cmd(req);
	uint64_t len;
	uint32_t numdl, numdu;

	*offset = (uint64_t)cmd->cdw12 | ((uint64_t)cmd->cdw13 << 32);
	numdl = cmd->cdw10_bits.get_log_page.numdl;
	numdu = cmd->cdw11_bits.get_log_page.numdu;
	len = ((numdu << 16) + numdl + (uint64_t)1) * 4;

	if (*offset > page_size) {
		return;
	}

	*copy_len = spdk_min(page_size - *offset, len);
}

static void
fixup_get_supported_log_pages(struct spdk_nvmf_request *req)
{
	struct spdk_nvme_supported_log_pages nvme_log_data = {};
	struct spdk_nvme_supported_log_pages nvmf_log_data = {};
	struct spdk_nvmf_ctrlr *ctrlr = spdk_nvmf_request_get_ctrlr(req);
	uint32_t page_size = sizeof(struct spdk_nvme_supported_log_pages);
	uint64_t offset;
	size_t datalen, copy_len = 0;

	get_log_page_offset_and_len(req, page_size, &offset, &copy_len);

	if (copy_len == 0) {
		return;
	}

	/* Those are supported log pages from the NVMe drive */
	datalen = spdk_nvmf_request_copy_to_buf(req, (uint8_t *) &nvme_log_data + offset,
						copy_len);

	/* Those are supported log pages from SPDK */
	spdk_nvmf_get_supported_log_pages(ctrlr, &nvmf_log_data);

	/* Make sure that logs handled by SPDK are added as well */
	nvme_log_data.lids[SPDK_NVME_LOG_ASYMMETRIC_NAMESPACE_ACCESS] =
		nvmf_log_data.lids[SPDK_NVME_LOG_ASYMMETRIC_NAMESPACE_ACCESS];
	nvme_log_data.lids[SPDK_NVME_LOG_CHANGED_NS_LIST] =
		nvmf_log_data.lids[SPDK_NVME_LOG_CHANGED_NS_LIST];
	nvme_log_data.lids[SPDK_NVME_LOG_FEATURE_IDS_EFFECTS] =
		nvmf_log_data.lids[SPDK_NVME_LOG_FEATURE_IDS_EFFECTS];
	nvme_log_data.lids[SPDK_NVME_LOG_COMMAND_EFFECTS_LOG] =
		nvmf_log_data.lids[SPDK_NVME_LOG_COMMAND_EFFECTS_LOG];

	/* Copy the data back to the request */
	spdk_nvmf_request_copy_from_buf(req, (uint8_t *) &nvme_log_data + offset, datalen);
}

static void
fixup_identify_ctrlr(struct spdk_nvmf_request *req)
{
@@ -396,6 +454,12 @@ fixup_identify_ctrlr(struct spdk_nvmf_request *req)
	memcpy(&nvmf_cdata.ieee[0], &nvme_cdata.ieee[0], sizeof(nvmf_cdata.ieee));
	/* FRU Globally Unique Identifier (FGUID) */

	if (g_spdk_nvmf_tgt_conf.admin_passthru.get_log_page) {
		nvmf_cdata.lpa = nvme_cdata.lpa;
		nvmf_cdata.elpe = nvme_cdata.elpe;
		nvmf_cdata.pels = nvme_cdata.pels;
	}

	/* Copy the fixed up data back to the response */
	spdk_nvmf_request_copy_from_buf(req, &nvmf_cdata, datalen);
}
@@ -452,6 +516,28 @@ nvmf_custom_admin_no_cb_hdlr(struct spdk_nvmf_request *req)
	return nvmf_admin_passthru_generic_hdlr(req, NULL);
}

static int
nvmf_custom_get_log_page_hdlr(struct spdk_nvmf_request *req)
{
	struct spdk_nvme_cmd *cmd = spdk_nvmf_request_get_cmd(req);

	switch (cmd->cdw10_bits.get_log_page.lid) {
	/* ANA log and Changed NS List have to be handled by SPDK.
	 * Do not passthru them to the drive.
	 */
	case SPDK_NVME_LOG_ASYMMETRIC_NAMESPACE_ACCESS:
	case SPDK_NVME_LOG_CHANGED_NS_LIST:
	/* SPDK is not supporting get/set_feature passthru, so disable log page with drive supported features */
	case SPDK_NVME_LOG_FEATURE_IDS_EFFECTS:
	case SPDK_NVME_LOG_COMMAND_EFFECTS_LOG:
		return -1;
	case SPDK_NVME_LOG_SUPPORTED_LOG_PAGES:
		return nvmf_admin_passthru_generic_hdlr(req, fixup_get_supported_log_pages);
	default:
		return nvmf_admin_passthru_generic_hdlr(req, NULL);
	}
}

static void
nvmf_tgt_advance_state(void)
{
@@ -477,6 +563,10 @@ nvmf_tgt_advance_state(void)
				SPDK_NOTICELOG("Custom identify ctrlr handler enabled\n");
				spdk_nvmf_set_custom_admin_cmd_hdlr(SPDK_NVME_OPC_IDENTIFY, nvmf_custom_identify_hdlr);
			}
			if (g_spdk_nvmf_tgt_conf.admin_passthru.get_log_page) {
				SPDK_NOTICELOG("Custom get log page handler enabled\n");
				spdk_nvmf_set_custom_admin_cmd_hdlr(SPDK_NVME_OPC_GET_LOG_PAGE, nvmf_custom_get_log_page_hdlr);
			}
			if (g_spdk_nvmf_tgt_conf.admin_passthru.vendor_specific) {
				int i;
				SPDK_NOTICELOG("Custom vendor specific commands handlers enabled\n");
@@ -597,6 +687,8 @@ nvmf_subsystem_write_config_json(struct spdk_json_write_ctx *w)
	spdk_json_write_named_object_begin(w, "admin_cmd_passthru");
	spdk_json_write_named_bool(w, "identify_ctrlr",
				   g_spdk_nvmf_tgt_conf.admin_passthru.identify_ctrlr);
	spdk_json_write_named_bool(w, "get_log_page",
				   g_spdk_nvmf_tgt_conf.admin_passthru.get_log_page);
	spdk_json_write_named_bool(w, "vendor_specific",
				   g_spdk_nvmf_tgt_conf.admin_passthru.vendor_specific);
	spdk_json_write_object_end(w);
+2 −2
Original line number Diff line number Diff line
@@ -26,7 +26,7 @@ def add_parser(subparsers):
            print('WARNING: -i|--passthru-identify-ctrlr is deprecated, please use -p|--passthru-admin-cmds identify_ctrlr.',
                  file=sys.stderr)
            admin_cmd_passthru.append('identify_ctrlr')
        all_admin_cmd_passthru = ('identify_ctrlr', 'vendor_specific')
        all_admin_cmd_passthru = ('identify_ctrlr', 'get_log_page', 'vendor_specific')
        if 'all' in admin_cmd_passthru:
            admin_cmd_passthru = {cmd: True for cmd in all_admin_cmd_passthru}
        else:
@@ -42,7 +42,7 @@ def add_parser(subparsers):
    when the controller has a single namespace that is an NVMe bdev (deprecated)""", action='store_true')
    p.add_argument('-p', '--passthru-admin-cmds', help="""Comma-separated list of admin commands to be passthru
                   when the controller has a single namespace that is an NVMe bdev.
                   Available options are: all, identify_ctrlr, vendor_specific""", type=lambda d: d.split(','))
                   Available options are: all, identify_ctrlr, get_log_page, vendor_specific""", type=lambda d: d.split(','))
    p.add_argument('-m', '--poll-groups-mask', help='Set cpumask for NVMf poll groups (optional)', type=str)
    p.add_argument('-d', '--discovery-filter', help="""Set discovery filter (optional), possible values are: `match_any` (default) or
         comma separated values: `transport`, `address`, `svcid`""", type=str)