Commit 43043c9b authored by Damien Le Moal's avatar Damien Le Moal Committed by Keith Busch
Browse files

nvmet: Introduce nvmet_req_transfer_len()



Add the new function nvmet_req_transfer_len() to parse a request command
to extract the transfer length of the command. This function
implementation relies on multiple helper functions for parsing I/O
commands (nvmet_io_cmd_transfer_len()), admin commands
(nvmet_admin_cmd_data_len()) and fabrics connect commands
(nvmet_connect_cmd_data_len).

Signed-off-by: default avatarDamien Le Moal <dlemoal@kernel.org>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
Tested-by: default avatarRick Wertenbroek <rick.wertenbroek@gmail.com>
Tested-by: default avatarManivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
Signed-off-by: default avatarKeith Busch <kbusch@kernel.org>
parent 62027831
Loading
Loading
Loading
Loading
+21 −0
Original line number Diff line number Diff line
@@ -1296,6 +1296,27 @@ void nvmet_execute_keep_alive(struct nvmet_req *req)
	nvmet_req_complete(req, status);
}

u32 nvmet_admin_cmd_data_len(struct nvmet_req *req)
{
	struct nvme_command *cmd = req->cmd;

	if (nvme_is_fabrics(cmd))
		return nvmet_fabrics_admin_cmd_data_len(req);
	if (nvmet_is_disc_subsys(nvmet_req_subsys(req)))
		return nvmet_discovery_cmd_data_len(req);

	switch (cmd->common.opcode) {
	case nvme_admin_get_log_page:
		return nvmet_get_log_page_len(cmd);
	case nvme_admin_identify:
		return NVME_IDENTIFY_DATA_SIZE;
	case nvme_admin_get_features:
		return nvmet_feat_data_len(req, le32_to_cpu(cmd->common.cdw10));
	default:
		return 0;
	}
}

u16 nvmet_parse_admin_cmd(struct nvmet_req *req)
{
	struct nvme_command *cmd = req->cmd;
+37 −0
Original line number Diff line number Diff line
@@ -911,6 +911,33 @@ static inline u16 nvmet_io_cmd_check_access(struct nvmet_req *req)
	return 0;
}

static u32 nvmet_io_cmd_transfer_len(struct nvmet_req *req)
{
	struct nvme_command *cmd = req->cmd;
	u32 metadata_len = 0;

	if (nvme_is_fabrics(cmd))
		return nvmet_fabrics_io_cmd_data_len(req);

	if (!req->ns)
		return 0;

	switch (req->cmd->common.opcode) {
	case nvme_cmd_read:
	case nvme_cmd_write:
	case nvme_cmd_zone_append:
		if (req->sq->ctrl->pi_support && nvmet_ns_has_pi(req->ns))
			metadata_len = nvmet_rw_metadata_len(req);
		return nvmet_rw_data_len(req) + metadata_len;
	case nvme_cmd_dsm:
		return nvmet_dsm_len(req);
	case nvme_cmd_zone_mgmt_recv:
		return (le32_to_cpu(req->cmd->zmr.numd) + 1) << 2;
	default:
		return 0;
	}
}

static u16 nvmet_parse_io_cmd(struct nvmet_req *req)
{
	struct nvme_command *cmd = req->cmd;
@@ -1059,6 +1086,16 @@ void nvmet_req_uninit(struct nvmet_req *req)
}
EXPORT_SYMBOL_GPL(nvmet_req_uninit);

size_t nvmet_req_transfer_len(struct nvmet_req *req)
{
	if (likely(req->sq->qid != 0))
		return nvmet_io_cmd_transfer_len(req);
	if (unlikely(!req->sq->ctrl))
		return nvmet_connect_cmd_data_len(req);
	return nvmet_admin_cmd_data_len(req);
}
EXPORT_SYMBOL_GPL(nvmet_req_transfer_len);

