Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F177570733
D61556.1794768258.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
14 KB
Referenced Files
None
Subscribers
None
D61556.1794768258.diff
View Options
diff --git a/tests/sys/cam/ctl/nvmft/README b/tests/sys/cam/ctl/nvmft/README
--- a/tests/sys/cam/ctl/nvmft/README
+++ b/tests/sys/cam/ctl/nvmft/README
@@ -15,6 +15,7 @@
test_suites.FreeBSD.nvmft.address = "127.0.0.1"
test_suites.FreeBSD.nvmft.port = "4420"
test_suites.FreeBSD.nvmft.nqn = "nqn.1994-09.org.freebsd:test"
+test_suites.FreeBSD.nvmft.nsid = "1"
In addition, the following optional configuration variables may also
be set (Note that the variable names all require a prefix of
diff --git a/tests/sys/cam/ctl/nvmft/nvmft.c b/tests/sys/cam/ctl/nvmft/nvmft.c
--- a/tests/sys/cam/ctl/nvmft/nvmft.c
+++ b/tests/sys/cam/ctl/nvmft/nvmft.c
@@ -1053,6 +1053,357 @@
identify_bad_size(tc, 4097);
}
+static void
+nvmf_init_read_sqe(void *sqe, uint32_t nsid, uint64_t lba, u_int nlb)
+{
+ struct nvme_command *cmd = sqe;
+
+ nvmf_init_sqe(cmd, NVME_OPC_READ);
+ cmd->nsid = htole32(nsid);
+ cmd->cdw10 = htole32(lba);
+ cmd->cdw11 = htole32(lba >> 32);
+ cmd->cdw12 = htole16(nlb - 1);
+}
+
+static struct nvmf_capsule *
+create_read_command(struct nvmf_qpair *io, uint32_t nsid, uint64_t lba,
+ u_int nlb, void *buf, size_t len)
+{
+ struct nvme_command cmd;
+ struct nvmf_capsule *cc;
+ int error;
+
+ nvmf_init_read_sqe(&cmd, nsid, lba, nlb);
+ cc = nvmf_allocate_command(io, &cmd);
+ if (cc == NULL)
+ atf_tc_fail("Failed to allocate command capsule: %s",
+ strerror(errno));
+
+ error = nvmf_capsule_append_data(cc, buf, len, false);
+ if (error != 0)
+ atf_tc_fail("Failed to append data to READ capsule: %s",
+ strerror(error));
+
+ return (cc);
+}
+
+ATF_TC(read_block);
+ATF_TC_HEAD(read_block, tc)
+{
+ require_nvmft(tc);
+}
+ATF_TC_BODY(read_block, tc)
+{
+ const struct nvme_completion *cpl;
+ struct nvmf_qpair_params qparams;
+ struct nvmf_association *na;
+ struct nvmf_qpair *admin, *io;
+ struct nvmf_capsule *cc, *rc;
+ char hostnqn[NVMF_NQN_MAX_LEN];
+ uint8_t hostid[16];
+ struct addrinfo *ai, *list;
+ char *buf;
+ size_t len;
+ u_int block_size, nsid;
+ int error;
+ uint16_t status;
+
+ init_hostid(hostid, hostnqn);
+
+ na = create_association(tc);
+
+ memset(&qparams, 0, sizeof(qparams));
+ qparams.admin = true;
+ qparams.tcp.fd = open_socket(tc, &ai, &list);
+
+ admin = connect_admin_queue(tc, na, &qparams, hostid, hostnqn, 0);
+ if (admin == NULL)
+ atf_tc_fail("Failed to create admin queue: %s",
+ nvmf_association_error(na));
+
+ require_nvm(admin);
+
+ memset(&qparams, 0, sizeof(qparams));
+ qparams.admin = false;
+ qparams.tcp.fd = open_socket_ai(ai);
+ freeaddrinfo(list);
+
+ io = connect_io_queue(tc, admin, na, &qparams, hostid, hostnqn);
+ nvmf_free_association(na);
+
+ nsid = validate_namespace(tc, admin, &block_size);
+
+ len = block_size;
+ buf = malloc(len);
+ cc = create_read_command(io, nsid, 0, 1, buf, len);
+
+ error = nvmf_host_transmit_command(cc);
+ if (error != 0)
+ atf_tc_fail("Failed to transmit READ capsule: %s",
+ strerror(errno));
+
+ error = nvmf_host_wait_for_response(cc, &rc);
+ nvmf_free_capsule(cc);
+ if (error != 0)
+ atf_tc_fail("Failed to receive READ response: %s",
+ strerror(error));
+
+ cpl = nvmf_capsule_cqe(rc);
+ status = le16toh(cpl->status);
+ ATF_REQUIRE(status == 0);
+ nvmf_free_capsule(rc);
+
+ shutdown_controller(admin);
+ nvmf_free_qpair(io);
+ nvmf_free_qpair(admin);
+}
+
+static void
+nvmf_init_compare_sqe(void *sqe, uint32_t nsid, uint64_t lba, u_int nlb)
+{
+ struct nvme_command *cmd = sqe;
+
+ nvmf_init_sqe(cmd, NVME_OPC_COMPARE);
+ cmd->nsid = htole32(nsid);
+ cmd->cdw10 = htole32(lba);
+ cmd->cdw11 = htole32(lba >> 32);
+ cmd->cdw12 = htole16(nlb - 1);
+}
+
+static struct nvmf_capsule *
+create_compare_command(struct nvmf_qpair *io, uint32_t nsid, uint64_t lba,
+ u_int nlb, void *buf, size_t len)
+{
+ struct nvme_command cmd;
+ struct nvmf_capsule *cc;
+ int error;
+
+ nvmf_init_compare_sqe(&cmd, nsid, lba, nlb);
+ cc = nvmf_allocate_command(io, &cmd);
+ if (cc == NULL)
+ atf_tc_fail("Failed to allocate command capsule: %s",
+ strerror(errno));
+
+ error = nvmf_capsule_append_data(cc, buf, len, true);
+ if (error != 0)
+ atf_tc_fail("Failed to append data to COMPARE capsule: %s",
+ strerror(error));
+
+ return (cc);
+}
+
+ATF_TC(compare_block);
+ATF_TC_HEAD(compare_block, tc)
+{
+ require_nvmft(tc);
+}
+ATF_TC_BODY(compare_block, tc)
+{
+ const struct nvme_completion *cpl;
+ struct nvmf_qpair_params qparams;
+ struct nvmf_association *na;
+ struct nvmf_qpair *admin, *io;
+ struct nvmf_capsule *cc, *rc;
+ char hostnqn[NVMF_NQN_MAX_LEN];
+ uint8_t hostid[16];
+ struct addrinfo *ai, *list;
+ char *buf;
+ size_t len;
+ u_int block_size, nsid;
+ int error;
+ uint16_t status;
+
+ init_hostid(hostid, hostnqn);
+
+ na = create_association(tc);
+
+ memset(&qparams, 0, sizeof(qparams));
+ qparams.admin = true;
+ qparams.tcp.fd = open_socket(tc, &ai, &list);
+
+ admin = connect_admin_queue(tc, na, &qparams, hostid, hostnqn, 0);
+ if (admin == NULL)
+ atf_tc_fail("Failed to create admin queue: %s",
+ nvmf_association_error(na));
+
+ require_compare(admin);
+
+ memset(&qparams, 0, sizeof(qparams));
+ qparams.admin = false;
+ qparams.tcp.fd = open_socket_ai(ai);
+ freeaddrinfo(list);
+
+ io = connect_io_queue(tc, admin, na, &qparams, hostid, hostnqn);
+ nvmf_free_association(na);
+
+ nsid = validate_namespace(tc, admin, &block_size);
+
+ /* First, read the first block. */
+ len = block_size;
+ buf = malloc(len);
+ cc = create_read_command(io, nsid, 0, 1, buf, len);
+
+ error = nvmf_host_transmit_command(cc);
+ if (error != 0)
+ atf_tc_fail("Failed to transmit READ capsule: %s",
+ strerror(errno));
+
+ error = nvmf_host_wait_for_response(cc, &rc);
+ nvmf_free_capsule(cc);
+ if (error != 0)
+ atf_tc_fail("Failed to receive READ response: %s",
+ strerror(error));
+
+ cpl = nvmf_capsule_cqe(rc);
+ status = le16toh(cpl->status);
+ ATF_REQUIRE(status == 0);
+ nvmf_free_capsule(rc);
+
+ /* Second, compare that block with the value just read. */
+ cc = create_compare_command(io, nsid, 0, 1, buf, len);
+
+ error = nvmf_host_transmit_command(cc);
+ if (error != 0)
+ atf_tc_fail("Failed to transmit COMPARE capsule: %s",
+ strerror(errno));
+
+ error = nvmf_host_wait_for_response(cc, &rc);
+ nvmf_free_capsule(cc);
+ if (error != 0)
+ atf_tc_fail("Failed to receive COMPARE response: %s",
+ strerror(error));
+
+ cpl = nvmf_capsule_cqe(rc);
+ status = le16toh(cpl->status);
+ ATF_REQUIRE(status == 0);
+ nvmf_free_capsule(rc);
+
+ shutdown_controller(admin);
+ nvmf_free_qpair(io);
+ nvmf_free_qpair(admin);
+}
+
+ATF_TC(compare_mismatch);
+ATF_TC_HEAD(compare_mismatch, tc)
+{
+ require_nvmft(tc);
+}
+ATF_TC_BODY(compare_mismatch, tc)
+{
+ const struct nvme_completion *cpl;
+ struct nvmf_qpair_params qparams;
+ struct nvmf_association *na;
+ struct nvmf_qpair *admin, *io;
+ struct nvmf_capsule *cc, *rc;
+ char hostnqn[NVMF_NQN_MAX_LEN];
+ uint8_t hostid[16];
+ struct addrinfo *ai, *list;
+ char *buf;
+ size_t len;
+ u_int block_size, nsid;
+ int error;
+ uint16_t status;
+
+ init_hostid(hostid, hostnqn);
+
+ na = create_association(tc);
+
+ memset(&qparams, 0, sizeof(qparams));
+ qparams.admin = true;
+ qparams.tcp.fd = open_socket(tc, &ai, &list);
+
+ admin = connect_admin_queue(tc, na, &qparams, hostid, hostnqn, 0);
+ if (admin == NULL)
+ atf_tc_fail("Failed to create admin queue: %s",
+ nvmf_association_error(na));
+
+ require_compare(admin);
+
+ memset(&qparams, 0, sizeof(qparams));
+ qparams.admin = false;
+ qparams.tcp.fd = open_socket_ai(ai);
+ freeaddrinfo(list);
+
+ io = connect_io_queue(tc, admin, na, &qparams, hostid, hostnqn);
+ nvmf_free_association(na);
+
+ nsid = validate_namespace(tc, admin, &block_size);
+
+ /* First, read the first block. */
+ len = block_size;
+ buf = malloc(len);
+ cc = create_read_command(io, nsid, 0, 1, buf, len);
+
+ error = nvmf_host_transmit_command(cc);
+ if (error != 0)
+ atf_tc_fail("Failed to transmit READ capsule: %s",
+ strerror(errno));
+
+ error = nvmf_host_wait_for_response(cc, &rc);
+ nvmf_free_capsule(cc);
+ if (error != 0)
+ atf_tc_fail("Failed to receive READ response: %s",
+ strerror(error));
+
+ cpl = nvmf_capsule_cqe(rc);
+ status = le16toh(cpl->status);
+ ATF_REQUIRE(status == 0);
+ nvmf_free_capsule(rc);
+
+ /* Second, flip some bits in the first byte of the block. */
+ buf[0] ^= 0xaa;
+
+ /* Third, compare that block with the altered values. */
+ cc = create_compare_command(io, nsid, 0, 1, buf, len);
+
+ error = nvmf_host_transmit_command(cc);
+ if (error != 0)
+ atf_tc_fail("Failed to transmit COMPARE capsule: %s",
+ strerror(errno));
+
+ error = nvmf_host_wait_for_response(cc, &rc);
+ nvmf_free_capsule(cc);
+ if (error != 0)
+ atf_tc_fail("Failed to receive COMPARE response: %s",
+ strerror(error));
+
+ cpl = nvmf_capsule_cqe(rc);
+ status = le16toh(cpl->status);
+ ATF_REQUIRE(status != 0);
+ ATF_REQUIRE(NVME_STATUS_GET_SCT(status) == NVME_SCT_MEDIA_ERROR);
+ ATF_REQUIRE(NVME_STATUS_GET_SC(status) == NVME_SC_COMPARE_FAILURE);
+ nvmf_free_capsule(rc);
+
+ /* Next, restore the first byte and flip some bits in the last byte. */
+ buf[0] ^= 0xaa;
+ buf[len - 1] ^= 0x55;
+
+ /* Last, one more compare. */
+ cc = create_compare_command(io, nsid, 0, 1, buf, len);
+
+ error = nvmf_host_transmit_command(cc);
+ if (error != 0)
+ atf_tc_fail("Failed to transmit COMPARE capsule: %s",
+ strerror(errno));
+
+ error = nvmf_host_wait_for_response(cc, &rc);
+ nvmf_free_capsule(cc);
+ if (error != 0)
+ atf_tc_fail("Failed to receive COMPARE response: %s",
+ strerror(error));
+
+ cpl = nvmf_capsule_cqe(rc);
+ status = le16toh(cpl->status);
+ ATF_REQUIRE(status != 0);
+ ATF_REQUIRE(NVME_STATUS_GET_SCT(status) == NVME_SCT_MEDIA_ERROR);
+ ATF_REQUIRE(NVME_STATUS_GET_SC(status) == NVME_SC_COMPARE_FAILURE);
+ nvmf_free_capsule(rc);
+
+ shutdown_controller(admin);
+ nvmf_free_qpair(io);
+ nvmf_free_qpair(admin);
+}
+
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, invalid_qid);
@@ -1078,6 +1429,9 @@
ATF_TP_ADD_TC(tp, fetch_reserved_log_page);
ATF_TP_ADD_TC(tp, identify_short);
ATF_TP_ADD_TC(tp, identify_long);
+ ATF_TP_ADD_TC(tp, read_block);
+ ATF_TP_ADD_TC(tp, compare_block);
+ ATF_TP_ADD_TC(tp, compare_mismatch);
return (atf_no_error());
}
diff --git a/tests/sys/cam/ctl/nvmft/nvmft_subr.h b/tests/sys/cam/ctl/nvmft/nvmft_subr.h
--- a/tests/sys/cam/ctl/nvmft/nvmft_subr.h
+++ b/tests/sys/cam/ctl/nvmft/nvmft_subr.h
@@ -11,13 +11,21 @@
struct nvmf_qpair *connect_admin_queue(const atf_tc_t *tc,
struct nvmf_association *na, const struct nvmf_qpair_params *params,
const uint8_t hostid[16], const char *hostnqn, uint32_t kato);
+struct nvmf_qpair *connect_io_queue(const atf_tc_t *tc,
+ struct nvmf_qpair *admin, struct nvmf_association *na,
+ const struct nvmf_qpair_params *params, const uint8_t hostid[16],
+ const char *hostnqn);
struct nvmf_association *create_association(const atf_tc_t *tc);
void init_hostid(uint8_t hostid[16], char hostnqn[NVMF_NQN_MAX_LEN]);
int open_socket(const atf_tc_t *tc, struct addrinfo **aip,
struct addrinfo **listp);
int open_socket_ai(struct addrinfo *ai);
uint16_t parse_cntlid(const atf_tc_t *tc);
+void require_compare(struct nvmf_qpair *qp);
+void require_nvm(struct nvmf_qpair *qp);
void require_nvmft(atf_tc_t *tc);
void shutdown_controller(struct nvmf_qpair *qp);
+u_int validate_namespace(const atf_tc_t *tc, struct nvmf_qpair *qp,
+ u_int *block_size);
#endif /* !__NVMFT_SUBR_H__ */
diff --git a/tests/sys/cam/ctl/nvmft/nvmft_subr.c b/tests/sys/cam/ctl/nvmft/nvmft_subr.c
--- a/tests/sys/cam/ctl/nvmft/nvmft_subr.c
+++ b/tests/sys/cam/ctl/nvmft/nvmft_subr.c
@@ -239,3 +239,104 @@
atf_tc_fail("Failed to set CC to trigger shutdown: %s",
strerror(error));
}
+
+void
+require_nvm(struct nvmf_qpair *qp)
+{
+ uint64_t cap;
+ int error;
+
+ error = nvmf_read_property(qp, NVMF_PROP_CAP, 8, &cap);
+ if (error != 0)
+ atf_tc_fail("Failed to fetch CAP: %s", strerror(error));
+
+ if (NVME_CAP_HI_CSS_NVM(cap >> 32) == 0)
+ atf_tc_skip("Controller does not support the NVM command set");
+}
+
+void
+require_compare(struct nvmf_qpair *qp)
+{
+ struct nvme_controller_data cdata;
+ int error;
+
+ require_nvm(qp);
+
+ error = nvmf_host_identify_controller(qp, &cdata);
+ if (error != 0)
+ atf_tc_fail("Failed to fetch controller data: %s",
+ strerror(error));
+
+ if (NVMEV(NVME_CTRLR_DATA_ONCS_COMPARE, cdata.oncs) == 0)
+ atf_tc_skip("Controller does not support the COMPARE command");
+}
+
+struct nvmf_qpair *
+connect_io_queue(const atf_tc_t *tc, struct nvmf_qpair *admin,
+ struct nvmf_association *na, const struct nvmf_qpair_params *params,
+ const uint8_t hostid[16], const char *hostnqn)
+{
+ struct nvme_controller_data cdata;
+ struct nvmf_qpair *io;
+ int error, queues;
+
+ error = nvmf_host_identify_controller(admin, &cdata);
+ if (error != 0)
+ atf_tc_fail("Failed to fetch controller data: %s",
+ strerror(error));
+ nvmf_update_assocation(na, &cdata);
+
+ error = nvmf_host_request_queues(admin, 1, &queues);
+ if (error != 0)
+ atf_tc_fail("Failed to request I/O queues: %s",
+ strerror(error));
+
+ io = nvmf_connect(na, params, 1, NVME_MIN_IO_ENTRIES, hostid,
+ nvmf_cntlid(admin), atf_tc_get_config_var(tc, "nvmft.nqn"),
+ hostnqn, 0);
+ if (io == NULL)
+ atf_tc_fail("Failed to create I/O queue: %s",
+ nvmf_association_error(na));
+ return (io);
+}
+
+u_int
+validate_namespace(const atf_tc_t *tc, struct nvmf_qpair *qp, u_int *block_size)
+{
+ struct nvme_namespace_data nsdata;
+ long val;
+ uint32_t nsid;
+ int error;
+ uint8_t lbads, lbaf;
+
+ if (!atf_tc_has_config_var(tc, "nvmft.nsid"))
+ atf_tc_skip("requires nvmft.nsid config variable");
+
+ val = atf_tc_get_config_var_as_long(tc, "nvmft.nsid");
+ nsid = val;
+ if (val < 1 || nsid >= NVME_GLOBAL_NAMESPACE_TAG)
+ atf_tc_fail("Invalid nsid: %ld", val);
+
+ error = nvmf_host_identify_namespace(qp, nsid, &nsdata);
+ if (error != 0)
+ atf_tc_fail("IDENTIFY failed for nsid %u", nsid);
+
+ nvme_namespace_data_swapbytes(&nsdata);
+
+ if (NVMEV(NVME_NS_DATA_DPS_PIT, nsdata.dps) != 0)
+ atf_tc_fail("Namespace %u uses data protection", nsid);
+
+ lbaf = NVMEV(NVME_NS_DATA_FLBAS_FORMAT, nsdata.flbas);
+ if (lbaf > nsdata.nlbaf)
+ atf_tc_fail("Invalid LBA format index for namespace %u", nsid);
+
+ if (NVMEV(NVME_NS_DATA_LBAF_MS, nsdata.lbaf[lbaf]) != 0)
+ atf_tc_fail("Namespace %u uses metadata", nsid);
+
+ lbads = NVMEV(NVME_NS_DATA_LBAF_LBADS, nsdata.lbaf[lbaf]);
+ if (lbads == 0)
+ atf_tc_fail("Namespace %u block size is zero", nsid);
+
+ *block_size = 1 << lbads;
+ return (nsid);
+}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Nov 15, 6:44 PM (23 h, 46 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
41746882
Default Alt Text
D61556.1794768258.diff (14 KB)
Attached To
Mode
D61556: nvmft: Add some simple I/O tests
Attached
Detach File
Event Timeline