Commit 1c5d9803 authored by Tomasz Kulasek's avatar Tomasz Kulasek Committed by Tomasz Zawadzki
Browse files

lib/nvme: add hw support for fused operations



Change-Id: I2a184a2d60f18439947afa2d4855d51b92ed282e
Signed-off-by: default avatarTomasz Kulasek <tomaszx.kulasek@intel.com>
Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/476137


Community-CI: SPDK CI Jenkins <sys_sgci@intel.com>
Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: default avatarShuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Reviewed-by: default avatarJim Harris <james.r.harris@intel.com>
Reviewed-by: default avatarBen Walker <benjamin.walker@intel.com>
Reviewed-by: default avatarPaul Luse <paul.e.luse@intel.com>
parent 8209c8cf
Loading
Loading
Loading
Loading
+16 −1
Original line number Diff line number Diff line
@@ -464,6 +464,16 @@ enum spdk_nvme_cc_ams {
	SPDK_NVME_CC_AMS_VS		= 0x7,	/**< vendor specific */
};

/**
 * Fused Operation
 */
enum spdk_nvme_cmd_fuse {
	SPDK_NVMF_CMD_FUSE_NONE		= 0x0,	/**< normal operation */
	SPDK_NVME_CMD_FUSE_FIRST	= 0x1,	/**< fused operation, first command */
	SPDK_NVME_CMD_FUSE_SECOND	= 0x2,	/**< fused operation, second command */
	/* 0x3 - reserved */
};

/**
 * Data used by Set Features/Get Features \ref SPDK_NVME_FEAT_ARBITRATION
 */
@@ -2821,6 +2831,10 @@ SPDK_STATIC_ASSERT(sizeof(struct spdk_nvme_fw_commit) == 4, "Incorrect size");
	  (cpl)->status.sc == SPDK_NVME_SC_APPLICATION_TAG_CHECK_ERROR ||	\
	  (cpl)->status.sc == SPDK_NVME_SC_REFERENCE_TAG_CHECK_ERROR))

/** Set fused operation */
#define SPDK_NVME_IO_FLAGS_FUSE_FIRST (1U << 0)
#define SPDK_NVME_IO_FLAGS_FUSE_SECOND (1U << 1)
#define SPDK_NVME_IO_FLAGS_FUSE_MASK (3U << 0)
/** Enable protection information checking of the Logical Block Reference Tag field */
#define SPDK_NVME_IO_FLAGS_PRCHK_REFTAG (1U << 26)
/** Enable protection information checking of the Application Tag field */
@@ -2833,7 +2847,8 @@ SPDK_STATIC_ASSERT(sizeof(struct spdk_nvme_fw_commit) == 4, "Incorrect size");
#define SPDK_NVME_IO_FLAGS_LIMITED_RETRY (1U << 31)

/** Mask of valid io flags mask */
#define SPDK_NVME_IO_FLAGS_VALID_MASK 0xFFFF0000
#define SPDK_NVME_IO_FLAGS_VALID_MASK 0xFFFF0003
#define SPDK_NVME_IO_FLAGS_CDW12_MASK 0xFFFF0000

#ifdef __cplusplus
}
+5 −2
Original line number Diff line number Diff line
@@ -165,8 +165,10 @@ _nvme_ns_cmd_setup_request(struct spdk_nvme_ns *ns, struct nvme_request *req,
		}
	}

	cmd->fuse = (io_flags & SPDK_NVME_IO_FLAGS_FUSE_MASK);

	cmd->cdw12 = lba_count - 1;
	cmd->cdw12 |= io_flags;
	cmd->cdw12 |= (io_flags & SPDK_NVME_IO_FLAGS_CDW12_MASK);

	cmd->cdw15 = apptag_mask;
	cmd->cdw15 = (cmd->cdw15 << 16 | apptag);
@@ -828,7 +830,8 @@ spdk_nvme_ns_cmd_write_zeroes(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *q
	tmp_lba = (uint64_t *)&cmd->cdw10;
	*tmp_lba = lba;
	cmd->cdw12 = lba_count - 1;
	cmd->cdw12 |= io_flags;
	cmd->fuse = (io_flags & SPDK_NVME_IO_FLAGS_FUSE_MASK);
	cmd->cdw12 |= (io_flags & SPDK_NVME_IO_FLAGS_CDW12_MASK);

	return nvme_qpair_submit_request(qpair, req);
}
+65 −0
Original line number Diff line number Diff line
@@ -746,6 +746,53 @@ test_nvme_ns_cmd_comparev(void)
	cleanup_after_test(&qpair);
}