bool nvmet_check_transfer_len(struct nvmet_req *req, size_t len)
{
	if (unlikely(len != req->transfer_len)) {
+14 −0
Original line number Diff line number Diff line
@@ -355,6 +355,20 @@ static void nvmet_execute_disc_get_features(struct nvmet_req *req)
	nvmet_req_complete(req, stat);
}

u32 nvmet_discovery_cmd_data_len(struct nvmet_req *req)
{
	struct nvme_command *cmd = req->cmd;

	switch (cmd->common.opcode) {
	case nvme_admin_get_log_page:
		return nvmet_get_log_page_len(req->cmd);
	case nvme_admin_identify:
		return NVME_IDENTIFY_DATA_SIZE;
	default:
		return 0;
	}
}

u16 nvmet_parse_discovery_cmd(struct nvmet_req *req)
{
	struct nvme_command *cmd = req->cmd;
+12 −2
Original line number Diff line number Diff line
@@ -179,6 +179,11 @@ static u8 nvmet_auth_failure2(void *d)
	return data->rescode_exp;
}

u32 nvmet_auth_send_data_len(struct nvmet_req *req)
{
	return le32_to_cpu(req->cmd->auth_send.tl);
}

void nvmet_execute_auth_send(struct nvmet_req *req)
{
	struct nvmet_ctrl *ctrl = req->sq->ctrl;
@@ -206,7 +211,7 @@ void nvmet_execute_auth_send(struct nvmet_req *req)
			offsetof(struct nvmf_auth_send_command, spsp1);
		goto done;
	}
	tl = le32_to_cpu(req->cmd->auth_send.tl);
	tl = nvmet_auth_send_data_len(req);
	if (!tl) {
		status = NVME_SC_INVALID_FIELD | NVME_STATUS_DNR;
		req->error_loc =
@@ -429,6 +434,11 @@ static void nvmet_auth_failure1(struct nvmet_req *req, void *d, int al)
	data->rescode_exp = req->sq->dhchap_status;
}

u32 nvmet_auth_receive_data_len(struct nvmet_req *req)
{
	return le32_to_cpu(req->cmd->auth_receive.al);
}

void nvmet_execute_auth_receive(struct nvmet_req *req)
{
	struct nvmet_ctrl *ctrl = req->sq->ctrl;
@@ -454,7 +464,7 @@ void nvmet_execute_auth_receive(struct nvmet_req *req)
			offsetof(struct nvmf_auth_receive_command, spsp1);
		goto done;
	}
	al = le32_to_cpu(req->cmd->auth_receive.al);
	al = nvmet_auth_receive_data_len(req);
	if (!al) {
		status = NVME_SC_INVALID_FIELD | NVME_STATUS_DNR;
		req->error_loc =
+43 −0
Original line number Diff line number Diff line
@@ -85,6 +85,22 @@ static void nvmet_execute_prop_get(struct nvmet_req *req)
	nvmet_req_complete(req, status);
}

u32 nvmet_fabrics_admin_cmd_data_len(struct nvmet_req *req)
{
	struct nvme_command *cmd = req->cmd;

	switch (cmd->fabrics.fctype) {
#ifdef CONFIG_NVME_TARGET_AUTH
	case nvme_fabrics_type_auth_send:
		return nvmet_auth_send_data_len(req);
	case nvme_fabrics_type_auth_receive:
		return nvmet_auth_receive_data_len(req);
#endif
	default:
		return 0;
	}
}

u16 nvmet_parse_fabrics_admin_cmd(struct nvmet_req *req)
{
	struct nvme_command *cmd = req->cmd;
@@ -114,6 +130,22 @@ u16 nvmet_parse_fabrics_admin_cmd(struct nvmet_req *req)
	return 0;
}

u32 nvmet_fabrics_io_cmd_data_len(struct nvmet_req *req)
{
	struct nvme_command *cmd = req->cmd;

	switch (cmd->fabrics.fctype) {
#ifdef CONFIG_NVME_TARGET_AUTH
	case nvme_fabrics_type_auth_send:
		return nvmet_auth_send_data_len(req);
	case nvme_fabrics_type_auth_receive:
		return nvmet_auth_receive_data_len(req);
#endif
	default:
		return 0;
	}
}

u16 nvmet_parse_fabrics_io_cmd(struct nvmet_req *req)
{
	struct nvme_command *cmd = req->cmd;
@@ -337,6 +369,17 @@ static void nvmet_execute_io_connect(struct nvmet_req *req)
	goto out;
}

u32 nvmet_connect_cmd_data_len(struct nvmet_req *req)
{
	struct nvme_command *cmd = req->cmd;

	if (!nvme_is_fabrics(cmd) ||
	    cmd->fabrics.fctype != nvme_fabrics_type_connect)
		return 0;

	return sizeof(struct nvmf_connect_data);
}

u16 nvmet_parse_connect_cmd(struct nvmet_req *req)
{
	struct nvme_command *cmd = req->cmd;
Loading