diff --git a/examples/meson.build b/examples/meson.build index 3139311a0..26d7b2159 100644 --- a/examples/meson.build +++ b/examples/meson.build @@ -40,6 +40,13 @@ executable( include_directories: [incdir, internal_incdir] ) +executable( + 'mi-mctp-csi-test', + ['mi-mctp-csi-test.c'], + dependencies: libnvme_mi_dep, + include_directories: [incdir, internal_incdir] +) + if libdbus_dep.found() executable( 'mi-conf', diff --git a/examples/mi-mctp-csi-test.c b/examples/mi-mctp-csi-test.c new file mode 100644 index 000000000..e049c32d5 --- /dev/null +++ b/examples/mi-mctp-csi-test.c @@ -0,0 +1,252 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/** + * This file is part of libnvme. + */ + +/** + * mi-mctp-csi-test: open a MI connection over MCTP, and send two commands + * in parallel with different CSI buffers + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +void fhexdump(FILE *fp, const unsigned char *buf, int len) +{ + const int row_len = 16; + int i, j; + + for (i = 0; i < len; i += row_len) { + char hbuf[row_len * strlen("00 ") + 1]; + char cbuf[row_len + strlen("|") + 1]; + + for (j = 0; (j < row_len) && ((i+j) < len); j++) { + unsigned char c = buf[i + j]; + + sprintf(hbuf + j * 3, "%02x ", c); + + if (!isprint(c)) + c = '.'; + + sprintf(cbuf + j, "%c", c); + } + + strcat(cbuf, "|"); + + fprintf(fp, "%08x %*s |%s\n", i, + 0 - (int)sizeof(hbuf) + 1, hbuf, cbuf); + } +} + +void hexdump(const unsigned char *buf, int len) +{ + fhexdump(stdout, buf, len); +} + +int do_get_log_page(nvme_mi_ep_t ep, int argc, char **argv) +{ + struct nvme_get_log_args args = { 0 }; + struct nvme_mi_ctrl *ctrl; + uint8_t buf[4096]; + uint16_t ctrl_id; + int rc, tmp; + + if (argc < 2) { + fprintf(stderr, "no controller ID specified\n"); + return -1; + } + + tmp = atoi(argv[1]); + if (tmp < 0 || tmp > 0xffff) { + fprintf(stderr, "invalid controller ID\n"); + return -1; + } + + ctrl_id = tmp & 0xffff; + + args.args_size = sizeof(args); + args.log = buf; + args.len = sizeof(buf); + + if (argc > 2) { + tmp = atoi(argv[2]); + args.lid = tmp & 0xff; + } else { + args.lid = 0x1; + } + + ctrl = nvme_mi_init_ctrl(ep, ctrl_id); + if (!ctrl) { + warn("can't create controller"); + return -1; + } + + rc = nvme_mi_admin_get_log(ctrl, &args); + if (rc) { + warn("can't perform Get Log page command"); + return -1; + } + + printf("Get log page (log id = 0x%02x) data:\n", args.lid); + hexdump(buf, args.len); + + return 0; +} + +struct thread_struct { + nvme_mi_ep_t ep; + int argc; + char **argv; + int rc; +}; + +void *csi_thread_helper(void *context) +{ + struct thread_struct *s = (struct thread_struct *) context; + + s->rc = do_get_log_page(s->ep, s->argc, s->argv); + return NULL; +} + +enum action { + ACTION_CSI_TEST, +}; + +int do_csi_test(nvme_root_t root, int net, __u8 eid, + int argc, char **argv) +{ + int rc = 0; + nvme_mi_ep_t ep1, ep2; + + ep1 = nvme_mi_open_mctp(root, net, eid); + if (!ep1) + errx(EXIT_FAILURE, "can't open MCTP endpoint %d:%d", net, eid); + ep2 = nvme_mi_open_mctp(root, net, eid); + if (!ep2) + errx(EXIT_FAILURE, "can't open MCTP endpoint %d:%d", net, eid); + + pthread_t thread; + + nvme_mi_set_csi(ep1, 0);//Not necessary, but to be explicit + nvme_mi_set_csi(ep2, 1); + struct thread_struct s; + + s.ep = ep2; + s.argc = argc; + s.argv = argv; + + // Create a new thread to run my_function + if (pthread_create(&thread, NULL, csi_thread_helper, &s)) { + fprintf(stderr, "Error creating thread\n"); + return 1; + } + + rc = do_get_log_page(ep1, argc, argv); + + // Main thread continues to do other work + printf("Main thread finished with rc=%d\n", rc); + + // Wait for the created thread to finish + if (pthread_join(thread, NULL)) { + fprintf(stderr, "Error joining thread\n"); + return 2; + } + + printf("Second thread finished with rc=%d\n", s.rc); + + nvme_mi_close(ep1); + nvme_mi_close(ep2); + + if (rc) + return rc; + if (s.rc) + return s.rc; + return 0; +} + +static int do_action_endpoint(enum action action, + nvme_root_t root, + int net, + uint8_t eid, + int argc, + char **argv) +{ + int rc; + + switch (action) { + case ACTION_CSI_TEST: + rc = do_csi_test(root, net, eid, argc, argv); + break; + default: + /* This shouldn't be possible, as we should be covering all + * of the enum action options above. Hoever, keep the compilers + * happy and fail gracefully. + */ + fprintf(stderr, "invalid action %d?\n", action); + rc = -1; + } + return rc; +} + +int main(int argc, char **argv) +{ + enum action action; + nvme_root_t root; + bool usage = true; + uint8_t eid = 0; + int rc = 0, net = 0; + + if (argc >= 5) { + usage = false; + net = atoi(argv[1]); + eid = atoi(argv[2]) & 0xff; + argv += 2; + argc -= 2; + } + + if (usage) { + fprintf(stderr, + "usage: %s [action] [action args]\n", + argv[0]); + fprintf(stderr, "where action is:\n" + " csi-test []\n" + "\n" + ); + return EXIT_FAILURE; + } + + char *action_str = argv[1]; + + argc--; + argv++; + + if (!strcmp(action_str, "csi-test")) { + action = ACTION_CSI_TEST; + } else { + fprintf(stderr, "invalid action '%s'\n", action_str); + return EXIT_FAILURE; + } + + root = nvme_mi_create_root(stderr, DEFAULT_LOGLEVEL); + if (!root) + err(EXIT_FAILURE, "can't create NVMe root"); + + rc = do_action_endpoint(action, root, net, eid, argc, argv); + nvme_mi_free_root(root); + + return rc ? EXIT_FAILURE : EXIT_SUCCESS; +} + + diff --git a/src/libnvme-mi.map b/src/libnvme-mi.map index a1482e3e5..cbd1285a9 100644 --- a/src/libnvme-mi.map +++ b/src/libnvme-mi.map @@ -1,6 +1,7 @@ # SPDX-License-Identifier: LGPL-2.1-or-later LIBNVME_MI_UNRELEASED { global: + nvme_mi_set_csi; nvme_mi_submit_entry; nvme_mi_submit_exit; }; diff --git a/src/nvme/mi.c b/src/nvme/mi.c index 4a3f8876f..aed0192ef 100644 --- a/src/nvme/mi.c +++ b/src/nvme/mi.c @@ -522,7 +522,20 @@ int nvme_mi_submit(nvme_mi_ep_t ep, struct nvme_mi_req *req, return 0; } -static void nvme_mi_admin_init_req(struct nvme_mi_req *req, +int nvme_mi_set_csi(nvme_mi_ep_t ep, uint8_t csi) +{ + uint8_t csi_bit = (csi) ? 1 : 0; + + if (nvme_mi_ep_has_quirk(ep, NVME_QUIRK_CSI_1_NOT_SUPPORTED) && csi_bit) + return -1; + + ep->csi = csi_bit; + + return 0; +} + +static void nvme_mi_admin_init_req(nvme_mi_ep_t ep, + struct nvme_mi_req *req, struct nvme_mi_admin_req_hdr *hdr, __u16 ctrl_id, __u8 opcode) { @@ -531,7 +544,8 @@ static void nvme_mi_admin_init_req(struct nvme_mi_req *req, hdr->hdr.type = NVME_MI_MSGTYPE_NVME; hdr->hdr.nmp = (NVME_MI_ROR_REQ << 7) | - (NVME_MI_MT_ADMIN << 3); /* we always use command slot 0 */ + (NVME_MI_MT_ADMIN << 3) | + (ep->csi & 1); hdr->opcode = opcode; hdr->ctrl_id = cpu_to_le16(ctrl_id); @@ -547,7 +561,8 @@ static void nvme_mi_admin_init_resp(struct nvme_mi_resp *resp, resp->hdr_len = sizeof(*hdr); } -static void nvme_mi_control_init_req(struct nvme_mi_req *req, +static void nvme_mi_control_init_req(nvme_mi_ep_t ep, + struct nvme_mi_req *req, struct nvme_mi_control_req *control_req, __u8 opcode, __u16 cpsp) { @@ -556,7 +571,8 @@ static void nvme_mi_control_init_req(struct nvme_mi_req *req, control_req->hdr.type = NVME_MI_MSGTYPE_NVME; control_req->hdr.nmp = (NVME_MI_ROR_REQ << 7) | - (NVME_MI_MT_CONTROL << 3); /* we always use command slot 0 */ + (NVME_MI_MT_CONTROL << 3) | + (ep->csi & 1); control_req->opcode = opcode; control_req->cpsp = cpu_to_le16(cpsp); @@ -693,7 +709,9 @@ int nvme_mi_admin_xfer(nvme_mi_ctrl_t ctrl, admin_req->hdr.type = NVME_MI_MSGTYPE_NVME; admin_req->hdr.nmp = (NVME_MI_ROR_REQ << 7) | - (NVME_MI_MT_ADMIN << 3); + (NVME_MI_MT_ADMIN << 3) | + (ctrl->ep->csi & 1); + admin_req->ctrl_id = cpu_to_le16(ctrl->id); memset(&req, 0, sizeof(req)); req.hdr = &admin_req->hdr; @@ -701,8 +719,6 @@ int nvme_mi_admin_xfer(nvme_mi_ctrl_t ctrl, req.data = admin_req + 1; req.data_len = req_data_size; - nvme_mi_calc_req_mic(&req); - memset(&resp, 0, sizeof(resp)); resp.hdr = &admin_resp->hdr; resp.hdr_len = sizeof(*admin_resp); @@ -771,7 +787,7 @@ int nvme_mi_admin_admin_passthru(nvme_mi_ctrl_t ctrl, __u8 opcode, __u8 flags, has_read_data = true; } - nvme_mi_admin_init_req(&req, &req_hdr, ctrl->id, opcode); + nvme_mi_admin_init_req(ctrl->ep, &req, &req_hdr, ctrl->id, opcode); req_hdr.cdw1 = cpu_to_le32(nsid); req_hdr.cdw2 = cpu_to_le32(cdw2); req_hdr.cdw3 = cpu_to_le32(cdw3); @@ -793,8 +809,6 @@ int nvme_mi_admin_admin_passthru(nvme_mi_ctrl_t ctrl, __u8 opcode, __u8 flags, req.data_len = data_len; } - nvme_mi_calc_req_mic(&req); - nvme_mi_admin_init_resp(&resp, &resp_hdr); if (has_read_data) { @@ -848,7 +862,7 @@ int nvme_mi_admin_identify_partial(nvme_mi_ctrl_t ctrl, return -1; } - nvme_mi_admin_init_req(&req, &req_hdr, ctrl->id, nvme_admin_identify); + nvme_mi_admin_init_req(ctrl->ep, &req, &req_hdr, ctrl->id, nvme_admin_identify); req_hdr.cdw1 = cpu_to_le32(args->nsid); req_hdr.cdw10 = cpu_to_le32(args->cntid << 16 | args->cns); req_hdr.cdw11 = cpu_to_le32((args->csi & 0xff) << 24 | @@ -861,8 +875,6 @@ int nvme_mi_admin_identify_partial(nvme_mi_ctrl_t ctrl, req_hdr.doff = cpu_to_le32(offset); } - nvme_mi_calc_req_mic(&req); - nvme_mi_admin_init_resp(&resp, &resp_hdr); resp.data = args->data; resp.data_len = size; @@ -894,7 +906,7 @@ int nvme_mi_control(nvme_mi_ep_t ep, __u8 opcode, struct nvme_mi_req req; int rc = 0; - nvme_mi_control_init_req(&req, &control_req, opcode, cpsp); + nvme_mi_control_init_req(ep, &req, &control_req, opcode, cpsp); nvme_mi_control_init_resp(&resp, &control_resp); rc = nvme_mi_submit(ep, &req, &resp); @@ -945,7 +957,8 @@ static int __nvme_mi_admin_get_log(nvme_mi_ctrl_t ctrl, ndw = (len >> 2) - 1; - nvme_mi_admin_init_req(&req, &req_hdr, ctrl->id, nvme_admin_get_log_page); + nvme_mi_admin_init_req(ctrl->ep, &req, &req_hdr, ctrl->id, + nvme_admin_get_log_page); req_hdr.cdw1 = cpu_to_le32(args->nsid); req_hdr.cdw10 = cpu_to_le32((ndw & 0xffff) << 16 | ((!final || args->rae) ? 1 : 0) << 15 | @@ -961,8 +974,6 @@ static int __nvme_mi_admin_get_log(nvme_mi_ctrl_t ctrl, req_hdr.flags = 0x1; req_hdr.dlen = cpu_to_le32(len & 0xffffffff); - nvme_mi_calc_req_mic(&req); - nvme_mi_admin_init_resp(&resp, &resp_hdr); resp.data = args->log + offset; resp.data_len = len; @@ -1177,7 +1188,7 @@ int nvme_mi_admin_security_send(nvme_mi_ctrl_t ctrl, return -1; } - nvme_mi_admin_init_req(&req, &req_hdr, ctrl->id, + nvme_mi_admin_init_req(ctrl->ep, &req, &req_hdr, ctrl->id, nvme_admin_security_send); req_hdr.cdw10 = cpu_to_le32(args->secp << 24 | @@ -1192,8 +1203,6 @@ int nvme_mi_admin_security_send(nvme_mi_ctrl_t ctrl, req.data = args->data; req.data_len = args->data_len; - nvme_mi_calc_req_mic(&req); - nvme_mi_admin_init_resp(&resp, &resp_hdr); rc = nvme_mi_submit(ctrl->ep, &req, &resp); @@ -1223,7 +1232,7 @@ int nvme_mi_admin_security_recv(nvme_mi_ctrl_t ctrl, return -1; } - nvme_mi_admin_init_req(&req, &req_hdr, ctrl->id, + nvme_mi_admin_init_req(ctrl->ep, &req, &req_hdr, ctrl->id, nvme_admin_security_recv); req_hdr.cdw10 = cpu_to_le32(args->secp << 24 | @@ -1236,8 +1245,6 @@ int nvme_mi_admin_security_recv(nvme_mi_ctrl_t ctrl, req_hdr.flags = 0x1; req_hdr.dlen = cpu_to_le32(args->data_len & 0xffffffff); - nvme_mi_calc_req_mic(&req); - nvme_mi_admin_init_resp(&resp, &resp_hdr); resp.data = args->data; resp.data_len = args->data_len; @@ -1269,7 +1276,7 @@ int nvme_mi_admin_get_features(nvme_mi_ctrl_t ctrl, return -1; } - nvme_mi_admin_init_req(&req, &req_hdr, ctrl->id, + nvme_mi_admin_init_req(ctrl->ep, &req, &req_hdr, ctrl->id, nvme_admin_get_features); req_hdr.cdw1 = cpu_to_le32(args->nsid); @@ -1277,8 +1284,6 @@ int nvme_mi_admin_get_features(nvme_mi_ctrl_t ctrl, req_hdr.cdw14 = cpu_to_le32(args->uuidx & 0x7f); req_hdr.cdw11 = cpu_to_le32(args->cdw11); - nvme_mi_calc_req_mic(&req); - nvme_mi_admin_init_resp(&resp, &resp_hdr); resp.data = args->data; resp.data_len = args->data_len; @@ -1310,7 +1315,7 @@ int nvme_mi_admin_set_features(nvme_mi_ctrl_t ctrl, return -1; } - nvme_mi_admin_init_req(&req, &req_hdr, ctrl->id, + nvme_mi_admin_init_req(ctrl->ep, &req, &req_hdr, ctrl->id, nvme_admin_set_features); req_hdr.cdw1 = cpu_to_le32(args->nsid); @@ -1325,8 +1330,6 @@ int nvme_mi_admin_set_features(nvme_mi_ctrl_t ctrl, req.data_len = args->data_len; req.data = args->data; - nvme_mi_calc_req_mic(&req); - nvme_mi_admin_init_resp(&resp, &resp_hdr); rc = nvme_mi_submit(ctrl->ep, &req, &resp); @@ -1359,7 +1362,7 @@ int nvme_mi_admin_ns_mgmt(nvme_mi_ctrl_t ctrl, return -1; } - nvme_mi_admin_init_req(&req, &req_hdr, ctrl->id, + nvme_mi_admin_init_req(ctrl->ep, &req, &req_hdr, ctrl->id, nvme_admin_ns_mgmt); req_hdr.cdw1 = cpu_to_le32(args->nsid); @@ -1385,8 +1388,6 @@ int nvme_mi_admin_ns_mgmt(nvme_mi_ctrl_t ctrl, req_hdr.flags = 0x1; } - nvme_mi_calc_req_mic(&req); - nvme_mi_admin_init_resp(&resp, &resp_hdr); rc = nvme_mi_submit(ctrl->ep, &req, &resp); @@ -1410,7 +1411,7 @@ int nvme_mi_admin_ns_attach(nvme_mi_ctrl_t ctrl, return -1; } - nvme_mi_admin_init_req(&req, &req_hdr, ctrl->id, + nvme_mi_admin_init_req(ctrl->ep, &req, &req_hdr, ctrl->id, nvme_admin_ns_attach); req_hdr.cdw1 = cpu_to_le32(args->nsid); @@ -1420,8 +1421,6 @@ int nvme_mi_admin_ns_attach(nvme_mi_ctrl_t ctrl, req_hdr.dlen = cpu_to_le32(sizeof(*args->ctrlist)); req_hdr.flags = 0x1; - nvme_mi_calc_req_mic(&req); - nvme_mi_admin_init_resp(&resp, &resp_hdr); rc = nvme_mi_submit(ctrl->ep, &req, &resp); @@ -1455,7 +1454,7 @@ int nvme_mi_admin_fw_download(nvme_mi_ctrl_t ctrl, return -1; } - nvme_mi_admin_init_req(&req, &req_hdr, ctrl->id, + nvme_mi_admin_init_req(ctrl->ep, &req, &req_hdr, ctrl->id, nvme_admin_fw_download); req_hdr.cdw10 = cpu_to_le32((args->data_len >> 2) - 1); @@ -1465,8 +1464,6 @@ int nvme_mi_admin_fw_download(nvme_mi_ctrl_t ctrl, req_hdr.dlen = cpu_to_le32(args->data_len); req_hdr.flags = 0x1; - nvme_mi_calc_req_mic(&req); - nvme_mi_admin_init_resp(&resp, &resp_hdr); rc = nvme_mi_submit(ctrl->ep, &req, &resp); @@ -1490,15 +1487,13 @@ int nvme_mi_admin_fw_commit(nvme_mi_ctrl_t ctrl, return -1; } - nvme_mi_admin_init_req(&req, &req_hdr, ctrl->id, + nvme_mi_admin_init_req(ctrl->ep, &req, &req_hdr, ctrl->id, nvme_admin_fw_commit); req_hdr.cdw10 = cpu_to_le32(((__u32)(args->bpid & 0x1) << 31) | ((args->action & 0x7) << 3) | ((args->slot & 0x7) << 0)); - nvme_mi_calc_req_mic(&req); - nvme_mi_admin_init_resp(&resp, &resp_hdr); rc = nvme_mi_submit(ctrl->ep, &req, &resp); @@ -1522,7 +1517,7 @@ int nvme_mi_admin_format_nvm(nvme_mi_ctrl_t ctrl, return -1; } - nvme_mi_admin_init_req(&req, &req_hdr, ctrl->id, + nvme_mi_admin_init_req(ctrl->ep, &req, &req_hdr, ctrl->id, nvme_admin_format_nvm); req_hdr.cdw1 = cpu_to_le32(args->nsid); @@ -1533,8 +1528,6 @@ int nvme_mi_admin_format_nvm(nvme_mi_ctrl_t ctrl, | ((args->mset & 0x1) << 4) | ((args->lbaf & 0xf) << 0)); - nvme_mi_calc_req_mic(&req); - nvme_mi_admin_init_resp(&resp, &resp_hdr); rc = nvme_mi_submit(ctrl->ep, &req, &resp); @@ -1558,7 +1551,7 @@ int nvme_mi_admin_sanitize_nvm(nvme_mi_ctrl_t ctrl, return -1; } - nvme_mi_admin_init_req(&req, &req_hdr, ctrl->id, + nvme_mi_admin_init_req(ctrl->ep, &req, &req_hdr, ctrl->id, nvme_admin_sanitize_nvm); req_hdr.cdw10 = cpu_to_le32(((args->nodas ? 1 : 0) << 9) @@ -1568,8 +1561,6 @@ int nvme_mi_admin_sanitize_nvm(nvme_mi_ctrl_t ctrl, | ((args->sanact & 0x7) << 0)); req_hdr.cdw11 = cpu_to_le32(args->ovrpat); - nvme_mi_calc_req_mic(&req); - nvme_mi_admin_init_resp(&resp, &resp_hdr); rc = nvme_mi_submit(ctrl->ep, &req, &resp); @@ -1579,6 +1570,25 @@ int nvme_mi_admin_sanitize_nvm(nvme_mi_ctrl_t ctrl, return nvme_mi_admin_parse_status(&resp, args->result); } +static void nvme_mi_mi_init_req(nvme_mi_ep_t ep, + struct nvme_mi_req *req, + struct nvme_mi_mi_req_hdr *hdr, + __u32 cdw0, __u8 opcode) +{ + memset(req, 0, sizeof(*req)); + memset(hdr, 0, sizeof(*hdr)); + + hdr->hdr.type = NVME_MI_MSGTYPE_NVME; + hdr->hdr.nmp = (NVME_MI_ROR_REQ << 7) | + (NVME_MI_MT_MI << 3) | + (ep->csi & 1); + hdr->opcode = opcode; + hdr->cdw0 = cpu_to_le32(cdw0); + + req->hdr = &hdr->hdr; + req->hdr_len = sizeof(*hdr); +} + static int nvme_mi_read_data(nvme_mi_ep_t ep, __u32 cdw0, void *data, size_t *data_len) { @@ -1588,16 +1598,8 @@ static int nvme_mi_read_data(nvme_mi_ep_t ep, __u32 cdw0, struct nvme_mi_req req; int rc; - memset(&req_hdr, 0, sizeof(req_hdr)); - req_hdr.hdr.type = NVME_MI_MSGTYPE_NVME; - req_hdr.hdr.nmp = (NVME_MI_ROR_REQ << 7) | - (NVME_MI_MT_MI << 3); /* we always use command slot 0 */ - req_hdr.opcode = nvme_mi_mi_opcode_mi_data_read; - req_hdr.cdw0 = cpu_to_le32(cdw0); - - memset(&req, 0, sizeof(req)); - req.hdr = &req_hdr.hdr; - req.hdr_len = sizeof(req_hdr); + nvme_mi_mi_init_req(ep, &req, &req_hdr, cdw0, + nvme_mi_mi_opcode_mi_data_read); memset(&resp, 0, sizeof(resp)); resp.hdr = &resp_hdr.hdr; @@ -1658,7 +1660,8 @@ int nvme_mi_mi_xfer(nvme_mi_ep_t ep, mi_req->hdr.type = NVME_MI_MSGTYPE_NVME; mi_req->hdr.nmp = (NVME_MI_ROR_REQ << 7) | - (NVME_MI_MT_MI << 3); + (NVME_MI_MT_MI << 3) | + (ep->csi & 1); memset(&req, 0, sizeof(req)); req.hdr = &mi_req->hdr; @@ -1666,8 +1669,6 @@ int nvme_mi_mi_xfer(nvme_mi_ep_t ep, req.data = mi_req + 1; req.data_len = req_data_size; - nvme_mi_calc_req_mic(&req); - memset(&resp, 0, sizeof(resp)); resp.hdr = &mi_resp->hdr; resp.hdr_len = sizeof(*mi_resp); @@ -1779,17 +1780,10 @@ int nvme_mi_mi_subsystem_health_status_poll(nvme_mi_ep_t ep, bool clear, struct nvme_mi_req req; int rc; - memset(&req_hdr, 0, sizeof(req_hdr)); - req_hdr.hdr.type = NVME_MI_MSGTYPE_NVME;; - req_hdr.hdr.nmp = (NVME_MI_ROR_REQ << 7) | - (NVME_MI_MT_MI << 3); - req_hdr.opcode = nvme_mi_mi_opcode_subsys_health_status_poll; + nvme_mi_mi_init_req(ep, &req, &req_hdr, 0, + nvme_mi_mi_opcode_subsys_health_status_poll); req_hdr.cdw1 = (clear ? 1 : 0) << 31; - memset(&req, 0, sizeof(req)); - req.hdr = &req_hdr.hdr; - req.hdr_len = sizeof(req_hdr); - memset(&resp, 0, sizeof(resp)); resp.hdr = &resp_hdr.hdr; resp.hdr_len = sizeof(resp_hdr); @@ -1824,17 +1818,10 @@ int nvme_mi_mi_config_get(nvme_mi_ep_t ep, __u32 dw0, __u32 dw1, struct nvme_mi_req req; int rc; - memset(&req_hdr, 0, sizeof(req_hdr)); - req_hdr.hdr.type = NVME_MI_MSGTYPE_NVME; - req_hdr.hdr.nmp = (NVME_MI_ROR_REQ << 7) | (NVME_MI_MT_MI << 3); - req_hdr.opcode = nvme_mi_mi_opcode_configuration_get; - req_hdr.cdw0 = cpu_to_le32(dw0); + nvme_mi_mi_init_req(ep, &req, &req_hdr, dw0, + nvme_mi_mi_opcode_configuration_get); req_hdr.cdw1 = cpu_to_le32(dw1); - memset(&req, 0, sizeof(req)); - req.hdr = &req_hdr.hdr; - req.hdr_len = sizeof(req_hdr); - memset(&resp, 0, sizeof(resp)); resp.hdr = &resp_hdr.hdr; resp.hdr_len = sizeof(resp_hdr); @@ -1861,17 +1848,10 @@ int nvme_mi_mi_config_set(nvme_mi_ep_t ep, __u32 dw0, __u32 dw1) struct nvme_mi_req req; int rc; - memset(&req_hdr, 0, sizeof(req_hdr)); - req_hdr.hdr.type = NVME_MI_MSGTYPE_NVME; - req_hdr.hdr.nmp = (NVME_MI_ROR_REQ << 7) | (NVME_MI_MT_MI << 3); - req_hdr.opcode = nvme_mi_mi_opcode_configuration_set; - req_hdr.cdw0 = cpu_to_le32(dw0); + nvme_mi_mi_init_req(ep, &req, &req_hdr, dw0, + nvme_mi_mi_opcode_configuration_set); req_hdr.cdw1 = cpu_to_le32(dw1); - memset(&req, 0, sizeof(req)); - req.hdr = &req_hdr.hdr; - req.hdr_len = sizeof(req_hdr); - memset(&resp, 0, sizeof(resp)); resp.hdr = &resp_hdr.hdr; resp.hdr_len = sizeof(resp_hdr); diff --git a/src/nvme/mi.h b/src/nvme/mi.h index bb816512b..985332f4a 100644 --- a/src/nvme/mi.h +++ b/src/nvme/mi.h @@ -478,6 +478,16 @@ struct nvme_mi_ep; */ typedef struct nvme_mi_ep * nvme_mi_ep_t; +/** + * nvme_mi_set_csi - Assign a CSI to an endpoint. + * @ep: Endpoint + * @csi: value to use for CSI bit in NMP (0 or 1) for this endpoint + * + * Return: 0 if successful, -1 otherwise (some endpoints may not support) + * + */ +int nvme_mi_set_csi(nvme_mi_ep_t ep, uint8_t csi); + /** * nvme_mi_first_endpoint - Start endpoint iterator * @m: &nvme_root_t object diff --git a/src/nvme/private.h b/src/nvme/private.h index 33cdd555d..52d4054c2 100644 --- a/src/nvme/private.h +++ b/src/nvme/private.h @@ -253,6 +253,11 @@ struct nvme_mi_transport { */ #define NVME_QUIRK_MIN_INTER_COMMAND_TIME (1 << 0) +/* Some devices may not support using CSI 1. Attempting to set an + * endpoint to use this with these devices should return an error + */ +#define NVME_QUIRK_CSI_1_NOT_SUPPORTED (1 << 1) + struct nvme_mi_ep { struct nvme_root *root; const struct nvme_mi_transport *transport; @@ -265,6 +270,8 @@ struct nvme_mi_ep { unsigned int mprt_max; unsigned long quirks; + __u8 csi; + /* inter-command delay, for NVME_QUIRK_MIN_INTER_COMMAND_TIME */ unsigned int inter_command_us; struct timespec last_resp_time; diff --git a/test/mi.c b/test/mi.c index 6126d8795..b6e152bb1 100644 --- a/test/mi.c +++ b/test/mi.c @@ -734,7 +734,7 @@ static void test_resp_invalid_type(nvme_mi_ep_t ep) } /* test: response with mis-matching command slot */ -static int test_resp_csi_cb(struct nvme_mi_ep *ep, +static int test_resp_csi_invert_cb(struct nvme_mi_ep *ep, struct nvme_mi_req *req, struct nvme_mi_resp *resp, void *data) @@ -744,15 +744,54 @@ static int test_resp_csi_cb(struct nvme_mi_ep *ep, return 0; } -static void test_resp_csi(nvme_mi_ep_t ep) +/* test: validation of proper csi setting */ +static int test_resp_csi_check_cb(struct nvme_mi_ep *ep, + struct nvme_mi_req *req, + struct nvme_mi_resp *resp, + void *data) +{ + assert((req->hdr->nmp & 1) == (ep->csi & 1)); + return 0; +} + +/* test: Ensure that csi bit is set properly in the request */ +static void test_resp_csi_request(nvme_mi_ep_t ep) +{ + struct nvme_mi_read_nvm_ss_info ss_info; + int rc; + + test_set_transport_callback(ep, test_resp_csi_check_cb, NULL); + + rc = nvme_mi_mi_read_mi_data_subsys(ep, &ss_info); + assert(rc != 0); + + nvme_mi_set_csi(ep, 1);//Change CSI + + rc = nvme_mi_mi_read_mi_data_subsys(ep, &ss_info); + assert(rc != 0); + + nvme_mi_set_csi(ep, 0);//Change CSI +} + +/* test: Ensure that when csi bit set wrong in response, + * it results in an error + */ +static void test_resp_csi_mismatch(nvme_mi_ep_t ep) { struct nvme_mi_read_nvm_ss_info ss_info; int rc; - test_set_transport_callback(ep, test_resp_csi_cb, NULL); + test_set_transport_callback(ep, test_resp_csi_invert_cb, NULL); + + rc = nvme_mi_mi_read_mi_data_subsys(ep, &ss_info); + assert(rc != 0); + + nvme_mi_set_csi(ep, 1);//Change CSI rc = nvme_mi_mi_read_mi_data_subsys(ep, &ss_info); assert(rc != 0); + + nvme_mi_set_csi(ep, 0);//Change CSI } /* test: config get MTU request & response layout, ensure we're handling @@ -2062,7 +2101,8 @@ struct test { DEFINE_TEST(resp_req), DEFINE_TEST(resp_hdr_small), DEFINE_TEST(resp_invalid_type), - DEFINE_TEST(resp_csi), + DEFINE_TEST(resp_csi_request), + DEFINE_TEST(resp_csi_mismatch), DEFINE_TEST(mi_config_get_mtu), DEFINE_TEST(mi_config_set_freq), DEFINE_TEST(mi_config_set_freq_invalid),