static void
test_nvme_ns_cmd_compare_and_write(void)
{
	struct spdk_nvme_ns		ns;
	struct spdk_nvme_ctrlr		ctrlr;
	struct spdk_nvme_qpair		qpair;
	int				rc = 0;
	uint64_t			lba = 0x1000;
	uint32_t			lba_count = 256;
	uint64_t			cmd_lba;
	uint32_t			cmd_lba_count;
	uint32_t			sector_size = 512;

	prepare_for_test(&ns, &ctrlr, &qpair, sector_size, 0, 128 * 1024, 0, false);

	rc = spdk_nvme_ns_cmd_compare(&ns, &qpair, NULL, lba, lba_count, NULL, NULL,
				      SPDK_NVME_IO_FLAGS_FUSE_FIRST);

	SPDK_CU_ASSERT_FATAL(rc == 0);
	SPDK_CU_ASSERT_FATAL(g_request != NULL);
	CU_ASSERT(g_request->cmd.opc == SPDK_NVME_OPC_COMPARE);
	CU_ASSERT(g_request->cmd.fuse == SPDK_NVME_CMD_FUSE_FIRST);
	CU_ASSERT(g_request->cmd.nsid == ns.id);

	nvme_cmd_interpret_rw(&g_request->cmd, &cmd_lba, &cmd_lba_count);
	CU_ASSERT_EQUAL(cmd_lba, lba);
	CU_ASSERT_EQUAL(cmd_lba_count, lba_count);

	nvme_free_request(g_request);

	rc = spdk_nvme_ns_cmd_write(&ns, &qpair, NULL, lba, lba_count, NULL, NULL,
				    SPDK_NVME_IO_FLAGS_FUSE_SECOND);

	SPDK_CU_ASSERT_FATAL(rc == 0);
	SPDK_CU_ASSERT_FATAL(g_request != NULL);
	CU_ASSERT(g_request->cmd.opc == SPDK_NVME_OPC_WRITE);
	CU_ASSERT(g_request->cmd.fuse == SPDK_NVME_CMD_FUSE_SECOND);
	CU_ASSERT(g_request->cmd.nsid == ns.id);
	nvme_cmd_interpret_rw(&g_request->cmd, &cmd_lba, &cmd_lba_count);
	CU_ASSERT_EQUAL(cmd_lba, lba);
	CU_ASSERT_EQUAL(cmd_lba_count, lba_count);

	nvme_free_request(g_request);

	cleanup_after_test(&qpair);
}

static void
test_io_flags(void)
{
@@ -755,6 +802,8 @@ test_io_flags(void)
	void			*payload;
	uint64_t		lba;
	uint32_t		lba_count;
	uint64_t		cmd_lba;
	uint32_t		cmd_lba_count;
	int			rc;

	prepare_for_test(&ns, &ctrlr, &qpair, 512, 0, 128 * 1024, 128 * 1024, false);
@@ -778,6 +827,21 @@ test_io_flags(void)
	CU_ASSERT((g_request->cmd.cdw12 & SPDK_NVME_IO_FLAGS_LIMITED_RETRY) != 0);
	nvme_free_request(g_request);

	rc = spdk_nvme_ns_cmd_write(&ns, &qpair, payload, lba, lba_count, NULL, NULL,
				    SPDK_NVME_IO_FLAGS_VALID_MASK);
	SPDK_CU_ASSERT_FATAL(rc == 0);
	SPDK_CU_ASSERT_FATAL(g_request != NULL);
	nvme_cmd_interpret_rw(&g_request->cmd, &cmd_lba, &cmd_lba_count);
	CU_ASSERT_EQUAL(cmd_lba_count, lba_count);
	CU_ASSERT_EQUAL(cmd_lba, lba);
	CU_ASSERT_EQUAL(g_request->cmd.cdw12 & SPDK_NVME_IO_FLAGS_CDW12_MASK,
			SPDK_NVME_IO_FLAGS_CDW12_MASK);
	nvme_free_request(g_request);

	rc = spdk_nvme_ns_cmd_write(&ns, &qpair, payload, lba, lba_count, NULL, NULL,
				    ~SPDK_NVME_IO_FLAGS_VALID_MASK);
	CU_ASSERT(rc == -EINVAL);

	free(payload);
	cleanup_after_test(&qpair);
}
@@ -1447,6 +1511,7 @@ int main(int argc, char **argv)
		|| CU_add_test(suite, "nvme_ns_cmd_writev", test_nvme_ns_cmd_writev) == NULL
		|| CU_add_test(suite, "nvme_ns_cmd_write_with_md", test_nvme_ns_cmd_write_with_md) == NULL
		|| CU_add_test(suite, "nvme_ns_cmd_comparev", test_nvme_ns_cmd_comparev) == NULL
		|| CU_add_test(suite, "nvme_ns_cmd_compare_and_write", test_nvme_ns_cmd_compare_and_write) == NULL
		|| CU_add_test(suite, "nvme_ns_cmd_compare_with_md", test_nvme_ns_cmd_compare_with_md) == NULL
	) {
		CU_cleanup_registry();