diff --git a/examples/discover-loop.c b/examples/discover-loop.c index 752806713..658a9ecbe 100644 --- a/examples/discover-loop.c +++ b/examples/discover-loop.c @@ -1,12 +1,12 @@ // SPDX-License-Identifier: LGPL-2.1-or-later -/** +/* * This file is part of libnvme. * Copyright (c) 2020 Western Digital Corporation or its affiliates. * * Authors: Keith Busch */ -/** +/* * discover-loop: Use fabrics commands to discover any loop targets and print * those records. You must have at least one configured nvme loop target on the * system (no existing connection required). The output will look more @@ -59,22 +59,24 @@ int main() nvmf_default_config(&cfg); - r = nvme_scan(NULL); - h = nvme_default_host(r); - if (!h) { + ret = nvme_scan(NULL, &r); + if (ret) + return ret; + ret = nvme_default_host(r, &h); + if (ret) { fprintf(stderr, "Failed to allocated memory\n"); - return ENOMEM; + return ret; } - c = nvme_create_ctrl(r, NVME_DISC_SUBSYS_NAME, "loop", - NULL, NULL, NULL, NULL); - if (!c) { + ret = nvme_create_ctrl(r, NVME_DISC_SUBSYS_NAME, "loop", + NULL, NULL, NULL, NULL, &c); + if (ret) { fprintf(stderr, "Failed to allocate memory\n"); return ENOMEM; } ret = nvmf_add_ctrl(h, c, &cfg); - if (ret < 0) { + if (ret) { fprintf(stderr, "no controller found\n"); - return errno; + return ret; } ret = nvmf_get_discovery_log(c, &log, 4); @@ -86,7 +88,7 @@ int main() else print_discover_log(log); - nvme_free_tree(r); + nvme_free_root(r); free(log); return 0; } diff --git a/examples/display-columnar.c b/examples/display-columnar.c index db98bdfec..1c356bf48 100644 --- a/examples/display-columnar.c +++ b/examples/display-columnar.c @@ -1,12 +1,12 @@ // SPDX-License-Identifier: LGPL-2.1-or-later -/** +/* * This file is part of libnvme. * Copyright (c) 2020 Western Digital Corporation or its affiliates. * * Authors: Keith Busch */ -/** +/* * display-columnar: Scans the nvme topology, prints each record type in a * column format for easy visual scanning. */ @@ -24,8 +24,7 @@ int main() nvme_path_t p; nvme_ns_t n; - r = nvme_scan(NULL); - if (!r) + if (nvme_scan(NULL, &r)) return -1; diff --git a/examples/display-tree.c b/examples/display-tree.c index b9ea75f89..4cab82e5c 100644 --- a/examples/display-tree.c +++ b/examples/display-tree.c @@ -1,12 +1,12 @@ // SPDX-License-Identifier: LGPL-2.1-or-later -/** +/* * This file is part of libnvme. * Copyright (c) 2020 Western Digital Corporation or its affiliates. * * Authors: Keith Busch */ -/** +/* * display-tree: Scans the nvme topology, prints as an ascii tree with some * selected attributes for each component. */ @@ -23,8 +23,7 @@ int main() nvme_path_t p, _p; nvme_ns_t n, _n; - r = nvme_scan(NULL); - if (!r) + if (nvme_scan(NULL, &r)) return -1; printf(".\n"); @@ -67,6 +66,6 @@ int main() } } } - nvme_free_tree(r); + nvme_free_root(r); return 0; } diff --git a/examples/mi-conf.c b/examples/mi-conf.c index e47d281f3..c9311e77a 100644 --- a/examples/mi-conf.c +++ b/examples/mi-conf.c @@ -1,12 +1,12 @@ // SPDX-License-Identifier: LGPL-2.1-or-later -/** +/* * This file is part of libnvme. * Copyright (c) 2022 Code Construct Pty Ltd. * * Authors: Jeremy Kerr */ -/** +/* * mi-conf: query a device for optimal MTU and set for both the local MCTP * route (through dbus to mctpd) and the device itself (through NVMe-MI * configuration commands) diff --git a/examples/mi-mctp-ae.c b/examples/mi-mctp-ae.c index d73a35987..b1ecc554a 100644 --- a/examples/mi-mctp-ae.c +++ b/examples/mi-mctp-ae.c @@ -1,9 +1,9 @@ // SPDX-License-Identifier: LGPL-2.1-or-later -/** +/* * This file is part of libnvme. */ -/** +/* * mi-mctp-ae: open a MI connection over MCTP, supporting asynchronous event messages */ @@ -131,7 +131,7 @@ int main(int argc, char **argv) } rc = nvme_mi_aem_enable(ep, &aem_config, &data); - if (rc && errno == EOPNOTSUPP) + if (rc == EOPNOTSUPP) errx(EXIT_FAILURE, "MCTP Peer-Bind is required for AEM"); else if (rc) err(EXIT_FAILURE, "Can't enable aem:%d", rc); diff --git a/examples/mi-mctp-csi-test.c b/examples/mi-mctp-csi-test.c index 2ca7e629e..d18b9b1ee 100644 --- a/examples/mi-mctp-csi-test.c +++ b/examples/mi-mctp-csi-test.c @@ -1,9 +1,9 @@ // 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 */ @@ -56,8 +56,8 @@ void hexdump(const unsigned char *buf, int 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; + enum nvme_cmd_get_log_lid lid; + struct nvme_link *link; uint8_t buf[4096]; uint16_t ctrl_id; int rc, tmp; @@ -75,31 +75,31 @@ int do_get_log_page(nvme_mi_ep_t ep, int argc, char **argv) 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; + lid = tmp & 0xff; } else { - args.lid = 0x1; + lid = 0x1; } - ctrl = nvme_mi_init_ctrl(ep, ctrl_id); - if (!ctrl) { + link = nvme_mi_init_link(ep, ctrl_id); + if (!link) { warn("can't create controller"); return -1; } - rc = nvme_mi_admin_get_log(ctrl, &args); + rc = nvme_get_log(link, NVME_NSID_NONE, false, NVME_LOG_LSP_NONE, + lid, NVME_LOG_LSI_NONE, NVME_CSI_NVM, + false, NVME_UUID_NONE, + 0, buf, sizeof(buf), + sizeof(buf), NULL); 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); + printf("Get log page (log id = 0x%02x) data:\n", lid); + hexdump(buf, sizeof(buf)); return 0; } diff --git a/examples/mi-mctp.c b/examples/mi-mctp.c index cea7ed89f..1342b80b3 100644 --- a/examples/mi-mctp.c +++ b/examples/mi-mctp.c @@ -1,12 +1,12 @@ // SPDX-License-Identifier: LGPL-2.1-or-later -/** +/* * This file is part of libnvme. * Copyright (c) 2021 Code Construct Pty Ltd. * * Authors: Jeremy Kerr */ -/** +/* * mi-mctp: open a MI connection over MCTP, and query controller info */ @@ -178,8 +178,7 @@ static const char *__copy_id_str(const void *field, size_t size, int do_identify(nvme_mi_ep_t ep, int argc, char **argv) { - struct nvme_identify_args id_args = { 0 }; - struct nvme_mi_ctrl *ctrl; + struct nvme_link *link; struct nvme_id_ctrl id; uint16_t ctrl_id; char buf[41]; @@ -201,29 +200,26 @@ int do_identify(nvme_mi_ep_t ep, int argc, char **argv) partial = argc > 2 && !strcmp(argv[2], "--partial"); - ctrl = nvme_mi_init_ctrl(ep, ctrl_id); - if (!ctrl) { + link = nvme_mi_init_link(ep, ctrl_id); + if (!link) { warn("can't create controller"); return -1; } - id_args.data = &id; - id_args.args_size = sizeof(id_args); - id_args.cns = NVME_IDENTIFY_CNS_CTRL; - id_args.nsid = NVME_NSID_NONE; - id_args.cntid = 0; - id_args.csi = NVME_CSI_NVM; - /* for this example code, we can either do a full or partial identify; * since we're only printing the fields before the 'rab' member, * these will be equivalent, aside from the size of the MI * response. */ if (partial) { - rc = nvme_mi_admin_identify_partial(ctrl, &id_args, 0, - offsetof(struct nvme_id_ctrl, rab)); + rc = nvme_identify_partial(link, NVME_NSID_NONE, 0, NVME_IDENTIFY_CNS_CTRL, + NVME_CSI_NVM, 0, 0, &id, + offsetof(struct nvme_id_ctrl, rab), + NULL); } else { - rc = nvme_mi_admin_identify(ctrl, &id_args); + rc = nvme_identify(link, 0, NVME_IDENTIFY_CNS_CTRL, + NVME_CSI_NVM, 0, 0, NVME_NSID_NONE, + &id, NULL); } if (rc) { @@ -373,8 +369,8 @@ void hexdump(const unsigned char *buf, int 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; + enum nvme_cmd_get_log_lid lid; + struct nvme_link *link; uint8_t buf[512]; uint16_t ctrl_id; int rc, tmp; @@ -392,31 +388,31 @@ int do_get_log_page(nvme_mi_ep_t ep, int argc, char **argv) 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; + lid = tmp & 0xff; } else { - args.lid = 0x1; + lid = 0x1; } - ctrl = nvme_mi_init_ctrl(ep, ctrl_id); - if (!ctrl) { + link = nvme_mi_init_link(ep, ctrl_id); + if (!link) { warn("can't create controller"); return -1; } - rc = nvme_mi_admin_get_log(ctrl, &args); + rc = nvme_get_log(link, NVME_NSID_NONE, false, NVME_LOG_LSP_NONE, + lid, NVME_LOG_LSI_NONE, NVME_CSI_NVM, + false, NVME_UUID_NONE, + 0, buf, sizeof(buf), + sizeof(buf),NULL); 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); + printf("Get log page (log id = 0x%02x) data:\n", lid); + hexdump(buf, sizeof(buf)); return 0; } @@ -425,7 +421,7 @@ int do_admin_raw(nvme_mi_ep_t ep, int argc, char **argv) { struct nvme_mi_admin_req_hdr req; struct nvme_mi_admin_resp_hdr *resp; - struct nvme_mi_ctrl *ctrl; + struct nvme_link *link; size_t resp_data_len; unsigned long tmp; uint8_t buf[512]; @@ -488,15 +484,15 @@ int do_admin_raw(nvme_mi_ep_t ep, int argc, char **argv) memset(buf, 0, sizeof(buf)); resp = (void *)buf; - ctrl = nvme_mi_init_ctrl(ep, ctrl_id); - if (!ctrl) { + link = nvme_mi_init_link(ep, ctrl_id); + if (!link) { warn("can't create controller"); return -1; } resp_data_len = sizeof(buf) - sizeof(*resp); - rc = nvme_mi_admin_xfer(ctrl, &req, 0, resp, 0, &resp_data_len); + rc = nvme_mi_admin_xfer(link, &req, 0, resp, 0, &resp_data_len); if (rc) { warn("nvme_admin_xfer failed: %d", rc); return -1; @@ -542,8 +538,7 @@ static const char *sec_proto_description(uint8_t id) int do_security_info(nvme_mi_ep_t ep, int argc, char **argv) { - struct nvme_security_receive_args args = { 0 }; - nvme_mi_ctrl_t ctrl; + nvme_link_t link; int i, rc, n_proto; unsigned long tmp; uint16_t ctrl_id; @@ -552,6 +547,9 @@ int do_security_info(nvme_mi_ep_t ep, int argc, char **argv) uint16_t len; uint8_t protocols[256]; } proto_info; + /* protocol 0x00, spsp 0x0000: retrieve supported protocols */ + void *data = &proto_info; + __u32 data_len = sizeof(proto_info); if (argc != 2) { fprintf(stderr, "no controller ID specified\n"); @@ -566,33 +564,27 @@ int do_security_info(nvme_mi_ep_t ep, int argc, char **argv) ctrl_id = tmp & 0xffff; - ctrl = nvme_mi_init_ctrl(ep, ctrl_id); - if (!ctrl) { + link = nvme_mi_init_link(ep, ctrl_id); + if (!link) { warn("can't create controller"); return -1; } - /* protocol 0x00, spsp 0x0000: retrieve supported protocols */ - args.args_size = sizeof(args); - args.data = &proto_info; - args.data_len = sizeof(proto_info); - - rc = nvme_mi_admin_security_recv(ctrl, &args); + rc = nvme_security_receive(link, 0, 0, 0, 0, 0, 0, data, data_len, NULL); if (rc) { warnx("can't perform Security Receive command: rc %d", rc); return -1; } - if (args.data_len < 6) { - warnx("Short response in security receive command (%d bytes)", - args.data_len); + if (data_len < 6) { + warnx("Short response in security receive command (%d bytes)", data_len); return -1; } n_proto = be16_to_cpu(proto_info.len); - if (args.data_len < 6 + n_proto) { - warnx("Short response in security receive command (%d bytes), " - "for %d protocols", args.data_len, n_proto); + if (data_len < 6 + n_proto) { + warnx("Short response in security receive command (%d bytes), for %d protocols", + data_len, n_proto); return -1; } diff --git a/examples/telemetry-listen.c b/examples/telemetry-listen.c index e38a8adf9..15904cd4a 100644 --- a/examples/telemetry-listen.c +++ b/examples/telemetry-listen.c @@ -1,12 +1,12 @@ // SPDX-License-Identifier: LGPL-2.1-or-later -/** +/* * This file is part of libnvme. * Copyright (c) 2020 Western Digital Corporation or its affiliates. * * Authors: Keith Busch */ -/** +/* * Open all nvme controller's uevent and listen for changes. If NVME_AEN event * is observed with controller telemetry data, read the log and save it to a * file in /var/log/ with the device's unique name and epoch timestamp. @@ -45,7 +45,7 @@ static void save_telemetry(nvme_ctrl_t c) time_t s; /* Clear the log (rae == false) at the end to see new telemetry events later */ - ret = nvme_get_ctrl_telemetry(nvme_ctrl_get_fd(c), false, &log, NVME_TELEMETRY_DA_3, &log_size); + ret = nvme_get_ctrl_telemetry(nvme_ctrl_get_link(c), false, &log, NVME_TELEMETRY_DA_3, &log_size); if (ret) return; @@ -133,8 +133,7 @@ int main() nvme_host_t h; nvme_root_t r; - r = nvme_scan(NULL); - if (!r) + if (nvme_scan(NULL, &r)) return EXIT_FAILURE; nvme_for_each_host(r, h) @@ -162,7 +161,7 @@ int main() } wait_events(&fds, e, i); - nvme_free_tree(r); + nvme_free_root(r); free(e); return EXIT_SUCCESS; diff --git a/libnvme/nvme.i b/libnvme/nvme.i index 4ede50e74..44f683a33 100644 --- a/libnvme/nvme.i +++ b/libnvme/nvme.i @@ -448,10 +448,13 @@ struct nvme_ns { %extend nvme_root { nvme_root(const char *config_file = NULL) { - return nvme_scan(config_file); + struct nvme_root *r; + if (nvme_scan(config_file, &r)) + return NULL; + return r; } ~nvme_root() { - nvme_free_tree($self); + nvme_free_root($self); } void log_level(const char *level) { int log_level = DEFAULT_LOGLEVEL; @@ -516,7 +519,11 @@ struct nvme_ns { const char *hostid = NULL, const char *hostkey = NULL, const char *hostsymname = NULL) { - nvme_host_t h = hostnqn ? nvme_lookup_host(r, hostnqn, hostid) : nvme_default_host(r); + nvme_host_t h; + if (hostnqn) + h = nvme_lookup_host(r, hostnqn, hostid); + if (nvme_default_host(r, &h)) + return NULL; if (hostsymname) nvme_host_set_hostsymname(h, hostsymname); if (hostkey) @@ -663,8 +670,11 @@ struct nvme_ns { const char *host_traddr = NULL, const char *host_iface = NULL, const char *trsvcid = NULL) { - return nvme_create_ctrl(r, subsysnqn, transport, traddr, - host_traddr, host_iface, trsvcid); + struct nvme_ctrl *c; + if (nvme_create_ctrl(r, subsysnqn, transport, traddr, + host_traddr, host_iface, trsvcid, &c)) + return NULL; + return c; } ~nvme_ctrl() { nvme_free_ctrl($self); @@ -748,7 +758,7 @@ struct nvme_ns { %newobject discover; struct nvmf_discovery_log *discover(int lsp = 0, int max_retries = 6) { - struct nvmf_discovery_log *logp; + struct nvmf_discovery_log *logp = NULL; struct nvme_get_discovery_args args = { .c = $self, .args_size = sizeof(args), @@ -759,7 +769,7 @@ struct nvme_ns { }; Py_BEGIN_ALLOW_THREADS /* Release Python GIL */ - logp = nvmf_get_discovery_wargs(&args); + nvmf_get_discovery_wargs(&args, &logp); Py_END_ALLOW_THREADS /* Reacquire Python GIL */ if (logp == NULL) discover_err = 1; @@ -773,7 +783,7 @@ struct nvme_ns { int ret = 0; Py_BEGIN_ALLOW_THREADS /* Release Python GIL */ - ret = nvme_get_log_supported_log_pages(nvme_ctrl_get_fd($self), rae, &log); + ret = nvme_get_log_supported_log_pages(nvme_ctrl_get_link($self), rae, &log); Py_END_ALLOW_THREADS /* Reacquire Python GIL */ if (ret < 0) { diff --git a/src/libnvme.map b/src/libnvme.map index ba5c8d569..60210684e 100644 --- a/src/libnvme.map +++ b/src/libnvme.map @@ -6,8 +6,7 @@ LIBNVME_2_0 { global: nvme_admin_passthru64; nvme_admin_passthru; - nvme_capacity_mgmt; - nvme_copy; + nvme_close; nvme_create_ctrl; nvme_create_root; nvme_ctrl_config_match; @@ -19,11 +18,11 @@ LIBNVME_2_0 { nvme_ctrl_get_config; nvme_ctrl_get_dhchap_host_key; nvme_ctrl_get_dhchap_key; - nvme_ctrl_get_fd; nvme_ctrl_get_firmware; nvme_ctrl_get_host_iface; nvme_ctrl_get_host_traddr; nvme_ctrl_get_keyring; + nvme_ctrl_get_link; nvme_ctrl_get_model; nvme_ctrl_get_name; nvme_ctrl_get_numa_node; @@ -47,7 +46,7 @@ LIBNVME_2_0 { nvme_ctrl_is_unique_discovery_ctrl; nvme_ctrl_next_ns; nvme_ctrl_next_path; - nvme_ctrl_release_fd; + nvme_ctrl_release_link; nvme_ctrl_reset; nvme_ctrl_set_dhchap_host_key; nvme_ctrl_set_dhchap_key; @@ -60,13 +59,7 @@ LIBNVME_2_0 { nvme_ctrls_filter; nvme_default_host; nvme_describe_key_serial; - nvme_dev_self_test; - nvme_dim_send; - nvme_directive_recv; - nvme_directive_send; - nvme_directive_send_id_endir; nvme_disconnect_ctrl; - nvme_dsm; nvme_dump_config; nvme_dump_tree; nvme_errno_to_string; @@ -74,15 +67,12 @@ LIBNVME_2_0 { nvme_export_tls_key_versioned; nvme_first_host; nvme_first_subsystem; - nvme_format_nvm; nvme_free_ctrl; nvme_free_host; nvme_free_ns; + nvme_free_root; nvme_free_subsystem; - nvme_free_tree; nvme_free_uri; - nvme_fw_commit; - nvme_fw_download; nvme_fw_download_seq; nvme_gen_dhchap_key; nvme_generate_tls_key_identity; @@ -94,49 +84,14 @@ LIBNVME_2_0 { nvme_get_ctrl_telemetry; nvme_get_debug; nvme_get_directive_receive_length; - nvme_get_feature_length; - nvme_get_features; - nvme_get_features_arbitration; - nvme_get_features_async_event; - nvme_get_features_auto_pst; - nvme_get_features_endurance_event_cfg; - nvme_get_features_err_recovery; - nvme_get_features_hctm; - nvme_get_features_host_behavior; - nvme_get_features_host_id; - nvme_get_features_host_mem_buf; - nvme_get_features_iocs_profile; - nvme_get_features_irq_coalesce; - nvme_get_features_irq_config; - nvme_get_features_kato; - nvme_get_features_lba_range; - nvme_get_features_lba_sts_interval; - nvme_get_features_nopsc; - nvme_get_features_num_queues; - nvme_get_features_plm_config; - nvme_get_features_plm_window; - nvme_get_features_power_mgmt; - nvme_get_features_resv_mask; - nvme_get_features_resv_persist; - nvme_get_features_rrl; - nvme_get_features_sanitize; - nvme_get_features_sw_progress; - nvme_get_features_temp_thresh; - nvme_get_features_timestamp; - nvme_get_features_volatile_wc; - nvme_get_features_write_atomic; - nvme_get_features_write_protect; nvme_get_host_telemetry; - nvme_get_lba_status; - nvme_get_log; - nvme_get_log_page; + nvme_get_log_partial; nvme_get_logging_level; nvme_get_logical_block_size; nvme_get_new_host_telemetry; nvme_get_ns_attr; nvme_get_nsid; nvme_get_path_attr; - nvme_get_property; nvme_get_subsys_attr; nvme_get_telemetry_log; nvme_get_telemetry_max; @@ -152,7 +107,6 @@ LIBNVME_2_0 { nvme_host_set_dhchap_key; nvme_host_set_hostsymname; nvme_host_set_pdc_enabled; - nvme_identify; nvme_import_tls_key; nvme_import_tls_key_versioned; nvme_init_copy_range; @@ -166,42 +120,23 @@ LIBNVME_2_0 { nvme_init_logging; nvme_insert_tls_key; nvme_insert_tls_key_versioned; - nvme_io; - nvme_io_mgmt_recv; - nvme_io_mgmt_send; nvme_io_passthru64; nvme_io_passthru; nvme_ipaddrs_eq; - nvme_lm_cdq; + nvme_link_get_fd; + nvme_link_get_name; + nvme_link_is_blkdev; + nvme_link_is_chardev; + nvme_link_is_direct; + nvme_link_is_mi; nvme_lm_get_features_ctrl_data_queue; - nvme_lm_migration_recv; - nvme_lm_migration_send; nvme_lm_set_features_ctrl_data_queue; - nvme_lm_track_send; - nvme_lockdown; nvme_lookup_ctrl; nvme_lookup_host; nvme_lookup_key; nvme_lookup_keyring; nvme_lookup_subsystem; nvme_mi_admin_admin_passthru; - nvme_mi_admin_format_nvm; - nvme_mi_admin_fw_commit; - nvme_mi_admin_fw_download; - nvme_mi_admin_get_ana_log_atomic; - nvme_mi_admin_get_features; - nvme_mi_admin_get_features_arbitration; - nvme_mi_admin_get_features_power_mgmt; - nvme_mi_admin_get_log; - nvme_mi_admin_get_log_page; - nvme_mi_admin_identify_partial; - nvme_mi_admin_ns_attach; - nvme_mi_admin_ns_mgmt; - nvme_mi_admin_sanitize_nvm; - nvme_mi_admin_security_recv; - nvme_mi_admin_security_send; - nvme_mi_admin_set_features; - nvme_mi_admin_set_features_power_mgmt; nvme_mi_admin_xfer; nvme_mi_aem_disable; nvme_mi_aem_enable; @@ -210,7 +145,7 @@ LIBNVME_2_0 { nvme_mi_aem_get_next_event; nvme_mi_aem_process; nvme_mi_close; - nvme_mi_close_ctrl; + nvme_mi_close_link; nvme_mi_control; nvme_mi_create_root; nvme_mi_ctrl_id; @@ -220,7 +155,7 @@ LIBNVME_2_0 { nvme_mi_first_ctrl; nvme_mi_first_endpoint; nvme_mi_free_root; - nvme_mi_init_ctrl; + nvme_mi_init_link; nvme_mi_mi_config_get; nvme_mi_mi_config_set; nvme_mi_mi_read_mi_data_ctrl; @@ -254,12 +189,12 @@ LIBNVME_2_0 { nvme_ns_get_csi; nvme_ns_get_ctrl; nvme_ns_get_eui64; - nvme_ns_get_fd; nvme_ns_get_firmware; nvme_ns_get_generic_name; nvme_ns_get_lba_count; nvme_ns_get_lba_size; nvme_ns_get_lba_util; + nvme_ns_get_link; nvme_ns_get_meta_size; nvme_ns_get_model; nvme_ns_get_name; @@ -270,9 +205,8 @@ LIBNVME_2_0 { nvme_ns_get_sysfs_dir; nvme_ns_get_uuid; nvme_ns_identify; - nvme_ns_mgmt; nvme_ns_read; - nvme_ns_release_fd; + nvme_ns_release_link; nvme_ns_rescan; nvme_ns_verify; nvme_ns_write; @@ -292,16 +226,11 @@ LIBNVME_2_0 { nvme_read_key; nvme_refresh_topology; nvme_rescan_ctrl; - nvme_resv_acquire; - nvme_resv_register; - nvme_resv_release; - nvme_resv_report; nvme_revoke_tls_key; nvme_root_get_application; nvme_root_release_fds; nvme_root_set_application; nvme_root_skip_namespaces; - nvme_sanitize_nvm; nvme_scan; nvme_scan_ctrl; nvme_scan_ctrl_namespace_paths; @@ -312,39 +241,8 @@ LIBNVME_2_0 { nvme_scan_subsystems; nvme_scan_tls_keys; nvme_scan_topology; - nvme_security_receive; - nvme_security_send; nvme_set_debug; - nvme_set_features; - nvme_set_features_arbitration; - nvme_set_features_async_event; - nvme_set_features_auto_pst; - nvme_set_features_endurance_evt_cfg; - nvme_set_features_err_recovery; - nvme_set_features_hctm; - nvme_set_features_host_behavior; - nvme_set_features_host_id; - nvme_set_features_iocs_profile; - nvme_set_features_irq_coalesce; - nvme_set_features_irq_config; - nvme_set_features_lba_range; - nvme_set_features_lba_sts_interval; - nvme_set_features_nopsc; - nvme_set_features_plm_config; - nvme_set_features_plm_window; - nvme_set_features_power_mgmt; - nvme_set_features_resv_mask; - nvme_set_features_resv_persist; - nvme_set_features_rrl; - nvme_set_features_sanitize; - nvme_set_features_sw_progress; - nvme_set_features_temp_thresh; - nvme_set_features_timestamp; - nvme_set_features_volatile_wc; - nvme_set_features_write_atomic; - nvme_set_features_write_protect; nvme_set_keyring; - nvme_set_property; nvme_set_root; nvme_status_to_errno; nvme_status_to_string; @@ -380,10 +278,6 @@ LIBNVME_2_0 { nvme_uuid_from_string; nvme_uuid_random; nvme_uuid_to_string; - nvme_virtual_mgmt; - nvme_zns_append; - nvme_zns_mgmt_recv; - nvme_zns_mgmt_send; nvmf_add_ctrl; nvmf_adrfam_str; nvmf_cms_str; diff --git a/src/nvme/api-types.h b/src/nvme/api-types.h index 149ba22c7..60ebc324e 100644 --- a/src/nvme/api-types.h +++ b/src/nvme/api-types.h @@ -13,1095 +13,31 @@ #ifndef _LIBNVME_API_TYPES_H #define _LIBNVME_API_TYPES_H +#include #include #include -/* - * _args struct definitions. These are used by both the ioctl-based and - * MI-based interfaces, as the call interface for (admin/io/etc) NVMe commands, - * passed to the nvme_*() and nvme_mi_*() functions. - * - * On MI-based interfaces, the fd and timeout members are unused, and should - * be set to zero. - */ - -/** - * struct nvme_identify_args - Arguments for the NVMe Identify command - * @result: The command completion result from CQE dword0 - * @data: User space destination address to transfer the data - * @args_size: Size of &struct nvme_identify_args - * @fd: File descriptor of nvme device - * @timeout: Timeout in ms (0 for default timeout) - * @cns: The Controller or Namespace structure, see @enum nvme_identify_cns - * @csi: Command Set Identifier - * @nsid: Namespace identifier, if applicable - * @cntid: The Controller Identifier, if applicable - * @cns_specific_id: Identifier that is required for a particular CNS value - * @uuidx: UUID Index if controller supports this id selection method - */ -struct nvme_identify_args { - __u32 *result; - void *data; - int args_size; - int fd; - __u32 timeout; - enum nvme_identify_cns cns; - enum nvme_csi csi; - __u32 nsid; - __u16 cntid; - __u16 cns_specific_id; - __u8 uuidx; -}; - -/** - * struct nvme_get_log_args - Arguments for the NVMe Admin Get Log command - * @lpo: Log page offset for partial log transfers - * @result: The command completion result from CQE dword0 - * @log: User space destination address to transfer the data - * @args_size: Length of the structure - * @fd: File descriptor of nvme device - * @timeout: Timeout in ms - * @lid: Log page identifier, see &enum nvme_cmd_get_log_lid for known - * values - * @len: Length of provided user buffer to hold the log data in bytes - * @nsid: Namespace identifier, if applicable - * @csi: Command set identifier, see &enum nvme_csi for known values - * @lsi: Log Specific Identifier - * @lsp: Log specific field - * @uuidx: UUID selection, if supported - * @rae: Retain asynchronous events - * @ot: Offset Type; if set @lpo specifies the index into the list - * of data structures, otherwise @lpo specifies the byte offset - * into the log page. - */ -struct nvme_get_log_args { - __u64 lpo; - __u32 *result; - void *log; - int args_size; - int fd; - __u32 timeout; - enum nvme_cmd_get_log_lid lid; - __u32 len; - __u32 nsid; - enum nvme_csi csi; - __u16 lsi; - __u8 lsp; - __u8 uuidx; - bool rae; - bool ot; -}; - -/** - * struct nvme_set_features_args - Arguments for the NVMe Admin Set Feature command - * @result: The command completion result from CQE dword0 - * @data: User address of feature data, if applicable - * @args_size: Size of &struct nvme_set_features_args - * @fd: File descriptor of nvme device - * @timeout: Timeout in ms - * @nsid: Namespace ID, if applicable - * @cdw11: Value to set the feature to - * @cdw12: Feature specific command dword12 field - * @cdw13: Feature specific command dword13 field - * @cdw15: Feature specific command dword15 field - * @data_len: Length of feature data, if applicable, in bytes - * @save: Save value across power states - * @uuidx: UUID Index for differentiating vendor specific encoding - * @fid: Feature identifier - */ -struct nvme_set_features_args { - __u32 *result; - void *data; - int args_size; - int fd; - __u32 timeout; - __u32 nsid; - __u32 cdw11; - __u32 cdw12; - __u32 cdw13; - __u32 cdw15; - __u32 data_len; - bool save; - __u8 uuidx; - __u8 fid; -}; - -/** - * struct nvme_get_features_args - Arguments for the NVMe Admin Get Feature command - * @args_size: Size of &struct nvme_get_features_args - * @fd: File descriptor of nvme device - * @result: The command completion result from CQE dword0 - * @timeout: Timeout in ms - * @nsid: Namespace ID, if applicable - * @sel: Select which type of attribute to return, - * see &enum nvme_get_features_sel - * @cdw11: Feature specific command dword11 field - * @data_len: Length of feature data, if applicable, in bytes - * @data: User address of feature data, if applicable - * @fid: Feature identifier, see &enum nvme_features_id - * @uuidx: UUID Index for differentiating vendor specific encoding - */ -struct nvme_get_features_args { - __u32 *result; - void *data; - int args_size; - int fd; - __u32 timeout; - __u32 nsid; - enum nvme_get_features_sel sel; - __u32 cdw11; - __u32 data_len; - __u8 fid; - __u8 uuidx; -}; - -/** - * struct nvme_format_nvm_args - Arguments for the Format Nvme Namespace command - * @result: The command completion result from CQE dword0 - * @args_size: Size of &struct nvme_format_nvm_args - * @fd: File descriptor of nvme device - * @timeout: Set to override default timeout to this value in milliseconds; - * useful for long running formats. 0 will use system default. - * @nsid: Namespace ID to format - * @mset: Metadata settings (extended or separated), true if extended - * @pi: Protection information type - * @pil: Protection information location (beginning or end), true if end - * @ses: Secure erase settings - * @lbaf: Logical block address format least significant 4 bits - * @rsvd1: Reserved - * @lbafu: Logical block address format most significant 2 bits - */ -struct nvme_format_nvm_args { - __u32 *result; - int args_size; - int fd; - __u32 timeout; - __u32 nsid; - enum nvme_cmd_format_mset mset; - enum nvme_cmd_format_pi pi; - enum nvme_cmd_format_pil pil; - enum nvme_cmd_format_ses ses; - __u8 lbaf; - __u8 rsvd1[7]; - __u8 lbafu; -}; - -/** - * struct nvme_ns_mgmt_args - Arguments for NVMe Namespace Management command - * @result: NVMe command result - * @ns: Namespace identification descriptors - * @args_size: Size of &struct nvme_ns_mgmt_args - * @fd: File descriptor of nvme device - * @timeout: Timeout in ms - * @nsid: Namespace identifier - * @sel: Type of management operation to perform - * @csi: Command Set Identifier - * @rsvd1: Reserved - * @rsvd2: Reserved - * @data: Host Software Specified Fields - */ -struct nvme_ns_mgmt_args { - __u32 *result; - struct nvme_id_ns *ns; - int args_size; - int fd; - __u32 timeout; - __u32 nsid; - enum nvme_ns_mgmt_sel sel; - __u8 csi; - __u8 rsvd1[3]; - void *rsvd2; - struct nvme_ns_mgmt_host_sw_specified *data; -}; - -/** - * struct nvme_ns_attach_args - Arguments for Nvme Namespace Management command - * @result: NVMe command result - * @ctrlist: Controller list to modify attachment state of nsid - * @args_size: Size of &struct nvme_ns_attach_args - * @fd: File descriptor of nvme device - * @timeout: Timeout in ms - * @nsid: Namespace ID to execute attach selection - * @sel: Attachment selection, see &enum nvme_ns_attach_sel - */ -struct nvme_ns_attach_args { - __u32 *result; - struct nvme_ctrl_list *ctrlist; - int args_size; - int fd; - __u32 timeout; - __u32 nsid; - enum nvme_ns_attach_sel sel; -}; - -/** - * struct nvme_fw_download_args - Arguments for the NVMe Firmware Download command - * @args_size: Size of &struct nvme_fw_download_args - * @fd: File descriptor of nvme device - * @result: The command completion result from CQE dword0 - * @timeout: Timeout in ms - * @offset: Offset in the firmware data - * @data: Userspace address of the firmware data - * @data_len: Length of data in this command in bytes - */ -struct nvme_fw_download_args { - __u32 *result; - void *data; - int args_size; - int fd; - __u32 timeout; - __u32 offset; - __u32 data_len; -}; - -/** - * struct nvme_fw_commit_args - Arguments for the NVMe Firmware Commit command - * @args_size: Size of &struct nvme_fw_commit_args - * @fd: File descriptor of nvme device - * @action: Action to use for the firmware image, see &enum nvme_fw_commit_ca - * @timeout: Timeout in ms - * @result: The command completion result from CQE dword0 - * @slot: Firmware slot to commit the downloaded image - * @bpid: Set to true to select the boot partition id - */ -struct nvme_fw_commit_args { - __u32 *result; - int args_size; - int fd; - __u32 timeout; - enum nvme_fw_commit_ca action; - __u8 slot; - bool bpid; -}; - -/** - * struct nvme_security_send_args - Arguments for the NVMe Security Send command - * @result: The command completion result from CQE dword0 - * @data: Security data payload to send - * @args_size: Size of &struct nvme_security_send_args - * @fd: File descriptor of nvme device - * @timeout: Timeout in ms - * @nsid: Namespace ID to issue security command on - * @tl: Protocol specific transfer length - * @data_len: Data length of the payload in bytes - * @nssf: NVMe Security Specific field - * @spsp0: Security Protocol Specific field - * @spsp1: Security Protocol Specific field - * @secp: Security Protocol - */ -struct nvme_security_send_args { - __u32 *result; - void *data; - int args_size; - int fd; - __u32 timeout; - __u32 nsid; - __u32 tl; - __u32 data_len; - __u8 nssf; - __u8 spsp0; - __u8 spsp1; - __u8 secp; -}; - -/** - * struct nvme_security_receive_args - Arguments for the NVMe Security Receive command - * @result: The command completion result from CQE dword0 - * @data: Security data payload to send - * @args_size: Size of &struct nvme_security_receive_args - * @fd: File descriptor of nvme device - * @timeout: Timeout in ms - * @nsid: Namespace ID to issue security command on - * @al: Protocol specific allocation length - * @data_len: Data length of the payload in bytes - * @nssf: NVMe Security Specific field - * @spsp0: Security Protocol Specific field - * @spsp1: Security Protocol Specific field - * @secp: Security Protocol - */ -struct nvme_security_receive_args { - __u32 *result; - void *data; - int args_size; - int fd; - __u32 timeout; - __u32 nsid; - __u32 al; - __u32 data_len; - __u8 nssf; - __u8 spsp0; - __u8 spsp1; - __u8 secp; -}; - -/** - * struct nvme_get_lba_status_args - Arguments for the NVMe Get LBA Status command - * @lbas: Data payload to return status descriptors - * @result: The command completion result from CQE dword0 - * @slba: Starting logical block address to check statuses - * @args_size: Size of &struct nvme_get_lba_status_args - * @fd: File descriptor of nvme device - * @timeout: Timeout in ms - * @nsid: Namespace ID to retrieve LBA status - * @mndw: Maximum number of dwords to return - * @atype: Action type mechanism to determine LBA status descriptors to - * return, see &enum nvme_lba_status_atype - * @rl: Range length from slba to perform the action - */ -struct nvme_get_lba_status_args { - __u64 slba; - __u32 *result; - struct nvme_lba_status *lbas; - int args_size; - int fd; - __u32 timeout; - __u32 nsid; - __u32 mndw; - enum nvme_lba_status_atype atype; - __u16 rl; -}; - -/** - * struct nvme_directive_send_args - Arguments for the NVMe Directive Send command - * @result: If successful, the CQE dword0 value - * @data: Data payload to be send - * @args_size: Size of &struct nvme_directive_send_args - * @fd: File descriptor of nvme device - * @timeout: Timeout in ms - * @nsid: Namespace ID, if applicable - * @doper: Directive send operation, see &enum nvme_directive_send_doper - * @dtype: Directive type, see &enum nvme_directive_dtype - * @cdw12: Directive specific command dword12 - * @data_len: Length of data payload in bytes - * @dspec: Directive specific field - */ -struct nvme_directive_send_args { - __u32 *result; - void *data; - int args_size; - int fd; - __u32 timeout; - __u32 nsid; - enum nvme_directive_send_doper doper; - enum nvme_directive_dtype dtype; - __u32 cdw12; - __u32 data_len; - __u16 dspec; -}; - -/** - * struct nvme_directive_recv_args - Arguments for the NVMe Directive Receive command - * @result: If successful, the CQE dword0 value - * @data: Userspace address of data payload - * @args_size: Size of &struct nvme_directive_recv_args - * @fd: File descriptor of nvme device - * @timeout: Timeout in ms - * @nsid: Namespace ID, if applicable - * @doper: Directive send operation, see &enum nvme_directive_send_doper - * @dtype: Directive type, see &enum nvme_directive_dtype - * @cdw12: Directive specific command dword12 - * @data_len: Length of data payload in bytes - * @dspec: Directive specific field - */ -struct nvme_directive_recv_args { - __u32 *result; - void *data; - int args_size; - int fd; - __u32 timeout; - __u32 nsid; - enum nvme_directive_receive_doper doper; - enum nvme_directive_dtype dtype; - __u32 cdw12; - __u32 data_len; - __u16 dspec; -}; - -/** - * struct nvme_capacity_mgmt_args - Arguments for the NVMe Capacity Management command - * @result: If successful, the CQE dword0 value - * @args_size: Size of &struct nvme_capacity_mgmt_args - * @fd: File descriptor of nvme device - * @cdw11: Least significant 32 bits of the capacity in bytes of the - * Endurance Group or NVM Set to be created - * @cdw12: Most significant 32 bits of the capacity in bytes of the - * Endurance Group or NVM Set to be created - * @timeout: Timeout in ms - * @element_id: Value specific to the value of the Operation field - * @op: Operation to be performed by the controller - */ -struct nvme_capacity_mgmt_args { - __u32 *result; - int args_size; - int fd; - __u32 timeout; - __u32 cdw11; - __u32 cdw12; - __u16 element_id; - __u8 op; -}; - -/** - * struct nvme_lockdown_args - Arguments for the NVME Lockdown command - * @args_size: Size of &struct nvme_lockdown_args - * @fd: File descriptor of nvme device - * @result: The command completion result from CQE dword0 - * @timeout: Timeout in ms (0 for default timeout) - * @scp: Scope of the command - * @prhbt: Prohibit or allow the command opcode or Set Features command - * @ifc: Affected interface - * @ofi: Opcode or Feature Identifier - * @uuidx: UUID Index if controller supports this id selection method - */ -struct nvme_lockdown_args { - __u32 *result; - int args_size; - int fd; - __u32 timeout; - __u8 scp; - __u8 prhbt; - __u8 ifc; - __u8 ofi; - __u8 uuidx; -}; - -/** - * struct nvme_set_property_args - Arguments for NVMe Set Property command - * @args_size: Size of &struct nvme_set_property_args - * @fd: File descriptor of nvme device - * @result: The command completion result from CQE dword0 - * @timeout: Timeout in ms - * @offset: Property offset from the base to set - * @value: The value to set the property - */ -struct nvme_set_property_args { - __u64 value; - __u32 *result; - int args_size; - int fd; - __u32 timeout; - int offset; -}; - -/** - * struct nvme_get_property_args - Arguments for NVMe Get Property command - * @value: Where the property's value will be stored on success - * @args_size: Size of &struct nvme_get_property_args - * @fd: File descriptor of nvme device - * @offset: Property offset from the base to retrieve - * @timeout: Timeout in ms - */ -struct nvme_get_property_args { - __u64 *value; - int args_size; - int fd; - __u32 timeout; - int offset; -}; - -/** - * struct nvme_sanitize_nvm_args - Arguments for the NVMe Sanitize NVM command - * @result: The command completion result from CQE dword0 - * @args_size: Size of &struct nvme_sanitize_nvm_args - * @fd: File descriptor of nvme device - * @timeout: Timeout in ms - * @ovrpat: Overwrite pattern - * @sanact: Sanitize action, see &enum nvme_sanitize_sanact - * @ause: Set to allow unrestricted sanitize exit - * @owpass: Overwrite pass count - * @oipbp: Set to overwrite invert pattern between passes - * @nodas: Set to not deallocate blocks after sanitizing - * @emvs: Set to enter media verification state - */ -struct nvme_sanitize_nvm_args { - __u32 *result; - int args_size; - int fd; - __u32 timeout; - enum nvme_sanitize_sanact sanact; - __u32 ovrpat; - bool ause; - __u8 owpass; - bool oipbp; - bool nodas; - bool emvs; -}; - -/** - * struct nvme_dev_self_test_args - Arguments for the NVMe Device Self Test command - * @result: The command completion result from CQE dword0 - * @args_size: Size of &struct nvme_dev_self_test_args - * @fd: File descriptor of nvme device - * @nsid: Namespace ID to test - * @stc: Self test code, see &enum nvme_dst_stc - * @timeout: Timeout in ms - */ -struct nvme_dev_self_test_args { - __u32 *result; - int args_size; - int fd; - __u32 timeout; - __u32 nsid; - enum nvme_dst_stc stc; -}; - -/** - * struct nvme_virtual_mgmt_args - Arguments for the NVMe Virtualization - * resource management command - * @args_size: Size of &struct nvme_virtual_mgmt_args - * @fd: File descriptor of nvme device - * @result: If successful, the CQE dword0 - * @timeout: Timeout in ms - * @act: Virtual resource action, see &enum nvme_virt_mgmt_act - * @rt: Resource type to modify, see &enum nvme_virt_mgmt_rt - * @cntlid: Controller id for which resources are bing modified - * @nr: Number of resources being allocated or assigned - */ -struct nvme_virtual_mgmt_args { - __u32 *result; - int args_size; - int fd; - __u32 timeout; - enum nvme_virt_mgmt_act act; - enum nvme_virt_mgmt_rt rt; - __u16 cntlid; - __u16 nr; -}; - -/** - * struct nvme_io_args - Arguments for NVMe I/O commands - * @slba: Starting logical block - * @storage_tag: This filed specifies Variable Sized Expected Logical Block - * Storage Tag (ELBST) or Logical Block Storage Tag (LBST) - * @result: The command completion result from CQE dword0 - * @data: Pointer to user address of the data buffer - * @metadata: Pointer to user address of the metadata buffer - * @args_size: Size of &struct nvme_io_args - * @fd: File descriptor of nvme device - * @timeout: Timeout in ms - * @nsid: Namespace ID - * @data_len: Length of user buffer, @data, in bytes - * @metadata_len:Length of user buffer, @metadata, in bytes - * @nlb: Number of logical blocks to send (0's based value) - * @control: Command control flags, see &enum nvme_io_control_flags. - * @apptag: This field specifies the Application Tag Mask expected value. - * Used only if the namespace is formatted to use end-to-end - * protection information. - * @appmask: This field specifies the Application Tag expected value. Used - * only if the namespace is formatted to use end-to-end protection - * information. - * @reftag: This field specifies the variable sized Expected Initial - * Logical Block Reference Tag (EILBRT) or Initial Logical Block - * Reference Tag (ILBRT). Used only if the namespace is formatted - * to use end-to-end protection information. - * @dspec: Directive specific value - * @dsm: Data set management attributes, see &enum nvme_io_dsm_flags - * @rsvd1: Reserved - * @reftag_u64: This field specifies the variable sized Expected Initial - * Logical Block Reference Tag (EILBRT) or Initial Logical Block - * Reference Tag (ILBRT). It is the 8 byte version required for - * enhanced protection information. Used only if the namespace is - * formatted to use end-to-end protection information. - * @sts: Storage tag size in bits, set by namespace Extended LBA Format - * @pif: Protection information format, determines how variable sized - * storage_tag and reftag are put into dwords 2, 3, and 14. Set by - * namespace Extended LBA Format. - */ -struct nvme_io_args { - __u64 slba; - __u64 storage_tag; - __u32 *result; - void *data; - void *metadata; - int args_size; - int fd; - __u32 timeout; - __u32 nsid; - __u32 reftag; - __u32 data_len; - __u32 metadata_len; - __u16 nlb; - __u16 control; - __u16 apptag; - __u16 appmask; - __u16 dspec; - __u8 dsm; - __u8 rsvd1[1]; - __u64 reftag_u64; - __u8 sts; - __u8 pif; -}; - -/** - * struct nvme_dsm_args - Arguments for the NVMe Dataset Management command - * @result: The command completion result from CQE dword0 - * @dsm: The data set management attributes - * @args_size: Size of &struct nvme_dsm_args - * @fd: File descriptor of nvme device - * @timeout: Timeout in ms - * @nsid: Namespace identifier - * @attrs: DSM attributes, see &enum nvme_dsm_attributes - * @nr_ranges: Number of block ranges in the data set management attributes - */ -struct nvme_dsm_args { - __u32 *result; - struct nvme_dsm_range *dsm; - int args_size; - int fd; - __u32 timeout; - __u32 nsid; - __u32 attrs; - __u16 nr_ranges; -}; - -/** - * struct nvme_copy_args - Arguments for the NVMe Copy command - * @sdlba: Start destination LBA - * @result: The command completion result from CQE dword0 - * @copy: Range description - * @args_size: Size of &struct nvme_copy_args - * @fd: File descriptor of the nvme device - * @timeout: Timeout in ms - * @nsid: Namespace identifier - * @ilbrt: Initial logical block reference tag - * @lr: Limited retry - * @fua: Force unit access - * @nr: Number of ranges - * @dspec: Directive specific value - * @lbatm: Logical block application tag mask - * @lbat: Logical block application tag - * @prinfor: Protection information field for read - * @prinfow: Protection information field for write - * @dtype: Directive type - * @format: Descriptor format - * @ilbrt_u64: Initial logical block reference tag - 8 byte - * version required for enhanced protection info - */ -struct nvme_copy_args { - __u64 sdlba; - __u32 *result; - struct nvme_copy_range *copy; - int args_size; - int fd; - __u32 timeout; - __u32 nsid; - __u32 ilbrt; - int lr; - int fua; - __u16 nr; - __u16 dspec; - __u16 lbatm; - __u16 lbat; - __u8 prinfor; - __u8 prinfow; - __u8 dtype; - __u8 format; - __u64 ilbrt_u64; -}; - -/** - * struct nvme_resv_acquire_args - Arguments for the NVMe Reservation Acquire Command - * @nrkey: The reservation key to be unregistered from the namespace if - * the action is preempt - * @iekey: Set to ignore the existing key - * @result: The command completion result from CQE dword0 - * @args_size: Size of &struct nvme_resv_acquire_args - * @fd: File descriptor of nvme device - * @timeout: Timeout in ms - * @nsid: Namespace identifier - * @rtype: The type of reservation to be create, see &enum nvme_resv_rtype - * @racqa: The action that is performed by the command, see &enum nvme_resv_racqa - * @crkey: The current reservation key associated with the host - */ -struct nvme_resv_acquire_args { - __u64 crkey; - __u64 nrkey; - __u32 *result; - int args_size; - int fd; - __u32 timeout; - __u32 nsid; - enum nvme_resv_rtype rtype; - enum nvme_resv_racqa racqa; - bool iekey; -}; - -/** - * struct nvme_resv_register_args - Arguments for the NVMe Reservation Register command - * @crkey: The current reservation key associated with the host - * @nrkey: The new reservation key to be register if action is register or - * replace - * @result: The command completion result from CQE dword0 - * @args_size: Size of &struct nvme_resv_register_args - * @fd: File descriptor of nvme device - * @nsid: Namespace identifier - * @rrega: The registration action, see &enum nvme_resv_rrega - * @cptpl: Change persist through power loss, see &enum nvme_resv_cptpl - * @iekey: Set to ignore the existing key - * @timeout: Timeout in ms - */ -struct nvme_resv_register_args { - __u64 crkey; - __u64 nrkey; - __u32 *result; - int args_size; - int fd; - __u32 timeout; - __u32 nsid; - enum nvme_resv_rrega rrega; - enum nvme_resv_cptpl cptpl; - bool iekey; -}; - -/** - * struct nvme_resv_release_args - Arguments for the NVMe Reservation Release Command - * @crkey: The current reservation key to release - * @result: The command completion result from CQE dword0 - * @args_size: Size of &struct nvme_resv_release_args - * @fd: File descriptor of nvme device - * @timeout: Timeout in ms - * @nsid: Namespace identifier - * @rtype: The type of reservation to be create, see &enum nvme_resv_rtype - * @rrela: Reservation release action, see &enum nvme_resv_rrela - * @iekey: Set to ignore the existing key - */ -struct nvme_resv_release_args { - __u64 crkey; - __u32 *result; - int args_size; - int fd; - __u32 timeout; - __u32 nsid; - enum nvme_resv_rtype rtype; - enum nvme_resv_rrela rrela; - bool iekey; -}; +struct nvme_root; +typedef struct nvme_root *nvme_root_t; +struct nvme_link; +typedef struct nvme_link *nvme_link_t; /** - * struct nvme_resv_report_args - Arguments for the NVMe Reservation Report command - * @result: The command completion result from CQE dword0 - * @report: The user space destination address to store the reservation - * report - * @args_size: Size of &struct nvme_resv_report_args - * @fd: File descriptor of nvme device - * @timeout: Timeout in ms - * @nsid: Namespace identifier - * @len: Number of bytes to request transferred with this command - * @eds: Request extended Data Structure - */ -struct nvme_resv_report_args { - __u32 *result; - struct nvme_resv_status *report; - int args_size; - int fd; - __u32 timeout; - __u32 nsid; - __u32 len; - bool eds; -}; - -/** - * struct nvme_io_mgmt_recv_args - Arguments for the NVMe I/O Management Receive command - * @data: Userspace address of the data - * @args_size: Size of &struct nvme_io_mgmt_recv_args - * @fd: File descriptor of nvme device - * @nsid: Namespace identifier - * @data_len: Length of @data - * @timeout: Timeout in ms - * @mos: Management Operation Specific - * @mo: Management Operation - */ -struct nvme_io_mgmt_recv_args { - void *data; - int args_size; - int fd; - __u32 nsid; - __u32 data_len; - __u32 timeout; - __u16 mos; - __u8 mo; -}; - -/** - * struct nvme_io_mgmt_send_args - Arguments for the NVMe I/O Management Send command - * @data: Userspace address of the data - * @args_size: Size of &struct nvme_io_mgmt_send_args - * @fd: File descriptor of nvme device - * @nsid: Namespace identifier - * @data_len: Length of @data - * @timeout: Timeout in ms - * @mos: Management Operation Specific - * @mo: Management Operation - */ -struct nvme_io_mgmt_send_args { - void *data; - int args_size; - int fd; - __u32 nsid; - __u32 data_len; - __u32 timeout; - __u16 mos; - __u8 mo; -}; - -/** - * struct nvme_zns_mgmt_send_args - Arguments for the NVMe ZNS Management Send command - * @slba: Starting logical block address - * @result: The command completion result from CQE dword0 - * @data: Userspace address of the data - * @args_size: Size of &struct nvme_zns_mgmt_send_args - * @fd: File descriptor of nvme device - * @timeout: timeout in ms - * @nsid: Namespace ID - * @zsa: Zone send action - * @data_len: Length of @data - * @select_all: Select all flag - * @zsaso: Zone Send Action Specific Option - */ -struct nvme_zns_mgmt_send_args { - __u64 slba; - __u32 *result; - void *data; - int args_size; - int fd; - __u32 timeout; - __u32 nsid; - enum nvme_zns_send_action zsa; - __u32 data_len; - bool select_all; - __u8 zsaso; -}; - -/** - * struct nvme_zns_mgmt_recv_args - Arguments for the NVMe ZNS Management Receive command - * @slba: Starting logical block address - * @result: The command completion result from CQE dword0 - * @data: Userspace address of the data - * @args_size: Size of &struct nvme_zns_mgmt_recv_args - * @fd: File descriptor of nvme device - * @timeout: timeout in ms - * @nsid: Namespace ID - * @zra: zone receive action - * @data_len: Length of @data - * @zrasf: Zone receive action specific field - * @zras_feat: Zone receive action specific features - */ -struct nvme_zns_mgmt_recv_args { - __u64 slba; - __u32 *result; - void *data; - int args_size; - int fd; - __u32 timeout; - __u32 nsid; - enum nvme_zns_recv_action zra; - __u32 data_len; - __u16 zrasf; - bool zras_feat; -}; - -/** - * struct nvme_zns_append_args - Arguments for the NVMe ZNS Append command - * @zslba: Zone start logical block address - * @result: The command completion result from CQE dword0 - * @data: Userspace address of the data - * @metadata: Userspace address of the metadata - * @args_size: Size of &struct nvme_zns_append_args - * @fd: File descriptor of nvme device - * @timeout: Timeout in ms - * @nsid: Namespace ID - * @ilbrt: Initial logical block reference tag - * @data_len: Length of @data - * @metadata_len: Length of @metadata - * @nlb: Number of logical blocks - * @control: - * @lbat: Logical block application tag - * @lbatm: Logical block application tag mask - * @rsvd1: Reserved - * @ilbrt_u64: Initial logical block reference tag - 8 byte - * version required for enhanced protection info + * nvme_create_root() - Initialize root object + * @fp: File descriptor for logging messages + * @log_level: Logging level to use * + * Return: Initialized &nvme_root_t object */ -struct nvme_zns_append_args { - __u64 zslba; - __u64 *result; - void *data; - void *metadata; - int args_size; - int fd; - __u32 timeout; - __u32 nsid; - __u32 ilbrt; - __u32 data_len; - __u32 metadata_len; - __u16 nlb; - __u16 control; - __u16 lbat; - __u16 lbatm; - __u8 rsvd1[4]; - __u64 ilbrt_u64; -}; - -/** - * struct nvme_dim_args - Arguments for the Discovery Information Management (DIM) command - * @result: Set on completion to the command's CQE DWORD 0 controller response. - * @data: Pointer to the DIM data - * @args_size: Length of the structure - * @fd: File descriptor of nvme device - * @timeout: Timeout in ms - * @data_len: Length of @data - * @tas: Task field of the Command Dword 10 (cdw10) - */ -struct nvme_dim_args { - __u32 *result; - void *data; - int args_size; - int fd; - __u32 timeout; - __u32 data_len; - __u8 tas; -}; - -/** - * struct nvme_lm_cdq_args - Arguments for Controller Data Queue (CDQ) command - * @result: Set on completion to the command's CQE DWORD 0 controller response - * @data: Pointer to data - * @args_size: Length of structure - * @fd: File descriptor of nvme device - * @timeout: Timeout in ms - * @mos: Management Operation Specific (MOS): This field is specific to the SEL type - * @cntlid: Controller ID: For Create CDQ, specifies the target migratable controller - * @cdqid: Controller Data Queue ID (CDQID): For Create CDQ, this field is the CDQID created - * by the controller if no error is present. For Delete CDQ, this field is the CDQID - * to delete. - * @sel: Select (SEL): This field specifies the type of management operation to perform. - * @sz_u8: For Create CDQ, specifies the size of CDQ, in dwords - 1 byte - * @rsvd1: Reserved - * @sz: For Create CDQ, specifies the size of CDQ, in dwords - 4 byte - */ -struct nvme_lm_cdq_args { - __u32 *result; - void *data; - int args_size; - int fd; - __u32 timeout; - __u16 mos; - __u16 cntlid; - __u16 cdqid; - __u8 sel; - __u8 sz_u8; - __u8 rsvd1[4]; - __u32 sz; -}; +nvme_root_t nvme_create_root(FILE *fp, int log_level); /** - * struct nvme_lm_track_send_args - Arguments for the Track Send command - * @result: Set on completion to the command's CQE DWORD 0 controller response - * @args_size: Length of structure - * @fd: File descriptor of nvme device - * @timeout: Timeout in ms - * @mos: Management Operation Specific (MOS): This field is specific to the SEL type - * @cdqid: Controller Data Queue ID (CDQID) - * @sel: Select (SEL): This field specifies the type of management operation to perform - */ -struct nvme_lm_track_send_args { - __u32 *result; - int args_size; - int fd; - __u32 timeout; - __u16 mos; - __u16 cdqid; - __u8 sel; -}; - -/** - * struct nvme_lm_migration_send_args - Arguments for the Migration Send command - * @offset: Offset: This field specifies the offset, in bytes, within the data available to be - * returned and specifies the starting point for that data for what is actually - * returned to the host. - * @result: Set on completion to the command's CQE DWORD 0 controller response - * @data: Pointer to data - * @args_size: Length of structure - * @fd: File descriptor of nvme device - * @timeout: Timeout in ms - * @numd: Number of Dwords (NUMD): This field specifies the number of dwords being transferred - * @mos: Management Operation Specific (MOS): This field is specific to the SEL type - * @cntlid: Controller ID: This field specifies the identifier of the controller to which the - * operation is performed. - * @csuuidi: Controller State UUID Index (CSUUIDI): A non-zero value in this field specifies the - * index to a specific entry in the Vendor Specific Controller State UUID Supported. - * list of the Supported Controller State Formats data structure. - * @sel: Select (SEL): This field specifies the type of management operation to perform. - * @uidx: UUID Index (UIDX): If this field is set to a non-zero value, then the value of this - * field is the index of a UUID in the UUID List (refer to Figure 320) that is used by - * the command. - * @stype: Suspend Type (STYPE): This field specifies the type of suspend. - * @seqind: Sequence Identifier (SEQIND): This field identified the sequences of this Migration - * Send command in relation to other Migration Send commands. - * @csvi: Controller State Version Index (CSVI): A non-zero value in this field specifies the - * index to a specific entry in the NVMe Controller State Version list of the Supported - * Controller State Formats data structure. - * @dudmq: Delete User Data Migration Queue (DUDMQ): If set, the migration queue is deleted - * is deleted as part of the Suspend operation. If cleared, it is retained. - */ -struct nvme_lm_migration_send_args { - __u64 offset; - __u32 *result; - void *data; - int args_size; - int fd; - __u32 timeout; - __u32 numd; - __u16 mos; - __u16 cntlid; - __u16 csuuidi; - __u8 sel; - __u8 uidx; - __u8 stype; - __u8 seqind; - __u8 csvi; - bool dudmq; -}; - -/** - * struct nvme_lm_migration_recv_args - Arguments for the Migration Receive command - * @offset: Offset: This field specifies the offset, in bytes, within the data available to be - * returned and specifies the starting point for that data for what is actually - * returned to the host. - * @result: Set on completion to the command's CQE DWORD 0 controller response - * @data: Pointer to data - * @args_size: Length of structure - * @fd: File descriptor of nvme device - * @timeout: Timeout in ms - * @numd: Number of Dwords (NUMD): This field specifies the number of dwords to return. This - * is a 0's based value. - * @mos: Management Operation Specific (MOS): This field is specific to the SEL type - * @cntlid: Controller ID: This field specifies the identifier of the controller to which the - * operation is performed. - * @csuuidi: Controller State UUID Index (CSUUIDI): A non-zero value in this field specifies the - * index to a specific entry in the Vendor Specific Controller State UUID Supported. - * list of the Supported Controller State Formats data structure. - * @sel: Select (SEL): This field specifies the type of management operation to perform - * @uidx: UUID Index (UIDX): If this field is set to a non-zero value, then the value of this - * field is the index of a UUID in the UUID List (refer to Figure 320) that is used by - * the command. - * @csuidxp: Controller State UUID Index Parameter (CSUIDXP): This field is vendor specific. + * nvme_free_root() - Free root object + * @r: &nvme_root_t object + * + * Free an &nvme_root_t object and all attached objects */ -struct nvme_lm_migration_recv_args { - __u64 offset; - __u32 *result; - void *data; - int args_size; - int fd; - __u32 timeout; - __u32 numd; - __u16 mos; - __u16 cntlid; - __u16 csuuidi; - __u8 sel; - __u8 uidx; - __u8 csuidxp; -}; +void nvme_free_root(nvme_root_t r); #endif /* _LIBNVME_API_TYPES_H */ diff --git a/src/nvme/cleanup.h b/src/nvme/cleanup.h index 432760046..4c275398d 100644 --- a/src/nvme/cleanup.h +++ b/src/nvme/cleanup.h @@ -6,6 +6,9 @@ #include #include #include +#include +#include +#include #define __cleanup__(fn) __attribute__((cleanup(fn))) @@ -38,4 +41,7 @@ static inline void cleanup_fd(int *fd) } #define _cleanup_fd_ __cleanup__(cleanup_fd) +static inline DEFINE_CLEANUP_FUNC(cleanup_addrinfo, struct addrinfo *, freeaddrinfo) +#define _cleanup_addrinfo_ __cleanup__(cleanup_addrinfo) + #endif diff --git a/src/nvme/fabrics.c b/src/nvme/fabrics.c index 6aa62eea5..1b424dfc2 100644 --- a/src/nvme/fabrics.c +++ b/src/nvme/fabrics.c @@ -300,8 +300,7 @@ static int __add_bool_argument(char **argstr, char *tok, bool arg) if (!arg) return 0; if (asprintf(&nstr, "%s,%s", *argstr, tok) < 0) { - errno = ENOMEM; - return -1; + return -ENOMEM; } free(*argstr); *argstr = nstr; @@ -316,8 +315,7 @@ static int __add_hex_argument(char **argstr, char *tok, int arg, bool allow_zero if (arg < 0 || (!arg && !allow_zero)) return 0; if (asprintf(&nstr, "%s,%s=0x%08x", *argstr, tok, arg) < 0) { - errno = ENOMEM; - return -1; + return -ENOMEM; } free(*argstr); *argstr = nstr; @@ -332,8 +330,7 @@ static int __add_int_argument(char **argstr, char *tok, int arg, bool allow_zero if (arg < 0 || (!arg && !allow_zero)) return 0; if (asprintf(&nstr, "%s,%s=%d", *argstr, tok, arg) < 0) { - errno = ENOMEM; - return -1; + return -ENOMEM; } free(*argstr); *argstr = nstr; @@ -348,8 +345,7 @@ static int __add_int_or_minus_one_argument(char **argstr, char *tok, int arg) if (arg < -1) return 0; if (asprintf(&nstr, "%s,%s=%d", *argstr, tok, arg) < 0) { - errno = ENOMEM; - return -1; + return -ENOMEM; } free(*argstr); *argstr = nstr; @@ -364,8 +360,7 @@ static int __add_argument(char **argstr, const char *tok, const char *arg) if (!arg || arg[0] == '\0' || !strcmp(arg, "none")) return 0; if (asprintf(&nstr, "%s,%s=%s", *argstr, tok, arg) < 0) { - errno = ENOMEM; - return -1; + return -ENOMEM; } free(*argstr); *argstr = nstr; @@ -591,23 +586,20 @@ static int build_options(nvme_host_t h, nvme_ctrl_t c, char **argstr) if (!transport) { nvme_msg(h->r, LOG_ERR, "need a transport (-t) argument\n"); - errno = ENVME_CONNECT_TARG; - return -1; + return -ENVME_CONNECT_TARG; } if (strncmp(transport, "loop", 4)) { if (!nvme_ctrl_get_traddr(c)) { nvme_msg(h->r, LOG_ERR, "need a address (-a) argument\n"); - errno = ENVME_CONNECT_AARG; - return -1; + return -ENVME_CONNECT_AARG; } } /* always specify nqn as first arg - this will init the string */ if (asprintf(argstr, "nqn=%s", nvme_ctrl_get_subsysnqn(c)) < 0) { - errno = ENOMEM; - return -1; + return -ENOMEM; } if (!strcmp(nvme_ctrl_get_subsysnqn(c), NVME_DISC_SUBSYS_NAME)) { @@ -629,10 +621,8 @@ static int build_options(nvme_host_t h, nvme_ctrl_t c, char **argstr) if (cfg->tls) { ret = __nvme_import_keys_from_config(h, c, &keyring_id, &key_id); - if (ret) { - errno = -ret; - return -1; - } + if (ret) + return ret; if (key_id == 0) { if (cfg->tls_configured_key) @@ -950,8 +940,7 @@ int nvmf_add_ctrl(nvme_host_t h, nvme_ctrl_t c, if (app && strcmp(app, root_app)) { nvme_msg(h->r, LOG_INFO, "skip %s, not managed by %s\n", nvme_subsystem_get_nqn(s), root_app); - errno = ENVME_CONNECT_IGNORED; - return -1; + return -ENVME_CONNECT_IGNORED; } } @@ -959,11 +948,9 @@ int nvmf_add_ctrl(nvme_host_t h, nvme_ctrl_t c, if (traddr_is_hostname(h->r, c)) { char *traddr = c->traddr; - c->traddr = hostname2traddr(h->r, traddr); - if (!c->traddr) { + if (hostname2traddr(h->r, traddr, &c->traddr)) { c->traddr = traddr; - errno = ENVME_CONNECT_TRADDR; - return -1; + return -ENVME_CONNECT_TRADDR; } free(traddr); } @@ -973,10 +960,8 @@ int nvmf_add_ctrl(nvme_host_t h, nvme_ctrl_t c, return ret; ret = __nvmf_add_ctrl(h->r, argstr); - if (ret < 0) { - errno = -ret; - return -1; - } + if (ret < 0) + return ret; nvme_msg(h->r, LOG_INFO, "nvme%d: %s connected\n", ret, nvme_ctrl_get_subsysnqn(c)); @@ -993,18 +978,17 @@ int nvmf_connect_ctrl(nvme_ctrl_t c) return ret; ret = __nvmf_add_ctrl(c->s->h->r, argstr); - if (ret < 0) { - errno = -ret; - return -1; - } + if (ret < 0) + return ret; return 0; } -nvme_ctrl_t nvmf_connect_disc_entry(nvme_host_t h, - struct nvmf_disc_log_entry *e, - const struct nvme_fabrics_config *cfg, - bool *discover) +int nvmf_connect_disc_entry(nvme_host_t h, + struct nvmf_disc_log_entry *e, + const struct nvme_fabrics_config *cfg, + bool *discover, + nvme_ctrl_t *cp) { const char *transport; char *traddr = NULL, *trsvcid = NULL; @@ -1024,8 +1008,7 @@ nvme_ctrl_t nvmf_connect_disc_entry(nvme_host_t h, nvme_msg(h->r, LOG_ERR, "skipping unsupported adrfam %d\n", e->adrfam); - errno = EINVAL; - return NULL; + return -EINVAL; } break; case NVMF_TRTYPE_FC: @@ -1037,8 +1020,7 @@ nvme_ctrl_t nvmf_connect_disc_entry(nvme_host_t h, nvme_msg(h->r, LOG_ERR, "skipping unsupported adrfam %d\n", e->adrfam); - errno = EINVAL; - return NULL; + return -EINVAL; } break; case NVMF_TRTYPE_LOOP: @@ -1047,8 +1029,7 @@ nvme_ctrl_t nvmf_connect_disc_entry(nvme_host_t h, default: nvme_msg(h->r, LOG_ERR, "skipping unsupported transport %d\n", e->trtype); - errno = EINVAL; - return NULL; + return -EINVAL; } transport = nvmf_trtype_str(e->trtype); @@ -1056,14 +1037,13 @@ nvme_ctrl_t nvmf_connect_disc_entry(nvme_host_t h, nvme_msg(h->r, LOG_DEBUG, "lookup ctrl " "(transport: %s, traddr: %s, trsvcid %s)\n", transport, traddr, trsvcid); - c = nvme_create_ctrl(h->r, e->subnqn, transport, traddr, - cfg->host_traddr, cfg->host_iface, trsvcid); - if (!c) { + ret = nvme_create_ctrl(h->r, e->subnqn, transport, traddr, + cfg->host_traddr, cfg->host_iface, trsvcid, &c); + if (!ret) { nvme_msg(h->r, LOG_DEBUG, "skipping discovery entry, " "failed to allocate %s controller with traddr %s\n", transport, traddr); - errno = ENOMEM; - return NULL; + return ret; } switch (e->subtype) { @@ -1091,8 +1071,7 @@ nvme_ctrl_t nvmf_connect_disc_entry(nvme_host_t h, if (nvme_ctrl_is_discovered(c)) { nvme_free_ctrl(c); - errno = EAGAIN; - return NULL; + return -EAGAIN; } if (e->treq & NVMF_TREQ_DISABLE_SQFLOW && @@ -1104,21 +1083,24 @@ nvme_ctrl_t nvmf_connect_disc_entry(nvme_host_t h, c->cfg.tls = true; ret = nvmf_add_ctrl(h, c, cfg); - if (!ret) - return c; + if (!ret) { + *cp = c; + return 0; + } - if (errno == EINVAL && c->cfg.disable_sqflow) { - errno = 0; + if (ret == EINVAL && c->cfg.disable_sqflow) { /* disable_sqflow is unrecognized option on older kernels */ nvme_msg(h->r, LOG_INFO, "failed to connect controller, " "retry with disabling SQ flow control\n"); c->cfg.disable_sqflow = false; ret = nvmf_add_ctrl(h, c, cfg); - if (!ret) - return c; + if (!ret) { + *cp = c; + return 0; + } } nvme_free_ctrl(c); - return NULL; + return -ENOENT; } /* @@ -1128,43 +1110,33 @@ nvme_ctrl_t nvmf_connect_disc_entry(nvme_host_t h, */ #define DISCOVERY_HEADER_LEN 20 -static struct nvmf_discovery_log *nvme_discovery_log( - const struct nvme_get_discovery_args *args) +static int nvme_discovery_log(const struct nvme_get_discovery_args *args, + struct nvmf_discovery_log **logp) { - nvme_root_t r = root_from_ctrl(args->c); struct nvmf_discovery_log *log; - int retries = 0; + int retries = 0, err; const char *name = nvme_ctrl_get_name(args->c); uint64_t genctr, numrec; - int fd = nvme_ctrl_get_fd(args->c); - struct nvme_get_log_args log_args = { - .result = args->result, - .args_size = sizeof(log_args), - .timeout = args->timeout, - .lid = NVME_LOG_LID_DISCOVER, - .nsid = NVME_NSID_NONE, - .csi = NVME_CSI_NVM, - .lsi = NVME_LOG_LSI_NONE, - .lsp = args->lsp, - .uuidx = NVME_UUID_NONE, - }; + nvme_link_t l = nvme_ctrl_get_link(args->c); log = __nvme_alloc(sizeof(*log)); if (!log) { - nvme_msg(r, LOG_ERR, + nvme_msg(l->root, LOG_ERR, "could not allocate memory for discovery log header\n"); - errno = ENOMEM; - return NULL; + return -ENOMEM; } - nvme_msg(r, LOG_DEBUG, "%s: get header (try %d/%d)\n", + nvme_msg(l->root, LOG_DEBUG, "%s: get header (try %d/%d)\n", name, retries, args->max_retries); - log_args.log = log; - log_args.len = DISCOVERY_HEADER_LEN; - if (nvme_get_log_page(fd, NVME_LOG_PAGE_PDU_SIZE, &log_args)) { - nvme_msg(r, LOG_INFO, + err = nvme_get_log(l, NVME_NSID_NONE, false, args->lsp, + NVME_LOG_LID_DISCOVER, NVME_LOG_LSI_NONE, NVME_CSI_NVM, + false, NVME_UUID_NONE, + 0, log, DISCOVERY_HEADER_LEN, + NVME_LOG_PAGE_PDU_SIZE, NULL); + if (err) { + nvme_msg(l->root, LOG_INFO, "%s: discover try %d/%d failed, error %d\n", - name, retries, args->max_retries, errno); + name, retries, args->max_retries, err); goto out_free_log; } @@ -1181,23 +1153,24 @@ static struct nvmf_discovery_log *nvme_discovery_log( entries_size = sizeof(*log->entries) * numrec; log = __nvme_alloc(sizeof(*log) + entries_size); if (!log) { - nvme_msg(r, LOG_ERR, + nvme_msg(l->root, LOG_ERR, "could not alloc memory for discovery log page\n"); - errno = ENOMEM; - return NULL; + return -ENOMEM; } - nvme_msg(r, LOG_DEBUG, + nvme_msg(l->root, LOG_DEBUG, "%s: get %" PRIu64 " records (genctr %" PRIu64 ")\n", name, numrec, genctr); - log_args.lpo = sizeof(*log); - log_args.log = log->entries; - log_args.len = entries_size; - if (nvme_get_log_page(fd, NVME_LOG_PAGE_PDU_SIZE, &log_args)) { - nvme_msg(r, LOG_INFO, + err = nvme_get_log(l, NVME_NSID_NONE, false, args->lsp, + NVME_LOG_LID_DISCOVER, NVME_LOG_LSI_NONE, NVME_CSI_NVM, + false, NVME_UUID_NONE, + sizeof(*log), log->entries, entries_size, + NVME_LOG_PAGE_PDU_SIZE, NULL); + if (err) { + nvme_msg(l->root, LOG_INFO, "%s: discover try %d/%d failed, error %d\n", - name, retries, args->max_retries, errno); + name, retries, args->max_retries, err); goto out_free_log; } @@ -1205,36 +1178,39 @@ static struct nvmf_discovery_log *nvme_discovery_log( * If the log page was read with multiple Get Log Page commands, * genctr must be checked afterwards to ensure atomicity */ - nvme_msg(r, LOG_DEBUG, "%s: get header again\n", name); - - log_args.lpo = 0; - log_args.log = log; - log_args.len = DISCOVERY_HEADER_LEN; - if (nvme_get_log_page(fd, NVME_LOG_PAGE_PDU_SIZE, &log_args)) { - nvme_msg(r, LOG_INFO, + nvme_msg(l->root, LOG_DEBUG, "%s: get header again\n", name); + + err = nvme_get_log(l, NVME_NSID_NONE, false, args->lsp, + NVME_LOG_LID_DISCOVER, NVME_LOG_LSI_NONE, NVME_CSI_NVM, + false, NVME_UUID_NONE, + 0, log, DISCOVERY_HEADER_LEN, + NVME_LOG_PAGE_PDU_SIZE, NULL); + if (err) { + nvme_msg(l->root, LOG_INFO, "%s: discover try %d/%d failed, error %d\n", - name, retries, args->max_retries, errno); + name, retries, args->max_retries, err); goto out_free_log; } } while (genctr != le64_to_cpu(log->genctr) && ++retries < args->max_retries); if (genctr != le64_to_cpu(log->genctr)) { - nvme_msg(r, LOG_INFO, "%s: discover genctr mismatch\n", name); - errno = EAGAIN; + nvme_msg(l->root, LOG_INFO, "%s: discover genctr mismatch\n", name); + err = -EAGAIN; } else if (numrec != le64_to_cpu(log->numrec)) { - nvme_msg(r, LOG_INFO, + nvme_msg(l->root, LOG_INFO, "%s: numrec changed unexpectedly " "from %" PRIu64 " to %" PRIu64 "\n", name, numrec, le64_to_cpu(log->numrec)); - errno = EBADSLT; + err = -EBADSLT; } else { - return log; + *logp = log; + return 0; } out_free_log: free(log); - return NULL; + return err; } static void sanitize_discovery_log_entry(struct nvmf_disc_log_entry *e) @@ -1253,22 +1229,25 @@ int nvmf_get_discovery_log(nvme_ctrl_t c, struct nvmf_discovery_log **logp, .lsp = NVMF_LOG_DISC_LSP_NONE, }; - *logp = nvmf_get_discovery_wargs(&args); - return *logp ? 0 : -1; + + return nvmf_get_discovery_wargs(&args, logp); } -struct nvmf_discovery_log *nvmf_get_discovery_wargs(struct nvme_get_discovery_args *args) +int nvmf_get_discovery_wargs(struct nvme_get_discovery_args *args, + struct nvmf_discovery_log **logp) { struct nvmf_discovery_log *log; + int err; - log = nvme_discovery_log(args); - if (!log) - return NULL; + err = nvme_discovery_log(args, &log); + if (err) + return err; for (int i = 0; i < le64_to_cpu(log->numrec); i++) sanitize_discovery_log_entry(&log->entries[i]); - return log; + *logp = log; + return 0; } static int uuid_from_device_tree(char *system_uuid) @@ -1622,52 +1601,39 @@ static int nvmf_dim(nvme_ctrl_t c, enum nvmf_dim_tas tas, __u8 trtype, __u32 tel; int ret; - struct nvme_dim_args args = { - .args_size = sizeof(args), - .fd = nvme_ctrl_get_fd(c), - .result = result, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .tas = tas - }; - if (!c->s) { nvme_msg(r, LOG_ERR, "%s: failed to perform DIM. subsystem undefined.\n", c->name); - errno = EINVAL; - return -1; + return -EINVAL; } if (!c->s->h) { nvme_msg(r, LOG_ERR, "%s: failed to perform DIM. host undefined.\n", c->name); - errno = EINVAL; - return -1; + return -EINVAL; } if (!c->s->h->hostid) { nvme_msg(r, LOG_ERR, "%s: failed to perform DIM. hostid undefined.\n", c->name); - errno = EINVAL; - return -1; + return -EINVAL; } if (!c->s->h->hostnqn) { nvme_msg(r, LOG_ERR, "%s: failed to perform DIM. hostnqn undefined.\n", c->name); - errno = EINVAL; - return -1; + return -EINVAL; } if (strcmp(c->transport, "tcp")) { nvme_msg(r, LOG_ERR, "%s: DIM only supported for TCP connections.\n", c->name); - errno = EINVAL; - return -1; + return -EINVAL; } /* Register one Discovery Information Entry (DIE) of size TEL */ @@ -1676,8 +1642,7 @@ static int nvmf_dim(nvme_ctrl_t c, enum nvmf_dim_tas tas, __u8 trtype, dim = (struct nvmf_dim_data *)calloc(1, tdl); if (!dim) { - errno = ENOMEM; - return -1; + return -ENOMEM; } dim->tdl = cpu_to_le32(tdl); @@ -1692,7 +1657,7 @@ static int nvmf_dim(nvme_ctrl_t c, enum nvmf_dim_tas tas, __u8 trtype, ret = get_entity_name(dim->ename, sizeof(dim->ename)); if (ret <= 0) nvme_msg(r, LOG_INFO, "%s: Failed to retrieve ENAME. %s.\n", - c->name, strerror(errno)); + c->name, strerror(ret)); ret = get_entity_version(dim->ever, sizeof(dim->ever)); if (ret <= 0) @@ -1701,9 +1666,7 @@ static int nvmf_dim(nvme_ctrl_t c, enum nvmf_dim_tas tas, __u8 trtype, die = &dim->die->extended; nvmf_fill_die(die, c->s->h, tel, trtype, adrfam, reg_addr, tsas); - args.data_len = tdl; - args.data = dim; - return nvme_dim_send(&args); + return nvme_dim_send(nvme_ctrl_get_link(c), tas, dim, tdl, result); } /** @@ -1714,7 +1677,7 @@ static int nvmf_dim(nvme_ctrl_t c, enum nvmf_dim_tas tas, __u8 trtype, * address from the socket, then we'll infer the address family from the * address of the DC since the DC address has the same address family. * - * @ctrl: Host NVMe controller instance maintaining the admin queue used to + * @c: Host NVMe controller instance maintaining the admin queue used to * submit the DIM command to the DC. * * Return: The address family of the source address associated with the @@ -1761,10 +1724,8 @@ static int nvme_fetch_cntrltype_dctype_from_id(nvme_ctrl_t c) int ret; id = __nvme_alloc(sizeof(*id)); - if (!id) { - errno = ENOMEM; - return -1; - } + if (!id) + return -ENOMEM; ret = nvme_ctrl_identify(c, id); if (ret) @@ -1797,10 +1758,8 @@ bool nvmf_is_registration_supported(nvme_ctrl_t c) int nvmf_register_ctrl(nvme_ctrl_t c, enum nvmf_dim_tas tas, __u32 *result) { - if (!nvmf_is_registration_supported(c)) { - errno = ENOTSUP; - return -1; - } + if (!nvmf_is_registration_supported(c)) + return -ENOTSUP; /* We're registering our source address with the DC. To do * that, we can simply send an empty string. This tells the DC @@ -1838,7 +1797,7 @@ static char *unescape_uri(const char *str, int len) return dst; } -struct nvme_fabrics_uri *nvme_parse_uri(const char *str) +int nvme_parse_uri(const char *str, struct nvme_fabrics_uri **urip) { struct nvme_fabrics_uri *uri; _cleanup_free_ char *scheme = NULL; @@ -1863,20 +1822,18 @@ struct nvme_fabrics_uri *nvme_parse_uri(const char *str) uri = calloc(1, sizeof(struct nvme_fabrics_uri)); if (!uri) - return NULL; + return -ENOMEM; if (sscanf(str, "%m[^:/]://%m[^/?#]%ms", &scheme, &authority, &path) < 2) { nvme_free_uri(uri); - errno = EINVAL; - return NULL; + return -EINVAL; } if (sscanf(scheme, "%m[^+]+%ms", &uri->scheme, &uri->protocol) < 1) { nvme_free_uri(uri); - errno = EINVAL; - return NULL; + return -EINVAL; } /* split userinfo */ @@ -1894,8 +1851,7 @@ struct nvme_fabrics_uri *nvme_parse_uri(const char *str) if (sscanf(host, "%m[^:]:%d", &h, &uri->port) < 1) { nvme_free_uri(uri); - errno = EINVAL; - return NULL; + return -EINVAL; } uri->host = unescape_uri(h, 0); } @@ -1934,7 +1890,8 @@ struct nvme_fabrics_uri *nvme_parse_uri(const char *str) } } - return uri; + *urip = uri; + return 0; } void nvme_free_uri(struct nvme_fabrics_uri *uri) diff --git a/src/nvme/fabrics.h b/src/nvme/fabrics.h index 4c84bd32f..01d3db6bd 100644 --- a/src/nvme/fabrics.h +++ b/src/nvme/fabrics.h @@ -219,7 +219,7 @@ void nvmf_update_config(nvme_ctrl_t c, const struct nvme_fabrics_config *cfg); * into the topology using @h as parent. * @c must be initialized and not connected to the topology. * - * Return: 0 on success; on failure errno is set and -1 is returned. + * Return: 0 on success, or an error code on failure. */ int nvmf_add_ctrl(nvme_host_t h, nvme_ctrl_t c, const struct nvme_fabrics_config *cfg); @@ -231,14 +231,14 @@ int nvmf_add_ctrl(nvme_host_t h, nvme_ctrl_t c, * Issues a 'connect' command to the NVMe-oF controller. * @c must be initialized and not connected to the topology. * - * Return: 0 on success; on failure errno is set and -1 is returned. + * Return: 0 on success, or an error code on failure. */ int nvmf_connect_ctrl(nvme_ctrl_t c); /** * nvmf_get_discovery_log() - Return the discovery log page * @c: Discovery controller to use - * @logp: Pointer to the log page to be returned + * @logp: Log page object to return * @max_retries: Number of retries in case of failure * * The memory allocated for the log page and returned in @logp @@ -246,7 +246,7 @@ int nvmf_connect_ctrl(nvme_ctrl_t c); * * Note: Consider using nvmf_get_discovery_wargs() instead. * - * Return: 0 on success; on failure -1 is returned and errno is set + * Return: 0 on success, or an error code on failure. */ int nvmf_get_discovery_log(nvme_ctrl_t c, struct nvmf_discovery_log **logp, int max_retries); @@ -272,6 +272,7 @@ struct nvme_get_discovery_args { /** * nvmf_get_discovery_wargs() - Get the discovery log page with args * @args: Argument structure + * @log: Discovery log page object to return * * This function is similar to nvmf_get_discovery_log(), but * takes an extensible @args parameter. @args provides more @@ -281,10 +282,10 @@ struct nvme_get_discovery_args { * and returns the DLP. The memory allocated for the returned * DLP must be freed by the caller using free(). * - * Return: Pointer to the discovery log page (to be freed). NULL - * on failure and errno is set. + * Return: 0 on success, or an error code on failure. */ -struct nvmf_discovery_log *nvmf_get_discovery_wargs(struct nvme_get_discovery_args *args); +int nvmf_get_discovery_wargs(struct nvme_get_discovery_args *args, + struct nvmf_discovery_log **log); /** * nvmf_hostnqn_generate() - Generate a machine specific host nqn @@ -343,12 +344,15 @@ char *nvmf_hostid_from_file(); * @e: Discovery log page entry * @defcfg: Default configuration to be used for the new controller * @discover: Set to 'true' if the new controller is a discovery controller + * @c: crtl object to return * - * Return: Pointer to the new controller + * Return: 0 on success, or an error code on failure. */ -nvme_ctrl_t nvmf_connect_disc_entry(nvme_host_t h, - struct nvmf_disc_log_entry *e, - const struct nvme_fabrics_config *defcfg, bool *discover); +int nvmf_connect_disc_entry(nvme_host_t h, + struct nvmf_disc_log_entry *e, + const struct nvme_fabrics_config *defcfg, + bool *discover, + nvme_ctrl_t *c); /** * nvmf_is_registration_supported - check whether registration can be performed. @@ -376,13 +380,14 @@ bool nvmf_is_registration_supported(nvme_ctrl_t c); * Perform registration task with a Discovery Controller (DC). Three * tasks are supported: register, deregister, and registration update. * - * Return: 0 on success; on failure -1 is returned and errno is set + * Return: 0 on success, or an error code on failure. */ int nvmf_register_ctrl(nvme_ctrl_t c, enum nvmf_dim_tas tas, __u32 *result); /** * nvme_parse_uri() - Parse the URI string * @str: URI string + * @uri: URI object to return * * Parse the URI string as defined in the NVM Express Boot Specification. * Supported URI elements looks as follows: @@ -392,7 +397,7 @@ int nvmf_register_ctrl(nvme_ctrl_t c, enum nvmf_dim_tas tas, __u32 *result); * Return: &nvme_fabrics_uri structure on success; NULL on failure with errno * set. */ -struct nvme_fabrics_uri *nvme_parse_uri(const char *str); +int nvme_parse_uri(const char *str, struct nvme_fabrics_uri **uri); /** * nvme_free_uri() - Free the URI structure diff --git a/src/nvme/ioctl.c b/src/nvme/ioctl.c index 567358916..da506c11c 100644 --- a/src/nvme/ioctl.c +++ b/src/nvme/ioctl.c @@ -29,83 +29,97 @@ #include "ioctl.h" #include "util.h" #include "log.h" +#include "private.h" -static int nvme_verify_chr(int fd) +static int nvme_verify_chr(nvme_link_t l) { static struct stat nvme_stat; - int err = fstat(fd, &nvme_stat); + int err = fstat(l->fd, &nvme_stat); if (err < 0) - return errno; + return -errno; - if (!S_ISCHR(nvme_stat.st_mode)) { - errno = ENOTBLK; - return -1; - } + if (!S_ISCHR(nvme_stat.st_mode)) + return -ENOTBLK; return 0; } -int nvme_subsystem_reset(int fd) +int nvme_subsystem_reset(nvme_link_t l) { int ret; - ret = nvme_verify_chr(fd); + ret = nvme_verify_chr(l); if (ret) return ret; - return ioctl(fd, NVME_IOCTL_SUBSYS_RESET); + ret = ioctl(l->fd, NVME_IOCTL_SUBSYS_RESET); + if (ret < 0) + return -errno; + return ret; } -int nvme_ctrl_reset(int fd) +int nvme_ctrl_reset(nvme_link_t l) { int ret; - ret = nvme_verify_chr(fd); + ret = nvme_verify_chr(l); if (ret) return ret; - return ioctl(fd, NVME_IOCTL_RESET); + ret = ioctl(l->fd, NVME_IOCTL_RESET); + if (ret < 0) + return -errno; + return ret; } -int nvme_ns_rescan(int fd) +int nvme_ns_rescan(nvme_link_t l) { int ret; - ret = nvme_verify_chr(fd); + ret = nvme_verify_chr(l); if (ret) return ret; - return ioctl(fd, NVME_IOCTL_RESCAN); + ret = ioctl(l->fd, NVME_IOCTL_RESCAN); + if (ret < 0) + return -errno; + return ret; } -int nvme_get_nsid(int fd, __u32 *nsid) +int nvme_get_nsid(nvme_link_t l, __u32 *nsid) { errno = 0; - *nsid = ioctl(fd, NVME_IOCTL_ID); - return -1 * (errno != 0); + *nsid = ioctl(l->fd, NVME_IOCTL_ID); + if (errno) + return -errno; + return 0; } __attribute__((weak)) -int nvme_submit_passthru64(int fd, unsigned long ioctl_cmd, +int nvme_submit_passthru64(nvme_link_t l, unsigned long ioctl_cmd, struct nvme_passthru_cmd64 *cmd, __u64 *result) { - int err = ioctl(fd, ioctl_cmd, cmd); + int err = ioctl(l->fd, ioctl_cmd, cmd); if (err >= 0 && result) *result = cmd->result; + if (err < 0) + return -errno; return err; } __attribute__((weak)) -int nvme_submit_passthru(int fd, unsigned long ioctl_cmd, +int nvme_submit_passthru(nvme_link_t l, unsigned long ioctl_cmd, struct nvme_passthru_cmd *cmd, __u32 *result) { - int err = ioctl(fd, ioctl_cmd, cmd); + int err = ioctl(l->fd, ioctl_cmd, cmd); if (err >= 0 && result) *result = cmd->result; + if (err < 0) + return -errno; return err; } -static int nvme_passthru64(int fd, unsigned long ioctl_cmd, __u8 opcode, +static int nvme_passthru64(nvme_link_t l, unsigned long ioctl_cmd, __u8 opcode, __u8 flags, __u16 rsvd, __u32 nsid, __u32 cdw2, __u32 cdw3, __u32 cdw10, __u32 cdw11, __u32 cdw12, __u32 cdw13, __u32 cdw14, __u32 cdw15, @@ -132,10 +146,10 @@ static int nvme_passthru64(int fd, unsigned long ioctl_cmd, __u8 opcode, .timeout_ms = timeout_ms, }; - return nvme_submit_passthru64(fd, ioctl_cmd, &cmd, result); + return nvme_submit_passthru64(l, ioctl_cmd, &cmd, result); } -static int nvme_passthru(int fd, unsigned long ioctl_cmd, __u8 opcode, +static int nvme_passthru(nvme_link_t l, unsigned long ioctl_cmd, __u8 opcode, __u8 flags, __u16 rsvd, __u32 nsid, __u32 cdw2, __u32 cdw3, __u32 cdw10, __u32 cdw11, __u32 cdw12, __u32 cdw13, __u32 cdw14, __u32 cdw15, __u32 data_len, @@ -162,164 +176,57 @@ static int nvme_passthru(int fd, unsigned long ioctl_cmd, __u8 opcode, .timeout_ms = timeout_ms, }; - return nvme_submit_passthru(fd, ioctl_cmd, &cmd, result); + return nvme_submit_passthru(l, ioctl_cmd, &cmd, result); } -int nvme_submit_admin_passthru64(int fd, struct nvme_passthru_cmd64 *cmd, +int nvme_submit_admin_passthru64(nvme_link_t l, struct nvme_passthru_cmd64 *cmd, __u64 *result) { - return nvme_submit_passthru64(fd, NVME_IOCTL_ADMIN64_CMD, cmd, result); + return nvme_submit_passthru64(l, NVME_IOCTL_ADMIN64_CMD, cmd, result); } -int nvme_admin_passthru64(int fd, __u8 opcode, __u8 flags, __u16 rsvd, +int nvme_admin_passthru64(nvme_link_t l, __u8 opcode, __u8 flags, __u16 rsvd, __u32 nsid, __u32 cdw2, __u32 cdw3, __u32 cdw10, __u32 cdw11, __u32 cdw12, __u32 cdw13, __u32 cdw14, __u32 cdw15, __u32 data_len, void *data, __u32 metadata_len, void *metadata, __u32 timeout_ms, __u64 *result) { - return nvme_passthru64(fd, NVME_IOCTL_ADMIN64_CMD, opcode, flags, rsvd, + return nvme_passthru64(l, NVME_IOCTL_ADMIN64_CMD, opcode, flags, rsvd, nsid, cdw2, cdw3, cdw10, cdw11, cdw12, cdw13, cdw14, cdw15, data_len, data, metadata_len, metadata, timeout_ms, result); } -int nvme_submit_admin_passthru(int fd, struct nvme_passthru_cmd *cmd, __u32 *result) +int nvme_submit_admin_passthru(nvme_link_t l, struct nvme_passthru_cmd *cmd, __u32 *result) { - return nvme_submit_passthru(fd, NVME_IOCTL_ADMIN_CMD, cmd, result); + switch (l->type) { + case NVME_LINK_TYPE_DIRECT: + return nvme_submit_passthru(l, NVME_IOCTL_ADMIN_CMD, cmd, result); + case NVME_LINK_TYPE_MI: + return nvme_mi_admin_admin_passthru( + l, cmd->opcode, cmd->flags, cmd->rsvd1, + cmd->nsid, cmd->cdw2, cmd->cdw3, cmd->cdw10, cmd->cdw11, cmd->cdw12, cmd->cdw13, + cmd->cdw14, cmd->cdw15, cmd->data_len, (void*)cmd->addr, cmd->metadata_len, + (void*)cmd->metadata, cmd->timeout_ms, result); + default: + return -ENOTSUP; + } } -int nvme_admin_passthru(int fd, __u8 opcode, __u8 flags, __u16 rsvd, +int nvme_admin_passthru(nvme_link_t l, __u8 opcode, __u8 flags, __u16 rsvd, __u32 nsid, __u32 cdw2, __u32 cdw3, __u32 cdw10, __u32 cdw11, __u32 cdw12, __u32 cdw13, __u32 cdw14, __u32 cdw15, __u32 data_len, void *data, __u32 metadata_len, void *metadata, __u32 timeout_ms, __u32 *result) { - return nvme_passthru(fd, NVME_IOCTL_ADMIN_CMD, opcode, flags, rsvd, + return nvme_passthru(l, NVME_IOCTL_ADMIN_CMD, opcode, flags, rsvd, nsid, cdw2, cdw3, cdw10, cdw11, cdw12, cdw13, cdw14, cdw15, data_len, data, metadata_len, metadata, timeout_ms, result); } -enum features { - NVME_FEATURES_ARBITRATION_BURST_SHIFT = 0, - NVME_FEATURES_ARBITRATION_LPW_SHIFT = 8, - NVME_FEATURES_ARBITRATION_MPW_SHIFT = 16, - NVME_FEATURES_ARBITRATION_HPW_SHIFT = 24, - NVME_FEATURES_ARBITRATION_BURST_MASK = 0x7, - NVME_FEATURES_ARBITRATION_LPW_MASK = 0xff, - NVME_FEATURES_ARBITRATION_MPW_MASK = 0xff, - NVME_FEATURES_ARBITRATION_HPW_MASK = 0xff, - NVME_FEATURES_PWRMGMT_PS_SHIFT = 0, - NVME_FEATURES_PWRMGMT_WH_SHIFT = 5, - NVME_FEATURES_PWRMGMT_PS_MASK = 0x1f, - NVME_FEATURES_PWRMGMT_WH_MASK = 0x7, - NVME_FEATURES_TMPTH_SHIFT = 0, - NVME_FEATURES_TMPSEL_SHIFT = 16, - NVME_FEATURES_THSEL_SHIFT = 20, - NVME_FEATURES_TMPTH_MASK = 0xff, - NVME_FEATURES_TMPSEL_MASK = 0xf, - NVME_FEATURES_THSEL_MASK = 0x3, - NVME_FEATURES_ERROR_RECOVERY_TLER_SHIFT = 0, - NVME_FEATURES_ERROR_RECOVERY_DULBE_SHIFT = 16, - NVME_FEATURES_ERROR_RECOVERY_TLER_MASK = 0xff, - NVME_FEATURES_ERROR_RECOVERY_DULBE_MASK = 0x1, - NVME_FEATURES_VWC_WCE_SHIFT = 0, - NVME_FEATURES_VWC_WCE_MASK = 0x1, - NVME_FEATURES_IRQC_THR_SHIFT = 0, - NVME_FEATURES_IRQC_TIME_SHIFT = 8, - NVME_FEATURES_IRQC_THR_MASK = 0xff, - NVME_FEATURES_IRQC_TIME_MASK = 0xff, - NVME_FEATURES_IVC_IV_SHIFT = 0, - NVME_FEATURES_IVC_CD_SHIFT = 16, - NVME_FEATURES_IVC_IV_MASK = 0xffff, - NVME_FEATURES_IVC_CD_MASK = 0x1, - NVME_FEATURES_WAN_DN_SHIFT = 0, - NVME_FEATURES_WAN_DN_MASK = 0x1, - NVME_FEATURES_APST_APSTE_SHIFT = 0, - NVME_FEATURES_APST_APSTE_MASK = 0x1, - NVME_FEATURES_HCTM_TMT2_SHIFT = 0, - NVME_FEATURES_HCTM_TMT1_SHIFT = 16, - NVME_FEATURES_HCTM_TMT2_MASK = 0xffff, - NVME_FEATURES_HCTM_TMT1_MASK = 0xffff, - NVME_FEATURES_NOPS_NOPPME_SHIFT = 0, - NVME_FEATURES_NOPS_NOPPME_MASK = 0x1, - NVME_FEATURES_PLM_PLE_SHIFT = 0, - NVME_FEATURES_PLM_PLE_MASK = 0x1, - NVME_FEATURES_PLM_WINDOW_SELECT_SHIFT = 0, - NVME_FEATURES_PLM_WINDOW_SELECT_MASK = 0xf, - NVME_FEATURES_LBAS_LSIRI_SHIFT = 0, - NVME_FEATURES_LBAS_LSIPI_SHIFT = 16, - NVME_FEATURES_LBAS_LSIRI_MASK = 0xffff, - NVME_FEATURES_LBAS_LSIPI_MASK = 0xffff, - NVME_FEATURES_IOCSP_IOCSCI_SHIFT = 0, - NVME_FEATURES_IOCSP_IOCSCI_MASK = 0xff, -}; - -int nvme_identify(struct nvme_identify_args *args) -{ - __u32 cdw10 = NVME_SET(args->cntid, IDENTIFY_CDW10_CNTID) | - NVME_SET(args->cns, IDENTIFY_CDW10_CNS); - __u32 cdw11 = NVME_SET(args->cns_specific_id, IDENTIFY_CDW11_CNSSPECID) | - NVME_SET(args->csi, IDENTIFY_CDW11_CSI); - __u32 cdw14 = NVME_SET(args->uuidx, IDENTIFY_CDW14_UUID); - - struct nvme_passthru_cmd cmd = { - .opcode = nvme_admin_identify, - .nsid = args->nsid, - .addr = (__u64)(uintptr_t)args->data, - .data_len = NVME_IDENTIFY_DATA_SIZE, - .cdw10 = cdw10, - .cdw11 = cdw11, - .cdw14 = cdw14, - .timeout_ms = args->timeout, - }; - - if (args->args_size < sizeof(*args)) { - errno = EINVAL; - return -1; - } - return nvme_submit_admin_passthru(args->fd, &cmd, args->result); -} - -int nvme_get_log(struct nvme_get_log_args *args) -{ - __u32 numd = (args->len >> 2) - 1; - __u16 numdu = numd >> 16, numdl = numd & 0xffff; - - __u32 cdw10 = NVME_SET(args->lid, LOG_CDW10_LID) | - NVME_SET(args->lsp, LOG_CDW10_LSP) | - NVME_SET(!!args->rae, LOG_CDW10_RAE) | - NVME_SET(numdl, LOG_CDW10_NUMDL); - __u32 cdw11 = NVME_SET(numdu, LOG_CDW11_NUMDU) | - NVME_SET(args->lsi, LOG_CDW11_LSI); - __u32 cdw12 = args->lpo & 0xffffffff; - __u32 cdw13 = args->lpo >> 32; - __u32 cdw14 = NVME_SET(args->uuidx, LOG_CDW14_UUID) | - NVME_SET(!!args->ot, LOG_CDW14_OT) | - NVME_SET(args->csi, LOG_CDW14_CSI); - - struct nvme_passthru_cmd cmd = { - .opcode = nvme_admin_get_log_page, - .nsid = args->nsid, - .addr = (__u64)(uintptr_t)args->log, - .data_len = args->len, - .cdw10 = cdw10, - .cdw11 = cdw11, - .cdw12 = cdw12, - .cdw13 = cdw13, - .cdw14 = cdw14, - .timeout_ms = args->timeout, - }; - - if (args->args_size < sizeof(struct nvme_get_log_args)) { - errno = EINVAL; - return -1; - } - return nvme_submit_admin_passthru(args->fd, &cmd, args->result); -} - static bool force_4k; __attribute__((constructor)) @@ -362,8 +269,10 @@ static void nvme_uring_cmd_probe() static int nvme_uring_cmd_setup(struct io_uring *ring) { - return io_uring_queue_init(NVME_URING_ENTRIES, ring, - IORING_SETUP_SQE128 | IORING_SETUP_CQE32); + if (io_uring_queue_init(NVME_URING_ENTRIES, ring, + IORING_SETUP_SQE128 | IORING_SETUP_CQE32)) + return -errno; + return 0; } static void nvme_uring_cmd_exit(struct io_uring *ring) @@ -371,79 +280,45 @@ static void nvme_uring_cmd_exit(struct io_uring *ring) io_uring_queue_exit(ring); } -static int nvme_uring_cmd_admin_passthru_async(struct io_uring *ring, struct nvme_get_log_args *args) +static int nvme_uring_cmd_admin_passthru_async(nvme_link_t l, struct io_uring *ring, + struct nvme_passthru_cmd *cmd, __u32 *result) { struct io_uring_sqe *sqe; - struct nvme_uring_cmd *cmd; int ret; - __u32 numd = (args->len >> 2) - 1; - __u16 numdu = numd >> 16, numdl = numd & 0xffff; - - __u32 cdw10 = NVME_SET(args->lid, LOG_CDW10_LID) | - NVME_SET(args->lsp, LOG_CDW10_LSP) | - NVME_SET(!!args->rae, LOG_CDW10_RAE) | - NVME_SET(numdl, LOG_CDW10_NUMDL); - __u32 cdw11 = NVME_SET(numdu, LOG_CDW11_NUMDU) | - NVME_SET(args->lsi, LOG_CDW11_LSI); - __u32 cdw12 = args->lpo & 0xffffffff; - __u32 cdw13 = args->lpo >> 32; - __u32 cdw14 = NVME_SET(args->uuidx, LOG_CDW14_UUID) | - NVME_SET(!!args->ot, LOG_CDW14_OT) | - NVME_SET(args->csi, LOG_CDW14_CSI); - - if (args->args_size < sizeof(struct nvme_get_log_args)) { - errno = EINVAL; - return -1; - } - sqe = io_uring_get_sqe(ring); if (!sqe) return -1; - cmd = (void *)&sqe->cmd; - cmd->opcode = nvme_admin_get_log_page, - cmd->nsid = args->nsid, - cmd->addr = (__u64)(uintptr_t)args->log, - cmd->data_len = args->len, - cmd->cdw10 = cdw10, - cmd->cdw11 = cdw11, - cmd->cdw12 = cdw12, - cmd->cdw13 = cdw13, - cmd->cdw14 = cdw14, - cmd->timeout_ms = args->timeout, - - sqe->fd = args->fd; + memcpy(&sqe->cmd, cmd, sizeof(*cmd)); + + sqe->fd = l->fd; sqe->opcode = IORING_OP_URING_CMD; sqe->cmd_op = NVME_URING_CMD_ADMIN; - sqe->user_data = (__u64)(uintptr_t)args; + sqe->user_data = (__u64)(uintptr_t)result; ret = io_uring_submit(ring); - if (ret < 0) { - errno = -ret; - return -1; - } + if (ret < 0) + return -errno; return 0; } static int nvme_uring_cmd_wait_complete(struct io_uring *ring, int n) { - struct nvme_get_log_args *args; struct io_uring_cqe *cqe; int i, ret = 0; + __u32 *result; for (i = 0; i < n; i++) { ret = io_uring_wait_cqe(ring, &cqe); - if (ret) { - errno = -ret; + if (ret) return -1; - } if (cqe->res) { - args = (struct nvme_get_log_args *)cqe->user_data; - if (args->result) - *args->result = cqe->res; + result = (__u32 *)cqe->user_data; + if (result) + *result = cqe->res; ret = cqe->res; break; } @@ -453,36 +328,49 @@ static int nvme_uring_cmd_wait_complete(struct io_uring *ring, int n) return ret; } -#endif -int nvme_get_log_page(int fd, __u32 xfer_len, struct nvme_get_log_args *args) +static bool nvme_uring_is_usable(nvme_link_t l) { - __u64 offset = 0, xfer, data_len = args->len; - __u64 start = args->lpo; - bool retain = args->rae; - void *ptr = args->log; - int ret; + struct stat st; - args->fd = fd; + if (io_uring_kernel_support != IO_URING_AVAILABLE || l->type != NVME_LINK_TYPE_DIRECT || + fstat(l->fd, &st) || !S_ISCHR(st.st_mode)) + return false; - if (force_4k) - xfer_len = NVME_LOG_PAGE_PDU_SIZE; + return true; +} +#endif /* CONFIG_LIBURING */ +int nvme_get_log_partial(nvme_link_t l, struct nvme_passthru_cmd *cmd, + __u64 lpo, void *log, __u32 len, + __u32 xfer_len, __u32 *result) +{ + __u64 offset = 0, xfer, data_len = len; + __u64 start = lpo; + void *ptr = log; + int ret; + bool rae; + __u32 numd; + __u16 numdu, numdl; + bool retain = NVME_GET(cmd->cdw10, LOG_CDW10_RAE); + __u32 cdw10 = cmd->cdw10 & (NVME_VAL(LOG_CDW10_LID) | + NVME_VAL(LOG_CDW10_LSP)); + __u32 cdw11 = cmd->cdw11 & NVME_VAL(LOG_CDW11_LSI); #ifdef CONFIG_LIBURING - int n = 0; + bool use_uring = nvme_uring_is_usable(l); struct io_uring ring; - struct stat st; - bool use_uring = false; - - if (io_uring_kernel_support == IO_URING_AVAILABLE) { - if (fstat(fd, &st) == 0 && S_ISCHR(st.st_mode)) { - use_uring = true; + int n = 0; - if (nvme_uring_cmd_setup(&ring)) - return -1; - } + if (use_uring) { + ret = nvme_uring_cmd_setup(&ring); + if (ret) + return ret; } -#endif +#endif /* CONFIG_LIBURING */ + + if (force_4k) + xfer_len = NVME_LOG_PAGE_PDU_SIZE; + /* * 4k is the smallest possible transfer unit, so restricting to 4k * avoids having to check the MDTS value of the controller. @@ -501,24 +389,42 @@ int nvme_get_log_page(int fd, __u32 xfer_len, struct nvme_get_log_args *args) * last portion of this log page so the data remains latched * during the fetch sequence. */ - args->lpo = start + offset; - args->len = xfer; - args->log = ptr; - args->rae = offset + xfer < data_len || retain; + lpo = start + offset; + numd = (xfer >> 2) - 1; + numdu = numd >> 16; + numdl = numd & 0xffff; + rae = offset + xfer < data_len || retain; + + cmd->cdw10 = cdw10 | + NVME_SET(!!rae, LOG_CDW10_RAE) | + NVME_SET(numdl, LOG_CDW10_NUMDL); + cmd->cdw11 = cdw11 | + NVME_SET(numdu, LOG_CDW11_NUMDU); + cmd->cdw12 = lpo & 0xffffffff; + cmd->cdw13 = lpo >> 32; + cmd->data_len = xfer; + cmd->addr = (__u64)(uintptr_t)ptr; + #ifdef CONFIG_LIBURING - if (io_uring_kernel_support == IO_URING_AVAILABLE && use_uring) { + if (use_uring) { if (n >= NVME_URING_ENTRIES) { - ret = nvme_uring_cmd_wait_complete(&ring, n); + nvme_uring_cmd_wait_complete(&ring, n); n = 0; } n += 1; - ret = nvme_uring_cmd_admin_passthru_async(&ring, args); + ret = nvme_uring_cmd_admin_passthru_async(l, &ring, cmd, result); if (ret) nvme_uring_cmd_exit(&ring); - } else -#endif - ret = nvme_get_log(args); + } else { + ret = nvme_submit_admin_passthru(l, cmd, result); + if (ret) + return ret; + } +#else /* CONFIG_LIBURING */ + ret = nvme_submit_admin_passthru(l, cmd, result); +#endif /* CONFIG_LIBURING */ + if (ret) return ret; @@ -527,29 +433,28 @@ int nvme_get_log_page(int fd, __u32 xfer_len, struct nvme_get_log_args *args) } while (offset < data_len); #ifdef CONFIG_LIBURING - if (io_uring_kernel_support == IO_URING_AVAILABLE && use_uring) { - ret = nvme_uring_cmd_wait_complete(&ring, n); + if (use_uring) { + nvme_uring_cmd_wait_complete(&ring, n); nvme_uring_cmd_exit(&ring); if (ret) return ret; } -#endif +#endif /* CONFIG_LIBURING */ + return 0; } -static int read_ana_chunk(int fd, enum nvme_log_ana_lsp lsp, bool rae, +static int read_ana_chunk(nvme_link_t l, enum nvme_log_ana_lsp lsp, bool rae, __u8 *log, __u8 **read, __u8 *to_read, __u8 *log_end) { - if (to_read > log_end) { - errno = ENOSPC; - return -1; - } + if (to_read > log_end) + return -ENOSPC; while (*read < to_read) { __u32 len = min_t(__u32, log_end - *read, NVME_LOG_PAGE_PDU_SIZE); int ret; - ret = nvme_get_log_ana(fd, lsp, rae, *read - log, len, *read); + ret = nvme_get_log_ana(l, rae, lsp, *read - log, *read, len); if (ret) return ret; @@ -558,7 +463,7 @@ static int read_ana_chunk(int fd, enum nvme_log_ana_lsp lsp, bool rae, return 0; } -static int try_read_ana(int fd, enum nvme_log_ana_lsp lsp, bool rae, +static int try_read_ana(nvme_link_t l, enum nvme_log_ana_lsp lsp, bool rae, struct nvme_ana_log *log, __u8 *log_end, __u8 *read, __u8 **to_read, bool *may_retry) { @@ -570,7 +475,7 @@ static int try_read_ana(int fd, enum nvme_log_ana_lsp lsp, bool rae, __le32 nnsids; *to_read += sizeof(*log->descs); - ret = read_ana_chunk(fd, lsp, rae, + ret = read_ana_chunk(l, lsp, rae, (__u8 *)log, &read, *to_read, log_end); if (ret) { /* @@ -579,7 +484,7 @@ static int try_read_ana(int fd, enum nvme_log_ana_lsp lsp, bool rae, * and the computed length was inaccurate. * Have the caller check chgcnt and retry. */ - *may_retry = errno == ENOSPC; + *may_retry = ret == -ENOSPC; return ret; } @@ -592,10 +497,10 @@ static int try_read_ana(int fd, enum nvme_log_ana_lsp lsp, bool rae, group + offsetof(struct nvme_ana_group_desc, nnsids), sizeof(nnsids)); *to_read += le32_to_cpu(nnsids) * sizeof(__le32); - ret = read_ana_chunk(fd, lsp, rae, + ret = read_ana_chunk(l, lsp, rae, (__u8 *)log, &read, *to_read, log_end); if (ret) { - *may_retry = errno == ENOSPC; + *may_retry = ret == -ENOSPC; return ret; } } @@ -604,8 +509,9 @@ static int try_read_ana(int fd, enum nvme_log_ana_lsp lsp, bool rae, return 0; } -int nvme_get_ana_log_atomic(int fd, bool rgo, bool rae, unsigned int retries, - struct nvme_ana_log *log, __u32 *len) +int nvme_get_ana_log_atomic(nvme_link_t l, bool rae, bool rgo, + struct nvme_ana_log *log, __u32 *len, + unsigned int retries) { const enum nvme_log_ana_lsp lsp = rgo ? NVME_LOG_ANA_LSP_RGO_GROUPS_ONLY : 0; @@ -615,13 +521,11 @@ int nvme_get_ana_log_atomic(int fd, bool rgo, bool rae, unsigned int retries, __u8 *to_read; int ret; - if (!retries) { - errno = EINVAL; - return -1; - } + if (!retries) + return -EINVAL; to_read = (__u8 *)log->descs; - ret = read_ana_chunk(fd, lsp, rae, + ret = read_ana_chunk(l, lsp, rae, (__u8 *)log, &read, to_read, log_end); if (ret) return ret; @@ -632,7 +536,7 @@ int nvme_get_ana_log_atomic(int fd, bool rgo, bool rae, unsigned int retries, int saved_errno; __le64 chgcnt; - saved_ret = try_read_ana(fd, lsp, rae, log, log_end, + saved_ret = try_read_ana(l, lsp, rae, log, log_end, read, &to_read, &may_retry); /* * If the log page was read with multiple Get Log Page commands, @@ -646,7 +550,7 @@ int nvme_get_ana_log_atomic(int fd, bool rgo, bool rae, unsigned int retries, chgcnt = log->chgcnt; read = (__u8 *)log; to_read = (__u8 *)log->descs; - ret = read_ana_chunk(fd, lsp, rae, + ret = read_ana_chunk(l, lsp, rae, (__u8 *)log, &read, to_read, log_end); if (ret) return ret; @@ -658,1823 +562,40 @@ int nvme_get_ana_log_atomic(int fd, bool rgo, bool rae, unsigned int retries, } } while (--retries); - errno = EAGAIN; - return -1; -} - -int nvme_set_features(struct nvme_set_features_args *args) -{ - __u32 cdw10 = NVME_SET(args->fid, FEATURES_CDW10_FID) | - NVME_SET(!!args->save, SET_FEATURES_CDW10_SAVE); - __u32 cdw14 = NVME_SET(args->uuidx, FEATURES_CDW14_UUID); - - struct nvme_passthru_cmd cmd = { - .opcode = nvme_admin_set_features, - .nsid = args->nsid, - .addr = (__u64)(uintptr_t)args->data, - .data_len = args->data_len, - .cdw10 = cdw10, - .cdw11 = args->cdw11, - .cdw12 = args->cdw12, - .cdw13 = args->cdw13, - .cdw14 = cdw14, - .cdw15 = args->cdw15, - .timeout_ms = args->timeout, - }; - if (args->args_size < sizeof(*args)) { - errno = EINVAL; - return -1; - } - return nvme_submit_admin_passthru(args->fd, &cmd, args->result); -} - -static int __nvme_set_features(int fd, __u8 fid, __u32 cdw11, bool save, - __u32 *result) -{ - struct nvme_set_features_args args = { - .args_size = sizeof(args), - .fd = fd, - .fid = fid, - .nsid = NVME_NSID_NONE, - .cdw11 = cdw11, - .cdw12 = 0, - .save = save, - .uuidx = NVME_UUID_NONE, - .cdw15 = 0, - .data_len = 0, - .data = NULL, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .result = result, - }; - return nvme_set_features(&args); -} - -int nvme_set_features_arbitration(int fd, __u8 ab, __u8 lpw, __u8 mpw, - __u8 hpw, bool save, __u32 *result) -{ - __u32 value = NVME_SET(ab, FEAT_ARBITRATION_BURST) | - NVME_SET(lpw, FEAT_ARBITRATION_LPW) | - NVME_SET(mpw, FEAT_ARBITRATION_MPW) | - NVME_SET(hpw, FEAT_ARBITRATION_HPW); - - return __nvme_set_features(fd, NVME_FEAT_FID_ARBITRATION, value, save, - result); -} - -int nvme_set_features_power_mgmt(int fd, __u8 ps, __u8 wh, bool save, - __u32 *result) -{ - __u32 value = NVME_SET(ps, FEAT_PWRMGMT_PS) | - NVME_SET(wh, FEAT_PWRMGMT_WH); - - return __nvme_set_features(fd, NVME_FEAT_FID_POWER_MGMT, value, save, - result); -} - -int nvme_set_features_lba_range(int fd, __u32 nsid, __u8 nr_ranges, bool save, - struct nvme_lba_range_type *data, __u32 *result) -{ - return nvme_set_features_data( - fd, NVME_FEAT_FID_LBA_RANGE, nsid, nr_ranges - 1, save, - sizeof(*data), data, result); -} - -int nvme_set_features_temp_thresh(int fd, __u16 tmpth, __u8 tmpsel, - enum nvme_feat_tmpthresh_thsel thsel, __u8 tmpthh, - bool save, __u32 *result) -{ - __u32 value = NVME_SET(tmpth, FEAT_TT_TMPTH) | - NVME_SET(tmpsel, FEAT_TT_TMPSEL) | - NVME_SET(thsel, FEAT_TT_THSEL) | - NVME_SET(tmpthh, FEAT_TT_TMPTHH); - - return __nvme_set_features(fd, NVME_FEAT_FID_TEMP_THRESH, value, save, - result); -} - -int nvme_set_features_err_recovery(int fd, __u32 nsid, __u16 tler, bool dulbe, - bool save, __u32 *result) -{ - __u32 value = NVME_SET(tler, FEAT_ERROR_RECOVERY_TLER) | - NVME_SET(!!dulbe, FEAT_ERROR_RECOVERY_DULBE); - - return nvme_set_features_simple( - fd, NVME_FEAT_FID_ERR_RECOVERY, nsid, value, save, result); -} - -int nvme_set_features_volatile_wc(int fd, bool wce, bool save, __u32 *result) -{ - __u32 value = NVME_SET(!!wce, FEAT_VWC_WCE); - - return __nvme_set_features(fd, NVME_FEAT_FID_VOLATILE_WC, value, save, - result); -} - -int nvme_set_features_irq_coalesce(int fd, __u8 thr, __u8 time, bool save, - __u32 *result) -{ - __u32 value = NVME_SET(thr, FEAT_IRQC_THR) | - NVME_SET(time, FEAT_IRQC_TIME); - - return __nvme_set_features(fd, NVME_FEAT_FID_IRQ_COALESCE, value, save, - result); -} - -int nvme_set_features_irq_config(int fd, __u16 iv, bool cd, bool save, - __u32 *result) -{ - __u32 value = NVME_SET(iv, FEAT_ICFG_IV) | - NVME_SET(!!cd, FEAT_ICFG_CD); - - return __nvme_set_features(fd, NVME_FEAT_FID_IRQ_CONFIG, value, save, - result); -} - -int nvme_set_features_write_atomic(int fd, bool dn, bool save, __u32 *result) -{ - __u32 value = NVME_SET(!!dn, FEAT_WA_DN); - - return __nvme_set_features(fd, NVME_FEAT_FID_WRITE_ATOMIC, value, save, - result); -} - -int nvme_set_features_async_event(int fd, __u32 events, - bool save, __u32 *result) -{ - return __nvme_set_features(fd, NVME_FEAT_FID_ASYNC_EVENT, events, save, - result); -} - -int nvme_set_features_auto_pst(int fd, bool apste, bool save, - struct nvme_feat_auto_pst *apst, __u32 *result) -{ - return nvme_set_features_data(fd, NVME_FEAT_FID_AUTO_PST, - NVME_NSID_NONE, NVME_SET(!!apste, FEAT_APST_APSTE), save, - sizeof(*apst), apst, result); -} - -int nvme_set_features_timestamp(int fd, bool save, __u64 timestamp) -{ - __le64 t = cpu_to_le64(timestamp); - struct nvme_timestamp ts = {}; - memcpy(ts.timestamp, &t, sizeof(ts.timestamp)); - - return nvme_set_features_data(fd, NVME_FEAT_FID_TIMESTAMP, - NVME_NSID_NONE, 0, save, sizeof(ts), &ts, NULL); -} - -int nvme_set_features_hctm(int fd, __u16 tmt2, __u16 tmt1, - bool save, __u32 *result) -{ - __u32 value = NVME_SET(tmt2, FEAT_HCTM_TMT2) | - NVME_SET(tmt1, FEAT_HCTM_TMT1); - - return __nvme_set_features(fd, NVME_FEAT_FID_HCTM, value, save, - result); -} - -int nvme_set_features_nopsc(int fd, bool noppme, bool save, __u32 *result) -{ - __u32 value = NVME_SET(noppme, FEAT_NOPS_NOPPME); - - return __nvme_set_features(fd, NVME_FEAT_FID_NOPSC, value, save, - result); -} - -int nvme_set_features_rrl(int fd, __u8 rrl, __u16 nvmsetid, - bool save, __u32 *result) -{ - struct nvme_set_features_args args = { - .args_size = sizeof(args), - .fd = fd, - .fid = NVME_FEAT_FID_RRL, - .nsid = NVME_NSID_NONE, - .cdw11 = nvmsetid, - .cdw12 = rrl, - .save = save, - .uuidx = NVME_UUID_NONE, - .cdw15 = 0, - .data_len = 0, - .data = NULL, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .result = result, - }; - - return nvme_set_features(&args); -} - -int nvme_set_features_plm_config(int fd, bool plm, __u16 nvmsetid, bool save, - struct nvme_plm_config *data, __u32 *result) -{ - struct nvme_set_features_args args = { - .args_size = sizeof(args), - .fd = fd, - .fid = NVME_FEAT_FID_PLM_CONFIG, - .nsid = NVME_NSID_NONE, - .cdw11 = nvmsetid, - .cdw12 = !!plm, - .save = save, - .uuidx = NVME_UUID_NONE, - .cdw15 = 0, - .data_len = sizeof(*data), - .data = data, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .result = result, - }; - - return nvme_set_features(&args); -} - -int nvme_set_features_plm_window(int fd, enum nvme_feat_plm_window_select sel, - __u16 nvmsetid, bool save, __u32 *result) -{ - __u32 cdw12 = NVME_SET(sel, FEAT_PLMW_WS); - struct nvme_set_features_args args = { - .args_size = sizeof(args), - .fd = fd, - .fid = NVME_FEAT_FID_PLM_WINDOW, - .nsid = NVME_NSID_NONE, - .cdw11 = nvmsetid, - .cdw12 = cdw12, - .save = save, - .uuidx = NVME_UUID_NONE, - .cdw15 = 0, - .data_len = 0, - .data = NULL, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .result = result, - }; - - return nvme_set_features(&args); -} - -int nvme_set_features_lba_sts_interval(int fd, __u16 lsiri, __u16 lsipi, - bool save, __u32 *result) -{ - __u32 value = NVME_SET(lsiri, FEAT_LBAS_LSIRI) | - NVME_SET(lsipi, FEAT_LBAS_LSIPI); - - return __nvme_set_features(fd, NVME_FEAT_FID_LBA_STS_INTERVAL, value, - save, result); -} - -int nvme_set_features_host_behavior(int fd, bool save, - struct nvme_feat_host_behavior *data) -{ - return nvme_set_features_data(fd, NVME_FEAT_FID_HOST_BEHAVIOR, - NVME_NSID_NONE, 0, false, sizeof(*data), data, NULL); -} - -int nvme_set_features_sanitize(int fd, bool nodrm, bool save, __u32 *result) -{ - return __nvme_set_features(fd, NVME_FEAT_FID_SANITIZE, !!nodrm, save, - result); -} - -int nvme_set_features_endurance_evt_cfg(int fd, __u16 endgid, __u8 egwarn, - bool save, __u32 *result) -{ - __u32 value = endgid | egwarn << 16; - - return __nvme_set_features(fd, NVME_FEAT_FID_ENDURANCE_EVT_CFG, value, - save, result); -} - -int nvme_set_features_sw_progress(int fd, __u8 pbslc, bool save, - __u32 *result) -{ - return __nvme_set_features(fd, NVME_FEAT_FID_SW_PROGRESS, pbslc, save, - result); -} - -int nvme_set_features_host_id(int fd, bool exhid, bool save, __u8 *hostid) -{ - __u32 len = exhid ? 16 : 8; - __u32 value = !!exhid; - - return nvme_set_features_data(fd, NVME_FEAT_FID_HOST_ID, - NVME_NSID_NONE, value, save, len, hostid, NULL); -} - -int nvme_set_features_resv_mask(int fd, __u32 nsid, __u32 mask, bool save, - __u32 *result) -{ - return nvme_set_features_simple( - fd, NVME_FEAT_FID_RESV_MASK, nsid, mask, save, result); -} - -int nvme_set_features_resv_persist(int fd, __u32 nsid, bool ptpl, bool save, - __u32 *result) -{ - return nvme_set_features_simple( - fd, NVME_FEAT_FID_RESV_PERSIST, nsid, !!ptpl, save, result); -} - -int nvme_set_features_write_protect(int fd, __u32 nsid, - enum nvme_feat_nswpcfg_state state, - bool save, __u32 *result) -{ - return nvme_set_features_simple( - fd, NVME_FEAT_FID_WRITE_PROTECT, nsid, state, false, result); -} - -int nvme_set_features_iocs_profile(int fd, __u16 iocsi, bool save) -{ - __u32 value = NVME_SET(iocsi, FEAT_IOCSP_IOCSCI); - - return __nvme_set_features(fd, NVME_FEAT_FID_IOCS_PROFILE, value, - save, NULL); -} - -int nvme_get_features(struct nvme_get_features_args *args) -{ - __u32 cdw10 = NVME_SET(args->fid, FEATURES_CDW10_FID) | - NVME_SET(args->sel, GET_FEATURES_CDW10_SEL); - __u32 cdw14 = NVME_SET(args->uuidx, FEATURES_CDW14_UUID); - - struct nvme_passthru_cmd cmd = { - .opcode = nvme_admin_get_features, - .nsid = args->nsid, - .addr = (__u64)(uintptr_t)args->data, - .data_len = args->data_len, - .cdw10 = cdw10, - .cdw11 = args->cdw11, - .cdw14 = cdw14, - .timeout_ms = args->timeout, - }; - - if (args->args_size < sizeof(*args)) { - errno = EINVAL; - return -1; - } - return nvme_submit_admin_passthru(args->fd, &cmd, args->result); -} - -static int __nvme_get_features(int fd, enum nvme_features_id fid, - enum nvme_get_features_sel sel, __u32 *result) -{ - struct nvme_get_features_args args = { - .args_size = sizeof(args), - .fd = fd, - .fid = fid, - .nsid = NVME_NSID_NONE, - .sel = sel, - .cdw11 = 0, - .uuidx = NVME_UUID_NONE, - .data_len = 0, - .data = NULL, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .result = result, - }; - - return nvme_get_features(&args); -} - -int nvme_get_features_arbitration(int fd, enum nvme_get_features_sel sel, - __u32 *result) -{ - return __nvme_get_features(fd, NVME_FEAT_FID_ARBITRATION, sel, result); -} - -int nvme_get_features_power_mgmt(int fd, enum nvme_get_features_sel sel, - __u32 *result) -{ - return __nvme_get_features(fd, NVME_FEAT_FID_POWER_MGMT, sel, result); -} - -int nvme_get_features_lba_range(int fd, enum nvme_get_features_sel sel, - __u32 nsid, struct nvme_lba_range_type *data, - __u32 *result) -{ - struct nvme_get_features_args args = { - .args_size = sizeof(args), - .fd = fd, - .fid = NVME_FEAT_FID_LBA_RANGE, - .nsid = nsid, - .sel = sel, - .uuidx = NVME_UUID_NONE, - .data = data, - .data_len = sizeof(*data), - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .result = result, - }; - - return nvme_get_features(&args); -} - -int nvme_get_features_temp_thresh(int fd, enum nvme_get_features_sel sel, __u8 tmpsel, - enum nvme_feat_tmpthresh_thsel thsel, __u32 *result) -{ - struct nvme_get_features_args args = { - .args_size = sizeof(args), - .fd = fd, - .fid = NVME_FEAT_FID_TEMP_THRESH, - .nsid = NVME_NSID_NONE, - .sel = sel, - .cdw11 = NVME_SET(tmpsel, FEAT_TT_TMPSEL) | NVME_SET(thsel, FEAT_TT_THSEL), - .uuidx = NVME_UUID_NONE, - .data_len = 0, - .data = NULL, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .result = result, - }; - - return nvme_get_features(&args); -} - -int nvme_get_features_err_recovery(int fd, enum nvme_get_features_sel sel, - __u32 nsid, __u32 *result) -{ - - struct nvme_get_features_args args = { - .args_size = sizeof(args), - .fd = fd, - .fid = NVME_FEAT_FID_ERR_RECOVERY, - .nsid = nsid, - .sel = sel, - .uuidx = NVME_UUID_NONE, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .result = result, - }; - - return nvme_get_features(&args); -} - -int nvme_get_features_volatile_wc(int fd, enum nvme_get_features_sel sel, - __u32 *result) -{ - return __nvme_get_features(fd, NVME_FEAT_FID_VOLATILE_WC, sel, result); -} - -int nvme_get_features_num_queues(int fd, enum nvme_get_features_sel sel, - __u32 *result) -{ - return __nvme_get_features(fd, NVME_FEAT_FID_NUM_QUEUES, sel, result); + return -EAGAIN; } -int nvme_get_features_irq_coalesce(int fd, enum nvme_get_features_sel sel, - __u32 *result) +int nvme_submit_io_passthru64(nvme_link_t l, struct nvme_passthru_cmd64 *cmd, + __u64 *result) { - return __nvme_get_features(fd, NVME_FEAT_FID_IRQ_COALESCE, sel, - result); + return nvme_submit_passthru64(l, NVME_IOCTL_IO64_CMD, cmd, result); } -int nvme_get_features_irq_config(int fd, enum nvme_get_features_sel sel, - __u16 iv, __u32 *result) +int nvme_io_passthru64(nvme_link_t l, __u8 opcode, __u8 flags, __u16 rsvd, + __u32 nsid, __u32 cdw2, __u32 cdw3, __u32 cdw10, + __u32 cdw11, __u32 cdw12, __u32 cdw13, __u32 cdw14, + __u32 cdw15, __u32 data_len, void *data, __u32 metadata_len, + void *metadata, __u32 timeout_ms, __u64 *result) { - struct nvme_get_features_args args = { - .args_size = sizeof(args), - .fd = fd, - .fid = NVME_FEAT_FID_IRQ_CONFIG, - .nsid = NVME_NSID_NONE, - .sel = sel, - .cdw11 = iv, - .uuidx = NVME_UUID_NONE, - .data_len = 0, - .data = NULL, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .result = result, - }; - - return nvme_get_features(&args); + return nvme_passthru64(l, NVME_IOCTL_IO64_CMD, opcode, flags, rsvd, + nsid, cdw2, cdw3, cdw10, cdw11, cdw12, cdw13, + cdw14, cdw15, data_len, data, metadata_len, metadata, + timeout_ms, result); } -int nvme_get_features_write_atomic(int fd, enum nvme_get_features_sel sel, - __u32 *result) +int nvme_submit_io_passthru(nvme_link_t l, struct nvme_passthru_cmd *cmd, __u32 *result) { - return __nvme_get_features(fd, NVME_FEAT_FID_WRITE_ATOMIC, sel, - result); + return nvme_submit_passthru(l, NVME_IOCTL_IO_CMD, cmd, result); } -int nvme_get_features_async_event(int fd, enum nvme_get_features_sel sel, - __u32 *result) +int nvme_io_passthru(nvme_link_t l, __u8 opcode, __u8 flags, __u16 rsvd, + __u32 nsid, __u32 cdw2, __u32 cdw3, __u32 cdw10, + __u32 cdw11, __u32 cdw12, __u32 cdw13, __u32 cdw14, + __u32 cdw15, __u32 data_len, void *data, __u32 metadata_len, + void *metadata, __u32 timeout_ms, __u32 *result) { - return __nvme_get_features(fd, NVME_FEAT_FID_ASYNC_EVENT, sel, result); -} - -int nvme_get_features_auto_pst(int fd, enum nvme_get_features_sel sel, - struct nvme_feat_auto_pst *apst, __u32 *result) -{ - struct nvme_get_features_args args = { - .args_size = sizeof(args), - .fd = fd, - .fid = NVME_FEAT_FID_AUTO_PST, - .nsid = NVME_NSID_NONE, - .sel = sel, - .cdw11 = 0, - .uuidx = NVME_UUID_NONE, - .data_len = sizeof(*apst), - .data = apst, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .result = result, - }; - - return nvme_get_features(&args); -} - -int nvme_get_features_host_mem_buf(int fd, enum nvme_get_features_sel sel, - struct nvme_host_mem_buf_attrs *attrs, - __u32 *result) -{ - struct nvme_get_features_args args = { - .args_size = sizeof(args), - .fd = fd, - .fid = NVME_FEAT_FID_HOST_MEM_BUF, - .nsid = NVME_NSID_NONE, - .sel = sel, - .uuidx = NVME_UUID_NONE, - .data = attrs, - .data_len = sizeof(*attrs), - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .result = result, - }; - - return nvme_get_features(&args); -} - -int nvme_get_features_timestamp(int fd, enum nvme_get_features_sel sel, - struct nvme_timestamp *ts) -{ - struct nvme_get_features_args args = { - .args_size = sizeof(args), - .fd = fd, - .fid = NVME_FEAT_FID_TIMESTAMP, - .nsid = NVME_NSID_NONE, - .sel = sel, - .cdw11 = 0, - .uuidx = NVME_UUID_NONE, - .data_len = sizeof(*ts), - .data = ts, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .result = NULL, - }; - - return nvme_get_features(&args); -} - -int nvme_get_features_kato(int fd, enum nvme_get_features_sel sel, __u32 *result) -{ - return __nvme_get_features(fd, NVME_FEAT_FID_KATO, sel, result); -} - -int nvme_get_features_hctm(int fd, enum nvme_get_features_sel sel, __u32 *result) -{ - return __nvme_get_features(fd, NVME_FEAT_FID_HCTM, sel, result); -} - -int nvme_get_features_nopsc(int fd, enum nvme_get_features_sel sel, __u32 *result) -{ - return __nvme_get_features(fd, NVME_FEAT_FID_NOPSC, sel, result); -} - -int nvme_get_features_rrl(int fd, enum nvme_get_features_sel sel, __u32 *result) -{ - return __nvme_get_features(fd, NVME_FEAT_FID_RRL, sel, result); -} - -int nvme_get_features_plm_config(int fd, enum nvme_get_features_sel sel, - __u16 nvmsetid, struct nvme_plm_config *data, - __u32 *result) -{ - struct nvme_get_features_args args = { - .args_size = sizeof(args), - .fd = fd, - .fid = NVME_FEAT_FID_PLM_CONFIG, - .nsid = NVME_NSID_NONE, - .sel = sel, - .cdw11 = nvmsetid, - .uuidx = NVME_UUID_NONE, - .data_len = sizeof(*data), - .data = data, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .result = result, - }; - - return nvme_get_features(&args); -} - -int nvme_get_features_plm_window(int fd, enum nvme_get_features_sel sel, - __u16 nvmsetid, __u32 *result) -{ - struct nvme_get_features_args args = { - .args_size = sizeof(args), - .fd = fd, - .fid = NVME_FEAT_FID_PLM_WINDOW, - .nsid = NVME_NSID_NONE, - .sel = sel, - .cdw11 = nvmsetid, - .uuidx = NVME_UUID_NONE, - .data_len = 0, - .data = NULL, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .result = result, - }; - - return nvme_get_features(&args); -} - -int nvme_get_features_lba_sts_interval(int fd, enum nvme_get_features_sel sel, - __u32 *result) -{ - return __nvme_get_features(fd, NVME_FEAT_FID_LBA_STS_INTERVAL, sel, - result); -} - -int nvme_get_features_host_behavior(int fd, enum nvme_get_features_sel sel, - struct nvme_feat_host_behavior *data, - __u32 *result) -{ - struct nvme_get_features_args args = { - .args_size = sizeof(args), - .fd = fd, - .fid = NVME_FEAT_FID_HOST_BEHAVIOR, - .nsid = NVME_NSID_NONE, - .sel = sel, - .cdw11 = 0, - .uuidx = NVME_UUID_NONE, - .data_len = sizeof(*data), - .data = data, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .result = result, - }; - - return nvme_get_features(&args); -} - -int nvme_get_features_sanitize(int fd, enum nvme_get_features_sel sel, - __u32 *result) -{ - return __nvme_get_features(fd, NVME_FEAT_FID_SANITIZE, sel, result); -} - -int nvme_get_features_endurance_event_cfg(int fd, enum nvme_get_features_sel sel, - __u16 endgid, __u32 *result) -{ - struct nvme_get_features_args args = { - .args_size = sizeof(args), - .fd = fd, - .fid = NVME_FEAT_FID_ENDURANCE_EVT_CFG, - .nsid = NVME_NSID_NONE, - .sel = sel, - .cdw11 = endgid, - .uuidx = NVME_UUID_NONE, - .data_len = 0, - .data = NULL, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .result = result, - }; - - return nvme_get_features(&args); -} - -int nvme_get_features_sw_progress(int fd, enum nvme_get_features_sel sel, - __u32 *result) -{ - return __nvme_get_features(fd, NVME_FEAT_FID_SW_PROGRESS, sel, result); -} - -int nvme_get_features_host_id(int fd, enum nvme_get_features_sel sel, - bool exhid, __u32 len, __u8 *hostid) -{ - struct nvme_get_features_args args = { - .args_size = sizeof(args), - .fd = fd, - .fid = NVME_FEAT_FID_HOST_ID, - .nsid = NVME_NSID_NONE, - .sel = sel, - .cdw11 = !!exhid, - .uuidx = NVME_UUID_NONE, - .data_len = len, - .data = hostid, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .result = NULL, - }; - - return nvme_get_features(&args); -} - -int nvme_get_features_resv_mask(int fd, enum nvme_get_features_sel sel, - __u32 nsid, __u32 *result) -{ - struct nvme_get_features_args args = { - .args_size = sizeof(args), - .fd = fd, - .fid = NVME_FEAT_FID_RESV_MASK, - .nsid = nsid, - .sel = sel, - .uuidx = NVME_UUID_NONE, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .result = result, - }; - - return nvme_get_features(&args); -} - -int nvme_get_features_resv_persist(int fd, enum nvme_get_features_sel sel, - __u32 nsid, __u32 *result) -{ - struct nvme_get_features_args args = { - .args_size = sizeof(args), - .fd = fd, - .fid = NVME_FEAT_FID_RESV_PERSIST, - .nsid = nsid, - .sel = sel, - .uuidx = NVME_UUID_NONE, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .result = result, - }; - - return nvme_get_features(&args); -} - -int nvme_get_features_write_protect(int fd, __u32 nsid, - enum nvme_get_features_sel sel, - __u32 *result) -{ - struct nvme_get_features_args args = { - .args_size = sizeof(args), - .fd = fd, - .fid = NVME_FEAT_FID_WRITE_PROTECT, - .nsid = nsid, - .sel = sel, - .cdw11 = 0, - .uuidx = NVME_UUID_NONE, - .data_len = 0, - .data = NULL, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .result = result, - }; - - return nvme_get_features(&args); -} - -int nvme_get_features_iocs_profile(int fd, enum nvme_get_features_sel sel, - __u32 *result) -{ - return __nvme_get_features(fd, NVME_FEAT_FID_IOCS_PROFILE, sel, result); -} - -int nvme_format_nvm(struct nvme_format_nvm_args *args) -{ - const size_t size_v1 = sizeof_args(struct nvme_format_nvm_args, lbaf, __u64); - const size_t size_v2 = sizeof_args(struct nvme_format_nvm_args, lbafu, __u64); - __u32 cdw10; - - if (args->args_size < size_v1 || args->args_size > size_v2) { - errno = EINVAL; - return -1; - } - - cdw10 = NVME_SET(args->lbaf, FORMAT_CDW10_LBAF) | - NVME_SET(args->mset, FORMAT_CDW10_MSET) | - NVME_SET(args->pi, FORMAT_CDW10_PI) | - NVME_SET(args->pil, FORMAT_CDW10_PIL) | - NVME_SET(args->ses, FORMAT_CDW10_SES); - - if (args->args_size == size_v2) { - /* set lbafu extension */ - cdw10 |= NVME_SET(args->lbafu, FORMAT_CDW10_LBAFU); - } - - struct nvme_passthru_cmd cmd = { - .opcode = nvme_admin_format_nvm, - .nsid = args->nsid, - .cdw10 = cdw10, - .timeout_ms = args->timeout, - }; - - return nvme_submit_admin_passthru(args->fd, &cmd, args->result); -} - -int nvme_ns_mgmt(struct nvme_ns_mgmt_args *args) -{ - const size_t size_v1 = sizeof_args(struct nvme_ns_mgmt_args, csi, __u64); - const size_t size_v2 = sizeof_args(struct nvme_ns_mgmt_args, data, __u64); - __u32 cdw10 = NVME_SET(args->sel, NAMESPACE_MGMT_CDW10_SEL); - __u32 cdw11 = NVME_SET(args->csi, NAMESPACE_MGMT_CDW11_CSI); - - if (args->args_size < size_v1 || args->args_size > size_v2) { - errno = EINVAL; - return -1; - } - - struct nvme_passthru_cmd cmd = { - .nsid = args->nsid, - .opcode = nvme_admin_ns_mgmt, - .cdw10 = cdw10, - .cdw11 = cdw11, - .timeout_ms = args->timeout, - }; - - if (args->args_size == size_v2) { - if (args->data) { - cmd.data_len = sizeof(*args->data); - cmd.addr = (__u64)(uintptr_t)args->data; - } - } - else { - if (args->ns) { - cmd.data_len = sizeof(*args->ns); - cmd.addr = (__u64)(uintptr_t)args->ns; - } - } - return nvme_submit_admin_passthru(args->fd, &cmd, args->result); -} - -int nvme_ns_attach(struct nvme_ns_attach_args *args) -{ - __u32 cdw10 = NVME_SET(args->sel, NAMESPACE_ATTACH_CDW10_SEL); - - struct nvme_passthru_cmd cmd = { - .opcode = nvme_admin_ns_attach, - .nsid = args->nsid, - .cdw10 = cdw10, - .data_len = sizeof(*args->ctrlist), - .addr = (__u64)(uintptr_t)args->ctrlist, - .timeout_ms = args->timeout, - }; - - if (args->args_size < sizeof(*args)) { - errno = EINVAL; - return -1; - } - return nvme_submit_admin_passthru(args->fd, &cmd, args->result); -} - -int nvme_fw_download(struct nvme_fw_download_args *args) -{ - __u32 cdw10 = (args->data_len >> 2) - 1; - __u32 cdw11 = args->offset >> 2; - - struct nvme_passthru_cmd cmd = { - .opcode = nvme_admin_fw_download, - .cdw10 = cdw10, - .cdw11 = cdw11, - .data_len = args->data_len, - .addr = (__u64)(uintptr_t)args->data, - .timeout_ms = args->timeout, - }; - - if (args->args_size < sizeof(*args)) { - errno = EINVAL; - return -1; - } - return nvme_submit_admin_passthru(args->fd, &cmd, args->result); -} - -int nvme_fw_commit(struct nvme_fw_commit_args *args) -{ - __u32 cdw10 = NVME_SET(args->slot, FW_COMMIT_CDW10_FS) | - NVME_SET(args->action, FW_COMMIT_CDW10_CA) | - NVME_SET(args->bpid, FW_COMMIT_CDW10_BPID); - - struct nvme_passthru_cmd cmd = { - .opcode = nvme_admin_fw_commit, - .cdw10 = cdw10, - .timeout_ms = args->timeout, - }; - - if (args->args_size < sizeof(*args)) { - errno = EINVAL; - return -1; - } - return nvme_submit_admin_passthru(args->fd, &cmd, args->result); -} - -int nvme_security_send(struct nvme_security_send_args *args) -{ - __u32 cdw10 = NVME_SET(args->secp, SECURITY_SECP) | - NVME_SET(args->spsp0, SECURITY_SPSP0) | - NVME_SET(args->spsp1, SECURITY_SPSP1) | - NVME_SET(args->nssf, SECURITY_NSSF); - __u32 cdw11 = args->tl; - - struct nvme_passthru_cmd cmd = { - .opcode = nvme_admin_security_send, - .nsid = args->nsid, - .cdw10 = cdw10, - .cdw11 = cdw11, - .data_len = args->data_len, - .addr = (__u64)(uintptr_t)args->data, - .timeout_ms = args->timeout, - }; - - if (args->args_size < sizeof(*args)) { - errno = EINVAL; - return -1; - } - return nvme_submit_admin_passthru(args->fd, &cmd, args->result); -} - -int nvme_security_receive(struct nvme_security_receive_args *args) -{ - __u32 cdw10 = NVME_SET(args->secp, SECURITY_SECP) | - NVME_SET(args->spsp0, SECURITY_SPSP0) | - NVME_SET(args->spsp1, SECURITY_SPSP1) | - NVME_SET(args->nssf, SECURITY_NSSF); - __u32 cdw11 = args->al; - - struct nvme_passthru_cmd cmd = { - .opcode = nvme_admin_security_recv, - .nsid = args->nsid, - .cdw10 = cdw10, - .cdw11 = cdw11, - .data_len = args->data_len, - .addr = (__u64)(uintptr_t)args->data, - .timeout_ms = args->timeout, - }; - - if (args->args_size < sizeof(*args)) { - errno = EINVAL; - return -1; - } - return nvme_submit_admin_passthru(args->fd, &cmd, args->result); -} - -int nvme_get_lba_status(struct nvme_get_lba_status_args *args) -{ - __u32 cdw10 = args->slba & 0xffffffff; - __u32 cdw11 = args->slba >> 32; - __u32 cdw12 = args->mndw; - __u32 cdw13 = NVME_SET(args->rl, GET_LBA_STATUS_CDW13_RL) | - NVME_SET(args->atype, GET_LBA_STATUS_CDW13_ATYPE); - - struct nvme_passthru_cmd cmd = { - .opcode = nvme_admin_get_lba_status, - .nsid = args->nsid, - .addr = (__u64)(uintptr_t)args->lbas, - .data_len = (args->mndw + 1) << 2, - .cdw10 = cdw10, - .cdw11 = cdw11, - .cdw12 = cdw12, - .cdw13 = cdw13, - .timeout_ms = args->timeout, - }; - - if (args->args_size < sizeof(*args)) { - errno = EINVAL; - return -1; - } - return nvme_submit_admin_passthru(args->fd, &cmd, args->result); -} - -int nvme_directive_send(struct nvme_directive_send_args *args) -{ - __u32 cdw10 = args->data_len ? (args->data_len >> 2) - 1 : 0; - __u32 cdw11 = NVME_SET(args->doper, DIRECTIVE_CDW11_DOPER) | - NVME_SET(args->dtype, DIRECTIVE_CDW11_DTYPE) | - NVME_SET(args->dspec, DIRECTIVE_CDW11_DPSEC); - - struct nvme_passthru_cmd cmd = { - .opcode = nvme_admin_directive_send, - .nsid = args->nsid, - .cdw10 = cdw10, - .cdw11 = cdw11, - .cdw12 = args->cdw12, - .data_len = args->data_len, - .addr = (__u64)(uintptr_t)args->data, - .timeout_ms = args->timeout, - }; - - if (args->args_size < sizeof(*args)) { - errno = EINVAL; - return -1; - } - return nvme_submit_admin_passthru(args->fd, &cmd, args->result); -} - -int nvme_directive_send_id_endir(int fd, __u32 nsid, bool endir, - enum nvme_directive_dtype dtype, - struct nvme_id_directives *id) -{ - __u32 cdw12 = NVME_SET(dtype, DIRECTIVE_SEND_IDENTIFY_CDW12_DTYPE) | - NVME_SET(endir, DIRECTIVE_SEND_IDENTIFY_CDW12_ENDIR); - struct nvme_directive_send_args args = { - .args_size = sizeof(args), - .fd = fd, - .nsid = nsid, - .dspec = 0, - .dtype = NVME_DIRECTIVE_DTYPE_IDENTIFY, - .doper = NVME_DIRECTIVE_SEND_IDENTIFY_DOPER_ENDIR, - .cdw12 = cdw12, - .data_len = sizeof(*id), - .data = id, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .result = NULL, - }; - - return nvme_directive_send(&args); -} - -int nvme_directive_recv(struct nvme_directive_recv_args *args) -{ - __u32 cdw10 = args->data_len ? (args->data_len >> 2) - 1 : 0; - __u32 cdw11 = NVME_SET(args->doper, DIRECTIVE_CDW11_DOPER) | - NVME_SET(args->dtype, DIRECTIVE_CDW11_DTYPE) | - NVME_SET(args->dspec, DIRECTIVE_CDW11_DPSEC); - - struct nvme_passthru_cmd cmd = { - .opcode = nvme_admin_directive_recv, - .nsid = args->nsid, - .cdw10 = cdw10, - .cdw11 = cdw11, - .cdw12 = args->cdw12, - .data_len = args->data_len, - .addr = (__u64)(uintptr_t)args->data, - .timeout_ms = args->timeout, - }; - - if (args->args_size < sizeof(*args)) { - errno = EINVAL; - return -1; - } - return nvme_submit_admin_passthru(args->fd, &cmd, args->result); -} - -int nvme_capacity_mgmt(struct nvme_capacity_mgmt_args *args) -{ - __u32 cdw10 = args->op | args->element_id << 16; - - struct nvme_passthru_cmd cmd = { - .opcode = nvme_admin_capacity_mgmt, - .cdw10 = cdw10, - .cdw11 = args->cdw11, - .cdw12 = args->cdw12, - .timeout_ms = args->timeout, - }; - - if (args->args_size < sizeof(*args)) { - errno = EINVAL; - return -1; - } - return nvme_submit_admin_passthru(args->fd, &cmd, args->result); -} - -int nvme_lockdown(struct nvme_lockdown_args *args) -{ - __u32 cdw10 = args->ofi << 8 | - (args->ifc & 0x3) << 5 | - (args->prhbt & 0x1) << 4 | - (args->scp & 0xF); - - struct nvme_passthru_cmd cmd = { - .opcode = nvme_admin_lockdown, - .cdw10 = cdw10, - .cdw14 = args->uuidx & 0x3F, - .timeout_ms = args->timeout, - }; - - if (args->args_size < sizeof(*args)) { - errno = EINVAL; - return -1; - } - return nvme_submit_admin_passthru(args->fd, &cmd, args->result); -} - -int nvme_set_property(struct nvme_set_property_args *args) -{ - __u32 cdw10 = nvme_is_64bit_reg(args->offset); - - struct nvme_passthru_cmd cmd = { - .opcode = nvme_admin_fabrics, - .nsid = nvme_fabrics_type_property_set, - .cdw10 = cdw10, - .cdw11 = args->offset, - .cdw12 = args->value & 0xffffffff, - .cdw13 = args->value >> 32, - .timeout_ms = args->timeout, - }; - - if (args->args_size < sizeof(*args)) { - errno = EINVAL; - return -1; - } - return nvme_submit_admin_passthru(args->fd, &cmd, args->result); -} - -int nvme_get_property(struct nvme_get_property_args *args) -{ - __u32 cdw10 = nvme_is_64bit_reg(args->offset); - - struct nvme_passthru_cmd64 cmd = { - .opcode = nvme_admin_fabrics, - .nsid = nvme_fabrics_type_property_get, - .cdw10 = cdw10, - .cdw11 = args->offset, - .timeout_ms = args->timeout, - }; - - if (args->args_size < sizeof(*args)) { - errno = EINVAL; - return -1; - } - return nvme_submit_admin_passthru64(args->fd, &cmd, args->value); -} - -int nvme_sanitize_nvm(struct nvme_sanitize_nvm_args *args) -{ - const size_t size_v1 = sizeof_args(struct nvme_sanitize_nvm_args, nodas, __u64); - const size_t size_v2 = sizeof_args(struct nvme_sanitize_nvm_args, emvs, __u64); - __u32 cdw10, cdw11; - - if (args->args_size < size_v1 || args->args_size > size_v2) { - errno = EINVAL; - return -1; - } - - cdw10 = NVME_SET(args->sanact, SANITIZE_CDW10_SANACT) | - NVME_SET(!!args->ause, SANITIZE_CDW10_AUSE) | - NVME_SET(args->owpass, SANITIZE_CDW10_OWPASS) | - NVME_SET(!!args->oipbp, SANITIZE_CDW10_OIPBP) | - NVME_SET(!!args->nodas, SANITIZE_CDW10_NODAS); - - if (args->args_size == size_v2) - cdw10 |= NVME_SET(!!args->emvs, SANITIZE_CDW10_EMVS); - - cdw11 = args->ovrpat; - - struct nvme_passthru_cmd cmd = { - .opcode = nvme_admin_sanitize_nvm, - .cdw10 = cdw10, - .cdw11 = cdw11, - .timeout_ms = args->timeout, - }; - - return nvme_submit_admin_passthru(args->fd, &cmd, args->result); -} - -int nvme_dev_self_test(struct nvme_dev_self_test_args *args) -{ - __u32 cdw10 = NVME_SET(args->stc, DEVICE_SELF_TEST_CDW10_STC); - - struct nvme_passthru_cmd cmd = { - .opcode = nvme_admin_dev_self_test, - .nsid = args->nsid, - .cdw10 = cdw10, - .timeout_ms = args->timeout, - }; - - if (args->args_size < sizeof(*args)) { - errno = EINVAL; - return -1; - } - return nvme_submit_admin_passthru(args->fd, &cmd, args->result); -} - -int nvme_virtual_mgmt(struct nvme_virtual_mgmt_args *args) -{ - __u32 cdw10 = NVME_SET(args->act, VIRT_MGMT_CDW10_ACT) | - NVME_SET(args->rt, VIRT_MGMT_CDW10_RT) | - NVME_SET(args->cntlid, VIRT_MGMT_CDW10_CNTLID); - __u32 cdw11 = NVME_SET(args->nr, VIRT_MGMT_CDW11_NR); - - struct nvme_passthru_cmd cmd = { - .opcode = nvme_admin_virtual_mgmt, - .cdw10 = cdw10, - .cdw11 = cdw11, - .timeout_ms = args->timeout, - }; - - if (args->args_size < sizeof(*args)) { - errno = EINVAL; - return -1; - } - return nvme_submit_admin_passthru(args->fd, &cmd, args->result); -} - -int nvme_submit_io_passthru64(int fd, struct nvme_passthru_cmd64 *cmd, - __u64 *result) -{ - return nvme_submit_passthru64(fd, NVME_IOCTL_IO64_CMD, cmd, result); -} - -int nvme_io_passthru64(int fd, __u8 opcode, __u8 flags, __u16 rsvd, - __u32 nsid, __u32 cdw2, __u32 cdw3, __u32 cdw10, - __u32 cdw11, __u32 cdw12, __u32 cdw13, __u32 cdw14, - __u32 cdw15, __u32 data_len, void *data, __u32 metadata_len, - void *metadata, __u32 timeout_ms, __u64 *result) -{ - return nvme_passthru64(fd, NVME_IOCTL_IO64_CMD, opcode, flags, rsvd, - nsid, cdw2, cdw3, cdw10, cdw11, cdw12, cdw13, - cdw14, cdw15, data_len, data, metadata_len, metadata, - timeout_ms, result); -} - -int nvme_submit_io_passthru(int fd, struct nvme_passthru_cmd *cmd, __u32 *result) -{ - return nvme_submit_passthru(fd, NVME_IOCTL_IO_CMD, cmd, result); -} - -int nvme_io_passthru(int fd, __u8 opcode, __u8 flags, __u16 rsvd, - __u32 nsid, __u32 cdw2, __u32 cdw3, __u32 cdw10, - __u32 cdw11, __u32 cdw12, __u32 cdw13, __u32 cdw14, - __u32 cdw15, __u32 data_len, void *data, __u32 metadata_len, - void *metadata, __u32 timeout_ms, __u32 *result) -{ - return nvme_passthru(fd, NVME_IOCTL_IO_CMD, opcode, flags, rsvd, nsid, + return nvme_passthru(l, NVME_IOCTL_IO_CMD, opcode, flags, rsvd, nsid, cdw2, cdw3, cdw10, cdw11, cdw12, cdw13, cdw14, cdw15, data_len, data, metadata_len, metadata, timeout_ms, result); } - -static int nvme_set_var_size_tags(__u32 *cmd_dw2, __u32 *cmd_dw3, __u32 *cmd_dw14, - __u8 pif, __u8 sts, __u64 reftag, __u64 storage_tag) -{ - __u32 cdw2 = 0, cdw3 = 0, cdw14; - - switch (pif) { - case NVME_NVM_PIF_16B_GUARD: - cdw14 = reftag & 0xffffffff; - cdw14 |= ((storage_tag << (32 - sts)) & 0xffffffff); - break; - case NVME_NVM_PIF_32B_GUARD: - cdw14 = reftag & 0xffffffff; - cdw3 = reftag >> 32; - cdw14 |= ((storage_tag << (80 - sts)) & 0xffff0000); - if (sts >= 48) - cdw3 |= ((storage_tag >> (sts - 48)) & 0xffffffff); - else - cdw3 |= ((storage_tag << (48 - sts)) & 0xffffffff); - cdw2 = (storage_tag >> (sts - 16)) & 0xffff; - break; - case NVME_NVM_PIF_64B_GUARD: - cdw14 = reftag & 0xffffffff; - cdw3 = (reftag >> 32) & 0xffff; - cdw14 |= ((storage_tag << (48 - sts)) & 0xffffffff); - if (sts >= 16) - cdw3 |= ((storage_tag >> (sts - 16)) & 0xffff); - else - cdw3 |= ((storage_tag << (16 - sts)) & 0xffff); - break; - default: - perror("Unsupported Protection Information Format"); - errno = EINVAL; - return -1; - } - - *cmd_dw2 = cdw2; - *cmd_dw3 = cdw3; - *cmd_dw14 = cdw14; - return 0; -} - -int nvme_io(struct nvme_io_args *args, __u8 opcode) -{ - const size_t size_v1 = sizeof_args(struct nvme_io_args, dsm, __u64); - const size_t size_v2 = sizeof_args(struct nvme_io_args, pif, __u64); - __u32 cdw2, cdw3, cdw10, cdw11, cdw12, cdw13, cdw14, cdw15; - - if (args->args_size < size_v1 || args->args_size > size_v2) { - errno = EINVAL; - return -1; - } - - cdw10 = args->slba & 0xffffffff; - cdw11 = args->slba >> 32; - cdw12 = args->nlb | (args->control << 16); - cdw13 = args->dsm | (args->dspec << 16); - cdw15 = args->apptag | (args->appmask << 16); - - if (args->args_size == size_v1) { - cdw2 = (args->storage_tag >> 32) & 0xffff; - cdw3 = args->storage_tag & 0xffffffff; - cdw14 = args->reftag; - } else { - if (nvme_set_var_size_tags(&cdw2, &cdw3, &cdw14, - args->pif, - args->sts, - args->reftag_u64, - args->storage_tag)) { - errno = EINVAL; - return -1; - } - } - - struct nvme_passthru_cmd cmd = { - .opcode = opcode, - .nsid = args->nsid, - .cdw2 = cdw2, - .cdw3 = cdw3, - .cdw10 = cdw10, - .cdw11 = cdw11, - .cdw12 = cdw12, - .cdw13 = cdw13, - .cdw14 = cdw14, - .cdw15 = cdw15, - .data_len = args->data_len, - .metadata_len = args->metadata_len, - .addr = (__u64)(uintptr_t)args->data, - .metadata = (__u64)(uintptr_t)args->metadata, - .timeout_ms = args->timeout, - }; - - return nvme_submit_io_passthru(args->fd, &cmd, args->result); -} - -int nvme_dsm(struct nvme_dsm_args *args) -{ - struct nvme_passthru_cmd cmd = { - .opcode = nvme_cmd_dsm, - .nsid = args->nsid, - .addr = (__u64)(uintptr_t)args->dsm, - .data_len = args->nr_ranges * sizeof(*args->dsm), - .cdw10 = args->nr_ranges - 1, - .cdw11 = args->attrs, - .timeout_ms = args->timeout, - }; - - if (args->args_size < sizeof(*args)) { - errno = EINVAL; - return -1; - } - return nvme_submit_io_passthru(args->fd, &cmd, args->result); -} - -int nvme_copy(struct nvme_copy_args *args) -{ - const size_t size_v1 = sizeof_args(struct nvme_copy_args, format, __u64); - const size_t size_v2 = sizeof_args(struct nvme_copy_args, ilbrt_u64, __u64); - __u32 cdw3, cdw12, cdw14, data_len; - - if (args->args_size < size_v1 || args->args_size > size_v2) { - errno = EINVAL; - return -1; - } - - cdw12 = ((args->nr - 1) & 0xff) | ((args->format & 0xf) << 8) | - ((args->prinfor & 0xf) << 12) | ((args->dtype & 0xf) << 20) | - ((args->prinfow & 0xf) << 26) | ((args->fua & 0x1) << 30) | - ((args->lr & 0x1) << 31); - - if (args->args_size == size_v1) { - cdw3 = 0; - cdw14 = args->ilbrt; - } else { - cdw3 = (args->ilbrt_u64 >> 32) & 0xffffffff; - cdw14 = args->ilbrt_u64 & 0xffffffff; - } - - if (args->format == 1) - data_len = args->nr * sizeof(struct nvme_copy_range_f1); - else if (args->format == 2) - data_len = args->nr * sizeof(struct nvme_copy_range_f2); - else if (args->format == 3) - data_len = args->nr * sizeof(struct nvme_copy_range_f3); - else - data_len = args->nr * sizeof(struct nvme_copy_range); - - struct nvme_passthru_cmd cmd = { - .opcode = nvme_cmd_copy, - .nsid = args->nsid, - .addr = (__u64)(uintptr_t)args->copy, - .data_len = data_len, - .cdw3 = cdw3, - .cdw10 = args->sdlba & 0xffffffff, - .cdw11 = args->sdlba >> 32, - .cdw12 = cdw12, - .cdw13 = (args->dspec & 0xffff) << 16, - .cdw14 = cdw14, - .cdw15 = (args->lbatm << 16) | args->lbat, - .timeout_ms = args->timeout, - }; - - return nvme_submit_io_passthru(args->fd, &cmd, args->result); -} - -int nvme_resv_acquire(struct nvme_resv_acquire_args *args) -{ - __le64 payload[2] = { - cpu_to_le64(args->crkey), - cpu_to_le64(args->nrkey) - }; - __u32 cdw10 = (args->racqa & 0x7) | - (args->iekey ? 1 << 3 : 0) | - (args->rtype << 8); - - struct nvme_passthru_cmd cmd = { - .opcode = nvme_cmd_resv_acquire, - .nsid = args->nsid, - .cdw10 = cdw10, - .data_len = sizeof(payload), - .addr = (__u64)(uintptr_t)(payload), - .timeout_ms = args->timeout, - }; - - if (args->args_size < sizeof(*args)) { - errno = EINVAL; - return -1; - } - return nvme_submit_io_passthru(args->fd, &cmd, args->result); -} - -int nvme_resv_register(struct nvme_resv_register_args *args) -{ - __le64 payload[2] = { - cpu_to_le64(args->crkey), - cpu_to_le64(args->nrkey) - }; - __u32 cdw10 = (args->rrega & 0x7) | - (args->iekey ? 1 << 3 : 0) | - (args->cptpl << 30); - - struct nvme_passthru_cmd cmd = { - .opcode = nvme_cmd_resv_register, - .nsid = args->nsid, - .cdw10 = cdw10, - .data_len = sizeof(payload), - .addr = (__u64)(uintptr_t)(payload), - .timeout_ms = args->timeout, - }; - - if (args->args_size < sizeof(*args)) { - errno = EINVAL; - return -1; - } - return nvme_submit_io_passthru(args->fd, &cmd, args->result); -} - -int nvme_resv_release(struct nvme_resv_release_args *args) -{ - __le64 payload[1] = { cpu_to_le64(args->crkey) }; - __u32 cdw10 = (args->rrela & 0x7) | - (args->iekey ? 1 << 3 : 0) | - (args->rtype << 8); - - struct nvme_passthru_cmd cmd = { - .opcode = nvme_cmd_resv_release, - .nsid = args->nsid, - .cdw10 = cdw10, - .addr = (__u64)(uintptr_t)(payload), - .data_len = sizeof(payload), - .timeout_ms = args->timeout, - }; - - if (args->args_size < sizeof(*args)) { - errno = EINVAL; - return -1; - } - return nvme_submit_io_passthru(args->fd, &cmd, args->result); -} - -int nvme_resv_report(struct nvme_resv_report_args *args) -{ - struct nvme_passthru_cmd cmd = { - .opcode = nvme_cmd_resv_report, - .nsid = args->nsid, - .cdw10 = (args->len >> 2) - 1, - .cdw11 = args->eds ? 1 : 0, - .addr = (__u64)(uintptr_t)args->report, - .data_len = args->len, - .timeout_ms = args->timeout, - }; - - if (args->args_size < sizeof(*args)) { - errno = EINVAL; - return -1; - } - return nvme_submit_io_passthru(args->fd, &cmd, args->result); -} - -int nvme_io_mgmt_recv(struct nvme_io_mgmt_recv_args *args) -{ - __u32 cdw10 = args->mo | (args->mos << 16); - __u32 cdw11 = (args->data_len >> 2) - 1; - - struct nvme_passthru_cmd cmd = { - .opcode = nvme_cmd_io_mgmt_recv, - .nsid = args->nsid, - .cdw10 = cdw10, - .cdw11 = cdw11, - .addr = (__u64)(uintptr_t)args->data, - .data_len = args->data_len, - .timeout_ms = args->timeout, - }; - - if (args->args_size < sizeof(*args)) { - errno = EINVAL; - return -1; - } - - return nvme_submit_io_passthru(args->fd, &cmd, NULL); -} - -int nvme_io_mgmt_send(struct nvme_io_mgmt_send_args *args) -{ - __u32 cdw10 = args->mo | (args->mos << 16); - - struct nvme_passthru_cmd cmd = { - .opcode = nvme_cmd_io_mgmt_send, - .nsid = args->nsid, - .cdw10 = cdw10, - .addr = (__u64)(uintptr_t)args->data, - .data_len = args->data_len, - .timeout_ms = args->timeout, - }; - - if (args->args_size < sizeof(*args)) { - errno = EINVAL; - return -1; - } - - return nvme_submit_io_passthru(args->fd, &cmd, NULL); -} - -int nvme_zns_mgmt_send(struct nvme_zns_mgmt_send_args *args) -{ - __u32 cdw10 = args->slba & 0xffffffff; - __u32 cdw11 = args->slba >> 32; - __u32 cdw13 = NVME_SET(args->zsaso, ZNS_MGMT_SEND_ZSASO) | - NVME_SET(!!args->select_all, ZNS_MGMT_SEND_SEL) | - NVME_SET(args->zsa, ZNS_MGMT_SEND_ZSA); - - struct nvme_passthru_cmd cmd = { - .opcode = nvme_zns_cmd_mgmt_send, - .nsid = args->nsid, - .cdw10 = cdw10, - .cdw11 = cdw11, - .cdw13 = cdw13, - .addr = (__u64)(uintptr_t)args->data, - .data_len = args->data_len, - .timeout_ms = args->timeout, - }; - - if (args->args_size < sizeof(*args)) { - errno = EINVAL; - return -1; - } - return nvme_submit_io_passthru(args->fd, &cmd, args->result); -} - -int nvme_zns_mgmt_recv(struct nvme_zns_mgmt_recv_args *args) -{ - __u32 cdw10 = args->slba & 0xffffffff; - __u32 cdw11 = args->slba >> 32; - __u32 cdw12 = (args->data_len >> 2) - 1; - __u32 cdw13 = NVME_SET(args->zra, ZNS_MGMT_RECV_ZRA) | - NVME_SET(args->zrasf, ZNS_MGMT_RECV_ZRASF) | - NVME_SET(args->zras_feat, ZNS_MGMT_RECV_ZRAS_FEAT); - - struct nvme_passthru_cmd cmd = { - .opcode = nvme_zns_cmd_mgmt_recv, - .nsid = args->nsid, - .cdw10 = cdw10, - .cdw11 = cdw11, - .cdw12 = cdw12, - .cdw13 = cdw13, - .addr = (__u64)(uintptr_t)args->data, - .data_len = args->data_len, - .timeout_ms = args->timeout, - }; - - if (args->args_size < sizeof(*args)) { - errno = EINVAL; - return -1; - } - return nvme_submit_io_passthru(args->fd, &cmd, args->result); -} - -int nvme_zns_append(struct nvme_zns_append_args *args) -{ - const size_t size_v1 = sizeof_args(struct nvme_zns_append_args, lbatm, __u64); - const size_t size_v2 = sizeof_args(struct nvme_zns_append_args, ilbrt_u64, __u64); - __u32 cdw3, cdw10, cdw11, cdw12, cdw14, cdw15; - - if (args->args_size < size_v1 || args->args_size > size_v2) { - errno = EINVAL; - return -1; - } - - cdw10 = args->zslba & 0xffffffff; - cdw11 = args->zslba >> 32; - cdw12 = args->nlb | (args->control << 16); - cdw15 = args->lbat | (args->lbatm << 16); - - if (args->args_size == size_v1) { - cdw3 = 0; - cdw14 = args->ilbrt; - } else { - cdw3 = (args->ilbrt_u64 >> 32) & 0xffffffff; - cdw14 = args->ilbrt_u64 & 0xffffffff; - } - - struct nvme_passthru_cmd64 cmd = { - .opcode = nvme_zns_cmd_append, - .nsid = args->nsid, - .cdw3 = cdw3, - .cdw10 = cdw10, - .cdw11 = cdw11, - .cdw12 = cdw12, - .cdw14 = cdw14, - .cdw15 = cdw15, - .data_len = args->data_len, - .addr = (__u64)(uintptr_t)args->data, - .metadata_len = args->metadata_len, - .metadata = (__u64)(uintptr_t)args->metadata, - .timeout_ms = args->timeout, - }; - - return nvme_submit_io_passthru64(args->fd, &cmd, args->result); -} - -int nvme_dim_send(struct nvme_dim_args *args) -{ - __u32 cdw10 = NVME_SET(args->tas, DIM_TAS); - - struct nvme_passthru_cmd cmd = { - .opcode = nvme_admin_discovery_info_mgmt, - .cdw10 = cdw10, - .addr = (__u64)(uintptr_t)args->data, - .data_len = args->data_len, - .timeout_ms = args->timeout, - }; - - if (args->args_size < sizeof(*args)) { - errno = EINVAL; - return -1; - } - - return nvme_submit_admin_passthru(args->fd, &cmd, args->result); -} - - -int nvme_lm_cdq(struct nvme_lm_cdq_args *args) -{ - const size_t size_v1 = sizeof_args(struct nvme_lm_cdq_args, sz_u8, __u64); - const size_t size_v2 = sizeof_args(struct nvme_lm_cdq_args, sz, __u64); - __u32 cdw10 = NVME_SET(args->sel, LM_CDQ_SEL) | - NVME_SET(args->mos, LM_CDQ_MOS); - __u32 cdw11 = 0, data_len = 0, sz = 0; - int err; - - if (args->args_size < size_v1 || args->args_size > size_v2) { - errno = EINVAL; - return -1; - } - - if (args->args_size == size_v1) - sz = args->sz_u8; - else - sz = args->sz; - - if (args->sel == NVME_LM_SEL_CREATE_CDQ) { - cdw11 = NVME_SET(NVME_SET(args->cntlid, LM_CREATE_CDQ_CNTLID), LM_CQS) | - NVME_LM_CREATE_CDQ_PC; - data_len = sz << 2; - } else if (args->sel == NVME_LM_SEL_DELETE_CDQ) { - cdw11 = NVME_SET(args->cdqid, LM_DELETE_CDQ_CDQID); - } - - struct nvme_passthru_cmd cmd = { - .opcode = nvme_admin_ctrl_data_queue, - .cdw10 = cdw10, - .cdw11 = cdw11, - .cdw12 = sz, - .addr = (__u64)(uintptr_t)args->data, - .data_len = data_len, - .timeout_ms = args->timeout, - }; - - if (args->args_size < sizeof(*args)) { - errno = EINVAL; - return -1; - } - - err = nvme_submit_admin_passthru(args->fd, &cmd, args->result); - - if (!err) - args->cdqid = NVME_GET(cmd.result, LM_CREATE_CDQ_CDQID); - - return err; -} - -int nvme_lm_track_send(struct nvme_lm_track_send_args *args) -{ - __u32 cdw10 = NVME_SET(args->sel, LM_TRACK_SEND_SEL) | - NVME_SET(args->mos, LM_TRACK_SEND_MOS); - - struct nvme_passthru_cmd cmd = { - .opcode = nvme_admin_track_send, - .cdw10 = cdw10, - .cdw11 = args->cdqid, - .timeout_ms = args->timeout, - }; - - if (args->args_size < sizeof(*args)) { - errno = EINVAL; - return -1; - } - - return nvme_submit_admin_passthru(args->fd, &cmd, args->result); -} - -int nvme_lm_migration_send(struct nvme_lm_migration_send_args *args) -{ - __u32 cdw10 = NVME_SET(args->sel, LM_MIGRATION_SEND_SEL) | - NVME_SET(args->mos, LM_MIGRATION_SEND_MOS); - __u32 cdw11 = 0; - - if (args->sel == NVME_LM_SEL_SUSPEND) { - cdw11 = NVME_SET(args->stype, LM_STYPE) | - NVME_SET(args->cntlid, LM_SUSPEND_CNTLID); - if (args->dudmq) - cdw11 |= NVME_LM_DUDMQ; - } else if (args->sel == NVME_LM_SEL_RESUME) { - cdw11 = NVME_SET(args->cntlid, LM_RESUME_CNTLID); - } else if (args->sel == NVME_LM_SEL_SET_CONTROLLER_STATE) { - cdw11 = NVME_SET(args->csuuidi, LM_SET_CONTROLLER_STATE_CSUUIDI) | - NVME_SET(args->csvi, LM_SET_CONTROLLER_STATE_CSVI) | - NVME_SET(args->cntlid, LM_SET_CONTROLLER_STATE_CNTLID); - } - - struct nvme_passthru_cmd cmd = { - .opcode = nvme_admin_migration_send, - .cdw10 = cdw10, - .cdw11 = cdw11, - .cdw12 = (__u32)args->offset, - .cdw13 = (__u32)(args->offset >> 32), - .cdw14 = NVME_SET(args->uidx, LM_MIGRATION_SEND_UIDX), - .cdw15 = args->numd, - .addr = (__u64)(uintptr_t)args->data, - .data_len = args->numd << 2, - .timeout_ms = args->timeout, - }; - - if (args->args_size < sizeof(*args)) { - errno = EINVAL; - return -1; - } - - return nvme_submit_admin_passthru(args->fd, &cmd, args->result); -} - -int nvme_lm_migration_recv(struct nvme_lm_migration_recv_args *args) -{ - __u32 cdw10 = NVME_SET(args->sel, LM_MIGRATION_RECV_SEL) | - NVME_SET(args->mos, LM_MIGRATION_RECV_MOS); - __u32 cdw11 = 0, data_len = 0; - - if (args->sel == NVME_LM_SEL_GET_CONTROLLER_STATE) { - cdw11 = NVME_SET(args->csuidxp, LM_GET_CONTROLLER_STATE_CSUIDXP) | - NVME_SET(args->csuuidi, LM_GET_CONTROLLER_STATE_CSUUIDI) | - NVME_SET(args->cntlid, LM_GET_CONTROLLER_STATE_CNTLID); - data_len = (args->numd + 1 /*0's based*/) << 2; - } - - struct nvme_passthru_cmd cmd = { - .opcode = nvme_admin_migration_receive, - .cdw10 = cdw10, - .cdw11 = cdw11, - .cdw12 = (__u32)args->offset, - .cdw13 = (__u32)(args->offset >> 32), - .cdw14 = NVME_SET(args->uidx, LM_MIGRATION_RECV_UIDX), - .cdw15 = args->numd, - .addr = (__u64)(uintptr_t)args->data, - .data_len = data_len, - .timeout_ms = args->timeout, - }; - - if (args->args_size < sizeof(*args)) { - errno = EINVAL; - return -1; - } - - return nvme_submit_admin_passthru(args->fd, &cmd, args->result); -} - -int nvme_lm_set_features_ctrl_data_queue(int fd, __u16 cdqid, __u32 hp, __u32 tpt, bool etpt, - __u32 *result) -{ - struct nvme_set_features_args args = { - .args_size = sizeof(args), - .fd = fd, - .fid = NVME_FEAT_FID_CTRL_DATA_QUEUE, - .nsid = NVME_NSID_NONE, - .cdw11 = cdqid | NVME_SET(etpt, LM_CTRL_DATA_QUEUE_ETPT), - .cdw12 = hp, - .cdw13 = tpt, - .save = false, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .result = result, - }; - - return nvme_set_features(&args); -} - -int nvme_lm_get_features_ctrl_data_queue(int fd, __u16 cdqid, - struct nvme_lm_ctrl_data_queue_fid_data *data, - __u32 *result) -{ - struct nvme_get_features_args args = { - .args_size = sizeof(args), - .fd = fd, - .fid = NVME_FEAT_FID_CTRL_DATA_QUEUE, - .nsid = NVME_NSID_NONE, - .cdw11 = cdqid, - .data = data, - .data_len = sizeof(*data), - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .result = result, - }; - - return nvme_get_features(&args); -} diff --git a/src/nvme/ioctl.h b/src/nvme/ioctl.h index c1975d965..5a6dceb5e 100644 --- a/src/nvme/ioctl.h +++ b/src/nvme/ioctl.h @@ -10,8 +10,10 @@ #ifndef _LIBNVME_IOCTL_H #define _LIBNVME_IOCTL_H +#include #include #include +#include #include #include @@ -277,13 +279,13 @@ enum nvme_cmd_dword_fields { NVME_VIRT_MGMT_CDW10_RT_MASK = 0x7, NVME_VIRT_MGMT_CDW10_CNTLID_MASK = 0xffff, NVME_VIRT_MGMT_CDW11_NR_MASK = 0xffff, - NVME_FORMAT_CDW10_LBAF_SHIFT = 0, + NVME_FORMAT_CDW10_LBAFL_SHIFT = 0, NVME_FORMAT_CDW10_MSET_SHIFT = 4, NVME_FORMAT_CDW10_PI_SHIFT = 5, NVME_FORMAT_CDW10_PIL_SHIFT = 8, NVME_FORMAT_CDW10_SES_SHIFT = 9, NVME_FORMAT_CDW10_LBAFU_SHIFT = 12, - NVME_FORMAT_CDW10_LBAF_MASK = 0xf, + NVME_FORMAT_CDW10_LBAFL_MASK = 0xf, NVME_FORMAT_CDW10_MSET_MASK = 0x1, NVME_FORMAT_CDW10_PI_MASK = 0x7, NVME_FORMAT_CDW10_PIL_MASK = 0x1, @@ -293,13 +295,13 @@ enum nvme_cmd_dword_fields { NVME_SANITIZE_CDW10_AUSE_SHIFT = 3, NVME_SANITIZE_CDW10_OWPASS_SHIFT = 4, NVME_SANITIZE_CDW10_OIPBP_SHIFT = 8, - NVME_SANITIZE_CDW10_NODAS_SHIFT = 9, + NVME_SANITIZE_CDW10_NDAS_SHIFT = 9, NVME_SANITIZE_CDW10_EMVS_SHIFT = 10, NVME_SANITIZE_CDW10_SANACT_MASK = 0x7, NVME_SANITIZE_CDW10_AUSE_MASK = 0x1, NVME_SANITIZE_CDW10_OWPASS_MASK = 0xf, NVME_SANITIZE_CDW10_OIPBP_MASK = 0x1, - NVME_SANITIZE_CDW10_NODAS_MASK = 0x1, + NVME_SANITIZE_CDW10_NDAS_MASK = 0x1, NVME_SANITIZE_CDW10_EMVS_MASK = 0x1, NVME_SECURITY_NSSF_SHIFT = 0, NVME_SECURITY_SPSP0_SHIFT = 8, @@ -321,32 +323,128 @@ enum nvme_cmd_dword_fields { NVME_ZNS_MGMT_SEND_ZSA_MASK = 0xff, NVME_ZNS_MGMT_RECV_ZRA_SHIFT = 0, NVME_ZNS_MGMT_RECV_ZRA_MASK = 0xff, - NVME_ZNS_MGMT_RECV_ZRASF_SHIFT = 8, - NVME_ZNS_MGMT_RECV_ZRASF_MASK = 0xff, - NVME_ZNS_MGMT_RECV_ZRAS_FEAT_SHIFT = 16, - NVME_ZNS_MGMT_RECV_ZRAS_FEAT_MASK = 0x1, + NVME_ZNS_MGMT_RECV_ZRAS_SHIFT = 8, + NVME_ZNS_MGMT_RECV_ZRAS_MASK = 0xff, + NVME_ZNS_MGMT_RECV_ZRASPF_SHIFT = 16, + NVME_ZNS_MGMT_RECV_ZRASPF_MASK = 0x1, NVME_DIM_TAS_SHIFT = 0, NVME_DIM_TAS_MASK = 0xF, + NVME_DSM_CDW10_NR_SHIFT = 0, + NVME_DSM_CDW10_NR_MASK = 0xff, + NVME_DSM_CDW11_IDR_SHIFT = 0, + NVME_DSM_CDW11_IDR_MASK = 0x1, + NVME_DSM_CDW11_IDW_SHIFT = 1, + NVME_DSM_CDW11_IDW_MASK = 0x1, + NVME_DSM_CDW11_AD_SHIFT = 2, + NVME_DSM_CDW11_AD_MASK = 0x1, + NVME_DSM_CDW11_ATTRS_SHIFT = NVME_DSM_CDW11_IDR_SHIFT, + NVME_DSM_CDW11_ATTRS_MASK = (NVME_VAL(DSM_CDW11_IDR) | + NVME_VAL(DSM_CDW11_IDW) | + NVME_VAL(DSM_CDW11_AD)) >> + NVME_DSM_CDW11_IDR_SHIFT, + NVME_NVM_CDW2_ELBTU_SHIFT = 0, + NVME_NVM_CDW2_ELBTU_MASK = 0xffff, + NVME_NVM_CDW3_ELBTU_SHIFT = 0, + NVME_NVM_CDW3_ELBTU_MASK = 0xffffffff, + NVME_NVM_CDW10_SLBAL_SHIFT = 0, + NVME_NVM_CDW10_SLBAL_MASK = 0xffffffff, + NVME_NVM_CDW11_SLBAU_SHIFT = 0, + NVME_NVM_CDW11_SLBAU_MASK = 0xffffffff, + NVME_NVM_CDW12_NLB_SHIFT = 0, + NVME_NVM_CDW12_NLB_MASK = 0xffff, + NVME_NVM_CDW12_CETYPE_SHIFT = 16, + NVME_NVM_CDW12_CETYPE_MASK = 0xf, + NVME_NVM_CDW12_STC_SHIFT = 24, + NVME_NVM_CDW12_STC_MASK = 0x1, + NVME_NVM_CDW12_PRINFO_SHIFT = 26, + NVME_NVM_CDW12_PRINFO_MASK = 0xf, + NVME_NVM_CDW12_FUA_SHIFT = 30, + NVME_NVM_CDW12_FUA_MASK = 0x1, + NVME_NVM_CDW12_LR_SHIFT = 31, + NVME_NVM_CDW12_LR_MASK = 0x1, + NVME_NVM_CDW12_CONTROL_SHIFT = NVME_NVM_CDW12_CETYPE_SHIFT, + NVME_NVM_CDW12_CONTROL_MASK = (NVME_VAL(NVM_CDW12_CETYPE) | + NVME_VAL(NVM_CDW12_STC) | + NVME_VAL(NVM_CDW12_PRINFO) | + NVME_VAL(NVM_CDW12_FUA) | + NVME_VAL(NVM_CDW12_LR)) >> + NVME_NVM_CDW12_CONTROL_SHIFT, + NVME_NVM_CDW13_DSM_AF_SHIFT = 0, + NVME_NVM_CDW13_DSM_AF_MASK = 0xf, + NVME_NVM_CDW13_DSM_AL_SHIFT = 4, + NVME_NVM_CDW13_DSM_AL_MASK = 0x3, + NVME_NVM_CDW13_DSM_SEQREQ_SHIFT = 6, + NVME_NVM_CDW13_DSM_SEQREQ_MASK = 0x1, + NVME_NVM_CDW13_DSM_INCPRS_SHIFT = 7, + NVME_NVM_CDW13_DSM_INCPRS_MASK = 0x1, + NVME_NVM_CDW13_DSM_SHIFT = NVME_NVM_CDW13_DSM_AF_SHIFT, + NVME_NVM_CDW13_DSM_MASK = (NVME_VAL(NVM_CDW13_DSM_AF) | + NVME_VAL(NVM_CDW13_DSM_AL) | + NVME_VAL(NVM_CDW13_DSM_SEQREQ) | + NVME_VAL(NVM_CDW13_DSM_INCPRS)) >> + NVME_NVM_CDW13_DSM_SHIFT, + NVME_NVM_CDW13_CEV_SHIFT = 0, + NVME_NVM_CDW13_CEV_MASK = 0xffff, + NVME_NVM_CDW13_DSPEC_SHIFT = 16, + NVME_NVM_CDW13_DSPEC_MASK = 0xffff, + NVME_NVM_CDW14_ELBTL_SHIFT = 0, + NVME_NVM_CDW14_ELBTL_MASK = 0xffffffff, + NVME_NVM_CDW15_ELBAT_SHIFT = 0, + NVME_NVM_CDW15_ELBAT_MASK = 0xffff, + NVME_NVM_CDW15_ELBATM_SHIFT = 16, + NVME_NVM_CDW15_ELBATM_MASK = 0xffff, + NVME_COPY_CDW3_LBTU_SHIFT = 0, + NVME_COPY_CDW3_LBTU_MASK = 0xffffffff, + NVME_COPY_CDW10_SDLBAL_SHIFT = 0, + NVME_COPY_CDW10_SDLBAL_MASK = 0xffffffff, + NVME_COPY_CDW11_SDLBAU_SHIFT = 0, + NVME_COPY_CDW11_SDLBAU_MASK = 0xffffffff, + NVME_COPY_CDW12_NR_SHIFT = 0, + NVME_COPY_CDW12_NR_MASK = 0xff, + NVME_COPY_CDW12_DESFMT_SHIFT = 8, + NVME_COPY_CDW12_DESFMT_MASK = 0xf, + NVME_COPY_CDW12_PRINFOR_SHIFT = 12, + NVME_COPY_CDW12_PRINFOR_MASK = 0xf, + NVME_COPY_CDW12_CETYPE_SHIFT = 16, + NVME_COPY_CDW12_CETYPE_MASK = 0xf, + NVME_COPY_CDW12_DTYPE_SHIFT = 20, + NVME_COPY_CDW12_DTYPE_MASK = 0xf, + NVME_COPY_CDW12_STCW_SHIFT = 24, + NVME_COPY_CDW12_STCW_MASK = 0x1, + NVME_COPY_CDW12_STCR_SHIFT = 25, + NVME_COPY_CDW12_STCR_MASK = 0x1, + NVME_COPY_CDW12_PRINFOW_SHIFT = 26, + NVME_COPY_CDW12_PRINFOW_MASK = 0xf, + NVME_COPY_CDW12_FUA_SHIFT = 30, + NVME_COPY_CDW12_FUA_MASK = 0x1, + NVME_COPY_CDW12_LR_SHIFT = 31, + NVME_COPY_CDW12_LR_MASK = 0x1, + NVME_COPY_CDW14_LBTL_SHIFT = 0, + NVME_COPY_CDW14_LBTL_MASK = 0xffffffff, + NVME_COPY_CDW15_LBAT_SHIFT = 0, + NVME_COPY_CDW15_LBAT_MASK = 0xffff, + NVME_COPY_CDW15_LBATM_SHIFT = 16, + NVME_COPY_CDW15_LBATM_MASK = 0xffff, }; /** * nvme_submit_admin_passthru64() - Submit a 64-bit nvme passthrough admin * command - * @fd: File descriptor of nvme device + * @l: Link handle * @cmd: The nvme admin command to send * @result: Optional field to return the result from the CQE DW0-1 * * Uses NVME_IOCTL_ADMIN64_CMD for the ioctl request. * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_submit_admin_passthru64(int fd, struct nvme_passthru_cmd64 *cmd, +int nvme_submit_admin_passthru64(nvme_link_t l, struct nvme_passthru_cmd64 *cmd, __u64 *result); /** * nvme_admin_passthru64() - Submit a 64-bit nvme passthrough command - * @fd: File descriptor of nvme device + * @l: Link handle * @opcode: The nvme io command to send * @flags: NVMe command flags (not used) * @rsvd: Reserved for future use @@ -371,10 +469,10 @@ int nvme_submit_admin_passthru64(int fd, struct nvme_passthru_cmd64 *cmd, * * Known values for @opcode are defined in &enum nvme_admin_opcode. * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_admin_passthru64(int fd, __u8 opcode, __u8 flags, __u16 rsvd, +int nvme_admin_passthru64(nvme_link_t l, __u8 opcode, __u8 flags, __u16 rsvd, __u32 nsid, __u32 cdw2, __u32 cdw3, __u32 cdw10, __u32 cdw11, __u32 cdw12, __u32 cdw13, __u32 cdw14, __u32 cdw15, __u32 data_len, void *data, __u32 metadata_len, void *metadata, @@ -382,21 +480,21 @@ int nvme_admin_passthru64(int fd, __u8 opcode, __u8 flags, __u16 rsvd, /** * nvme_submit_admin_passthru() - Submit an nvme passthrough admin command - * @fd: File descriptor of nvme device + * @l: Link handle * @cmd: The nvme admin command to send * @result: Optional field to return the result from the CQE DW0 * * Uses NVME_IOCTL_ADMIN_CMD for the ioctl request. * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_submit_admin_passthru(int fd, struct nvme_passthru_cmd *cmd, +int nvme_submit_admin_passthru(nvme_link_t l, struct nvme_passthru_cmd *cmd, __u32 *result); /** * nvme_admin_passthru() - Submit an nvme passthrough command - * @fd: File descriptor of nvme device + * @l: Link handle * @opcode: The nvme io command to send * @flags: NVMe command flags (not used) * @rsvd: Reserved for future use @@ -421,10 +519,10 @@ int nvme_submit_admin_passthru(int fd, struct nvme_passthru_cmd *cmd, * * Known values for @opcode are defined in &enum nvme_admin_opcode. * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_admin_passthru(int fd, __u8 opcode, __u8 flags, __u16 rsvd, +int nvme_admin_passthru(nvme_link_t l, __u8 opcode, __u8 flags, __u16 rsvd, __u32 nsid, __u32 cdw2, __u32 cdw3, __u32 cdw10, __u32 cdw11, __u32 cdw12, __u32 cdw13, __u32 cdw14, __u32 cdw15, __u32 data_len, void *data, __u32 metadata_len, void *metadata, @@ -432,21 +530,21 @@ int nvme_admin_passthru(int fd, __u8 opcode, __u8 flags, __u16 rsvd, /** * nvme_submit_io_passthru64() - Submit a 64-bit nvme passthrough command - * @fd: File descriptor of nvme device + * @l: Link handle * @cmd: The nvme io command to send * @result: Optional field to return the result from the CQE DW0-1 * * Uses NVME_IOCTL_IO64_CMD for the ioctl request. * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_submit_io_passthru64(int fd, struct nvme_passthru_cmd64 *cmd, +int nvme_submit_io_passthru64(nvme_link_t l, struct nvme_passthru_cmd64 *cmd, __u64 *result); /** * nvme_io_passthru64() - Submit an nvme io passthrough command - * @fd: File descriptor of nvme device + * @l: Link handle * @opcode: The nvme io command to send * @flags: NVMe command flags (not used) * @rsvd: Reserved for future use @@ -471,10 +569,10 @@ int nvme_submit_io_passthru64(int fd, struct nvme_passthru_cmd64 *cmd, * * Known values for @opcode are defined in &enum nvme_io_opcode. * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_io_passthru64(int fd, __u8 opcode, __u8 flags, __u16 rsvd, +int nvme_io_passthru64(nvme_link_t l, __u8 opcode, __u8 flags, __u16 rsvd, __u32 nsid, __u32 cdw2, __u32 cdw3, __u32 cdw10, __u32 cdw11, __u32 cdw12, __u32 cdw13, __u32 cdw14, __u32 cdw15, __u32 data_len, void *data, __u32 metadata_len, void *metadata, @@ -482,22 +580,22 @@ int nvme_io_passthru64(int fd, __u8 opcode, __u8 flags, __u16 rsvd, /** * nvme_submit_io_passthru() - Submit an nvme passthrough command - * @fd: File descriptor of nvme device + * @l: Link handle * @cmd: The nvme io command to send * @result: Optional field to return the result from the CQE dword 0 * @result: Optional field to return the result from the CQE DW0 * * Uses NVME_IOCTL_IO_CMD for the ioctl request. * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_submit_io_passthru(int fd, struct nvme_passthru_cmd *cmd, +int nvme_submit_io_passthru(nvme_link_t l, struct nvme_passthru_cmd *cmd, __u32 *result); /** * nvme_io_passthru() - Submit an nvme io passthrough command - * @fd: File descriptor of nvme device + * @l: Link handle * @opcode: The nvme io command to send * @flags: NVMe command flags (not used) * @rsvd: Reserved for future use @@ -522,10 +620,10 @@ int nvme_submit_io_passthru(int fd, struct nvme_passthru_cmd *cmd, * * Known values for @opcode are defined in &enum nvme_io_opcode. * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_io_passthru(int fd, __u8 opcode, __u8 flags, __u16 rsvd, +int nvme_io_passthru(nvme_link_t l, __u8 opcode, __u8 flags, __u16 rsvd, __u32 nsid, __u32 cdw2, __u32 cdw3, __u32 cdw10, __u32 cdw11, __u32 cdw12, __u32 cdw13, __u32 cdw14, __u32 cdw15, __u32 data_len, void *data, __u32 metadata_len, void *metadata, @@ -533,38 +631,38 @@ int nvme_io_passthru(int fd, __u8 opcode, __u8 flags, __u16 rsvd, /** * nvme_subsystem_reset() - Initiate a subsystem reset - * @fd: File descriptor of nvme device + * @l: Link handle * * This should only be sent to controller handles, not to namespaces. * * Return: Zero if a subsystem reset was initiated or -1 with errno set * otherwise. */ -int nvme_subsystem_reset(int fd); +int nvme_subsystem_reset(nvme_link_t l); /** * nvme_ctrl_reset() - Initiate a controller reset - * @fd: File descriptor of nvme device + * @l: Link handle * * This should only be sent to controller handles, not to namespaces. * * Return: 0 if a reset was initiated or -1 with errno set otherwise. */ -int nvme_ctrl_reset(int fd); +int nvme_ctrl_reset(nvme_link_t l); /** * nvme_ns_rescan() - Initiate a controller rescan - * @fd: File descriptor of nvme device + * @l: Link handle * * This should only be sent to controller handles, not to namespaces. * * Return: 0 if a rescan was initiated or -1 with errno set otherwise. */ -int nvme_ns_rescan(int fd); +int nvme_ns_rescan(nvme_link_t l); /** * nvme_get_nsid() - Retrieve the NSID from a namespace file descriptor - * @fd: File descriptor of nvme namespace + * @l: Link handle * @nsid: User pointer to namespace id * * This should only be sent to namespace handles, not to controllers. The @@ -574,61 +672,108 @@ int nvme_ns_rescan(int fd); * * Return: 0 if @nsid was set successfully or -1 with errno set otherwise. */ -int nvme_get_nsid(int fd, __u32 *nsid); +int nvme_get_nsid(nvme_link_t l, __u32 *nsid); /** - * nvme_identify() - Send the NVMe Identify command - * @args: &struct nvme_identify_args argument structure + * nvme_identify_partial() - NVMe Identify command + * @l: Link handle + * @nsid: Namespace identifier, if applicable + * @cntid: The Controller Identifier, if applicable + * @cns: The Controller or Namespace structure, see @enum nvme_identify_cns + * @csi: Command Set Identifier + * @cnssid: Identifier that is required for a particular CNS value + * @uidx: UUID Index if controller supports this id selection method + * @data: User space destination address to transfer the data + * @len: size of identify data to return + * @result: The command completion result from CQE dword0 * * The Identify command returns a data buffer that describes information about * the NVM subsystem, the controller or the namespace(s). * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_identify(struct nvme_identify_args *args); - -static inline int nvme_identify_cns_nsid(int fd, enum nvme_identify_cns cns, - __u32 nsid, void *data) +static inline int nvme_identify_partial(nvme_link_t l, __u32 nsid, __u16 cntid, + enum nvme_identify_cns cns, + enum nvme_csi csi, __u16 cnssid, + __u8 uidx, void *data, __u32 len, + __u32 *result) { - struct nvme_identify_args args = { - .result = NULL, - .data = data, - .args_size = sizeof(args), - .fd = fd, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .cns = cns, - .csi = NVME_CSI_NVM, - .nsid = nsid, - .cntid = NVME_CNTLID_NONE, - .cns_specific_id = NVME_CNSSPECID_NONE, - .uuidx = NVME_UUID_NONE, + __u32 cdw10 = NVME_SET(cntid, IDENTIFY_CDW10_CNTID) | + NVME_SET(cns, IDENTIFY_CDW10_CNS); + __u32 cdw11 = NVME_SET(cnssid, IDENTIFY_CDW11_CNSSPECID) | + NVME_SET(csi, IDENTIFY_CDW11_CSI); + __u32 cdw14 = NVME_SET(uidx, IDENTIFY_CDW14_UUID); + + struct nvme_passthru_cmd cmd = { + .opcode = nvme_admin_identify, + .nsid = nsid, + .addr = (__u64)(uintptr_t)data, + .data_len = len, + .cdw10 = cdw10, + .cdw11 = cdw11, + .cdw14 = cdw14, }; - return nvme_identify(&args); + return nvme_submit_admin_passthru(l, &cmd, result); +} + +/** + * nvme_identify() - NVMe Identify command + * @l: Link handle + * @nsid: Namespace identifier, if applicable + * @cntid: The Controller Identifier, if applicable + * @cns: The Controller or Namespace structure, see @enum nvme_identify_cns + * @csi: Command Set Identifier + * @cnssid: Identifier that is required for a particular CNS value + * @uidx: UUID Index if controller supports this id selection method + * @data: User space destination address to transfer the data + * @result: The command completion result from CQE dword0 + * + * The Identify command returns a data buffer that describes information about + * the NVM subsystem, the controller or the namespace(s). + * + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. + */ +static inline int nvme_identify(nvme_link_t l, __u32 nsid, __u16 cntid, + enum nvme_identify_cns cns, enum nvme_csi csi, + __u16 cnssid, __u8 uidx, + void *data, __u32 *result) +{ + return nvme_identify_partial(l, nsid, cntid, cns, csi, cnssid, uidx, + data, NVME_IDENTIFY_DATA_SIZE, result); +} + +static inline int nvme_identify_cns_nsid(nvme_link_t l, __u32 nsid, enum nvme_identify_cns cns, + void *data) +{ + return nvme_identify(l, nsid, NVME_CNTLID_NONE, cns, NVME_CSI_NVM, + NVME_CNSSPECID_NONE, NVME_UUID_NONE, + data, NULL); } /** * nvme_identify_ctrl() - Retrieves nvme identify controller - * @fd: File descriptor of nvme device + * @l: Link handle * @id: User space destination address to transfer the data, * * Sends nvme identify with CNS value %NVME_IDENTIFY_CNS_CTRL. * * See &struct nvme_id_ctrl for details on the data returned. * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_identify_ctrl(int fd, struct nvme_id_ctrl *id) +static inline int nvme_identify_ctrl(nvme_link_t l, struct nvme_id_ctrl *id) { - return nvme_identify_cns_nsid(fd, NVME_IDENTIFY_CNS_CTRL, - NVME_NSID_NONE, id); + return nvme_identify_cns_nsid(l, NVME_NSID_NONE, NVME_IDENTIFY_CNS_CTRL, + id); } /** * nvme_identify_ns() - Retrieves nvme identify namespace - * @fd: File descriptor of nvme device + * @l: Link handle * @nsid: Namespace to identify * @ns: User space destination address to transfer the data * @@ -643,34 +788,34 @@ static inline int nvme_identify_ctrl(int fd, struct nvme_id_ctrl *id) * * See &struct nvme_id_ns for details on the structure returned. * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_identify_ns(int fd, __u32 nsid, struct nvme_id_ns *ns) +static inline int nvme_identify_ns(nvme_link_t l, __u32 nsid, struct nvme_id_ns *ns) { - return nvme_identify_cns_nsid(fd, NVME_IDENTIFY_CNS_NS, nsid, ns); + return nvme_identify_cns_nsid(l, nsid, NVME_IDENTIFY_CNS_NS, ns); } /** * nvme_identify_allocated_ns() - Same as nvme_identify_ns, but only for * allocated namespaces - * @fd: File descriptor of nvme device + * @l: Link handle * @nsid: Namespace to identify * @ns: User space destination address to transfer the data * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_identify_allocated_ns(int fd, __u32 nsid, +static inline int nvme_identify_allocated_ns(nvme_link_t l, __u32 nsid, struct nvme_id_ns *ns) { - return nvme_identify_cns_nsid(fd, NVME_IDENTIFY_CNS_ALLOCATED_NS, - nsid, ns); + return nvme_identify_cns_nsid(l, nsid, + NVME_IDENTIFY_CNS_ALLOCATED_NS, ns); } /** * nvme_identify_active_ns_list() - Retrieves active namespaces id list - * @fd: File descriptor of nvme device + * @l: Link handle * @nsid: Return namespaces greater than this identifier * @list: User space destination address to transfer the data * @@ -680,19 +825,19 @@ static inline int nvme_identify_allocated_ns(int fd, __u32 nsid, * * See &struct nvme_ns_list for the definition of the returned structure. * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_identify_active_ns_list(int fd, __u32 nsid, +static inline int nvme_identify_active_ns_list(nvme_link_t l, __u32 nsid, struct nvme_ns_list *list) { - return nvme_identify_cns_nsid(fd, NVME_IDENTIFY_CNS_NS_ACTIVE_LIST, - nsid, list); + return nvme_identify_cns_nsid(l, nsid, + NVME_IDENTIFY_CNS_NS_ACTIVE_LIST, list); } /** * nvme_identify_allocated_ns_list() - Retrieves allocated namespace id list - * @fd: File descriptor of nvme device + * @l: Link handle * @nsid: Return namespaces greater than this identifier * @list: User space destination address to transfer the data * @@ -702,19 +847,19 @@ static inline int nvme_identify_active_ns_list(int fd, __u32 nsid, * * See &struct nvme_ns_list for the definition of the returned structure. * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_identify_allocated_ns_list(int fd, __u32 nsid, +static inline int nvme_identify_allocated_ns_list(nvme_link_t l, __u32 nsid, struct nvme_ns_list *list) { - return nvme_identify_cns_nsid(fd, NVME_IDENTIFY_CNS_ALLOCATED_NS_LIST, - nsid, list); + return nvme_identify_cns_nsid(l, nsid, NVME_IDENTIFY_CNS_ALLOCATED_NS_LIST, + list); } /** * nvme_identify_ctrl_list() - Retrieves identify controller list - * @fd: File descriptor of nvme device + * @l: Link handle * @cntid: Starting CNTLID to return in the list * @cntlist: User space destination address to transfer the data * @@ -724,32 +869,20 @@ static inline int nvme_identify_allocated_ns_list(int fd, __u32 nsid, * * See &struct nvme_ctrl_list for a definition of the structure returned. * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_identify_ctrl_list(int fd, __u16 cntid, +static inline int nvme_identify_ctrl_list(nvme_link_t l, __u16 cntid, struct nvme_ctrl_list *cntlist) { - struct nvme_identify_args args = { - .result = NULL, - .data = cntlist, - .args_size = sizeof(args), - .fd = fd, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .cns = NVME_IDENTIFY_CNS_CTRL_LIST, - .csi = NVME_CSI_NVM, - .nsid = NVME_NSID_NONE, - .cntid = cntid, - .cns_specific_id = NVME_CNSSPECID_NONE, - .uuidx = NVME_UUID_NONE, - }; - - return nvme_identify(&args); + return nvme_identify(l, NVME_NSID_NONE, cntid, NVME_IDENTIFY_CNS_CTRL_LIST, + NVME_CSI_NVM, NVME_CNSSPECID_NONE, NVME_UUID_NONE, + cntlist, NULL); } /** * nvme_identify_nsid_ctrl_list() - Retrieves controller list attached to an nsid - * @fd: File descriptor of nvme device + * @l: Link handle * @nsid: Return controllers that are attached to this nsid * @cntid: Starting CNTLID to return in the list * @cntlist: User space destination address to transfer the data @@ -763,29 +896,17 @@ static inline int nvme_identify_ctrl_list(int fd, __u16 cntid, * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 */ -static inline int nvme_identify_nsid_ctrl_list(int fd, __u32 nsid, __u16 cntid, +static inline int nvme_identify_nsid_ctrl_list(nvme_link_t l, __u32 nsid, __u16 cntid, struct nvme_ctrl_list *cntlist) { - struct nvme_identify_args args = { - .result = NULL, - .data = cntlist, - .args_size = sizeof(args), - .fd = fd, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .cns = NVME_IDENTIFY_CNS_NS_CTRL_LIST, - .csi = NVME_CSI_NVM, - .nsid = nsid, - .cntid = cntid, - .cns_specific_id = NVME_CNSSPECID_NONE, - .uuidx = NVME_UUID_NONE, - }; - - return nvme_identify(&args); + return nvme_identify(l, nsid, cntid, NVME_IDENTIFY_CNS_NS_CTRL_LIST, + NVME_CSI_NVM, NVME_CNSSPECID_NONE, NVME_UUID_NONE, + cntlist, NULL); } /** * nvme_identify_ns_descs() - Retrieves namespace descriptor list - * @fd: File descriptor of nvme device + * @l: Link handle * @nsid: The namespace id to retrieve descriptors * @descs: User space destination address to transfer the data * @@ -797,19 +918,19 @@ static inline int nvme_identify_nsid_ctrl_list(int fd, __u32 nsid, __u16 cntid, * * See &struct nvme_ns_id_desc for the definition of the returned structure. * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_identify_ns_descs(int fd, __u32 nsid, +static inline int nvme_identify_ns_descs(nvme_link_t l, __u32 nsid, struct nvme_ns_id_desc *descs) { - return nvme_identify_cns_nsid(fd, NVME_IDENTIFY_CNS_NS_DESC_LIST, - nsid, descs); + return nvme_identify_cns_nsid(l, nsid, NVME_IDENTIFY_CNS_NS_DESC_LIST, + descs); } /** * nvme_identify_nvmset_list() - Retrieves NVM Set List - * @fd: File descriptor of nvme device + * @l: Link handle * @nvmsetid: NVM Set Identifier * @nvmset: User space destination address to transfer the data * @@ -820,64 +941,41 @@ static inline int nvme_identify_ns_descs(int fd, __u32 nsid, * * See &struct nvme_id_nvmset_list for the definition of the returned structure. * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_identify_nvmset_list(int fd, __u16 nvmsetid, +static inline int nvme_identify_nvmset_list(nvme_link_t l, __u16 nvmsetid, struct nvme_id_nvmset_list *nvmset) { - struct nvme_identify_args args = { - .result = NULL, - .data = nvmset, - .args_size = sizeof(args), - .fd = fd, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .cns = NVME_IDENTIFY_CNS_NVMSET_LIST, - .csi = NVME_CSI_NVM, - .nsid = NVME_NSID_NONE, - .cntid = NVME_CNTLID_NONE, - .cns_specific_id = nvmsetid, - .uuidx = NVME_UUID_NONE, - }; - - return nvme_identify(&args); + return nvme_identify(l, NVME_NSID_NONE, NVME_CNTLID_NONE, + NVME_IDENTIFY_CNS_NVMSET_LIST, + NVME_CSI_NVM, nvmsetid, NVME_UUID_NONE, + nvmset, NULL); } /** * nvme_identify_primary_ctrl() - Retrieve NVMe Primary Controller * identification - * @fd: File descriptor of nvme device + * @l: Link handle * @cntid: Return controllers starting at this identifier * @cap: User space destination buffer address to transfer the data * * See &struct nvme_primary_ctrl_cap for the definition of the returned structure, @cap. * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_identify_primary_ctrl(int fd, __u16 cntid, +static inline int nvme_identify_primary_ctrl(nvme_link_t l, __u16 cntid, struct nvme_primary_ctrl_cap *cap) { - struct nvme_identify_args args = { - .result = NULL, - .data = cap, - .args_size = sizeof(args), - .fd = fd, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .cns = NVME_IDENTIFY_CNS_PRIMARY_CTRL_CAP, - .csi = NVME_CSI_NVM, - .nsid = NVME_NSID_NONE, - .cntid = cntid, - .cns_specific_id = NVME_CNSSPECID_NONE, - .uuidx = NVME_UUID_NONE, - }; - - return nvme_identify(&args); + return nvme_identify(l, NVME_NSID_NONE, cntid, NVME_IDENTIFY_CNS_PRIMARY_CTRL_CAP, + NVME_CSI_NVM, NVME_CNSSPECID_NONE, NVME_UUID_NONE, + cap, NULL); } /** * nvme_identify_secondary_ctrl_list() - Retrieves secondary controller list - * @fd: File descriptor of nvme device + * @l: Link handle * @cntid: Return controllers starting at this identifier * @sc_list: User space destination address to transfer the data * @@ -889,33 +987,22 @@ static inline int nvme_identify_primary_ctrl(int fd, __u16 cntid, * See &struct nvme_secondary_ctrls_list for a definition of the returned * structure. * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_identify_secondary_ctrl_list(int fd, +static inline int nvme_identify_secondary_ctrl_list(nvme_link_t l, __u16 cntid, struct nvme_secondary_ctrl_list *sc_list) { - struct nvme_identify_args args = { - .result = NULL, - .data = sc_list, - .args_size = sizeof(args), - .fd = fd, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .cns = NVME_IDENTIFY_CNS_SECONDARY_CTRL_LIST, - .csi = NVME_CSI_NVM, - .nsid = NVME_NSID_NONE, - .cntid = cntid, - .cns_specific_id = NVME_CNSSPECID_NONE, - .uuidx = NVME_UUID_NONE, - }; - - return nvme_identify(&args); + return nvme_identify(l, NVME_NSID_NONE, cntid, + NVME_IDENTIFY_CNS_SECONDARY_CTRL_LIST, + NVME_CSI_NVM, NVME_CNSSPECID_NONE, NVME_UUID_NONE, + sc_list, NULL); } /** * nvme_identify_ns_granularity() - Retrieves namespace granularity * identification - * @fd: File descriptor of nvme device + * @l: Link handle * @gr_list: User space destination address to transfer the data * * If the controller supports reporting of Namespace Granularity, then a @@ -925,19 +1012,19 @@ static inline int nvme_identify_secondary_ctrl_list(int fd, * See &struct nvme_id_ns_granularity_list for the definition of the returned * structure. * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_identify_ns_granularity(int fd, +static inline int nvme_identify_ns_granularity(nvme_link_t l, struct nvme_id_ns_granularity_list *gr_list) { - return nvme_identify_cns_nsid(fd, NVME_IDENTIFY_CNS_NS_GRANULARITY, - NVME_NSID_NONE, gr_list); + return nvme_identify_cns_nsid(l, NVME_NSID_NONE, + NVME_IDENTIFY_CNS_NS_GRANULARITY, gr_list); } /** * nvme_identify_uuid() - Retrieves device's UUIDs - * @fd: File descriptor of nvme device + * @l: Link handle * @uuid_list: User space destination address to transfer the data * * Each UUID List entry is either 0h, the NVMe Invalid UUID, or a valid UUID. @@ -945,52 +1032,40 @@ static inline int nvme_identify_ns_granularity(int fd, * * See &struct nvme_id_uuid_list for the definition of the returned structure. * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_identify_uuid(int fd, struct nvme_id_uuid_list *uuid_list) +static inline int nvme_identify_uuid(nvme_link_t l, struct nvme_id_uuid_list *uuid_list) { - return nvme_identify_cns_nsid(fd, NVME_IDENTIFY_CNS_UUID_LIST, - NVME_NSID_NONE, uuid_list); + return nvme_identify_cns_nsid(l, NVME_NSID_NONE, + NVME_IDENTIFY_CNS_UUID_LIST, uuid_list); } /** * nvme_identify_ns_csi() - I/O command set specific identify namespace data - * @fd: File descriptor of nvme device + * @l: Link handle * @nsid: Namespace to identify - * @uuidx: UUID Index for differentiating vendor specific encoding * @csi: Command Set Identifier + * @uidx: UUID Index for differentiating vendor specific encoding * @data: User space destination address to transfer the data * * An I/O Command Set specific Identify Namespace data structure is returned * for the namespace specified in @nsid. * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_identify_ns_csi(int fd, __u32 nsid, __u8 uuidx, - enum nvme_csi csi, void *data) +static inline int nvme_identify_ns_csi(nvme_link_t l, __u32 nsid, + enum nvme_csi csi, __u8 uidx, void *data) { - struct nvme_identify_args args = { - .result = NULL, - .data = data, - .args_size = sizeof(args), - .fd = fd, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .cns = NVME_IDENTIFY_CNS_CSI_NS, - .csi = csi, - .nsid = nsid, - .cntid = NVME_CNTLID_NONE, - .cns_specific_id = NVME_CNSSPECID_NONE, - .uuidx = uuidx, - }; - - return nvme_identify(&args); + return nvme_identify(l, nsid, NVME_CNTLID_NONE, NVME_IDENTIFY_CNS_CSI_NS, + csi, NVME_CNSSPECID_NONE, uidx, + data, NULL); } /** * nvme_identify_ctrl_csi() - I/O command set specific Identify Controller data - * @fd: File descriptor of nvme device + * @l: Link handle * @csi: Command Set Identifier * @data: User space destination address to transfer the data * @@ -998,31 +1073,20 @@ static inline int nvme_identify_ns_csi(int fd, __u32 nsid, __u8 uuidx, * to the host for the controller processing the command. The specific Identify * Controller data structure to be returned is specified by @csi. * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_identify_ctrl_csi(int fd, enum nvme_csi csi, void *data) -{ - struct nvme_identify_args args = { - .result = NULL, - .data = data, - .args_size = sizeof(args), - .fd = fd, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .cns = NVME_IDENTIFY_CNS_CSI_CTRL, - .csi = csi, - .nsid = NVME_NSID_NONE, - .cntid = NVME_CNTLID_NONE, - .cns_specific_id = NVME_CNSSPECID_NONE, - .uuidx = NVME_UUID_NONE, - }; - - return nvme_identify(&args); +static inline int nvme_identify_ctrl_csi(nvme_link_t l, enum nvme_csi csi, void *data) +{ + return nvme_identify(l, NVME_NSID_NONE, NVME_CNTLID_NONE, + NVME_IDENTIFY_CNS_CSI_CTRL, + csi, NVME_CNSSPECID_NONE, NVME_UUID_NONE, + data, NULL); } /** * nvme_identify_active_ns_list_csi() - Active namespace ID list associated with a specified I/O command set - * @fd: File descriptor of nvme device + * @l: Link handle * @nsid: Return namespaces greater than this identifier * @csi: Command Set Identifier * @ns_list: User space destination address to transfer the data @@ -1034,32 +1098,21 @@ static inline int nvme_identify_ctrl_csi(int fd, enum nvme_csi csi, void *data) * * See &struct nvme_ns_list for the definition of the returned structure. * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_identify_active_ns_list_csi(int fd, __u32 nsid, +static inline int nvme_identify_active_ns_list_csi(nvme_link_t l, __u32 nsid, enum nvme_csi csi, struct nvme_ns_list *ns_list) { - struct nvme_identify_args args = { - .result = NULL, - .data = ns_list, - .args_size = sizeof(args), - .fd = fd, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .cns = NVME_IDENTIFY_CNS_CSI_NS_ACTIVE_LIST, - .csi = csi, - .nsid = nsid, - .cntid = NVME_CNTLID_NONE, - .cns_specific_id = NVME_CNSSPECID_NONE, - .uuidx = NVME_UUID_NONE, - }; - - return nvme_identify(&args); + return nvme_identify(l, nsid, NVME_CNTLID_NONE, + NVME_IDENTIFY_CNS_CSI_NS_ACTIVE_LIST, + csi, NVME_CNSSPECID_NONE, NVME_UUID_NONE, + ns_list, NULL); } /** * nvme_identify_allocated_ns_list_csi() - Allocated namespace ID list associated with a specified I/O command set - * @fd: File descriptor of nvme device + * @l: Link handle * @nsid: Return namespaces greater than this identifier * @csi: Command Set Identifier * @ns_list: User space destination address to transfer the data @@ -1071,32 +1124,21 @@ static inline int nvme_identify_active_ns_list_csi(int fd, __u32 nsid, * * See &struct nvme_ns_list for the definition of the returned structure. * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_identify_allocated_ns_list_csi(int fd, __u32 nsid, +static inline int nvme_identify_allocated_ns_list_csi(nvme_link_t l, __u32 nsid, enum nvme_csi csi, struct nvme_ns_list *ns_list) { - struct nvme_identify_args args = { - .result = NULL, - .data = ns_list, - .args_size = sizeof(args), - .fd = fd, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .cns = NVME_IDENTIFY_CNS_CSI_ALLOCATED_NS_LIST, - .csi = csi, - .nsid = nsid, - .cntid = NVME_CNTLID_NONE, - .cns_specific_id = NVME_CNSSPECID_NONE, - .uuidx = NVME_UUID_NONE, - }; - - return nvme_identify(&args); + return nvme_identify(l, nsid, NVME_CNTLID_NONE, + NVME_IDENTIFY_CNS_CSI_ALLOCATED_NS_LIST, + csi, NVME_CNSSPECID_NONE, NVME_UUID_NONE, + ns_list, NULL); } /** * nvme_identify_independent_identify_ns() - I/O command set independent Identify namespace data - * @fd: File descriptor of nvme device + * @l: Link handle * @nsid: Return namespaces greater than this identifier * @ns: I/O Command Set Independent Identify Namespace data * structure @@ -1104,106 +1146,84 @@ static inline int nvme_identify_allocated_ns_list_csi(int fd, __u32 nsid, * The I/O command set independent Identify namespace data structure for * the namespace identified with @ns is returned to the host. * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_identify_independent_identify_ns(int fd, __u32 nsid, +static inline int nvme_identify_independent_identify_ns(nvme_link_t l, __u32 nsid, struct nvme_id_independent_id_ns *ns) { - return nvme_identify_cns_nsid( - fd, NVME_IDENTIFY_CNS_CSI_INDEPENDENT_ID_NS, nsid, ns); + return nvme_identify_cns_nsid(l, nsid, + NVME_IDENTIFY_CNS_CSI_INDEPENDENT_ID_NS, ns); } /** * nvme_identify_ns_csi_user_data_format() - Identify namespace user data format - * @fd: File descriptor of nvme device + * @l: Link handle * @user_data_format: Return namespaces capability of identifier - * @uuidx: UUID selection, if supported + * @uidx: UUID selection, if supported * @csi: Command Set Identifier * @data: User space destination address to transfer the data * * Identify Namespace data structure for the specified User Data Format * index containing the namespace capabilities for the NVM Command Set. * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_identify_ns_csi_user_data_format(int fd, - __u16 user_data_format, __u8 uuidx, +static inline int nvme_identify_ns_csi_user_data_format(nvme_link_t l, + __u16 user_data_format, __u8 uidx, enum nvme_csi csi, void *data) { - struct nvme_identify_args args = { - .result = NULL, - .data = data, - .args_size = sizeof(args), - .fd = fd, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .cns = NVME_IDENTIFY_CNS_NS_USER_DATA_FORMAT, - .csi = csi, - .nsid = NVME_NSID_NONE, - .cntid = NVME_CNTLID_NONE, - .cns_specific_id = user_data_format, - .uuidx = uuidx, - }; - - return nvme_identify(&args); + return nvme_identify(l, NVME_NSID_NONE, NVME_CNTLID_NONE, + NVME_IDENTIFY_CNS_NS_USER_DATA_FORMAT, + csi, user_data_format, uidx, + data, NULL); } /** * nvme_identify_iocs_ns_csi_user_data_format() - Identify I/O command set namespace data structure - * @fd: File descriptor of nvme device - * @user_data_format: Return namespaces capability of identifier - * @uuidx: UUID selection, if supported + * @l: Link handle * @csi: Command Set Identifier + * @user_data_format: Return namespaces capability of identifier + * @uidx: UUID selection, if supported * @data: User space destination address to transfer the data * * I/O Command Set specific Identify Namespace data structure for * the specified User Data Format index containing the namespace * capabilities for the I/O Command Set specified in the CSI field. * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_identify_iocs_ns_csi_user_data_format(int fd, - __u16 user_data_format, __u8 uuidx, - enum nvme_csi csi, void *data) +static inline int nvme_identify_iocs_ns_csi_user_data_format(nvme_link_t l, + enum nvme_csi csi, __u16 user_data_format, __u8 uidx, + void *data) { - struct nvme_identify_args args = { - .result = NULL, - .data = data, - .args_size = sizeof(args), - .fd = fd, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .cns = NVME_IDENTIFY_CNS_CSI_NS_USER_DATA_FORMAT, - .csi = csi, - .nsid = NVME_NSID_NONE, - .cntid = NVME_CNTLID_NONE, - .cns_specific_id = user_data_format, - .uuidx = uuidx, - }; - - return nvme_identify(&args); + return nvme_identify(l, NVME_NSID_NONE, NVME_CNTLID_NONE, + NVME_IDENTIFY_CNS_CSI_NS_USER_DATA_FORMAT, + csi, user_data_format, uidx, + data, NULL); } /** * nvme_nvm_identify_ctrl() - Identify controller data - * @fd: File descriptor of nvme device + * @l: Link handle * @id: User space destination address to transfer the data * * Return an identify controller data structure to the host of * processing controller. * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_nvm_identify_ctrl(int fd, struct nvme_id_ctrl_nvm *id) +static inline int nvme_nvm_identify_ctrl(nvme_link_t l, struct nvme_id_ctrl_nvm *id) { - return nvme_identify_ctrl_csi(fd, NVME_CSI_NVM, id); + return nvme_identify_ctrl_csi(l, NVME_CSI_NVM, id); } /** * nvme_identify_domain_list() - Domain list data - * @fd: File descriptor of nvme device + * @l: Link handle * @domid: Domain ID * @list: User space destination address to transfer data * @@ -1214,235 +1234,230 @@ static inline int nvme_nvm_identify_ctrl(int fd, struct nvme_id_ctrl_nvm *id) * See &struct nvme_identify_domain_attr for the definition of the * returned structure. * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_identify_domain_list(int fd, __u16 domid, +static inline int nvme_identify_domain_list(nvme_link_t l, __u16 domid, struct nvme_id_domain_list *list) { - struct nvme_identify_args args = { - .result = NULL, - .data = list, - .args_size = sizeof(args), - .fd = fd, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .cns = NVME_IDENTIFY_CNS_DOMAIN_LIST, - .csi = NVME_CSI_NVM, - .nsid = NVME_NSID_NONE, - .cntid = NVME_CNTLID_NONE, - .cns_specific_id = domid, - .uuidx = NVME_UUID_NONE, - }; - - return nvme_identify(&args); + return nvme_identify(l, NVME_NSID_NONE, NVME_CNTLID_NONE, + NVME_IDENTIFY_CNS_DOMAIN_LIST, + NVME_CSI_NVM, domid, NVME_UUID_NONE, + list, NULL); } /** * nvme_identify_endurance_group_list() - Endurance group list data - * @fd: File descriptor of nvme device + * @l: Link handle * @endgrp_id: Endurance group identifier * @list: Array of endurance group identifiers * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_identify_endurance_group_list(int fd, __u16 endgrp_id, +static inline int nvme_identify_endurance_group_list(nvme_link_t l, __u16 endgrp_id, struct nvme_id_endurance_group_list *list) { - struct nvme_identify_args args = { - .result = NULL, - .data = list, - .args_size = sizeof(args), - .fd = fd, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .cns = NVME_IDENTIFY_CNS_ENDURANCE_GROUP_ID, - .csi = NVME_CSI_NVM, - .nsid = NVME_NSID_NONE, - .cntid = NVME_CNTLID_NONE, - .cns_specific_id = endgrp_id, - .uuidx = NVME_UUID_NONE, - }; - - return nvme_identify(&args); + return nvme_identify(l, NVME_NSID_NONE, NVME_CNTLID_NONE, + NVME_IDENTIFY_CNS_ENDURANCE_GROUP_ID, + NVME_CSI_NVM, endgrp_id, NVME_UUID_NONE, + list, NULL); } /** * nvme_identify_iocs() - I/O command set data structure - * @fd: File descriptor of nvme device + * @l: Link handle * @cntlid: Controller ID * @iocs: User space destination address to transfer the data * * Retrieves list of the controller's supported io command set vectors. See * &struct nvme_id_iocs. * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_identify_iocs(int fd, __u16 cntlid, +static inline int nvme_identify_iocs(nvme_link_t l, __u16 cntlid, struct nvme_id_iocs *iocs) { - struct nvme_identify_args args = { - .result = NULL, - .data = iocs, - .args_size = sizeof(args), - .fd = fd, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .cns = NVME_IDENTIFY_CNS_COMMAND_SET_STRUCTURE, - .csi = NVME_CSI_NVM, - .nsid = NVME_NSID_NONE, - .cntid = cntlid, - .cns_specific_id = NVME_CNSSPECID_NONE, - .uuidx = NVME_UUID_NONE, - }; - - return nvme_identify(&args); + return nvme_identify(l, NVME_NSID_NONE, cntlid, + NVME_IDENTIFY_CNS_COMMAND_SET_STRUCTURE, + NVME_CSI_NVM, NVME_CNSSPECID_NONE, NVME_UUID_NONE, + iocs, NULL); } /** * nvme_zns_identify_ns() - ZNS identify namespace data - * @fd: File descriptor of nvme device + * @l: Link handle * @nsid: Namespace to identify * @data: User space destination address to transfer the data * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_zns_identify_ns(int fd, __u32 nsid, +static inline int nvme_zns_identify_ns(nvme_link_t l, __u32 nsid, struct nvme_zns_id_ns *data) { return nvme_identify_ns_csi( - fd, nsid, NVME_UUID_NONE, NVME_CSI_ZNS, data); + l, nsid, NVME_CSI_ZNS, NVME_UUID_NONE, data); } /** * nvme_zns_identify_ctrl() - ZNS identify controller data - * @fd: File descriptor of nvme device + * @l: Link handle * @id: User space destination address to transfer the data * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_zns_identify_ctrl(int fd, struct nvme_zns_id_ctrl *id) +static inline int nvme_zns_identify_ctrl(nvme_link_t l, struct nvme_zns_id_ctrl *id) { - return nvme_identify_ctrl_csi(fd, NVME_CSI_ZNS, id); + return nvme_identify_ctrl_csi(l, NVME_CSI_ZNS, id); } /** - * nvme_get_log() - NVMe Admin Get Log command - * @args: &struct nvme_get_log_args argument structure + * nvme_get_log_partial() - Get log page data + * @l: Link handle + * @cmd: Passthru command to use + * @lpo: Log page offset for partial log transfers + * @log: User space destination address to transfer the data + * @len: Length of provided user buffer to hold the log data in bytes + * @xfer_len: Max log transfer size per request to split the total. + * @result: The command completion result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_get_log(struct nvme_get_log_args *args); +int nvme_get_log_partial(nvme_link_t l, struct nvme_passthru_cmd *cmd, + __u64 lpo, void *log, __u32 len, __u32 xfer_len, + __u32 *result); /** - * nvme_get_log_page() - Get log page data - * @fd: File descriptor of nvme device + * nvme_get_log() - NVMe Admin Get Log command + * @l: Link handle + * @nsid: Namespace identifier, if applicable + * @rae: Retain asynchronous events + * @lsp: Log specific field + * @lid: Log page identifier, see &enum nvme_cmd_get_log_lid for known + * values + * @lsi: Log Specific Identifier + * @csi: Command set identifier, see &enum nvme_csi for known values + * @ot: Offset Type; if set @lpo specifies the index into the list + * of data structures, otherwise @lpo specifies the byte offset + * into the log page. + * @uidx: UUID selection, if supported + * @lpo: Log page offset for partial log transfers + * @log: User space destination address to transfer the data + * @len: Length of provided user buffer to hold the log data in bytes * @xfer_len: Max log transfer size per request to split the total. - * @args: &struct nvme_get_log_args argument structure + * @result: The command completion result from CQE dword0 * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise. */ -int nvme_get_log_page(int fd, __u32 xfer_len, struct nvme_get_log_args *args); - -static inline int nvme_get_nsid_log(int fd, bool rae, - enum nvme_cmd_get_log_lid lid, - __u32 nsid, __u32 len, void *log) -{ - struct nvme_get_log_args args = { - .lpo = 0, - .result = NULL, - .log = log, - .args_size = sizeof(args), - .fd = fd, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .lid = lid, - .len = len, - .nsid = nsid, - .csi = NVME_CSI_NVM, - .lsi = NVME_LOG_LSI_NONE, - .lsp = NVME_LOG_LSP_NONE, - .uuidx = NVME_UUID_NONE, - .rae = rae, - .ot = false, +static inline int nvme_get_log(nvme_link_t l, + __u32 nsid, bool rae, __u8 lsp, + enum nvme_cmd_get_log_lid lid, + __u16 lsi, enum nvme_csi csi, + bool ot, __u8 uidx, + __u64 lpo, void *log, __u32 len, + __u32 xfer_len, __u32 *result) +{ + __u32 numd = (len >> 2) - 1; + __u16 numdu = numd >> 16, numdl = numd & 0xffff; + + __u32 cdw10 = NVME_SET(lid, LOG_CDW10_LID) | + NVME_SET(lsp, LOG_CDW10_LSP) | + NVME_SET(!!rae, LOG_CDW10_RAE) | + NVME_SET(numdl, LOG_CDW10_NUMDL); + __u32 cdw11 = NVME_SET(numdu, LOG_CDW11_NUMDU) | + NVME_SET(lsi, LOG_CDW11_LSI); + __u32 cdw12 = lpo & 0xffffffff; + __u32 cdw13 = lpo >> 32; + __u32 cdw14 = NVME_SET(uidx, LOG_CDW14_UUID) | + NVME_SET(!!ot, LOG_CDW14_OT) | + NVME_SET(csi, LOG_CDW14_CSI); + + struct nvme_passthru_cmd cmd = { + .opcode = nvme_admin_get_log_page, + .nsid = nsid, + .addr = (__u64)(uintptr_t)log, + .data_len = len, + .cdw10 = cdw10, + .cdw11 = cdw11, + .cdw12 = cdw12, + .cdw13 = cdw13, + .cdw14 = cdw14, }; - return nvme_get_log_page(fd, NVME_LOG_PAGE_PDU_SIZE, &args); -} - -static inline int nvme_get_endgid_log(int fd, bool rae, enum nvme_cmd_get_log_lid lid, __u16 endgid, - __u32 len, void *log) -{ - struct nvme_get_log_args args = { - .lpo = 0, - .result = NULL, - .log = log, - .args_size = sizeof(args), - .fd = fd, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .lid = lid, - .len = len, - .nsid = NVME_NSID_NONE, - .csi = NVME_CSI_NVM, - .lsi = endgid, - .lsp = NVME_LOG_LSP_NONE, - .uuidx = NVME_LOG_LSP_NONE, - .rae = rae, - .ot = false, - }; + return nvme_get_log_partial(l, &cmd, lpo, log, len, xfer_len, result); +} + +static inline int nvme_get_nsid_log(nvme_link_t l, __u32 nsid, bool rae, + enum nvme_cmd_get_log_lid lid, + void *log, __u32 len) +{ + return nvme_get_log(l, nsid, rae, NVME_LOG_LSP_NONE, + lid, NVME_LOG_LSI_NONE, NVME_CSI_NVM, + false, NVME_UUID_NONE, + 0, log, len, NVME_LOG_PAGE_PDU_SIZE, NULL); +} - return nvme_get_log_page(fd, NVME_LOG_PAGE_PDU_SIZE, &args); +static inline int nvme_get_endgid_log(nvme_link_t l, bool rae, enum nvme_cmd_get_log_lid lid, + __u16 endgid, void *log, __u32 len) +{ + return nvme_get_log(l, NVME_NSID_NONE, rae, NVME_LOG_LSP_NONE, + lid, endgid, NVME_CSI_NVM, + false, NVME_UUID_NONE, + 0, log, len, NVME_LOG_PAGE_PDU_SIZE, NULL); } -static inline int nvme_get_log_simple(int fd, enum nvme_cmd_get_log_lid lid, - __u32 len, void *log) +static inline int nvme_get_log_simple(nvme_link_t l, enum nvme_cmd_get_log_lid lid, + void *log, __u32 len) { - return nvme_get_nsid_log(fd, false, lid, NVME_NSID_ALL, len, log); + return nvme_get_nsid_log(l, NVME_NSID_ALL, false, lid, log, len); } /** * nvme_get_log_supported_log_pages() - Retrieve nmve supported log pages - * @fd: File descriptor of nvme device + * @l: Link handle * @rae: Retain asynchronous events * @log: Array of LID supported and Effects data structures * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_get_log_supported_log_pages(int fd, bool rae, +static inline int nvme_get_log_supported_log_pages(nvme_link_t l, bool rae, struct nvme_supported_log_pages *log) { - return nvme_get_nsid_log(fd, rae, NVME_LOG_LID_SUPPORTED_LOG_PAGES, - NVME_NSID_ALL, sizeof(*log), log); + return nvme_get_nsid_log(l, NVME_NSID_ALL, rae, + NVME_LOG_LID_SUPPORTED_LOG_PAGES, + log, sizeof(*log)); } /** * nvme_get_log_error() - Retrieve nvme error log - * @fd: File descriptor of nvme device - * @nr_entries: Number of error log entries allocated + * @l: Link handle * @rae: Retain asynchronous events + * @nr_entries: Number of error log entries allocated * @err_log: Array of error logs of size 'entries' * * This log page describes extended error information for a command that * completed with error, or may report an error that is not specific to a * particular command. * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_get_log_error(int fd, unsigned int nr_entries, bool rae, +static inline int nvme_get_log_error(nvme_link_t l, bool rae, unsigned int nr_entries, struct nvme_error_log_page *err_log) { - return nvme_get_nsid_log(fd, rae, NVME_LOG_LID_ERROR, - NVME_NSID_ALL, sizeof(*err_log) * nr_entries, - err_log); + return nvme_get_nsid_log(l, NVME_NSID_ALL, rae, NVME_LOG_LID_ERROR, + err_log, sizeof(*err_log) * nr_entries); } /** * nvme_get_log_smart() - Retrieve nvme smart log - * @fd: File descriptor of nvme device + * @l: Link handle * @nsid: Optional namespace identifier * @rae: Retain asynchronous events * @smart_log: User address to store the smart log @@ -1454,19 +1469,19 @@ static inline int nvme_get_log_error(int fd, unsigned int nr_entries, bool rae, * page on a per namespace basis, as indicated by bit 0 of the LPA field in the * Identify Controller data structure. * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_get_log_smart(int fd, __u32 nsid, bool rae, +static inline int nvme_get_log_smart(nvme_link_t l, __u32 nsid, bool rae, struct nvme_smart_log *smart_log) { - return nvme_get_nsid_log(fd, rae, NVME_LOG_LID_SMART, - nsid, sizeof(*smart_log), smart_log); + return nvme_get_nsid_log(l, nsid, rae, NVME_LOG_LID_SMART, + smart_log, sizeof(*smart_log)); } /** * nvme_get_log_fw_slot() - Retrieves the controller firmware log - * @fd: File descriptor of nvme device + * @l: Link handle * @rae: Retain asynchronous events * @fw_log: User address to store the log page * @@ -1474,19 +1489,19 @@ static inline int nvme_get_log_smart(int fd, __u32 nsid, bool rae, * supported. The firmware revision is indicated as an ASCII string. The log * page also indicates the active slot number. * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_get_log_fw_slot(int fd, bool rae, +static inline int nvme_get_log_fw_slot(nvme_link_t l, bool rae, struct nvme_firmware_slot *fw_log) { - return nvme_get_nsid_log(fd, rae, NVME_LOG_LID_FW_SLOT, - NVME_NSID_ALL, sizeof(*fw_log), fw_log); + return nvme_get_nsid_log(l, NVME_NSID_ALL, rae, NVME_LOG_LID_FW_SLOT, + fw_log, sizeof(*fw_log)); } /** * nvme_get_log_changed_ns_list() - Retrieve namespace changed list - * @fd: File descriptor of nvme device + * @l: Link handle * @rae: Retain asynchronous events * @ns_log: User address to store the log page * @@ -1494,193 +1509,143 @@ static inline int nvme_get_log_fw_slot(int fd, bool rae, * changed since the last time the namespace was identified, been added, or * deleted. * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_get_log_changed_ns_list(int fd, bool rae, +static inline int nvme_get_log_changed_ns_list(nvme_link_t l, bool rae, struct nvme_ns_list *ns_log) { - return nvme_get_nsid_log(fd, rae, NVME_LOG_LID_CHANGED_NS, - NVME_NSID_ALL, sizeof(*ns_log), ns_log); + return nvme_get_nsid_log(l, NVME_NSID_ALL, rae, NVME_LOG_LID_CHANGED_NS, + ns_log, sizeof(*ns_log)); } /** * nvme_get_log_cmd_effects() - Retrieve nvme command effects log - * @fd: File descriptor of nvme device + * @l: Link handle * @csi: Command Set Identifier * @effects_log:User address to store the effects log * * This log page describes the commands that the controller supports and the * effects of those commands on the state of the NVM subsystem. * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_get_log_cmd_effects(int fd, enum nvme_csi csi, +static inline int nvme_get_log_cmd_effects(nvme_link_t l, enum nvme_csi csi, struct nvme_cmd_effects_log *effects_log) { - struct nvme_get_log_args args = { - .lpo = 0, - .result = NULL, - .log = effects_log, - .args_size = sizeof(args), - .fd = fd, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .lid = NVME_LOG_LID_CMD_EFFECTS, - .len = sizeof(*effects_log), - .nsid = NVME_NSID_ALL, - .csi = csi, - .lsi = NVME_LOG_LSI_NONE, - .lsp = NVME_LOG_LSP_NONE, - .uuidx = NVME_UUID_NONE, - .rae = false, - .ot = false, - }; - return nvme_get_log_page(fd, NVME_LOG_PAGE_PDU_SIZE, &args); + return nvme_get_log(l, NVME_NSID_ALL, false, NVME_LOG_LSP_NONE, + NVME_LOG_LID_CMD_EFFECTS, NVME_LOG_LSI_NONE, csi, + false, NVME_UUID_NONE, + 0, effects_log, sizeof(*effects_log), + NVME_LOG_PAGE_PDU_SIZE, NULL); } /** * nvme_get_log_device_self_test() - Retrieve the device self test log - * @fd: File descriptor of nvme device + * @l: Link handle * @log: Userspace address of the log payload * * The log page indicates the status of an in progress self test and the * percent complete of that operation, and the results of the previous 20 * self-test operations. * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_get_log_device_self_test(int fd, +static inline int nvme_get_log_device_self_test(nvme_link_t l, struct nvme_self_test_log *log) { - return nvme_get_nsid_log(fd, false, NVME_LOG_LID_DEVICE_SELF_TEST, - NVME_NSID_ALL, sizeof(*log), log); + return nvme_get_nsid_log(l, NVME_NSID_ALL, false, + NVME_LOG_LID_DEVICE_SELF_TEST, + log, sizeof(*log)); } /** * nvme_get_log_create_telemetry_host_mcda() - Create host telemetry log - * @fd: File descriptor of nvme device + * @l: Link handle * @mcda: Maximum Created Data Area * @log: Userspace address of the log payload * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_get_log_create_telemetry_host_mcda(int fd, +static inline int nvme_get_log_create_telemetry_host_mcda(nvme_link_t l, enum nvme_telemetry_da mcda, struct nvme_telemetry_log *log) { - struct nvme_get_log_args args = { - .lpo = 0, - .result = NULL, - .log = log, - .args_size = sizeof(args), - .fd = fd, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .lid = NVME_LOG_LID_TELEMETRY_HOST, - .len = sizeof(*log), - .nsid = NVME_NSID_NONE, - .csi = NVME_CSI_NVM, - .lsi = NVME_LOG_LSI_NONE, - .lsp = (__u8)((mcda << 1) | NVME_LOG_TELEM_HOST_LSP_CREATE), - .uuidx = NVME_UUID_NONE, - .rae = false, - .ot = false, - }; - return nvme_get_log_page(fd, NVME_LOG_PAGE_PDU_SIZE, &args); + return nvme_get_log(l, NVME_NSID_NONE, false, + (__u8)((mcda << 1) | NVME_LOG_TELEM_HOST_LSP_CREATE), + NVME_LOG_LID_TELEMETRY_HOST, NVME_LOG_LSI_NONE, + NVME_CSI_NVM, false, NVME_UUID_NONE, + 0, log, sizeof(*log), + NVME_LOG_PAGE_PDU_SIZE, NULL); } /** * nvme_get_log_create_telemetry_host() - Create host telemetry log - * @fd: File descriptor of nvme device + * @l: Link handle * @log: Userspace address of the log payload * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_get_log_create_telemetry_host(int fd, +static inline int nvme_get_log_create_telemetry_host(nvme_link_t l, struct nvme_telemetry_log *log) { - return nvme_get_log_create_telemetry_host_mcda(fd, NVME_TELEMETRY_DA_CTRL_DETERMINE, log); + return nvme_get_log_create_telemetry_host_mcda(l, + NVME_TELEMETRY_DA_CTRL_DETERMINE, log); } /** * nvme_get_log_telemetry_host() - Get Telemetry Host-Initiated log page - * @fd: File descriptor of nvme device - * @offset: Offset into the telemetry data - * @len: Length of provided user buffer to hold the log data in bytes + * @l: Link handle + * @lpo: Offset into the telemetry data * @log: User address for log page data + * @len: Length of provided user buffer to hold the log data in bytes * * Retrieves the Telemetry Host-Initiated log page at the requested offset * using the previously existing capture. * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_get_log_telemetry_host(int fd, __u64 offset, - __u32 len, void *log) -{ - struct nvme_get_log_args args = { - .lpo = offset, - .result = NULL, - .log = log, - .args_size = sizeof(args), - .fd = fd, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .lid = NVME_LOG_LID_TELEMETRY_HOST, - .len = len, - .nsid = NVME_NSID_NONE, - .csi = NVME_CSI_NVM, - .lsi = NVME_LOG_LSI_NONE, - .lsp = NVME_LOG_TELEM_HOST_LSP_RETAIN, - .uuidx = NVME_UUID_NONE, - .rae = false, - .ot = false, - }; - return nvme_get_log_page(fd, NVME_LOG_PAGE_PDU_SIZE, &args); +static inline int nvme_get_log_telemetry_host(nvme_link_t l, __u64 lpo, + void *log, __u32 len) +{ + return nvme_get_log(l, NVME_NSID_NONE, false, + NVME_LOG_TELEM_HOST_LSP_RETAIN, NVME_LOG_LID_TELEMETRY_HOST, + NVME_LOG_LSI_NONE, NVME_CSI_NVM, + false, NVME_UUID_NONE, + lpo, log, len, NVME_LOG_PAGE_PDU_SIZE, NULL); } /** * nvme_get_log_telemetry_ctrl() - Get Telemetry Controller-Initiated log page - * @fd: File descriptor of nvme device + * @l: Link handle * @rae: Retain asynchronous events - * @offset: Offset into the telemetry data - * @len: Length of provided user buffer to hold the log data in bytes + * @lpo: Offset into the telemetry data * @log: User address for log page data + * @len: Length of provided user buffer to hold the log data in bytes * * Retrieves the Telemetry Controller-Initiated log page at the requested offset * using the previously existing capture. * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_get_log_telemetry_ctrl(int fd, bool rae, - __u64 offset, __u32 len, void *log) -{ - struct nvme_get_log_args args = { - .lpo = offset, - .result = NULL, - .log = log, - .args_size = sizeof(args), - .fd = fd, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .lid = NVME_LOG_LID_TELEMETRY_CTRL, - .len = len, - .nsid = NVME_NSID_NONE, - .csi = NVME_CSI_NVM, - .lsi = NVME_LOG_LSI_NONE, - .lsp = NVME_LOG_LSP_NONE, - .uuidx = NVME_UUID_NONE, - .rae = rae, - .ot = false, - }; - return nvme_get_log_page(fd, NVME_LOG_PAGE_PDU_SIZE, &args); +static inline int nvme_get_log_telemetry_ctrl(nvme_link_t l, bool rae, + __u64 lpo, void *log, __u32 len) +{ + return nvme_get_log(l, NVME_NSID_NONE, rae, NVME_LOG_LSP_NONE, + NVME_LOG_LID_TELEMETRY_CTRL, NVME_LOG_LSI_NONE, + NVME_CSI_NVM, false, NVME_UUID_NONE, + lpo, log, len, NVME_LOG_PAGE_PDU_SIZE, NULL); } /** * nvme_get_log_endurance_group() - Get Endurance Group log - * @fd: File descriptor of nvme device + * @l: Link handle * @endgid: Starting group identifier to return in the list * @log: User address to store the endurance log * @@ -1691,226 +1656,140 @@ static inline int nvme_get_log_telemetry_ctrl(int fd, bool rae, * generated when an entry for an Endurance Group is newly added to this log * page. * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_get_log_endurance_group(int fd, __u16 endgid, +static inline int nvme_get_log_endurance_group(nvme_link_t l, __u16 endgid, struct nvme_endurance_group_log *log) { - struct nvme_get_log_args args = { - .lpo = 0, - .result = NULL, - .log = log, - .args_size = sizeof(args), - .fd = fd, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .lid = NVME_LOG_LID_ENDURANCE_GROUP, - .len = sizeof(*log), - .nsid = NVME_NSID_NONE, - .csi = NVME_CSI_NVM, - .lsi = endgid, - .lsp = NVME_LOG_LSP_NONE, - .uuidx = NVME_UUID_NONE, - .rae = false, - .ot = false, - }; - return nvme_get_log_page(fd, NVME_LOG_PAGE_PDU_SIZE, &args); + return nvme_get_log(l, NVME_NSID_NONE, false, NVME_LOG_LSP_NONE, + NVME_LOG_LID_ENDURANCE_GROUP, endgid, NVME_CSI_NVM, + false, NVME_UUID_NONE, + 0, log, sizeof(*log), + NVME_LOG_PAGE_PDU_SIZE, NULL); } /** * nvme_get_log_predictable_lat_nvmset() - Predictable Latency Per NVM Set - * @fd: File descriptor of nvme device + * @l: Link handle * @nvmsetid: NVM set id * @log: User address to store the predictable latency log * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_get_log_predictable_lat_nvmset(int fd, __u16 nvmsetid, +static inline int nvme_get_log_predictable_lat_nvmset(nvme_link_t l, __u16 nvmsetid, struct nvme_nvmset_predictable_lat_log *log) { - struct nvme_get_log_args args = { - .lpo = 0, - .result = NULL, - .log = log, - .args_size = sizeof(args), - .fd = fd, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .lid = NVME_LOG_LID_PREDICTABLE_LAT_NVMSET, - .len = sizeof(*log), - .nsid = NVME_NSID_NONE, - .csi = NVME_CSI_NVM, - .lsi = nvmsetid, - .lsp = NVME_LOG_LSP_NONE, - .uuidx = NVME_UUID_NONE, - .rae = false, - .ot = false, - }; - return nvme_get_log_page(fd, NVME_LOG_PAGE_PDU_SIZE, &args); + return nvme_get_log(l, NVME_NSID_NONE, false, NVME_LOG_LSP_NONE, + NVME_LOG_LID_PREDICTABLE_LAT_NVMSET, nvmsetid, NVME_CSI_NVM, + false, NVME_UUID_NONE, + 0, log, sizeof(*log), + NVME_LOG_PAGE_PDU_SIZE, NULL); } /** * nvme_get_log_predictable_lat_event() - Retrieve Predictable Latency Event Aggregate Log Page - * @fd: File descriptor of nvme device + * @l: Link handle * @rae: Retain asynchronous events - * @offset: Offset into the predictable latency event - * @len: Length of provided user buffer to hold the log data in bytes + * @lpo: Offset into the predictable latency event * @log: User address for log page data + * @len: Length of provided user buffer to hold the log data in bytes * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_get_log_predictable_lat_event(int fd, bool rae, - __u32 offset, __u32 len, void *log) -{ - struct nvme_get_log_args args = { - .lpo = offset, - .result = NULL, - .log = log, - .args_size = sizeof(args), - .fd = fd, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .lid = NVME_LOG_LID_PREDICTABLE_LAT_AGG, - .len = len, - .nsid = NVME_NSID_NONE, - .csi = NVME_CSI_NVM, - .lsi = NVME_LOG_LSI_NONE, - .lsp = NVME_LOG_LSP_NONE, - .uuidx = NVME_UUID_NONE, - .rae = rae, - .ot = false, - }; - return nvme_get_log_page(fd, NVME_LOG_PAGE_PDU_SIZE, &args); +static inline int nvme_get_log_predictable_lat_event(nvme_link_t l, bool rae, + __u64 lpo, void *log, __u32 len) +{ + return nvme_get_log(l, NVME_NSID_NONE, rae, NVME_LOG_LSP_NONE, + NVME_LOG_LID_PREDICTABLE_LAT_AGG, NVME_LOG_LSI_NONE, NVME_CSI_NVM, + false, NVME_UUID_NONE, + lpo, log, len, + NVME_LOG_PAGE_PDU_SIZE, NULL); } /** * nvme_get_log_fdp_configurations() - Get list of Flexible Data Placement configurations - * @fd: File descriptor of nvme device + * @l: Link handle * @egid: Endurance group identifier - * @offset: Offset into log page + * @lpo: Offset into log page * @len: Length (in bytes) of provided user buffer to hold the log data * @log: Log page data buffer */ -static inline int nvme_get_log_fdp_configurations(int fd, __u16 egid, - __u32 offset, __u32 len, void *log) -{ - struct nvme_get_log_args args = { - .lpo = offset, - .result = NULL, - .log = log, - .args_size = sizeof(args), - .fd = fd, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .lid = NVME_LOG_LID_FDP_CONFIGS, - .len = len, - .nsid = NVME_NSID_NONE, - .csi = NVME_CSI_NVM, - .lsi = egid, - .lsp = NVME_LOG_LSP_NONE, - .uuidx = NVME_UUID_NONE, - }; - - return nvme_get_log(&args); +static inline int nvme_get_log_fdp_configurations(nvme_link_t l, __u16 egid, + __u64 lpo, __u32 len, void *log) +{ + return nvme_get_log(l, NVME_NSID_NONE, false, NVME_LOG_LSP_NONE, + NVME_LOG_LID_FDP_CONFIGS, egid, NVME_CSI_NVM, + false, NVME_UUID_NONE, + lpo, log, len, + NVME_LOG_PAGE_PDU_SIZE, NULL); } /** * nvme_get_log_reclaim_unit_handle_usage() - Get reclaim unit handle usage - * @fd: File descriptor of nvme device + * @l: Link handle * @egid: Endurance group identifier - * @offset: Offset into log page - * @len: Length (in bytes) of provided user buffer to hold the log data + * @lpo: Offset into log page * @log: Log page data buffer + * @len: Length (in bytes) of provided user buffer to hold the log data */ -static inline int nvme_get_log_reclaim_unit_handle_usage(int fd, __u16 egid, - __u32 offset, __u32 len, void *log) -{ - struct nvme_get_log_args args = { - .lpo = offset, - .result = NULL, - .log = log, - .args_size = sizeof(args), - .fd = fd, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .lid = NVME_LOG_LID_FDP_RUH_USAGE, - .len = len, - .nsid = NVME_NSID_NONE, - .csi = NVME_CSI_NVM, - .lsi = egid, - .lsp = NVME_LOG_LSP_NONE, - .uuidx = NVME_UUID_NONE, - }; - - return nvme_get_log(&args); +static inline int nvme_get_log_reclaim_unit_handle_usage(nvme_link_t l, __u16 egid, + __u64 lpo, void *log, __u32 len) +{ + return nvme_get_log(l, NVME_NSID_NONE, false, NVME_LOG_LSP_NONE, + NVME_LOG_LID_FDP_RUH_USAGE, egid, NVME_CSI_NVM, + false, NVME_UUID_NONE, + lpo, log, len, + NVME_LOG_PAGE_PDU_SIZE, NULL); } /** * nvme_get_log_fdp_stats() - Get Flexible Data Placement statistics - * @fd: File descriptor of nvme device + * @l: Link handle * @egid: Endurance group identifier - * @offset: Offset into log page - * @len: Length (in bytes) of provided user buffer to hold the log data + * @lpo: Offset into log page * @log: Log page data buffer + * @len: Length (in bytes) of provided user buffer to hold the log data */ -static inline int nvme_get_log_fdp_stats(int fd, __u16 egid, __u32 offset, __u32 len, void *log) -{ - struct nvme_get_log_args args = { - .lpo = offset, - .result = NULL, - .log = log, - .args_size = sizeof(args), - .fd = fd, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .lid = NVME_LOG_LID_FDP_STATS, - .len = len, - .nsid = NVME_NSID_NONE, - .csi = NVME_CSI_NVM, - .lsi = egid, - .lsp = NVME_LOG_LSP_NONE, - .uuidx = NVME_UUID_NONE, - }; - - return nvme_get_log(&args); +static inline int nvme_get_log_fdp_stats(nvme_link_t l, __u16 egid, + __u64 lpo, void *log, __u32 len) +{ + return nvme_get_log(l, NVME_NSID_NONE, false, NVME_LOG_LSP_NONE, + NVME_LOG_LID_FDP_STATS, egid, NVME_CSI_NVM, + false, NVME_UUID_NONE, + lpo, log, len, + NVME_LOG_PAGE_PDU_SIZE, NULL); } /** * nvme_get_log_fdp_events() - Get Flexible Data Placement events - * @fd: File descriptor of nvme device + * @l: Link handle * @egid: Endurance group identifier * @host_events: Whether to report host or controller events - * @offset: Offset into log page - * @len: Length (in bytes) of provided user buffer to hold the log data + * @lpo: Offset into log page * @log: Log page data buffer + * @len: Length (in bytes) of provided user buffer to hold the log data */ -static inline int nvme_get_log_fdp_events(int fd, __u16 egid, bool host_events, __u32 offset, - __u32 len, void *log) -{ - struct nvme_get_log_args args = { - .lpo = offset, - .result = NULL, - .log = log, - .args_size = sizeof(args), - .fd = fd, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .lid = NVME_LOG_LID_FDP_EVENTS, - .len = len, - .nsid = NVME_NSID_NONE, - .csi = NVME_CSI_NVM, - .lsi = egid, - .lsp = (__u8)(host_events ? 0x1 : 0x0), - .uuidx = NVME_UUID_NONE, - }; - - return nvme_get_log(&args); +static inline int nvme_get_log_fdp_events(nvme_link_t l, __u16 egid, + bool host_events, __u64 lpo, void *log, __u32 len) +{ + return nvme_get_log(l, NVME_NSID_NONE, false, (__u8)(host_events ? 0x1 : 0x0), + NVME_LOG_LID_FDP_EVENTS, egid, NVME_CSI_NVM, + false, NVME_UUID_NONE, + lpo, log, len, + NVME_LOG_PAGE_PDU_SIZE, NULL); } /** * nvme_get_log_ana() - Retrieve Asymmetric Namespace Access log page - * @fd: File descriptor of nvme device - * @lsp: Log specific, see &enum nvme_get_log_ana_lsp + * @l: Link handle * @rae: Retain asynchronous events - * @offset: Offset to the start of the log page - * @len: The allocated length of the log page + * @lsp: Log specific, see &enum nvme_get_log_ana_lsp + * @lpo: Offset to the start of the log page * @log: User address to store the ana log + * @len: The allocated length of the log page * * This log consists of a header describing the log and descriptors containing * the asymmetric namespace access information for ANA Groups that contain @@ -1918,60 +1797,47 @@ static inline int nvme_get_log_fdp_events(int fd, __u16 egid, bool host_events, * * See &struct nvme_ana_log for the definition of the returned structure. * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_get_log_ana(int fd, enum nvme_log_ana_lsp lsp, bool rae, - __u64 offset, __u32 len, void *log) -{ - struct nvme_get_log_args args = { - .lpo = offset, - .result = NULL, - .log = log, - .args_size = sizeof(args), - .fd = fd, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .lid = NVME_LOG_LID_ANA, - .len = len, - .nsid = NVME_NSID_NONE, - .csi = NVME_CSI_NVM, - .lsi = NVME_LOG_LSI_NONE, - .lsp = (__u8)lsp, - .uuidx = NVME_UUID_NONE, - .rae = rae, - .ot = false, - }; - return nvme_get_log_page(fd, NVME_LOG_PAGE_PDU_SIZE, &args); +static inline int nvme_get_log_ana(nvme_link_t l, bool rae, enum nvme_log_ana_lsp lsp, + __u64 lpo, void *log, __u32 len) +{ + return nvme_get_log(l, NVME_NSID_NONE, rae, (__u8)lsp, + NVME_LOG_LID_ANA, NVME_LOG_LSI_NONE, NVME_CSI_NVM, + false, NVME_UUID_NONE, + lpo, log, len, + NVME_LOG_PAGE_PDU_SIZE, NULL); } /** * nvme_get_log_ana_groups() - Retrieve Asymmetric Namespace Access groups only log page - * @fd: File descriptor of nvme device + * @l: Link handle * @rae: Retain asynchronous events - * @len: The allocated length of the log page * @log: User address to store the ana group log + * @len: The allocated length of the log page * * See &struct nvme_ana_log for the definition of the returned structure. * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_get_log_ana_groups(int fd, bool rae, __u32 len, - struct nvme_ana_log *log) +static inline int nvme_get_log_ana_groups(nvme_link_t l, bool rae, + struct nvme_ana_log *log, __u32 len) { - return nvme_get_log_ana(fd, NVME_LOG_ANA_LSP_RGO_GROUPS_ONLY, rae, 0, - len, log); + return nvme_get_log_ana(l, rae, NVME_LOG_ANA_LSP_RGO_GROUPS_ONLY, + 0, log, len); } /** * nvme_get_ana_log_atomic() - Retrieve Asymmetric Namespace Access log page atomically - * @fd: File descriptor of nvme device - * @rgo: Whether to retrieve ANA groups only (no NSIDs) + * @l: Link handle * @rae: Whether to retain asynchronous events - * @retries: The maximum number of times to retry on log page changes + * @rgo: Whether to retrieve ANA groups only (no NSIDs) * @log: Pointer to a buffer to receive the ANA log page * @len: Input: the length of the log page buffer. * Output: the actual length of the ANA log page. + * @retries: The maximum number of times to retry on log page changes * * See &struct nvme_ana_log for the definition of the returned structure. * @@ -1983,1666 +1849,1965 @@ static inline int nvme_get_log_ana_groups(int fd, bool rae, __u32 len, * because chgcnt changed during each of the retries attempts. * Sets errno = ENOSPC if the full log page does not fit in the provided buffer. */ -int nvme_get_ana_log_atomic(int fd, bool rgo, bool rae, unsigned int retries, - struct nvme_ana_log *log, __u32 *len); +int nvme_get_ana_log_atomic(nvme_link_t l, bool rae, bool rgo, + struct nvme_ana_log *log, __u32 *len, + unsigned int retries); /** * nvme_get_log_lba_status() - Retrieve LBA Status - * @fd: File descriptor of nvme device + * @l: Link handle * @rae: Retain asynchronous events - * @offset: Offset to the start of the log page - * @len: The allocated length of the log page + * @lpo: Offset to the start of the log page * @log: User address to store the log page + * @len: The allocated length of the log page * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_get_log_lba_status(int fd, bool rae, - __u64 offset, __u32 len, void *log) -{ - struct nvme_get_log_args args = { - .lpo = offset, - .result = NULL, - .log = log, - .args_size = sizeof(args), - .fd = fd, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .lid = NVME_LOG_LID_LBA_STATUS, - .len = len, - .nsid = NVME_NSID_NONE, - .csi = NVME_CSI_NVM, - .lsi = NVME_LOG_LSI_NONE, - .lsp = NVME_LOG_LSP_NONE, - .uuidx = NVME_UUID_NONE, - .rae = rae, - .ot = false, - }; - return nvme_get_log_page(fd, NVME_LOG_PAGE_PDU_SIZE, &args); +static inline int nvme_get_log_lba_status(nvme_link_t l, bool rae, + __u64 lpo, void *log, __u32 len) +{ + return nvme_get_log(l, NVME_NSID_NONE, rae, NVME_LOG_LSP_NONE, + NVME_LOG_LID_LBA_STATUS, NVME_LOG_LSI_NONE, NVME_CSI_NVM, + false, NVME_UUID_NONE, + lpo, log, len, + NVME_LOG_PAGE_PDU_SIZE, NULL); } /** * nvme_get_log_endurance_grp_evt() - Retrieve Endurance Group Event Aggregate - * @fd: File descriptor of nvme device + * @l: Link handle * @rae: Retain asynchronous events - * @offset: Offset to the start of the log page - * @len: The allocated length of the log page + * @lpo: Offset to the start of the log page * @log: User address to store the log page + * @len: The allocated length of the log page * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_get_log_endurance_grp_evt(int fd, bool rae, - __u32 offset, __u32 len, void *log) -{ - struct nvme_get_log_args args = { - .lpo = offset, - .result = NULL, - .log = log, - .args_size = sizeof(args), - .fd = fd, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .lid = NVME_LOG_LID_ENDURANCE_GRP_EVT, - .len = len, - .nsid = NVME_NSID_NONE, - .csi = NVME_CSI_NVM, - .lsi = NVME_LOG_LSI_NONE, - .lsp = NVME_LOG_LSP_NONE, - .uuidx = NVME_UUID_NONE, - .rae = rae, - .ot = false, - }; - return nvme_get_log_page(fd, NVME_LOG_PAGE_PDU_SIZE, &args); +static inline int nvme_get_log_endurance_grp_evt(nvme_link_t l, bool rae, + __u64 lpo, void *log, __u32 len) +{ + return nvme_get_log(l, NVME_NSID_NONE, rae, NVME_LOG_LSP_NONE, + NVME_LOG_LID_ENDURANCE_GRP_EVT, NVME_LOG_LSI_NONE, NVME_CSI_NVM, + false, NVME_UUID_NONE, + lpo, log, len, + NVME_LOG_PAGE_PDU_SIZE, NULL); } /** * nvme_get_log_fid_supported_effects() - Retrieve Feature Identifiers Supported and Effects - * @fd: File descriptor of nvme device + * @l: Link handle * @rae: Retain asynchronous events * @log: FID Supported and Effects data structure * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise */ -static inline int nvme_get_log_fid_supported_effects(int fd, bool rae, +static inline int nvme_get_log_fid_supported_effects(nvme_link_t l, bool rae, struct nvme_fid_supported_effects_log *log) { - return nvme_get_nsid_log(fd, rae, NVME_LOG_LID_FID_SUPPORTED_EFFECTS, - NVME_NSID_NONE, sizeof(*log), log); + return nvme_get_nsid_log(l, NVME_NSID_NONE, rae, + NVME_LOG_LID_FID_SUPPORTED_EFFECTS, + log, sizeof(*log)); } /** * nvme_get_log_mi_cmd_supported_effects() - displays the MI Commands Supported by the controller - * @fd: File descriptor of nvme device - * @rae: Retain asynchronous events - * @log: MI Command Supported and Effects data structure + * @l: Link handle + * @rae: Retain asynchronous events + * @log: MI Command Supported and Effects data structure * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise */ -static inline int nvme_get_log_mi_cmd_supported_effects(int fd, bool rae, +static inline int nvme_get_log_mi_cmd_supported_effects(nvme_link_t l, bool rae, struct nvme_mi_cmd_supported_effects_log *log) { - return nvme_get_nsid_log(fd, rae, NVME_LOG_LID_MI_CMD_SUPPORTED_EFFECTS, - NVME_NSID_NONE, sizeof(*log), log); + return nvme_get_nsid_log(l, NVME_NSID_NONE, rae, + NVME_LOG_LID_MI_CMD_SUPPORTED_EFFECTS, + log, sizeof(*log)); } /** * nvme_get_log_boot_partition() - Retrieve Boot Partition - * @fd: File descriptor of nvme device + * @l: Link handle * @rae: Retain asynchronous events * @lsp: The log specified field of LID + * @part: User address to store the log page * @len: The allocated size, minimum * struct nvme_boot_partition - * @part: User address to store the log page * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise */ -static inline int nvme_get_log_boot_partition(int fd, bool rae, - __u8 lsp, __u32 len, struct nvme_boot_partition *part) -{ - struct nvme_get_log_args args = { - .lpo = 0, - .result = NULL, - .log = part, - .args_size = sizeof(args), - .fd = fd, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .lid = NVME_LOG_LID_BOOT_PARTITION, - .len = len, - .nsid = NVME_NSID_NONE, - .csi = NVME_CSI_NVM, - .lsi = NVME_LOG_LSI_NONE, - .lsp = lsp, - .uuidx = NVME_UUID_NONE, - .rae = rae, - .ot = false, - }; - return nvme_get_log_page(fd, NVME_LOG_PAGE_PDU_SIZE, &args); +static inline int nvme_get_log_boot_partition(nvme_link_t l, bool rae, + __u8 lsp, struct nvme_boot_partition *part, __u32 len) +{ + return nvme_get_log(l, NVME_NSID_NONE, rae, lsp, + NVME_LOG_LID_BOOT_PARTITION, NVME_LOG_LSI_NONE, NVME_CSI_NVM, + false, NVME_UUID_NONE, + 0, part, len, + NVME_LOG_PAGE_PDU_SIZE, NULL); } /** * nvme_get_log_rotational_media_info() - Retrieve Rotational Media Information Log - * @fd: File descriptor of nvme device + * @l: Link handle * @endgid: Endurance Group Identifier - * @len: The allocated length of the log page * @log: User address to store the log page + * @len: The allocated length of the log page * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise */ -static inline int nvme_get_log_rotational_media_info(int fd, __u16 endgid, __u32 len, - struct nvme_rotational_media_info_log *log) +static inline int nvme_get_log_rotational_media_info(nvme_link_t l, __u16 endgid, + struct nvme_rotational_media_info_log *log, + __u32 len) { - return nvme_get_endgid_log(fd, false, NVME_LOG_LID_ROTATIONAL_MEDIA_INFO, endgid, len, log); + return nvme_get_endgid_log(l, false, + NVME_LOG_LID_ROTATIONAL_MEDIA_INFO, + endgid, log, len); } /** * nvme_get_log_dispersed_ns_participating_nss() - Retrieve Dispersed Namespace Participating NVM * Subsystems Log - * @fd: File descriptor of nvme device + * @l: Link handle * @nsid: Namespace Identifier - * @len: The allocated length of the log page * @log: User address to store the log page + * @len: The allocated length of the log page * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise */ -static inline int nvme_get_log_dispersed_ns_participating_nss(int fd, __u32 nsid, __u32 len, - struct nvme_dispersed_ns_participating_nss_log *log) +static inline int nvme_get_log_dispersed_ns_participating_nss(nvme_link_t l, __u32 nsid, + struct nvme_dispersed_ns_participating_nss_log *log, + __u32 len) { - return nvme_get_nsid_log(fd, false, NVME_LOG_LID_DISPERSED_NS_PARTICIPATING_NSS, nsid, len, - log); + return nvme_get_nsid_log(l, nsid, false, + NVME_LOG_LID_DISPERSED_NS_PARTICIPATING_NSS, + log, len); } /** * nvme_get_log_mgmt_addr_list() - Retrieve Management Address List Log - * @fd: File descriptor of nvme device - * @len: The allocated length of the log page + * @l: Link handle * @log: User address to store the log page + * @len: The allocated length of the log page * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise */ -static inline int nvme_get_log_mgmt_addr_list(int fd, __u32 len, - struct nvme_mgmt_addr_list_log *log) +static inline int nvme_get_log_mgmt_addr_list(nvme_link_t l, + struct nvme_mgmt_addr_list_log *log, __u32 len) { - return nvme_get_log_simple(fd, NVME_LOG_LID_MGMT_ADDR_LIST, len, log); + return nvme_get_log_simple(l, NVME_LOG_LID_MGMT_ADDR_LIST, log, len); } /** * nvme_get_log_phy_rx_eom() - Retrieve Physical Interface Receiver Eye Opening Measurement Log - * @fd: File descriptor of nvme device + * @l: Link handle * @lsp: Log specific, controls action and measurement quality * @controller: Target controller ID + * @log: User address to store the log page * @len: The allocated size, minimum * struct nvme_phy_rx_eom_log - * @log: User address to store the log page * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise */ -static inline int nvme_get_log_phy_rx_eom(int fd, __u8 lsp, __u16 controller, - __u32 len, struct nvme_phy_rx_eom_log *log) -{ - struct nvme_get_log_args args = { - .lpo = 0, - .result = NULL, - .log = log, - .args_size = sizeof(args), - .fd = fd, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .lid = NVME_LOG_LID_PHY_RX_EOM, - .len = len, - .nsid = NVME_NSID_NONE, - .csi = NVME_CSI_NVM, - .lsi = controller, - .lsp = lsp, - .uuidx = NVME_UUID_NONE, - .rae = false, - .ot = false, - }; - return nvme_get_log_page(fd, NVME_LOG_PAGE_PDU_SIZE, &args); +static inline int nvme_get_log_phy_rx_eom(nvme_link_t l, __u8 lsp, + __u16 controller, struct nvme_phy_rx_eom_log *log, + __u32 len) +{ + return nvme_get_log(l, NVME_NSID_NONE, false, lsp, + NVME_LOG_LID_PHY_RX_EOM, controller, NVME_CSI_NVM, + false, NVME_UUID_NONE, + 0, log, len, + NVME_LOG_PAGE_PDU_SIZE, NULL); } /** * nvme_get_log_reachability_groups() - Retrieve Reachability Groups Log - * @fd: File descriptor of nvme device - * @rgo: Return groups only + * @l: Link handle * @rae: Retain asynchronous events - * @len: The allocated length of the log page + * @rgo: Return groups only * @log: User address to store the log page + * @len: The allocated length of the log page * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise */ -static inline int nvme_get_log_reachability_groups(int fd, bool rgo, bool rae, __u32 len, - struct nvme_reachability_groups_log *log) -{ - struct nvme_get_log_args args = { - .lpo = 0, - .result = NULL, - .log = log, - .args_size = sizeof(args), - .fd = fd, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .lid = NVME_LOG_LID_REACHABILITY_GROUPS, - .len = len, - .nsid = NVME_NSID_ALL, - .csi = NVME_CSI_NVM, - .lsi = NVME_LOG_LSI_NONE, - .lsp = rgo, - .uuidx = NVME_LOG_LSP_NONE, - .rae = rae, - .ot = false, - }; - - return nvme_get_log_page(fd, NVME_LOG_PAGE_PDU_SIZE, &args); +static inline int nvme_get_log_reachability_groups(nvme_link_t l, bool rae, bool rgo, + struct nvme_reachability_groups_log *log, __u32 len) +{ + return nvme_get_log(l, NVME_NSID_ALL, rae, (__u8)rgo, + NVME_LOG_LID_REACHABILITY_GROUPS, NVME_LOG_LSI_NONE, NVME_CSI_NVM, + false, NVME_UUID_NONE, + 0, log, len, + NVME_LOG_PAGE_PDU_SIZE, NULL); } /** * nvme_get_log_reachability_associations() - Retrieve Reachability Associations Log - * @fd: File descriptor of nvme device - * @rao: Return associations only + * @l: Link handle * @rae: Retain asynchronous events - * @len: The allocated length of the log page + * @rao: Return associations only * @log: User address to store the log page + * @len: The allocated length of the log page * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise */ -static inline int nvme_get_log_reachability_associations(int fd, bool rao, bool rae, __u32 len, - struct nvme_reachability_associations_log *log) -{ - struct nvme_get_log_args args = { - .lpo = 0, - .result = NULL, - .log = log, - .args_size = sizeof(args), - .fd = fd, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .lid = NVME_LOG_LID_REACHABILITY_ASSOCIATIONS, - .len = len, - .nsid = NVME_NSID_ALL, - .csi = NVME_CSI_NVM, - .lsi = NVME_LOG_LSI_NONE, - .lsp = rao, - .uuidx = NVME_LOG_LSP_NONE, - .rae = rae, - .ot = false, - }; - - return nvme_get_log_page(fd, NVME_LOG_PAGE_PDU_SIZE, &args); +static inline int nvme_get_log_reachability_associations(nvme_link_t l, bool rae, bool rao, + struct nvme_reachability_associations_log *log, __u32 len) +{ + return nvme_get_log(l, NVME_NSID_ALL, rae, (__u8)rao, + NVME_LOG_LID_REACHABILITY_ASSOCIATIONS, NVME_LOG_LSI_NONE, NVME_CSI_NVM, + false, NVME_UUID_NONE, + 0, log, len, + NVME_LOG_PAGE_PDU_SIZE, NULL); } /** * nvme_get_log_changed_alloc_ns_list() - Retrieve Changed Allocated Namespace List Log - * @fd: File descriptor of nvme device + * @l: Link handle * @rae: Retain asynchronous events - * @len: The allocated length of the log page * @log: User address to store the log page + * @len: The allocated length of the log page * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise */ -static inline int nvme_get_log_changed_alloc_ns_list(int fd, bool rae, __u32 len, - struct nvme_ns_list *log) +static inline int nvme_get_log_changed_alloc_ns_list(nvme_link_t l, bool rae, + struct nvme_ns_list *log, __u32 len) { - return nvme_get_nsid_log(fd, rae, NVME_LOG_LID_CHANGED_ALLOC_NS_LIST, NVME_NSID_ALL, len, - log); + return nvme_get_nsid_log(l, NVME_NSID_ALL, rae, + NVME_LOG_LID_CHANGED_ALLOC_NS_LIST, log, len); } /** * nvme_get_log_discovery() - Retrieve Discovery log page - * @fd: File descriptor of nvme device + * @l: Link handle * @rae: Retain asynchronous events - * @offset: Offset of this log to retrieve - * @len: The allocated size for this portion of the log + * @lpo: Offset of this log to retrieve * @log: User address to store the discovery log + * @len: The allocated size for this portion of the log * * Supported only by fabrics discovery controllers, returning discovery * records. * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_get_log_discovery(int fd, bool rae, - __u32 offset, __u32 len, void *log) -{ - struct nvme_get_log_args args = { - .lpo = offset, - .result = NULL, - .log = log, - .args_size = sizeof(args), - .fd = fd, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .lid = NVME_LOG_LID_DISCOVER, - .len = len, - .nsid = NVME_NSID_NONE, - .csi = NVME_CSI_NVM, - .lsi = NVME_LOG_LSI_NONE, - .lsp = NVME_LOG_LSP_NONE, - .uuidx = NVME_UUID_NONE, - .rae = rae, - .ot = false, - }; - return nvme_get_log_page(fd, NVME_LOG_PAGE_PDU_SIZE, &args); +static inline int nvme_get_log_discovery(nvme_link_t l, bool rae, + __u64 lpo, __u32 len, void *log) +{ + return nvme_get_log(l, NVME_NSID_NONE, rae, NVME_LOG_LSP_NONE, + NVME_LOG_LID_DISCOVER, NVME_LOG_LSI_NONE, NVME_CSI_NVM, + false, NVME_UUID_NONE, + lpo, log, len, + NVME_LOG_PAGE_PDU_SIZE, NULL); } /** * nvme_get_log_host_discover() - Retrieve Host Discovery Log - * @fd: File descriptor of nvme device - * @allhoste: All host entries + * @l: Link handle * @rae: Retain asynchronous events - * @len: The allocated length of the log page + * @allhoste: All host entries * @log: User address to store the log page + * @len: The allocated length of the log page * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise */ -static inline int nvme_get_log_host_discover(int fd, bool allhoste, bool rae, __u32 len, - struct nvme_host_discover_log *log) -{ - struct nvme_get_log_args args = { - .lpo = 0, - .result = NULL, - .log = log, - .args_size = sizeof(args), - .fd = fd, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .lid = NVME_LOG_LID_HOST_DISCOVER, - .len = len, - .nsid = NVME_NSID_ALL, - .csi = NVME_CSI_NVM, - .lsi = NVME_LOG_LSI_NONE, - .lsp = allhoste, - .uuidx = NVME_LOG_LSP_NONE, - .rae = rae, - .ot = false, - }; - - return nvme_get_log_page(fd, NVME_LOG_PAGE_PDU_SIZE, &args); +static inline int nvme_get_log_host_discover(nvme_link_t l, bool rae, bool allhoste, + struct nvme_host_discover_log *log, __u32 len) +{ + return nvme_get_log(l, NVME_NSID_ALL, rae, (__u8)allhoste, + NVME_LOG_LID_HOST_DISCOVER, NVME_LOG_LSI_NONE, NVME_CSI_NVM, + false, NVME_UUID_NONE, + 0, log, len, + NVME_LOG_PAGE_PDU_SIZE, NULL); } /** * nvme_get_log_ave_discover() - Retrieve AVE Discovery Log - * @fd: File descriptor of nvme device + * @l: Link handle * @rae: Retain asynchronous events - * @len: The allocated length of the log page * @log: User address to store the log page + * @len: The allocated length of the log page * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise */ -static inline int nvme_get_log_ave_discover(int fd, bool rae, __u32 len, - struct nvme_ave_discover_log *log) +static inline int nvme_get_log_ave_discover(nvme_link_t l, bool rae, + struct nvme_ave_discover_log *log, __u32 len) { - return nvme_get_nsid_log(fd, rae, NVME_LOG_LID_AVE_DISCOVER, NVME_NSID_ALL, len, log); + return nvme_get_nsid_log(l, NVME_NSID_ALL, rae, + NVME_LOG_LID_AVE_DISCOVER, log, len); } /** * nvme_get_log_pull_model_ddc_req() - Retrieve Pull Model DDC Request Log - * @fd: File descriptor of nvme device + * @l: Link handle * @rae: Retain asynchronous events - * @len: The allocated length of the log page * @log: User address to store the log page + * @len: The allocated length of the log page * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise */ -static inline int nvme_get_log_pull_model_ddc_req(int fd, bool rae, __u32 len, - struct nvme_pull_model_ddc_req_log *log) +static inline int nvme_get_log_pull_model_ddc_req(nvme_link_t l, bool rae, + struct nvme_pull_model_ddc_req_log *log, __u32 len) { - return nvme_get_nsid_log(fd, rae, NVME_LOG_LID_PULL_MODEL_DDC_REQ, NVME_NSID_ALL, len, log); + return nvme_get_nsid_log(l, NVME_NSID_ALL, rae, + NVME_LOG_LID_PULL_MODEL_DDC_REQ, log, len); } /** * nvme_get_log_media_unit_stat() - Retrieve Media Unit Status - * @fd: File descriptor of nvme device + * @l: Link handle * @domid: Domain Identifier selection, if supported * @mus: User address to store the Media Unit statistics log * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise */ -static inline int nvme_get_log_media_unit_stat(int fd, __u16 domid, +static inline int nvme_get_log_media_unit_stat(nvme_link_t l, __u16 domid, struct nvme_media_unit_stat_log *mus) { - struct nvme_get_log_args args = { - .lpo = 0, - .result = NULL, - .log = mus, - .args_size = sizeof(args), - .fd = fd, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .lid = NVME_LOG_LID_MEDIA_UNIT_STATUS, - .len = sizeof(*mus), - .nsid = NVME_NSID_NONE, - .csi = NVME_CSI_NVM, - .lsi = domid, - .lsp = NVME_LOG_LSP_NONE, - .uuidx = NVME_UUID_NONE, - .rae = false, - .ot = false, - }; - return nvme_get_log_page(fd, NVME_LOG_PAGE_PDU_SIZE, &args); + return nvme_get_log(l, NVME_NSID_NONE, false, NVME_LOG_LSP_NONE, + NVME_LOG_LID_MEDIA_UNIT_STATUS, domid, NVME_CSI_NVM, + false, NVME_UUID_NONE, + 0, mus, sizeof(*mus), + NVME_LOG_PAGE_PDU_SIZE, NULL); } /** * nvme_get_log_support_cap_config_list() - Retrieve Supported Capacity Configuration List - * @fd: File descriptor of nvme device + * @l: Link handle * @domid: Domain Identifier selection, if supported * @cap: User address to store supported capabilities config list * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise */ -static inline int nvme_get_log_support_cap_config_list(int fd, __u16 domid, +static inline int nvme_get_log_support_cap_config_list(nvme_link_t l, __u16 domid, struct nvme_supported_cap_config_list_log *cap) { - struct nvme_get_log_args args = { - .lpo = 0, - .result = NULL, - .log = cap, - .args_size = sizeof(args), - .fd = fd, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .lid = NVME_LOG_LID_SUPPORTED_CAP_CONFIG_LIST, - .len = sizeof(*cap), - .nsid = NVME_NSID_NONE, - .csi = NVME_CSI_NVM, - .lsi = domid, - .lsp = NVME_LOG_LSP_NONE, - .uuidx = NVME_UUID_NONE, - .rae = false, - .ot = false, - }; - return nvme_get_log_page(fd, NVME_LOG_PAGE_PDU_SIZE, &args); + return nvme_get_log(l, NVME_NSID_NONE, false, NVME_LOG_LSP_NONE, + NVME_LOG_LID_SUPPORTED_CAP_CONFIG_LIST, domid, NVME_CSI_NVM, + false, NVME_UUID_NONE, + 0, cap, sizeof(*cap), + NVME_LOG_PAGE_PDU_SIZE, NULL); } /** * nvme_get_log_reservation() - Retrieve Reservation Notification - * @fd: File descriptor of nvme device + * @l: Link handle * @rae: Retain asynchronous events * @log: User address to store the reservation log * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise */ -static inline int nvme_get_log_reservation(int fd, bool rae, +static inline int nvme_get_log_reservation(nvme_link_t l, bool rae, struct nvme_resv_notification_log *log) { - return nvme_get_nsid_log(fd, rae, NVME_LOG_LID_RESERVATION, - NVME_NSID_ALL, sizeof(*log), log); + return nvme_get_nsid_log(l, NVME_NSID_ALL, rae, + NVME_LOG_LID_RESERVATION, + log, sizeof(*log)); } /** * nvme_get_log_sanitize() - Retrieve Sanitize Status - * @fd: File descriptor of nvme device + * @l: Link handle * @rae: Retain asynchronous events * @log: User address to store the sanitize log * * The Sanitize Status log page reports sanitize operation time estimates and * information about the most recent sanitize operation. * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_get_log_sanitize(int fd, bool rae, +static inline int nvme_get_log_sanitize(nvme_link_t l, bool rae, struct nvme_sanitize_log_page *log) { - return nvme_get_nsid_log(fd, rae, NVME_LOG_LID_SANITIZE, - NVME_NSID_ALL, sizeof(*log), log); + return nvme_get_nsid_log(l, NVME_NSID_ALL, rae, + NVME_LOG_LID_SANITIZE, + log, sizeof(*log)); } /** * nvme_get_log_zns_changed_zones() - Retrieve list of zones that have changed - * @fd: File descriptor of nvme device + * @l: Link handle * @nsid: Namespace ID * @rae: Retain asynchronous events * @log: User address to store the changed zone log * * The list of zones that have changed state due to an exceptional event. * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_get_log_zns_changed_zones(int fd, __u32 nsid, bool rae, - struct nvme_zns_changed_zone_log *log) -{ - struct nvme_get_log_args args = { - .lpo = 0, - .result = NULL, - .log = log, - .args_size = sizeof(args), - .fd = fd, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .lid = NVME_LOG_LID_ZNS_CHANGED_ZONES, - .len = sizeof(*log), - .nsid = nsid, - .csi = NVME_CSI_ZNS, - .lsi = NVME_LOG_LSI_NONE, - .lsp = NVME_LOG_LSP_NONE, - .uuidx = NVME_UUID_NONE, - .rae = rae, - .ot = false, - }; - return nvme_get_log_page(fd, NVME_LOG_PAGE_PDU_SIZE, &args); +static inline int nvme_get_log_zns_changed_zones(nvme_link_t l, __u32 nsid, + bool rae, struct nvme_zns_changed_zone_log *log) +{ + return nvme_get_log(l, nsid, rae, NVME_LOG_LSP_NONE, + NVME_LOG_LID_ZNS_CHANGED_ZONES, NVME_LOG_LSI_NONE, NVME_CSI_ZNS, + false, NVME_UUID_NONE, + 0, log, sizeof(*log), + NVME_LOG_PAGE_PDU_SIZE, NULL); } /** * nvme_get_log_persistent_event() - Retrieve Persistent Event Log - * @fd: File descriptor of nvme device + * @l: Link handle * @action: Action the controller should take during processing this command - * @size: Size of @pevent_log * @pevent_log: User address to store the persistent event log + * @len: Size of @pevent_log * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_get_log_persistent_event(int fd, +static inline int nvme_get_log_persistent_event(nvme_link_t l, enum nvme_pevent_log_action action, - __u32 size, void *pevent_log) -{ - struct nvme_get_log_args args = { - .lpo = 0, - .result = NULL, - .log = pevent_log, - .args_size = sizeof(args), - .fd = fd, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .lid = NVME_LOG_LID_PERSISTENT_EVENT, - .len = size, - .nsid = NVME_NSID_ALL, - .csi = NVME_CSI_NVM, - .lsi = NVME_LOG_LSI_NONE, - .lsp = (__u8)action, - .uuidx = NVME_UUID_NONE, - .rae = false, - .ot = false, - }; - return nvme_get_log_page(fd, NVME_LOG_PAGE_PDU_SIZE, &args); + void *pevent_log, __u32 len) +{ + return nvme_get_log(l, NVME_NSID_ALL, false, (__u8)action, + NVME_LOG_LID_PERSISTENT_EVENT, NVME_LOG_LSI_NONE, NVME_CSI_NVM, + false, NVME_UUID_NONE, + 0, pevent_log, len, + NVME_LOG_PAGE_PDU_SIZE, NULL); } /** * nvme_get_log_lockdown() - Retrieve lockdown Log - * @fd: File descriptor of nvme device + * @l: Link handle * @cnscp: Contents and Scope of Command and Feature Identifier Lists * @lockdown_log: Buffer to store the lockdown log * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_get_log_lockdown(int fd, +static inline int nvme_get_log_lockdown(nvme_link_t l, __u8 cnscp, struct nvme_lockdown_log *lockdown_log) { - struct nvme_get_log_args args = { - .lpo = 0, - .result = NULL, - .log = lockdown_log, - .args_size = sizeof(args), - .fd = fd, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .lid = NVME_LOG_LID_CMD_AND_FEAT_LOCKDOWN, - .len = sizeof(*lockdown_log), - .nsid = NVME_NSID_ALL, - .csi = NVME_CSI_NVM, - .lsi = NVME_LOG_LSI_NONE, - .lsp = cnscp, - .uuidx = NVME_UUID_NONE, - .rae = false, - .ot = false, - }; - return nvme_get_log_page(fd, NVME_LOG_PAGE_PDU_SIZE, &args); + return nvme_get_log(l, NVME_NSID_ALL, false, cnscp, + NVME_LOG_LID_CMD_AND_FEAT_LOCKDOWN, NVME_LOG_LSI_NONE, NVME_CSI_NVM, + false, NVME_UUID_NONE, + 0, lockdown_log, sizeof(*lockdown_log), + NVME_LOG_PAGE_PDU_SIZE, NULL); } /** * nvme_set_features() - Set a feature attribute - * @args: &struct nvme_set_features_args argument structure + * @l: Link handle + * @nsid: Namespace ID, if applicable + * @fid: Feature identifier + * @sv: Save value across power states + * @cdw11: Value to set the feature to + * @cdw12: Feature specific command dword12 field + * @cdw13: Feature specific command dword13 field + * @cdw15: Feature specific command dword15 field + * @uidx: UUID Index for differentiating vendor specific encoding + * @data: User address of feature data, if applicable + * @data_len: Length of feature data, if applicable, in bytes + * @result: The command completion result from CQE dword0 + * + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. + */ +static inline int nvme_set_features(nvme_link_t l, __u32 nsid, __u8 fid, + bool sv, __u32 cdw11, __u32 cdw12, + __u32 cdw13, __u32 cdw15, + __u8 uidx, void *data, + __u32 data_len, __u32 *result) +{ + __u32 cdw10 = NVME_SET(fid, FEATURES_CDW10_FID) | + NVME_SET(sv, SET_FEATURES_CDW10_SAVE); + __u32 cdw14 = NVME_SET(uidx, FEATURES_CDW14_UUID); + + struct nvme_passthru_cmd cmd = { + .opcode = nvme_admin_set_features, + .nsid = nsid, + .addr = (__u64)(uintptr_t)data, + .data_len = data_len, + .cdw10 = cdw10, + .cdw11 = cdw11, + .cdw12 = cdw12, + .cdw13 = cdw13, + .cdw14 = cdw14, + .cdw15 = cdw15, + .timeout_ms = NVME_DEFAULT_IOCTL_TIMEOUT, + }; + + return nvme_submit_admin_passthru(l, &cmd, result); +} + +/** + * __nvme_set_features() - Internal helper function for @nvme_set_features() + * @l: Link handle + * @fid: Feature identifier + * @sv: Save value across power states + * @cdw11: Value to set the feature to + * @result: The command completion result from CQE dword0 * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise. */ -int nvme_set_features(struct nvme_set_features_args *args); +static int __nvme_set_features(nvme_link_t l, __u8 fid, bool sv, __u32 cdw11, + __u32 *result) +{ + return nvme_set_features(l, NVME_NSID_NONE, fid, sv, cdw11, 0, 0, 0, + NVME_UUID_NONE, NULL, 0, result); +} /** * nvme_set_features_data() - Helper function for @nvme_set_features() - * @fd: File descriptor of nvme device - * @fid: Feature identifier + * @l: Link handle * @nsid: Namespace ID, if applicable + * @fid: Feature identifier + * @sv: Save value across power states * @cdw11: Value to set the feature to - * @save: Save value across power states - * @data_len: Length of feature data, if applicable, in bytes * @data: User address of feature data, if applicable + * @data_len: Length of feature data, if applicable, in bytes * @result: The command completion result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_set_features_data(int fd, __u8 fid, __u32 nsid, - __u32 cdw11, bool save, __u32 data_len, void *data, - __u32 *result) +static inline int nvme_set_features_data(nvme_link_t l, __u32 nsid, __u8 fid, + bool sv, __u32 cdw11, void *data, + __u32 data_len, __u32 *result) { - struct nvme_set_features_args args = { - .result = result, - .data = data, - .args_size = sizeof(args), - .fd = fd, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .nsid = nsid, - .cdw11 = cdw11, - .cdw12 = 0, - .cdw13 = 0, - .cdw15 = 0, - .data_len = data_len, - .save = save, - .uuidx = NVME_UUID_NONE, - .fid = fid, - }; - return nvme_set_features(&args); + return nvme_set_features(l, nsid, fid, sv, cdw11, 0, 0, 0, + NVME_UUID_NONE, data, data_len, result); } /** * nvme_set_features_simple() - Helper function for @nvme_set_features() - * @fd: File descriptor of nvme device - * @fid: Feature identifier + * @l: Link handle * @nsid: Namespace ID, if applicable + * @fid: Feature identifier + * @sv: Save value across power states * @cdw11: Value to set the feature to - * @save: Save value across power states * @result: The command completion result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_set_features_simple(int fd, __u8 fid, __u32 nsid, - __u32 cdw11, bool save, __u32 *result) +static inline int nvme_set_features_simple(nvme_link_t l, __u32 nsid, + __u8 fid, bool sv, __u32 cdw11, + __u32 *result) { - return nvme_set_features_data(fd, fid, nsid, cdw11, save, 0, NULL, - result); + return nvme_set_features_data(l, nsid, fid, sv, cdw11, NULL, 0, + result); } /** * nvme_set_features_arbitration() - Set arbitration features - * @fd: File descriptor of nvme device + * @l: Link handle + * @sv: Save value across power states * @ab: Arbitration Burst * @lpw: Low Priority Weight * @mpw: Medium Priority Weight * @hpw: High Priority Weight - * @save: Save value across power states * @result: The command completion result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_set_features_arbitration(int fd, __u8 ab, __u8 lpw, __u8 mpw, - __u8 hpw, bool save, __u32 *result); +static inline int nvme_set_features_arbitration(nvme_link_t l, bool sv, __u8 ab, + __u8 lpw, __u8 mpw, __u8 hpw, + __u32 *result) +{ + __u32 cdw11 = NVME_SET(ab, FEAT_ARBITRATION_BURST) | + NVME_SET(lpw, FEAT_ARBITRATION_LPW) | + NVME_SET(mpw, FEAT_ARBITRATION_MPW) | + NVME_SET(hpw, FEAT_ARBITRATION_HPW); + + return __nvme_set_features(l, NVME_FEAT_FID_ARBITRATION, sv, cdw11, + result); +} /** * nvme_set_features_power_mgmt() - Set power management feature - * @fd: File descriptor of nvme device + * @l: Link handle + * @sv: Save value across power states * @ps: Power State * @wh: Workload Hint - * @save: Save value across power states * @result: The command completion result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_set_features_power_mgmt(int fd, __u8 ps, __u8 wh, bool save, - __u32 *result); +static inline int nvme_set_features_power_mgmt(nvme_link_t l, bool sv, + __u8 ps, __u8 wh, + __u32 *result) +{ + __u32 cdw11 = NVME_SET(ps, FEAT_PWRMGMT_PS) | + NVME_SET(wh, FEAT_PWRMGMT_WH); + + return __nvme_set_features(l, NVME_FEAT_FID_POWER_MGMT, sv, cdw11, + result); +} /** * nvme_set_features_lba_range() - Set LBA range feature - * @fd: File descriptor of nvme device + * @l: Link handle * @nsid: Namespace ID - * @nr_ranges: Number of ranges in @data - * @save: Save value across power states + * @sv: Save value across power states + * @num: Number of ranges in @data * @data: User address of feature data * @result: The command completion result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_set_features_lba_range(int fd, __u32 nsid, __u8 nr_ranges, bool save, - struct nvme_lba_range_type *data, __u32 *result); +static inline int nvme_set_features_lba_range(nvme_link_t l, __u32 nsid, + bool sv, __u8 num, + struct nvme_lba_range_type *data, + __u32 *result) +{ + return nvme_set_features_data(l, nsid, + NVME_FEAT_FID_LBA_RANGE, sv, + num - 1, data, + sizeof(*data), result); +} /** * nvme_set_features_temp_thresh() - Set temperature threshold feature - * @fd: File descriptor of nvme device + * @l: Link handle + * @sv: Save value across power states * @tmpth: Temperature Threshold * @tmpsel: Threshold Temperature Select * @thsel: Threshold Type Select * @tmpthh: Temperature Threshold Hysteresis - * @save: Save value across power states * @result: The command completion result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_set_features_temp_thresh(int fd, __u16 tmpth, __u8 tmpsel, - enum nvme_feat_tmpthresh_thsel thsel, __u8 tmpthh, - bool save, __u32 *result); +static inline int nvme_set_features_temp_thresh(nvme_link_t l, bool sv, __u16 tmpth, + __u8 tmpsel, + enum nvme_feat_tmpthresh_thsel thsel, + __u8 tmpthh, __u32 *result) +{ + __u32 cdw11 = NVME_SET(tmpth, FEAT_TT_TMPTH) | + NVME_SET(tmpsel, FEAT_TT_TMPSEL) | + NVME_SET(thsel, FEAT_TT_THSEL) | + NVME_SET(tmpthh, FEAT_TT_TMPTHH); + + return __nvme_set_features(l, NVME_FEAT_FID_TEMP_THRESH, sv, cdw11, + result); +} /** * nvme_set_features_err_recovery() - Set error recovery feature - * @fd: File descriptor of nvme device + * @l: Link handle * @nsid: Namespace ID + * @sv: Save value across power states * @tler: Time-limited error recovery value * @dulbe: Deallocated or Unwritten Logical Block Error Enable - * @save: Save value across power states * @result: The command completion result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_set_features_err_recovery(int fd, __u32 nsid, __u16 tler, - bool dulbe, bool save, __u32 *result); +static inline int nvme_set_features_err_recovery(nvme_link_t l, __u32 nsid, bool sv, + __u16 tler, bool dulbe, __u32 *result) +{ + __u32 cdw11 = NVME_SET(tler, FEAT_ERROR_RECOVERY_TLER) | + NVME_SET(dulbe, FEAT_ERROR_RECOVERY_DULBE); + + return nvme_set_features_simple(l, nsid, NVME_FEAT_FID_ERR_RECOVERY, sv, + cdw11, result); +} /** * nvme_set_features_volatile_wc() - Set volatile write cache feature - * @fd: File descriptor of nvme device + * @l: Link handle + * @sv: Save value across power states * @wce: Write cache enable - * @save: Save value across power states * @result: The command completion result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_set_features_volatile_wc(int fd, bool wce, bool save, - __u32 *result); +static inline int nvme_set_features_volatile_wc(nvme_link_t l, bool sv, bool wce, + __u32 *result) +{ + __u32 cdw11 = NVME_SET(wce, FEAT_VWC_WCE); + return __nvme_set_features(l, NVME_FEAT_FID_VOLATILE_WC, sv, cdw11, + result); +} /** * nvme_set_features_irq_coalesce() - Set IRQ coalesce feature - * @fd: File descriptor of nvme device + * @l: Link handle + * @sv: Save value across power states * @thr: Aggregation Threshold * @time: Aggregation Time - * @save: Save value across power states * @result: The command completion result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_set_features_irq_coalesce(int fd, __u8 thr, __u8 time, - bool save, __u32 *result); +static inline int nvme_set_features_irq_coalesce(nvme_link_t l, bool sv, + __u8 thr, __u8 time, + __u32 *result) +{ + __u32 cdw11 = NVME_SET(thr, FEAT_IRQC_THR) | + NVME_SET(time, FEAT_IRQC_TIME); + + return __nvme_set_features(l, NVME_FEAT_FID_IRQ_COALESCE, sv, cdw11, + result); +} /** * nvme_set_features_irq_config() - Set IRQ config feature - * @fd: File descriptor of nvme device + * @l: Link handle + * @sv: Save value across power states * @iv: Interrupt Vector * @cd: Coalescing Disable - * @save: Save value across power states * @result: The command completion result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_set_features_irq_config(int fd, __u16 iv, bool cd, bool save, - __u32 *result); +static inline int nvme_set_features_irq_config(nvme_link_t l, bool sv, __u16 iv, + bool cd, __u32 *result) +{ + __u32 cdw11 = NVME_SET(iv, FEAT_ICFG_IV) | + NVME_SET(cd, FEAT_ICFG_CD); + + return __nvme_set_features(l, NVME_FEAT_FID_IRQ_CONFIG, sv, cdw11, + result); +} /** * nvme_set_features_write_atomic() - Set write atomic feature - * @fd: File descriptor of nvme device + * @l: Link handle + * @sv: Save value across power states * @dn: Disable Normal - * @save: Save value across power states * @result: The command completion result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_set_features_write_atomic(int fd, bool dn, bool save, - __u32 *result); +static inline int nvme_set_features_write_atomic(nvme_link_t l, bool sv, + bool dn, __u32 *result) +{ + __u32 cdw11 = NVME_SET(dn, FEAT_WA_DN); + + return __nvme_set_features(l, NVME_FEAT_FID_WRITE_ATOMIC, sv, cdw11, + result); +} /** * nvme_set_features_async_event() - Set asynchronous event feature - * @fd: File descriptor of nvme device + * @l: Link handle + * @sv: Save value across power states * @events: Events to enable - * @save: Save value across power states * @result: The command completion result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_set_features_async_event(int fd, __u32 events, bool save, - __u32 *result); +static inline int nvme_set_features_async_event(nvme_link_t l, bool sv, + __u32 events, __u32 *result) +{ + return __nvme_set_features(l, NVME_FEAT_FID_ASYNC_EVENT, sv, events, + result); +} /** * nvme_set_features_auto_pst() - Set autonomous power state feature - * @fd: File descriptor of nvme device + * @l: Link handle + * @sv: Save value across power states * @apste: Autonomous Power State Transition Enable * @apst: Autonomous Power State Transition - * @save: Save value across power states * @result: The command completion result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_set_features_auto_pst(int fd, bool apste, bool save, - struct nvme_feat_auto_pst *apst, - __u32 *result); +static inline int nvme_set_features_auto_pst(nvme_link_t l, bool sv, bool apste, + struct nvme_feat_auto_pst *apst, + __u32 *result) +{ + __u32 cdw11 = NVME_SET(apste, FEAT_APST_APSTE); + + return nvme_set_features_data(l, NVME_NSID_NONE, + NVME_FEAT_FID_AUTO_PST, sv, + cdw11, apst, + sizeof(*apst), result); +} /** * nvme_set_features_timestamp() - Set timestamp feature - * @fd: File descriptor of nvme device - * @save: Save value across power states - * @timestamp: The current timestamp value to assign to this feature + * @l: Link handle + * @sv: Save value across power states + * @tstmp: The current timestamp value to assign to this feature * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_set_features_timestamp(int fd, bool save, __u64 timestamp); +static inline int nvme_set_features_timestamp(nvme_link_t l, __u64 tstmp, bool sv) +{ + __le64 t = htole64(tstmp); + struct nvme_timestamp ts = {}; + + memcpy(ts.timestamp, &t, sizeof(ts.timestamp)); + return nvme_set_features_data(l, NVME_NSID_NONE, + NVME_FEAT_FID_TIMESTAMP, sv, + 0, &ts, sizeof(ts), NULL); +} /** * nvme_set_features_hctm() - Set thermal management feature - * @fd: File descriptor of nvme device + * @l: Link handle + * @sv: Save value across power states * @tmt2: Thermal Management Temperature 2 * @tmt1: Thermal Management Temperature 1 - * @save: Save value across power states * @result: The command completion result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_set_features_hctm(int fd, __u16 tmt2, __u16 tmt1, bool save, - __u32 *result); +static inline int nvme_set_features_hctm(nvme_link_t l, bool sv, + __u16 tmt2, __u16 tmt1, + __u32 *result) +{ + __u32 cdw11 = NVME_SET(tmt2, FEAT_HCTM_TMT2) | + NVME_SET(tmt1, FEAT_HCTM_TMT1); + + return __nvme_set_features(l, NVME_FEAT_FID_HCTM, sv, cdw11, + result); +} /** * nvme_set_features_nopsc() - Set non-operational power state feature - * @fd: File descriptor of nvme device + * @l: Link handle + * @sv: Save value across power states * @noppme: Non-Operational Power State Permissive Mode Enable - * @save: Save value across power states * @result: The command completion result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_set_features_nopsc(int fd, bool noppme, bool save, __u32 *result); +static inline int nvme_set_features_nopsc(nvme_link_t l, bool sv, + bool noppme, __u32 *result) +{ + __u32 cdw11 = NVME_SET(noppme, FEAT_NOPS_NOPPME); + + return __nvme_set_features(l, NVME_FEAT_FID_NOPSC, sv, cdw11, + result); +} /** * nvme_set_features_rrl() - Set read recovery level feature - * @fd: File descriptor of nvme device - * @rrl: Read recovery level setting + * @l: Link handle + * @sv: Save value across power states * @nvmsetid: NVM set id - * @save: Save value across power states + * @rrl: Read recovery level setting * @result: The command completion result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_set_features_rrl(int fd, __u8 rrl, __u16 nvmsetid, bool save, - __u32 *result); +static inline int nvme_set_features_rrl(nvme_link_t l, bool sv, __u16 nvmsetid, + __u8 rrl, __u32 *result) +{ + return nvme_set_features(l, NVME_NSID_NONE, + NVME_FEAT_FID_RRL, sv, + nvmsetid, rrl, 0, 0, + NVME_UUID_NONE, NULL, 0, + result); +} /** * nvme_set_features_plm_config() - Set predictable latency feature - * @fd: File descriptor of nvme device - * @enable: Predictable Latency Enable + * @l: Link handle + * @sv: Save value across power states * @nvmsetid: NVM Set Identifier - * @save: Save value across power states + * @lpe: Predictable Latency Enable * @data: Pointer to structure nvme_plm_config * @result: The command completion result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_set_features_plm_config(int fd, bool enable, __u16 nvmsetid, - bool save, struct nvme_plm_config *data, - __u32 *result); +static inline int nvme_set_features_plm_config(nvme_link_t l, bool sv, __u16 nvmsetid, + bool lpe, struct nvme_plm_config *data, + __u32 *result) +{ + return nvme_set_features(l, NVME_NSID_NONE, + NVME_FEAT_FID_PLM_CONFIG, sv, + nvmsetid, lpe, 0, 0, + NVME_UUID_NONE, data, sizeof(*data), + result); +} /** * nvme_set_features_plm_window() - Set window select feature - * @fd: File descriptor of nvme device - * @sel: Window Select + * @l: Link handle + * @sv: Save value across power states * @nvmsetid: NVM Set Identifier - * @save: Save value across power states + * @wsel: Window Select * @result: The command completion result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_set_features_plm_window(int fd, enum nvme_feat_plm_window_select sel, - __u16 nvmsetid, bool save, __u32 *result); +static inline int nvme_set_features_plm_window(nvme_link_t l, bool sv, __u16 nvmsetid, + enum nvme_feat_plm_window_select wsel, + __u32 *result) +{ + return nvme_set_features(l, NVME_NSID_NONE, + NVME_FEAT_FID_PLM_WINDOW, sv, + nvmsetid, NVME_SET(wsel, FEAT_PLMW_WS), 0, 0, + NVME_UUID_NONE, NULL, 0, result); +} /** * nvme_set_features_lba_sts_interval() - Set LBA status information feature - * @fd: File descriptor of nvme device - * @save: Save value across power states + * @l: Link handle + * @sv: Save value across power states * @lsiri: LBA Status Information Report Interval * @lsipi: LBA Status Information Poll Interval * @result: The command completion result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_set_features_lba_sts_interval(int fd, __u16 lsiri, __u16 lsipi, - bool save, __u32 *result); +static inline int nvme_set_features_lba_sts_interval(nvme_link_t l, bool sv, + __u16 lsiri, __u16 lsipi, + __u32 *result) +{ + __u32 cdw11 = NVME_SET(lsiri, FEAT_LBAS_LSIRI) | + NVME_SET(lsipi, FEAT_LBAS_LSIPI); + + return __nvme_set_features(l, NVME_FEAT_FID_LBA_STS_INTERVAL, sv, + cdw11, result); +} /** * nvme_set_features_host_behavior() - Set host behavior feature - * @fd: File descriptor of nvme device - * @save: Save value across power states + * @l: Link handle + * @sv: Save value across power states * @data: Pointer to structure nvme_feat_host_behavior * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_set_features_host_behavior(int fd, bool save, - struct nvme_feat_host_behavior *data); +static inline int nvme_set_features_host_behavior(nvme_link_t l, bool sv, + struct nvme_feat_host_behavior *data) +{ + return nvme_set_features_data(l, NVME_NSID_NONE, + NVME_FEAT_FID_HOST_BEHAVIOR, sv, + 0, data, sizeof(*data), NULL); +} /** * nvme_set_features_sanitize() - Set sanitize feature - * @fd: File descriptor of nvme device + * @l: Link handle + * @sv: Save value across power states * @nodrm: No-Deallocate Response Mode - * @save: Save value across power states * @result: The command completion result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_set_features_sanitize(int fd, bool nodrm, bool save, __u32 *result); +static inline int nvme_set_features_sanitize(nvme_link_t l, bool sv, bool nodrm, + __u32 *result) +{ + return __nvme_set_features(l, NVME_FEAT_FID_SANITIZE, sv, nodrm, + result); +} /** * nvme_set_features_endurance_evt_cfg() - Set endurance event config feature - * @fd: File descriptor of nvme device + * @l: Link handle + * @sv: Save value across power states * @endgid: Endurance Group Identifier - * @egwarn: Flags to enable warning, see &enum nvme_eg_critical_warning_flags - * @save: Save value across power states + * @egcw: Flags to enable warning, see &enum nvme_eg_critical_warning_flags * @result: The command completion result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_set_features_endurance_evt_cfg(int fd, __u16 endgid, __u8 egwarn, - bool save, __u32 *result); +static inline int nvme_set_features_endurance_evt_cfg(nvme_link_t l, bool sv, + __u16 endgid, __u8 egcw, + __u32 *result) +{ + __u32 cdw11 = endgid | egcw << 16; + + return __nvme_set_features(l, NVME_FEAT_FID_ENDURANCE_EVT_CFG, sv, + cdw11, result); +} /** * nvme_set_features_sw_progress() - Set pre-boot software load count feature - * @fd: File descriptor of nvme device + * @l: Link handle + * @sv: Save value across power states * @pbslc: Pre-boot Software Load Count - * @save: Save value across power states * @result: The command completion result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_set_features_sw_progress(int fd, __u8 pbslc, bool save, - __u32 *result); +static inline int nvme_set_features_sw_progress(nvme_link_t l, bool sv, __u8 pbslc, + __u32 *result) +{ + return __nvme_set_features(l, NVME_FEAT_FID_SW_PROGRESS, sv, pbslc, + result); +} /** * nvme_set_features_host_id() - Set enable extended host identifiers feature - * @fd: File descriptor of nvme device + * @l: Link handle + * @sv: Save value across power states * @exhid: Enable Extended Host Identifier - * @save: Save value across power states * @hostid: Host ID to set * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_set_features_host_id(int fd, bool exhid, bool save, __u8 *hostid); +static inline int nvme_set_features_host_id(nvme_link_t l, bool sv, bool exhid, + __u8 *hostid) +{ + __u32 len = exhid ? 16 : 8; + __u32 cdw11 = exhid; + + return nvme_set_features_data(l, NVME_NSID_NONE, NVME_FEAT_FID_HOST_ID, + sv, cdw11, hostid, len, NULL); +} /** * nvme_set_features_resv_mask() - Set reservation notification mask feature - * @fd: File descriptor of nvme device + * @l: Link handle * @nsid: Namespace ID + * @sv: Save value across power states * @mask: Reservation Notification Mask Field - * @save: Save value across power states * @result: The command completion result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_set_features_resv_mask(int fd, __u32 nsid, __u32 mask, bool save, - __u32 *result); +static inline int nvme_set_features_resv_mask(nvme_link_t l, __u32 nsid, bool sv, + __u32 mask, __u32 *result) +{ + return nvme_set_features_simple(l, nsid, NVME_FEAT_FID_RESV_MASK, + sv, mask, result); +} /** * nvme_set_features_resv_persist() - Set persist through power loss feature - * @fd: File descriptor of nvme device + * @l: Link handle * @nsid: Namespace ID + * @sv: Save value across power states * @ptpl: Persist Through Power Loss - * @save: Save value across power states * @result: The command completion result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_set_features_resv_persist(int fd, __u32 nsid, bool ptpl, bool save, - __u32 *result); +static inline int nvme_set_features_resv_persist(nvme_link_t l, __u32 nsid, bool sv, + bool ptpl, __u32 *result) +{ + return nvme_set_features_simple(l, nsid, + NVME_FEAT_FID_RESV_PERSIST, sv, + ptpl, result); +} /** * nvme_set_features_write_protect() - Set write protect feature - * @fd: File descriptor of nvme device + * @l: Link handle * @nsid: Namespace ID - * @state: Write Protection State - * @save: Save value across power states + * @sv: Save value across power states + * @wps: Write Protection State * @result: The command completion result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_set_features_write_protect(int fd, __u32 nsid, - enum nvme_feat_nswpcfg_state state, - bool save, __u32 *result); +static inline int nvme_set_features_write_protect(nvme_link_t l, __u32 nsid, + bool sv, + enum nvme_feat_nswpcfg_state wps, + __u32 *result) +{ + return nvme_set_features_simple(l, nsid, + NVME_FEAT_FID_WRITE_PROTECT, sv, + wps, result); +} /** * nvme_set_features_iocs_profile() - Set I/O command set profile feature - * @fd: File descriptor of nvme device - * @iocsi: I/O Command Set Combination Index - * @save: Save value across power states + * @l: Link handle + * @sv: Save value across power states + * @iocsci: I/O Command Set Combination Index + * @result: The command completions result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_set_features_iocs_profile(int fd, __u16 iocsi, bool save); +static inline int nvme_set_features_iocs_profile(nvme_link_t l, bool sv, + __u16 iocsci, __u32 *result) +{ + __u32 cdw11 = NVME_SET(iocsci, FEAT_IOCSP_IOCSCI); + + return __nvme_set_features(l, NVME_FEAT_FID_IOCS_PROFILE, + sv, cdw11, result); +} /** * nvme_get_features() - Retrieve a feature attribute - * @args: &struct nvme_get_features_args argument structure + * @l: Link handle + * @nsid: Namespace ID, if applicable + * @fid: Feature identifier, see &enum nvme_features_id + * @sel: Select which type of attribute to return, + * see &enum nvme_get_features_sel + * @cdw11: Feature specific command dword11 field + * @uidx: UUID Index for differentiating vendor specific encoding + * @data: User address of feature data, if applicable + * @data_len: Length of feature data, if applicable, in bytes + * @result: The command completion result from CQE dword0 + * + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. + */ +static inline int nvme_get_features(nvme_link_t l, __u32 nsid, __u8 fid, + enum nvme_get_features_sel sel, __u32 cdw11, + __u8 uidx, void *data, __u32 data_len, + __u32 *result) +{ + __u32 cdw10 = NVME_SET(fid, FEATURES_CDW10_FID) | + NVME_SET(sel, GET_FEATURES_CDW10_SEL); + __u32 cdw14 = NVME_SET(uidx, FEATURES_CDW14_UUID); + + struct nvme_passthru_cmd cmd = { + .opcode = nvme_admin_get_features, + .nsid = nsid, + .addr = (__u64)(uintptr_t)data, + .data_len = data_len, + .cdw10 = cdw10, + .cdw11 = cdw11, + .cdw14 = cdw14, + .timeout_ms = NVME_DEFAULT_IOCTL_TIMEOUT, + }; + + return nvme_submit_admin_passthru(l, &cmd, result); +} + +/** + * __nvme_get_features() - Internal helper function for @nvme_get_features() + * @l: Link handle + * @fid: Feature identifier, see &enum nvme_features_id + * @sel: Select which type of attribute to return, + * see &enum nvme_get_features_sel + * @result: The command completion result from CQE dword0 * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise. */ -int nvme_get_features(struct nvme_get_features_args *args); +static inline int __nvme_get_features(nvme_link_t l, enum nvme_features_id fid, + enum nvme_get_features_sel sel, __u32 *result) +{ + return nvme_get_features(l, NVME_NSID_NONE, fid, sel, 0, NVME_UUID_NONE, + NULL, 0, result); +} /** * nvme_get_features_data() - Helper function for @nvme_get_features() - * @fd: File descriptor of nvme device - * @fid: Feature identifier + * @l: Link handle * @nsid: Namespace ID, if applicable - * @data_len: Length of feature data, if applicable, in bytes + * @fid: Feature identifier * @data: User address of feature data, if applicable + * @data_len: Length of feature data, if applicable, in bytes * @result: The command completion result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_get_features_data(int fd, enum nvme_features_id fid, - __u32 nsid, __u32 data_len, void *data, __u32 *result) +static inline int nvme_get_features_data(nvme_link_t l, __u32 nsid, + enum nvme_features_id fid, + void *data, __u32 data_len, + __u32 *result) { - struct nvme_get_features_args args = { - .result = result, - .data = data, - .args_size = sizeof(args), - .fd = fd, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .nsid = nsid, - .sel = NVME_GET_FEATURES_SEL_CURRENT, - .cdw11 = 0, - .data_len = data_len, - .fid = (__u8)fid, - .uuidx = NVME_UUID_NONE, - }; - - return nvme_get_features(&args); + return nvme_get_features(l, nsid, fid, NVME_GET_FEATURES_SEL_CURRENT, 0, + NVME_UUID_NONE, data, data_len, result); } /** * nvme_get_features_simple() - Helper function for @nvme_get_features() - * @fd: File descriptor of nvme device - * @fid: Feature identifier + * @l: Link handle * @nsid: Namespace ID, if applicable + * @fid: Feature identifier * @result: The command completion result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_get_features_simple(int fd, enum nvme_features_id fid, - __u32 nsid, __u32 *result) +static inline int nvme_get_features_simple(nvme_link_t l, __u32 nsid, + enum nvme_features_id fid, + __u32 *result) { - return nvme_get_features_data(fd, fid, nsid, 0, NULL, result); + return nvme_get_features_data(l, nsid, fid, NULL, 0, result); } /** * nvme_get_features_arbitration() - Get arbitration feature - * @fd: File descriptor of nvme device - * @sel: Select which type of attribute to return, see &enum nvme_get_features_sel + * @l: Link handle + * @sel: Select which type of attribute to return, + * see &enum nvme_get_features_sel * @result: The command completion result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_get_features_arbitration(int fd, enum nvme_get_features_sel sel, - __u32 *result); +static inline int nvme_get_features_arbitration(nvme_link_t l, + enum nvme_get_features_sel sel, + __u32 *result) +{ + return __nvme_get_features(l, NVME_FEAT_FID_ARBITRATION, sel, result); +} /** * nvme_get_features_power_mgmt() - Get power management feature - * @fd: File descriptor of nvme device - * @sel: Select which type of attribute to return, see &enum nvme_get_features_sel + * @l: Link handle + * @sel: Select which type of attribute to return, + * see &enum nvme_get_features_sel * @result: The command completion result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_get_features_power_mgmt(int fd, enum nvme_get_features_sel sel, - __u32 *result); +static inline int nvme_get_features_power_mgmt(nvme_link_t l, + enum nvme_get_features_sel sel, + __u32 *result) +{ + return __nvme_get_features(l, NVME_FEAT_FID_POWER_MGMT, sel, result); +} /** * nvme_get_features_lba_range() - Get LBA range feature - * @fd: File descriptor of nvme device - * @sel: Select which type of attribute to return, see &enum nvme_get_features_sel + * @l: Link handle * @nsid: Namespace ID - * @data: Buffer to receive LBA Range Type data structure + * @sel: Select which type of attribute to return, + * see &enum nvme_get_features_sel + * @lrt: Buffer to receive LBA Range Type data structure * @result: The command completion result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_get_features_lba_range(int fd, enum nvme_get_features_sel sel, - __u32 nsid, struct nvme_lba_range_type *data, - __u32 *result); +static inline int nvme_get_features_lba_range(nvme_link_t l, __u32 nsid, + enum nvme_get_features_sel sel, + struct nvme_lba_range_type *lrt, + __u32 *result) +{ + return nvme_get_features(l, nsid, NVME_FEAT_FID_LBA_RANGE, sel, 0, + NVME_UUID_NONE, lrt, sizeof(*lrt), result); +} /** * nvme_get_features_temp_thresh() - Get temperature threshold feature - * @fd: File descriptor of nvme device - * @sel: Select which type of attribute to return, see &enum nvme_get_features_sel + * @l: Link handle + * @sel: Select which type of attribute to return, + * see &enum nvme_get_features_sel * @tmpsel: Threshold Temperature Select * @thsel: Threshold Type Select * @result: The command completion result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_get_features_temp_thresh(int fd, enum nvme_get_features_sel sel, __u8 tmpsel, - enum nvme_feat_tmpthresh_thsel thsel, __u32 *result); +static inline int nvme_get_features_temp_thresh(nvme_link_t l, + enum nvme_get_features_sel sel, + __u8 tmpsel, + enum nvme_feat_tmpthresh_thsel thsel, + __u32 *result) +{ + __u32 cdw11 = NVME_SET(tmpsel, FEAT_TT_TMPSEL) | + NVME_SET(thsel, FEAT_TT_THSEL); + + return nvme_get_features(l, NVME_NSID_NONE, NVME_FEAT_FID_TEMP_THRESH, + sel, cdw11, NVME_UUID_NONE, NULL, 0, result); +} /** * nvme_get_features_err_recovery() - Get error recovery feature - * @fd: File descriptor of nvme device - * @sel: Select which type of attribute to return, see &enum nvme_get_features_sel + * @l: Link handle * @nsid: Namespace ID + * @sel: Select which type of attribute to return, + * see &enum nvme_get_features_sel * @result: The command completion result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_get_features_err_recovery(int fd, enum nvme_get_features_sel sel, - __u32 nsid, __u32 *result); +static inline int nvme_get_features_err_recovery(nvme_link_t l, __u32 nsid, + enum nvme_get_features_sel sel, + __u32 *result) +{ + return nvme_get_features(l, nsid, NVME_FEAT_FID_ERR_RECOVERY, sel, 0, + NVME_UUID_NONE, NULL, 0, result); +} /** * nvme_get_features_volatile_wc() - Get volatile write cache feature - * @fd: File descriptor of nvme device - * @sel: Select which type of attribute to return, see &enum nvme_get_features_sel + * @l: Link handle + * @sel: Select which type of attribute to return, + * see &enum nvme_get_features_sel * @result: The command completion result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_get_features_volatile_wc(int fd, enum nvme_get_features_sel sel, - __u32 *result); +static inline int nvme_get_features_volatile_wc(nvme_link_t l, + enum nvme_get_features_sel sel, + __u32 *result) +{ + return __nvme_get_features(l, NVME_FEAT_FID_VOLATILE_WC, sel, result); +} /** * nvme_get_features_num_queues() - Get number of queues feature - * @fd: File descriptor of nvme device - * @sel: Select which type of attribute to return, see &enum nvme_get_features_sel + * @l: Link handle + * @sel: Select which type of attribute to return, + * see &enum nvme_get_features_sel * @result: The command completion result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_get_features_num_queues(int fd, enum nvme_get_features_sel sel, - __u32 *result); +static inline int nvme_get_features_num_queues(nvme_link_t l, + enum nvme_get_features_sel sel, + __u32 *result) +{ + return __nvme_get_features(l, NVME_FEAT_FID_NUM_QUEUES, sel, result); +} /** * nvme_get_features_irq_coalesce() - Get IRQ coalesce feature - * @fd: File descriptor of nvme device - * @sel: Select which type of attribute to return, see &enum nvme_get_features_sel + * @l: Link handle + * @sel: Select which type of attribute to return, + * see &enum nvme_get_features_sel * @result: The command completion result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_get_features_irq_coalesce(int fd, enum nvme_get_features_sel sel, - __u32 *result); +static inline int nvme_get_features_irq_coalesce(nvme_link_t l, + enum nvme_get_features_sel sel, + __u32 *result) +{ + return __nvme_get_features(l, NVME_FEAT_FID_IRQ_COALESCE, sel, result); +} /** * nvme_get_features_irq_config() - Get IRQ config feature - * @fd: File descriptor of nvme device - * @sel: Select which type of attribute to return, see &enum nvme_get_features_sel - * @iv: + * @l: Link handle + * @sel: Select which type of attribute to return, + * see &enum nvme_get_features_sel + * @iv: Interrupt Vector + * @cd: Coalescing Disable * @result: The command completion result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_get_features_irq_config(int fd, enum nvme_get_features_sel sel, - __u16 iv, __u32 *result); +static inline int nvme_get_features_irq_config(nvme_link_t l, + enum nvme_get_features_sel sel, + __u16 iv, bool cd, __u32 *result) +{ + __u32 cdw11 = NVME_SET(iv, FEAT_ICFG_IV) | + NVME_SET(cd, FEAT_ICFG_CD); + + return nvme_get_features(l, NVME_NSID_NONE, NVME_FEAT_FID_IRQ_CONFIG, + sel, cdw11, NVME_UUID_NONE, NULL, 0, result); +} /** * nvme_get_features_write_atomic() - Get write atomic feature - * @fd: File descriptor of nvme device - * @sel: Select which type of attribute to return, see &enum nvme_get_features_sel + * @l: Link handle + * @sel: Select which type of attribute to return, + * see &enum nvme_get_features_sel * @result: The command completion result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_get_features_write_atomic(int fd, enum nvme_get_features_sel sel, - __u32 *result); +static inline int nvme_get_features_write_atomic(nvme_link_t l, + enum nvme_get_features_sel sel, + __u32 *result) +{ + return __nvme_get_features(l, NVME_FEAT_FID_WRITE_ATOMIC, sel, result); +} /** * nvme_get_features_async_event() - Get asynchronous event feature - * @fd: File descriptor of nvme device - * @sel: Select which type of attribute to return, see &enum nvme_get_features_sel + * @l: Link handle + * @sel: Select which type of attribute to return, + * see &enum nvme_get_features_sel * @result: The command completion result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_get_features_async_event(int fd, enum nvme_get_features_sel sel, - __u32 *result); +static inline int nvme_get_features_async_event(nvme_link_t l, + enum nvme_get_features_sel sel, + __u32 *result) +{ + return __nvme_get_features(l, NVME_FEAT_FID_ASYNC_EVENT, sel, result); +} /** * nvme_get_features_auto_pst() - Get autonomous power state feature - * @fd: File descriptor of nvme device - * @sel: Select which type of attribute to return, see &enum nvme_get_features_sel - * @apst: + * @l: Link handle + * @sel: Select which type of attribute to return, + * see &enum nvme_get_features_sel + * @apst: Autonomous Power State Transition * @result: The command completion result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_get_features_auto_pst(int fd, enum nvme_get_features_sel sel, - struct nvme_feat_auto_pst *apst, __u32 *result); +static inline int nvme_get_features_auto_pst(nvme_link_t l, + enum nvme_get_features_sel sel, + struct nvme_feat_auto_pst *apst, + __u32 *result) +{ + return nvme_get_features(l, NVME_NSID_NONE, NVME_FEAT_FID_AUTO_PST, sel, + 0, NVME_UUID_NONE, apst, sizeof(*apst), result); +} /** * nvme_get_features_host_mem_buf() - Get host memory buffer feature - * @fd: File descriptor of nvme device - * @sel: Select which type of attribute to return, see &enum nvme_get_features_sel + * @l: Link handle + * @sel: Select which type of attribute to return, + * see &enum nvme_get_features_sel * @attrs: Buffer for returned Host Memory Buffer Attributes * @result: The command completion result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_get_features_host_mem_buf(int fd, enum nvme_get_features_sel sel, - struct nvme_host_mem_buf_attrs *attrs, - __u32 *result); +static inline int nvme_get_features_host_mem_buf(nvme_link_t l, + enum nvme_get_features_sel sel, + struct nvme_host_mem_buf_attrs *attrs, + __u32 *result) +{ + return nvme_get_features(l, NVME_NSID_NONE, NVME_FEAT_FID_HOST_MEM_BUF, + sel, 0, NVME_UUID_NONE, + attrs, sizeof(*attrs), result); +} /** * nvme_get_features_timestamp() - Get timestamp feature - * @fd: File descriptor of nvme device - * @sel: Select which type of attribute to return, see &enum nvme_get_features_sel + * @l: Link handle + * @sel: Select which type of attribute to return, + * see &enum nvme_get_features_sel * @ts: Current timestamp * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_get_features_timestamp(int fd, enum nvme_get_features_sel sel, - struct nvme_timestamp *ts); +static inline int nvme_get_features_timestamp(nvme_link_t l, + enum nvme_get_features_sel sel, + struct nvme_timestamp *ts) +{ + return nvme_get_features(l, NVME_NSID_NONE, NVME_FEAT_FID_TIMESTAMP, + sel, 0, NVME_UUID_NONE, ts, sizeof(*ts), NULL); +} /** * nvme_get_features_kato() - Get keep alive timeout feature - * @fd: File descriptor of nvme device - * @sel: Select which type of attribute to return, see &enum nvme_get_features_sel + * @l: Link handle + * @sel: Select which type of attribute to return, + * see &enum nvme_get_features_sel * @result: The command completion result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_get_features_kato(int fd, enum nvme_get_features_sel sel, __u32 *result); +static inline int nvme_get_features_kato(nvme_link_t l, + enum nvme_get_features_sel sel, + __u32 *result) +{ + return __nvme_get_features(l, NVME_FEAT_FID_KATO, sel, result); +} /** * nvme_get_features_hctm() - Get thermal management feature - * @fd: File descriptor of nvme device - * @sel: Select which type of attribute to return, see &enum nvme_get_features_sel + * @l: Link handle + * @sel: Select which type of attribute to return, + * see &enum nvme_get_features_sel * @result: The command completion result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_get_features_hctm(int fd, enum nvme_get_features_sel sel, __u32 *result); +static inline int nvme_get_features_hctm(nvme_link_t l, + enum nvme_get_features_sel sel, + __u32 *result) +{ + return __nvme_get_features(l, NVME_FEAT_FID_HCTM, sel, result); +} /** * nvme_get_features_nopsc() - Get non-operational power state feature - * @fd: File descriptor of nvme device - * @sel: Select which type of attribute to return, see &enum nvme_get_features_sel + * @l: Link handle + * @sel: Select which type of attribute to return, + * see &enum nvme_get_features_sel * @result: The command completion result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_get_features_nopsc(int fd, enum nvme_get_features_sel sel, __u32 *result); +static inline int nvme_get_features_nopsc(nvme_link_t l, + enum nvme_get_features_sel sel, + __u32 *result) +{ + return __nvme_get_features(l, NVME_FEAT_FID_NOPSC, sel, result); +} /** * nvme_get_features_rrl() - Get read recovery level feature - * @fd: File descriptor of nvme device - * @sel: Select which type of attribute to return, see &enum nvme_get_features_sel + * @l: Link handle + * @sel: Select which type of attribute to return, + * see &enum nvme_get_features_sel * @result: The command completion result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_get_features_rrl(int fd, enum nvme_get_features_sel sel, __u32 *result); +static inline int nvme_get_features_rrl(nvme_link_t l, + enum nvme_get_features_sel sel, + __u32 *result) +{ + return __nvme_get_features(l, NVME_FEAT_FID_RRL, sel, result); +} /** * nvme_get_features_plm_config() - Get predictable latency feature - * @fd: File descriptor of nvme device - * @sel: Select which type of attribute to return, see &enum nvme_get_features_sel + * @l: Link handle + * @sel: Select which type of attribute to return, + * see &enum nvme_get_features_sel * @nvmsetid: NVM set id - * @data: + * @plmc: Buffer for returned Predictable Latency Mode Config * @result: The command completion result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_get_features_plm_config(int fd, enum nvme_get_features_sel sel, - __u16 nvmsetid, struct nvme_plm_config *data, - __u32 *result); +static inline int nvme_get_features_plm_config(nvme_link_t l, + enum nvme_get_features_sel sel, + __u16 nvmsetid, + struct nvme_plm_config *plmc, + __u32 *result) +{ + return nvme_get_features(l, NVME_NSID_NONE, NVME_FEAT_FID_PLM_CONFIG, + sel, nvmsetid, NVME_UUID_NONE, + plmc, sizeof(*plmc), result); +} /** * nvme_get_features_plm_window() - Get window select feature - * @fd: File descriptor of nvme device - * @sel: Select which type of attribute to return, see &enum nvme_get_features_sel + * @l: Link handle + * @sel: Select which type of attribute to return, + * see &enum nvme_get_features_sel * @nvmsetid: NVM set id * @result: The command completion result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_get_features_plm_window(int fd, enum nvme_get_features_sel sel, - __u16 nvmsetid, __u32 *result); +static inline int nvme_get_features_plm_window(nvme_link_t l, + enum nvme_get_features_sel sel, + __u16 nvmsetid, __u32 *result) +{ + return nvme_get_features(l, NVME_NSID_NONE, NVME_FEAT_FID_PLM_WINDOW, + sel, nvmsetid, NVME_UUID_NONE, + NULL, 0, result); +} /** * nvme_get_features_lba_sts_interval() - Get LBA status information feature - * @fd: File descriptor of nvme device - * @sel: Select which type of attribute to return, see &enum nvme_get_features_sel + * @l: Link handle + * @sel: Select which type of attribute to return, + * see &enum nvme_get_features_sel * @result: The command completion result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_get_features_lba_sts_interval(int fd, enum nvme_get_features_sel sel, - __u32 *result); +static inline int nvme_get_features_lba_sts_interval(nvme_link_t l, + enum nvme_get_features_sel sel, + __u32 *result) +{ + return __nvme_get_features(l, NVME_FEAT_FID_LBA_STS_INTERVAL, sel, result); +} /** * nvme_get_features_host_behavior() - Get host behavior feature - * @fd: File descriptor of nvme device - * @sel: Select which type of attribute to return, see &enum nvme_get_features_sel - * @data: Pointer to structure nvme_feat_host_behavior + * @l: Link handle + * @sel: Select which type of attribute to return, + * see &enum nvme_get_features_sel + * @fhb: Pointer to structure nvme_feat_host_behavior * @result: The command completion result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_get_features_host_behavior(int fd, enum nvme_get_features_sel sel, - struct nvme_feat_host_behavior *data, - __u32 *result); +static inline int nvme_get_features_host_behavior(nvme_link_t l, + enum nvme_get_features_sel sel, + struct nvme_feat_host_behavior *fhb, + __u32 *result) +{ + return nvme_get_features(l, NVME_NSID_NONE, NVME_FEAT_FID_HOST_BEHAVIOR, + sel, 0, NVME_UUID_NONE, + fhb, sizeof(*fhb), result); +} /** * nvme_get_features_sanitize() - Get sanitize feature - * @fd: File descriptor of nvme device - * @sel: Select which type of attribute to return, see &enum nvme_get_features_sel + * @l: Link handle + * @sel: Select which type of attribute to return, + * see &enum nvme_get_features_sel * @result: The command completion result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_get_features_sanitize(int fd, enum nvme_get_features_sel sel, - __u32 *result); +static inline int nvme_get_features_sanitize(nvme_link_t l, + enum nvme_get_features_sel sel, + __u32 *result) +{ + return __nvme_get_features(l, NVME_FEAT_FID_SANITIZE, sel, result); +} /** * nvme_get_features_endurance_event_cfg() - Get endurance event config feature - * @fd: File descriptor of nvme device - * @sel: Select which type of attribute to return, see &enum nvme_get_features_sel + * @l: Link handle + * @sel: Select which type of attribute to return, + * see &enum nvme_get_features_sel * @endgid: Endurance Group Identifier * @result: The command completion result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_get_features_endurance_event_cfg(int fd, enum nvme_get_features_sel sel, - __u16 endgid, __u32 *result); +static inline int nvme_get_features_endurance_event_cfg(nvme_link_t l, + enum nvme_get_features_sel sel, + __u16 endgid, __u32 *result) +{ + return nvme_get_features(l, NVME_NSID_NONE, NVME_FEAT_FID_ENDURANCE_EVT_CFG, + sel, endgid, NVME_UUID_NONE, NULL, 0, result); +} /** * nvme_get_features_sw_progress() - Get software progress feature - * @fd: File descriptor of nvme device - * @sel: Select which type of attribute to return, see &enum nvme_get_features_sel + * @l: Link handle + * @sel: Select which type of attribute to return, + * see &enum nvme_get_features_sel * @result: The command completion result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_get_features_sw_progress(int fd, enum nvme_get_features_sel sel, - __u32 *result); +static inline int nvme_get_features_sw_progress(nvme_link_t l, + enum nvme_get_features_sel sel, + __u32 *result) +{ + return __nvme_get_features(l, NVME_FEAT_FID_SW_PROGRESS, sel, result); +} /** * nvme_get_features_host_id() - Get host id feature - * @fd: File descriptor of nvme device - * @sel: Select which type of attribute to return, see &enum nvme_get_features_sel + * @l: Link handle + * @sel: Select which type of attribute to return, + * see &enum nvme_get_features_sel * @exhid: Enable Extended Host Identifier * @len: Length of @hostid * @hostid: Buffer for returned host ID * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_get_features_host_id(int fd, enum nvme_get_features_sel sel, - bool exhid, __u32 len, __u8 *hostid); +static inline int nvme_get_features_host_id(nvme_link_t l, enum nvme_get_features_sel sel, + bool exhid, __u32 len, __u8 *hostid) +{ + return nvme_get_features(l, NVME_NSID_NONE, NVME_FEAT_FID_HOST_ID, + sel, exhid, NVME_UUID_NONE, hostid, len, NULL); +} /** * nvme_get_features_resv_mask() - Get reservation mask feature - * @fd: File descriptor of nvme device - * @sel: Select which type of attribute to return, see &enum nvme_get_features_sel + * @l: Link handle * @nsid: Namespace ID + * @sel: Select which type of attribute to return, + * see &enum nvme_get_features_sel * @result: The command completion result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_get_features_resv_mask(int fd, enum nvme_get_features_sel sel, - __u32 nsid, __u32 *result); +static inline int nvme_get_features_resv_mask(nvme_link_t l, __u32 nsid, + enum nvme_get_features_sel sel, + __u32 *result) +{ + return nvme_get_features(l, nsid, NVME_FEAT_FID_RESV_MASK, + sel, 0, NVME_UUID_NONE, NULL, 0, result); +} /** * nvme_get_features_resv_persist() - Get reservation persist feature - * @fd: File descriptor of nvme device - * @sel: Select which type of attribute to return, see &enum nvme_get_features_sel + * @l: Link handle * @nsid: Namespace ID + * @sel: Select which type of attribute to return, + * see &enum nvme_get_features_sel * @result: The command completion result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_get_features_resv_persist(int fd, enum nvme_get_features_sel sel, - __u32 nsid, __u32 *result); +static inline int nvme_get_features_resv_persist(nvme_link_t l, __u32 nsid, + enum nvme_get_features_sel sel, + __u32 *result) +{ + return nvme_get_features(l, nsid, NVME_FEAT_FID_RESV_PERSIST, + sel, 0, NVME_UUID_NONE, NULL, 0, result); +} /** * nvme_get_features_write_protect() - Get write protect feature - * @fd: File descriptor of nvme device + * @l: Link handle * @nsid: Namespace ID - * @sel: Select which type of attribute to return, see &enum nvme_get_features_sel + * @sel: Select which type of attribute to return, + * see &enum nvme_get_features_sel * @result: The command completion result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_get_features_write_protect(int fd, __u32 nsid, - enum nvme_get_features_sel sel, - __u32 *result); +static inline int nvme_get_features_write_protect(nvme_link_t l, __u32 nsid, + enum nvme_get_features_sel sel, + __u32 *result) +{ + return nvme_get_features(l, nsid, NVME_FEAT_FID_WRITE_PROTECT, + sel, 0, NVME_UUID_NONE, NULL, 0, result); +} /** * nvme_get_features_iocs_profile() - Get IOCS profile feature - * @fd: File descriptor of nvme device - * @sel: Select which type of attribute to return, see &enum nvme_get_features_sel + * @l: Link handle + * @sel: Select which type of attribute to return, + * see &enum nvme_get_features_sel * @result: The command completion result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_get_features_iocs_profile(int fd, enum nvme_get_features_sel sel, - __u32 *result); +static inline int nvme_get_features_iocs_profile(nvme_link_t l, + enum nvme_get_features_sel sel, + __u32 *result) +{ + return __nvme_get_features(l, NVME_FEAT_FID_IOCS_PROFILE, sel, result); +} /** * nvme_format_nvm() - Format nvme namespace(s) - * @args: &struct nvme_format_nvme_args argument structure + * @l: Link handle + * @nsid: Namespace ID to format + * @lbaf: Logical block address format + * @mset: Metadata settings (extended or separated), true if extended + * @pi: Protection information type + * @pil: Protection information location (beginning or end), true if end + * @ses: Secure erase settings + * @result: The command completion result from CQE dword0 * * The Format NVM command low level formats the NVM media. This command is used * by the host to change the LBA data size and/or metadata size. A low level * format may destroy all data and metadata associated with all namespaces or * only the specific namespace associated with the command * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_format_nvm(struct nvme_format_nvm_args *args); +static inline int nvme_format_nvm(nvme_link_t l, __u32 nsid, __u8 lbaf, + enum nvme_cmd_format_mset mset, + enum nvme_cmd_format_pi pi, + enum nvme_cmd_format_pil pil, + enum nvme_cmd_format_ses ses, + __u32 *result) +{ + __u32 cdw10 = NVME_SET(lbaf, FORMAT_CDW10_LBAFL) | + NVME_SET(mset, FORMAT_CDW10_MSET) | + NVME_SET(pi, FORMAT_CDW10_PI) | + NVME_SET(pil, FORMAT_CDW10_PIL) | + NVME_SET(ses, FORMAT_CDW10_SES) | + NVME_SET((lbaf >> 4), FORMAT_CDW10_LBAFU); + + struct nvme_passthru_cmd cmd = { + .opcode = nvme_admin_format_nvm, + .nsid = nsid, + .cdw10 = cdw10, + }; + + return nvme_submit_admin_passthru(l, &cmd, result); +} /** * nvme_ns_mgmt() - Issue a Namespace management command - * @args: &struct nvme_ns_mgmt_args Argument structure + * @l: Link handle + * @nsid: Namespace identifier + * @sel: Type of management operation to perform + * @csi: Command Set Identifier + * @data: Host Software Specified Fields + * @result: NVMe command result * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_ns_mgmt(struct nvme_ns_mgmt_args *args); +static inline int nvme_ns_mgmt(nvme_link_t l, __u32 nsid, + enum nvme_ns_mgmt_sel sel, __u8 csi, + struct nvme_ns_mgmt_host_sw_specified *data, + __u32 *result) +{ + __u32 cdw10 = NVME_SET(sel, NAMESPACE_MGMT_CDW10_SEL); + __u32 cdw11 = NVME_SET(csi, NAMESPACE_MGMT_CDW11_CSI); + __u32 len = 0; + + if (data) + len = sizeof(*data); + + struct nvme_passthru_cmd cmd = { + .opcode = nvme_admin_ns_mgmt, + .nsid = nsid, + .addr = (__u64)(uintptr_t)data, + .data_len = len, + .cdw10 = cdw10, + .cdw11 = cdw11, + }; + + return nvme_submit_admin_passthru(l, &cmd, result); +} /** * nvme_ns_mgmt_create() - Create a non attached namespace - * @fd: File descriptor of nvme device - * @ns: Namespace identification that defines ns creation parameters - * @nsid: On success, set to the namespace id that was created - * @timeout: Override the default timeout to this value in milliseconds; - * set to 0 to use the system default. - * @csi: Command Set Identifier + * @l: Link handle + * @csi: Command Set Identifier * @data: Host Software Specified Fields that defines ns creation parameters + * @nsid: On success, set to the namespace id that was created * * On successful creation, the namespace exists in the subsystem, but is not * attached to any controller. Use the nvme_ns_attach_ctrls() to assign the * namespace to one or more controllers. * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. - */ -static inline int nvme_ns_mgmt_create(int fd, struct nvme_id_ns *ns, - __u32 *nsid, __u32 timeout, __u8 csi, - struct nvme_ns_mgmt_host_sw_specified *data) -{ - struct nvme_ns_mgmt_args args = { - .result = nsid, - .ns = ns, - .args_size = sizeof(args), - .fd = fd, - .timeout = timeout, - .nsid = NVME_NSID_NONE, - .sel = NVME_NS_MGMT_SEL_CREATE, - .csi = csi, - .rsvd1 = { 0, }, - .rsvd2 = NULL, - .data = data, - }; - - return nvme_ns_mgmt(&args); -} - -/** - * nvme_ns_mgmt_delete_timeout() - Delete a non attached namespace with timeout - * @fd: File descriptor of nvme device - * @nsid: Namespace identifier to delete - * @timeout: Override the default timeout to this value in milliseconds; - * set to 0 to use the system default. - * - * It is recommended that a namespace being deleted is not attached to any - * controller. Use the nvme_ns_detach_ctrls() first if the namespace is still - * attached. - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_ns_mgmt_delete_timeout(int fd, __u32 nsid, __u32 timeout) +static inline int nvme_ns_mgmt_create(nvme_link_t l, __u8 csi, + struct nvme_ns_mgmt_host_sw_specified *data, + __u32 *nsid) { - struct nvme_ns_mgmt_args args = { - .result = NULL, - .ns = NULL, - .args_size = sizeof(args), - .fd = fd, - .timeout = timeout, - .nsid = nsid, - .sel = NVME_NS_MGMT_SEL_DELETE, - .csi = 0, - .rsvd1 = { 0, }, - .rsvd2 = NULL, - .data = NULL, - }; - - return nvme_ns_mgmt(&args); + return nvme_ns_mgmt(l, NVME_NSID_NONE, NVME_NS_MGMT_SEL_CREATE, + csi, data, nsid); } /** * nvme_ns_mgmt_delete() - Delete a non attached namespace - * @fd: File descriptor of nvme device + * @l: Link handle * @nsid: Namespace identifier to delete * * It is recommended that a namespace being deleted is not attached to any * controller. Use the nvme_ns_detach_ctrls() first if the namespace is still * attached. * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_ns_mgmt_delete(int fd, __u32 nsid) +static inline int nvme_ns_mgmt_delete(nvme_link_t l, __u32 nsid) { - return nvme_ns_mgmt_delete_timeout(fd, nsid, 0); + return nvme_ns_mgmt(l, nsid, NVME_NS_MGMT_SEL_DELETE, 0, NULL, NULL); } /** * nvme_ns_attach() - Attach or detach namespace to controller(s) - * @args: &struct nvme_ns_attach_args Argument structure + * @l: Link handle + * @nsid: Namespace ID to execute attach selection + * @sel: Attachment selection, see &enum nvme_ns_attach_sel + * @ctrlist: Controller list to modify attachment state of nsid + * @result: NVMe command result * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_ns_attach(struct nvme_ns_attach_args *args); +static inline int nvme_ns_attach(nvme_link_t l, __u32 nsid, + enum nvme_ns_attach_sel sel, + struct nvme_ctrl_list *ctrlist, + __u32 *result) +{ + __u32 cdw10 = NVME_SET(sel, NAMESPACE_ATTACH_CDW10_SEL); + + struct nvme_passthru_cmd cmd = { + .opcode = nvme_admin_ns_attach, + .nsid = nsid, + .addr = (__u64)(uintptr_t)ctrlist, + .data_len = sizeof(*ctrlist), + .cdw10 = cdw10, + }; + + return nvme_submit_admin_passthru(l, &cmd, result); +} /** * nvme_ns_attach_ctrls() - Attach namespace to controllers - * @fd: File descriptor of nvme device + * @l: Link handle * @nsid: Namespace ID to attach * @ctrlist: Controller list to modify attachment state of nsid * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_ns_attach_ctrls(int fd, __u32 nsid, +static inline int nvme_ns_attach_ctrls(nvme_link_t l, __u32 nsid, struct nvme_ctrl_list *ctrlist) { - struct nvme_ns_attach_args args = { - .result = NULL, - .ctrlist = ctrlist, - .args_size = sizeof(args), - .fd = fd, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .nsid = nsid, - .sel = NVME_NS_ATTACH_SEL_CTRL_ATTACH, - }; - - return nvme_ns_attach(&args); + return nvme_ns_attach(l, nsid, NVME_NS_ATTACH_SEL_CTRL_ATTACH, + ctrlist, NULL); } /** * nvme_ns_detach_ctrls() - Detach namespace from controllers - * @fd: File descriptor of nvme device + * @l: Link handle * @nsid: Namespace ID to detach * @ctrlist: Controller list to modify attachment state of nsid * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_ns_detach_ctrls(int fd, __u32 nsid, +static inline int nvme_ns_detach_ctrls(nvme_link_t l, __u32 nsid, struct nvme_ctrl_list *ctrlist) { - struct nvme_ns_attach_args args = { - .result = NULL, - .ctrlist = ctrlist, - .args_size = sizeof(args), - .fd = fd, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .nsid = nsid, - .sel = NVME_NS_ATTACH_SEL_CTRL_DEATTACH, - }; - - return nvme_ns_attach(&args); + return nvme_ns_attach(l, nsid, NVME_NS_ATTACH_SEL_CTRL_DEATTACH, + ctrlist, NULL); } /** * nvme_fw_download() - Download part or all of a firmware image to the * controller - * @args: &struct nvme_fw_download_args argument structure + * @l: Link handle + * @data: Userspace address of the firmware data + * @data_len: Length of data in this command in bytes + * @offset: Offset in the firmware data + * @result: The command completion result from CQE dword0 * * The Firmware Image Download command downloads all or a portion of an image * for a future update to the controller. The Firmware Image Download command @@ -3657,14 +3822,39 @@ static inline int nvme_ns_detach_ctrls(int fd, __u32 nsid, * Download command. Use the nvme_fw_commit() to activate a newly downloaded * image. * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_fw_download(struct nvme_fw_download_args *args); +static inline int nvme_fw_download(nvme_link_t l, void *data, __u32 data_len, + __u32 offset, __u32 *result) +{ + __u32 cdw10 = (data_len >> 2) - 1; + __u32 cdw11 = offset >> 2; + + struct nvme_passthru_cmd cmd = { + .opcode = nvme_admin_fw_download, + .addr = (__u64)(uintptr_t)data, + .data_len = data_len, + .cdw10 = cdw10, + .cdw11 = cdw11, + }; + + if ((data_len & 0x3) || (!data_len)) + return -EINVAL; + + if (offset & 0x3) + return -EINVAL; + + return nvme_submit_admin_passthru(l, &cmd, result); +} /** * nvme_fw_commit() - Commit firmware using the specified action - * @args: &struct nvme_fw_commit_args argument structure + * @l: Link handle + * @fs: Firmware slot to commit the downloaded image + * @ca: Action to use for the firmware image, see &enum nvme_fw_commit_ca + * @bpid: Set to true to select the boot partition id + * @result: The command completion result from CQE dword0 * * The Firmware Commit command modifies the firmware image or Boot Partitions. * @@ -3673,11 +3863,32 @@ int nvme_fw_download(struct nvme_fw_download_args *args); * status response may specify additional reset actions required to complete * the commit process. */ -int nvme_fw_commit(struct nvme_fw_commit_args *args); +static inline int nvme_fw_commit(nvme_link_t l, __u8 fs, enum nvme_fw_commit_ca ca, + bool bpid, __u32 *result) +{ + __u32 cdw10 = NVME_SET(fs, FW_COMMIT_CDW10_FS) | + NVME_SET(ca, FW_COMMIT_CDW10_CA) | + NVME_SET(bpid, FW_COMMIT_CDW10_BPID); + + struct nvme_passthru_cmd cmd = { + .opcode = nvme_admin_fw_commit, + .cdw10 = cdw10, + }; + + return nvme_submit_admin_passthru(l, &cmd, result); +} /** * nvme_security_send() - Security Send command - * @args: &struct nvme_security_send argument structure + * @l: Link handle + * @nsid: Namespace ID to issue security command on + * @nssf: NVMe Security Specific field + * @spsp: Security Protocol Specific field + * @secp: Security Protocol + * @tl: Protocol specific transfer length + * @data: Security data payload to send + * @data_len: Data length of the payload in bytes + * @result: The command completion result from CQE dword0 * * The Security Send command transfers security protocol data to the * controller. The data structure transferred to the controller as part of this @@ -3688,35 +3899,128 @@ int nvme_fw_commit(struct nvme_fw_commit_args *args); * The security data is protocol specific and is not defined by the NVMe * specification. * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_security_send(struct nvme_security_send_args *args); +static inline int nvme_security_send(nvme_link_t l, __u32 nsid,__u8 nssf, + __u16 spsp, __u8 secp, __u32 tl, + void *data, __u32 data_len, + __u32 *result) +{ + __u32 cdw10 = NVME_SET(secp, SECURITY_SECP) | + NVME_SET(spsp, SECURITY_SPSP0) | + NVME_SET((spsp >> 8), SECURITY_SPSP1) | + NVME_SET(nssf, SECURITY_NSSF); + __u32 cdw11 = tl; + + struct nvme_passthru_cmd cmd = { + .opcode = nvme_admin_security_send, + .nsid = nsid, + .addr = (__u64)(uintptr_t)data, + .data_len = data_len, + .cdw10 = cdw10, + .cdw11 = cdw11, + }; + + return nvme_submit_admin_passthru(l, &cmd, result); +} /** * nvme_security_receive() - Security Receive command - * @args: &struct nvme_security_receive argument structure + * @l: Link handle + * @nsid: Namespace ID to issue security command on + * @nssf: NVMe Security Specific field + * @spsp0: Security Protocol Specific field + * @spsp1: Security Protocol Specific field + * @secp: Security Protocol + * @al: Protocol specific allocation length + * @data: Security data payload to send + * @data_len: Data length of the payload in bytes + * @result: The command completion result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_security_receive(struct nvme_security_receive_args *args); +static inline int nvme_security_receive(nvme_link_t l, __u32 nsid, + __u8 nssf, __u8 spsp0, + __u8 spsp1, __u8 secp, + __u32 al, void *data, + __u32 data_len, __u32 *result) +{ + __u32 cdw10 = NVME_SET(secp, SECURITY_SECP) | + NVME_SET(spsp0, SECURITY_SPSP0) | + NVME_SET(spsp1, SECURITY_SPSP1) | + NVME_SET(nssf, SECURITY_NSSF); + __u32 cdw11 = al; + + struct nvme_passthru_cmd cmd = { + .opcode = nvme_admin_security_recv, + .nsid = nsid, + .addr = (__u64)(uintptr_t)data, + .data_len = data_len, + .cdw10 = cdw10, + .cdw11 = cdw11, + }; + + return nvme_submit_admin_passthru(l, &cmd, result); +} + /** * nvme_get_lba_status() - Retrieve information on possibly unrecoverable LBAs - * @args: &struct nvme_get_lba_status_args argument structure + * @l: Link handle + * @nsid: Namespace ID to retrieve LBA status + * @slba: Starting logical block address to check statuses + * @mndw: Maximum number of dwords to return + * @atype: Action type mechanism to determine LBA status descriptors to + * return, see &enum nvme_lba_status_atype + * @rl: Range length from slba to perform the action + * @lbas: Data payload to return status descriptors + * @result: The command completion result from CQE dword0 * * The Get LBA Status command requests information about Potentially * Unrecoverable LBAs. Refer to the specification for action type descriptions. * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_get_lba_status(struct nvme_get_lba_status_args *args); +static inline int nvme_get_lba_status(nvme_link_t l, __u32 nsid, __u64 slba, + __u32 mndw, + enum nvme_lba_status_atype atype, __u16 rl, + struct nvme_lba_status *lbas, + __u32 *result) +{ + __u32 cdw10 = slba & 0xffffffff; + __u32 cdw11 = slba >> 32; + __u32 cdw12 = mndw; + __u32 cdw13 = NVME_SET(rl, GET_LBA_STATUS_CDW13_RL) | + NVME_SET(atype, GET_LBA_STATUS_CDW13_ATYPE); + + struct nvme_passthru_cmd cmd = { + .opcode = nvme_admin_get_lba_status, + .nsid = nsid, + .addr = (__u64)(uintptr_t)lbas, + .data_len = (mndw + 1) << 2, + .cdw10 = cdw10, + .cdw11 = cdw11, + .cdw12 = cdw12, + .cdw13 = cdw13, + }; + + return nvme_submit_admin_passthru(l, &cmd, result); +} /** * nvme_directive_send() - Send directive command - * @args: &struct nvme_directive_send_args argument structure + * @l: Link handle + * @nsid: Namespace ID, if applicable + * @doper: Directive send operation, see &enum nvme_directive_send_doper + * @dtype: Directive type, see &enum nvme_directive_dtype + * @dspec: Directive specific field + * @cdw12: Directive specific command dword12 + * @data: Data payload to be send + * @data_len: Length of data payload in bytes + * @result: If successful, the CQE dword0 value * * Directives is a mechanism to enable host and NVM subsystem or controller * information exchange. The Directive Send command transfers data related to a @@ -3724,260 +4028,339 @@ int nvme_get_lba_status(struct nvme_get_lba_status_args *args); * * See the NVMe specification for more information. * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_directive_send(struct nvme_directive_send_args *args); +static inline int nvme_directive_send(nvme_link_t l, __u32 nsid, + enum nvme_directive_send_doper doper, + enum nvme_directive_dtype dtype, + __u16 dspec, __u32 cdw12, + void *data, __u32 data_len, __u32 *result) +{ + __u32 cdw10 = data_len ? (data_len >> 2) - 1 : 0; + __u32 cdw11 = NVME_SET(doper, DIRECTIVE_CDW11_DOPER) | + NVME_SET(dtype, DIRECTIVE_CDW11_DTYPE) | + NVME_SET(dspec, DIRECTIVE_CDW11_DPSEC); + + struct nvme_passthru_cmd cmd = { + .opcode = nvme_admin_directive_send, + .nsid = nsid, + .addr = (__u64)(uintptr_t)data, + .data_len = data_len, + .cdw10 = cdw10, + .cdw11 = cdw11, + .cdw12 = cdw12, + }; + + return nvme_submit_admin_passthru(l, &cmd, result); +} /** * nvme_directive_send_id_endir() - Directive Send Enable Directive - * @fd: File descriptor of nvme device + * @l: Link handle * @nsid: Namespace Identifier * @endir: Enable Directive * @dtype: Directive Type * @id: Pointer to structure nvme_id_directives * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_directive_send_id_endir(int fd, __u32 nsid, bool endir, - enum nvme_directive_dtype dtype, - struct nvme_id_directives *id); +static inline int nvme_directive_send_id_endir(nvme_link_t l, __u32 nsid, bool endir, + enum nvme_directive_dtype dtype, + struct nvme_id_directives *id) +{ + __u32 cdw12 = NVME_SET(dtype, DIRECTIVE_SEND_IDENTIFY_CDW12_DTYPE) | + NVME_SET(endir, DIRECTIVE_SEND_IDENTIFY_CDW12_ENDIR); + + return nvme_directive_send(l, nsid, + NVME_DIRECTIVE_SEND_IDENTIFY_DOPER_ENDIR, + NVME_DIRECTIVE_DTYPE_IDENTIFY, 0, cdw12, + id, sizeof(*id), NULL); +} /** * nvme_directive_send_stream_release_identifier() - Directive Send Stream release - * @fd: File descriptor of nvme device + * @l: Link handle * @nsid: Namespace ID * @stream_id: Stream identifier * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_directive_send_stream_release_identifier(int fd, - __u32 nsid, __u16 stream_id) +static inline int nvme_directive_send_stream_release_identifier(nvme_link_t l, + __u32 nsid, + __u16 stream_id) { - struct nvme_directive_send_args args = { - .result = NULL, - .data = NULL, - .args_size = sizeof(args), - .fd = fd, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .nsid = nsid, - .doper = NVME_DIRECTIVE_SEND_STREAMS_DOPER_RELEASE_IDENTIFIER, - .dtype = NVME_DIRECTIVE_DTYPE_STREAMS, - .cdw12 = 0, - .data_len = 0, - .dspec = stream_id, - }; - - return nvme_directive_send(&args); + return nvme_directive_send(l, nsid, + NVME_DIRECTIVE_SEND_STREAMS_DOPER_RELEASE_IDENTIFIER, + NVME_DIRECTIVE_DTYPE_STREAMS, stream_id, + 0, NULL, 0, NULL); } /** * nvme_directive_send_stream_release_resource() - Directive Send Stream release resources - * @fd: File descriptor of nvme device + * @l: Link handle * @nsid: Namespace ID * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_directive_send_stream_release_resource(int fd, __u32 nsid) +static inline int nvme_directive_send_stream_release_resource(nvme_link_t l, + __u32 nsid) { - struct nvme_directive_send_args args = { - .result = NULL, - .data = NULL, - .args_size = sizeof(args), - .fd = fd, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .nsid = nsid, - .doper = NVME_DIRECTIVE_SEND_STREAMS_DOPER_RELEASE_RESOURCE, - .dtype = NVME_DIRECTIVE_DTYPE_STREAMS, - .cdw12 = 0, - .data_len = 0, - .dspec = 0, - }; - - return nvme_directive_send(&args); + return nvme_directive_send(l, nsid, + NVME_DIRECTIVE_SEND_STREAMS_DOPER_RELEASE_RESOURCE, + NVME_DIRECTIVE_DTYPE_STREAMS, + 0, 0, NULL, 0, NULL); } /** * nvme_directive_recv() - Receive directive specific data - * @args: &struct nvme_directive_recv_args argument structure + * @l: Link handle + * @nsid: Namespace ID, if applicable + * @doper: Directive send operation, see &enum nvme_directive_send_doper + * @dtype: Directive type, see &enum nvme_directive_dtype + * @dspec: Directive specific field + * @cdw12: Directive specific command dword12 + * @data: Userspace address of data payload + * @data_len: Length of data payload in bytes + * @result: If successful, the CQE dword0 value * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_directive_recv(struct nvme_directive_recv_args *args); +static inline int nvme_directive_recv(nvme_link_t l, __u32 nsid, + enum nvme_directive_receive_doper doper, + enum nvme_directive_dtype dtype, + __u16 dspec, __u32 cdw12, + void *data, __u32 data_len, __u32 *result) +{ + __u32 cdw10 = data_len ? (data_len >> 2) - 1 : 0; + __u32 cdw11 = NVME_SET(doper, DIRECTIVE_CDW11_DOPER) | + NVME_SET(dtype, DIRECTIVE_CDW11_DTYPE) | + NVME_SET(dspec, DIRECTIVE_CDW11_DPSEC); + + struct nvme_passthru_cmd cmd = { + .opcode = nvme_admin_directive_recv, + .nsid = nsid, + .addr = (__u64)(uintptr_t)data, + .data_len = data_len, + .cdw10 = cdw10, + .cdw11 = cdw11, + .cdw12 = cdw12, + }; + + return nvme_submit_admin_passthru(l, &cmd, result); +} /** * nvme_directive_recv_identify_parameters() - Directive receive identifier parameters - * @fd: File descriptor of nvme device + * @l: Link handle * @nsid: Namespace ID * @id: Identify parameters buffer * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_directive_recv_identify_parameters(int fd, __u32 nsid, - struct nvme_id_directives *id) +static inline int nvme_directive_recv_identify_parameters(nvme_link_t l, + __u32 nsid, + struct nvme_id_directives *id) { - struct nvme_directive_recv_args args = { - .result = NULL, - .data = id, - .args_size = sizeof(args), - .fd = fd, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .nsid = nsid, - .doper = NVME_DIRECTIVE_RECEIVE_IDENTIFY_DOPER_PARAM, - .dtype = NVME_DIRECTIVE_DTYPE_IDENTIFY, - .cdw12 = 0, - .data_len = sizeof(*id), - .dspec = 0, - }; - - return nvme_directive_recv(&args); + return nvme_directive_recv(l, nsid, + NVME_DIRECTIVE_RECEIVE_IDENTIFY_DOPER_PARAM, + NVME_DIRECTIVE_DTYPE_IDENTIFY, + 0, 0, id, sizeof(*id), NULL); } /** * nvme_directive_recv_stream_parameters() - Directive receive stream parameters - * @fd: File descriptor of nvme device + * @l: Link handle * @nsid: Namespace ID * @parms: Streams directive parameters buffer * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_directive_recv_stream_parameters(int fd, __u32 nsid, - struct nvme_streams_directive_params *parms) +static inline int nvme_directive_recv_stream_parameters(nvme_link_t l, + __u32 nsid, + struct nvme_streams_directive_params *parms) { - struct nvme_directive_recv_args args = { - .result = NULL, - .data = parms, - .args_size = sizeof(args), - .fd = fd, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .nsid = nsid, - .doper = NVME_DIRECTIVE_RECEIVE_STREAMS_DOPER_PARAM, - .dtype = NVME_DIRECTIVE_DTYPE_STREAMS, - .cdw12 = 0, - .data_len = sizeof(*parms), - .dspec = 0, - }; - - return nvme_directive_recv(&args); + return nvme_directive_recv(l, nsid, + NVME_DIRECTIVE_RECEIVE_STREAMS_DOPER_PARAM, + NVME_DIRECTIVE_DTYPE_STREAMS, + 0, 0, parms, sizeof(*parms), NULL); } /** * nvme_directive_recv_stream_status() - Directive receive stream status - * @fd: File descriptor of nvme device + * @l: Link handle * @nsid: Namespace ID * @nr_entries: Number of streams to receive * @id: Stream status buffer * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_directive_recv_stream_status(int fd, __u32 nsid, - unsigned int nr_entries, - struct nvme_streams_directive_status *id) +static inline int nvme_directive_recv_stream_status(nvme_link_t l, __u32 nsid, + unsigned int nr_entries, + struct nvme_streams_directive_status *id) { if (nr_entries > NVME_STREAM_ID_MAX) { errno = EINVAL; return -1; } - struct nvme_directive_recv_args args = { - .result = NULL, - .data = id, - .args_size = sizeof(args), - .fd = fd, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .nsid = nsid, - .doper = NVME_DIRECTIVE_RECEIVE_STREAMS_DOPER_STATUS, - .dtype = NVME_DIRECTIVE_DTYPE_STREAMS, - .cdw12 = 0, - .data_len = (__u32)(sizeof(*id) + nr_entries * sizeof(__le16)), - .dspec = 0, - }; - - return nvme_directive_recv(&args); + return nvme_directive_recv(l, nsid, + NVME_DIRECTIVE_RECEIVE_STREAMS_DOPER_STATUS, + NVME_DIRECTIVE_DTYPE_STREAMS, 0, 0, id, + (__u32)(sizeof(*id) + nr_entries * sizeof(__le16)), + NULL); } /** * nvme_directive_recv_stream_allocate() - Directive receive stream allocate - * @fd: File descriptor of nvme device + * @l: Link handle * @nsid: Namespace ID * @nsr: Namespace Streams Requested * @result: If successful, the CQE dword0 value * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_directive_recv_stream_allocate(int fd, __u32 nsid, - __u16 nsr, __u32 *result) +static inline int nvme_directive_recv_stream_allocate(nvme_link_t l, __u32 nsid, + __u16 nsr, + __u32 *result) { - struct nvme_directive_recv_args args = { - .result = result, - .data = NULL, - .args_size = sizeof(args), - .fd = fd, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .nsid = nsid, - .doper = NVME_DIRECTIVE_RECEIVE_STREAMS_DOPER_RESOURCE, - .dtype = NVME_DIRECTIVE_DTYPE_STREAMS, - .cdw12 = nsr, - .data_len = 0, - .dspec = 0, - }; - - return nvme_directive_recv(&args); + return nvme_directive_recv(l, nsid, + NVME_DIRECTIVE_RECEIVE_STREAMS_DOPER_RESOURCE, + NVME_DIRECTIVE_DTYPE_STREAMS, + 0, nsr, NULL, 0, result); } /** * nvme_capacity_mgmt() - Capacity management command - * @args: &struct nvme_capacity_mgmt_args argument structure + * @l: Link handle + * @op: Operation to be performed by the controller + * @elid: Value specific to the value of the Operation field + * @cdw11: Least significant 32 bits of the capacity in bytes of the + * Endurance Group or NVM Set to be created + * @cdw12: Most significant 32 bits of the capacity in bytes of the + * Endurance Group or NVM Set to be created + * @result: If successful, the CQE dword0 value * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_capacity_mgmt(struct nvme_capacity_mgmt_args *args); +static inline int nvme_capacity_mgmt(nvme_link_t l, __u8 op, __u16 elid, + __u32 cdw11, __u32 cdw12, __u32 *result) +{ + __u32 cdw10 = op | elid << 16; + + struct nvme_passthru_cmd cmd = { + .opcode = nvme_admin_capacity_mgmt, + .cdw10 = cdw10, + .cdw11 = cdw11, + .cdw12 = cdw12, + }; + + return nvme_submit_admin_passthru(l, &cmd, result); +} /** * nvme_lockdown() - Issue lockdown command - * @args: &struct nvme_lockdown_args argument structure + * @l: Link handle + * @scp: Scope of the command + * @prhbt: Prohibit or allow the command opcode or Set Features command + * @ifc: Affected interface + * @ofi: Opcode or Feature Identifier + * @uuidx: UUID Index if controller supports this id selection method + * @result: The command completion result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_lockdown(struct nvme_lockdown_args *args); +static inline int nvme_lockdown(nvme_link_t l, __u8 scp, __u8 prhbt, + __u8 ifc, __u8 ofi, __u8 uuidx, + __u32 *result) +{ + __u32 cdw10 = ofi << 8 | (ifc & 0x3) << 5 | (prhbt & 0x1) << 4 | (scp & 0xF); + + struct nvme_passthru_cmd cmd = { + .opcode = nvme_admin_lockdown, + .cdw10 = cdw10, + .cdw14 = (__u32)(uuidx & 0x3F), + }; + + return nvme_submit_admin_passthru(l, &cmd, result); +} /** * nvme_set_property() - Set controller property - * @args: &struct nvme_set_property_args argument structure + * @l: Link handle + * @offset: Property offset from the base to set + * @value: The value to set the property + * @result: The command completion result from CQE dword0 * * This is an NVMe-over-Fabrics specific command, not applicable to PCIe. These * properties align to the PCI MMIO controller registers. * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_set_property(struct nvme_set_property_args *args); +static inline int nvme_set_property(nvme_link_t l, int offset, __u64 value, __u32 *result) +{ + __u32 cdw10 = nvme_is_64bit_reg(offset); + + struct nvme_passthru_cmd cmd = { + .opcode = nvme_admin_fabrics, + .nsid = nvme_fabrics_type_property_set, + .cdw10 = cdw10, + .cdw11 = (__u32)offset, + .cdw12 = (__u32)(value & 0xffffffff), + .cdw13 = (__u32)(value >> 32), + }; + + return nvme_submit_admin_passthru(l, &cmd, result); +} /** * nvme_get_property() - Get a controller property - * @args: &struct nvme_get_propert_args argument structure + * @l: Link handle + * @offset: Property offset from the base to retrieve + * @value: Where the property's value will be stored on success * * This is an NVMe-over-Fabrics specific command, not applicable to PCIe. These * properties align to the PCI MMIO controller registers. * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_get_property(struct nvme_get_property_args *args); +static inline int nvme_get_property(nvme_link_t l, int offset, __u64 *value) +{ + __u32 cdw10 = nvme_is_64bit_reg(offset); + + struct nvme_passthru_cmd64 cmd = { + .opcode = nvme_admin_fabrics, + .nsid = nvme_fabrics_type_property_get, + .cdw10 = cdw10, + .cdw11 = (__u32)offset, + }; + + return nvme_submit_admin_passthru64(l, &cmd, value); +} /** * nvme_sanitize_nvm() - Start a sanitize operation - * @args: &struct nvme_sanitize_nvm_args argument structure + * @l: Link handle + * @sanact: Sanitize action, see &enum nvme_sanitize_sanact + * @ause: Set to allow unrestricted sanitize exit + * @owpass: Overwrite pass count + * @oipbp: Set to overwrite invert pattern between passes + * @ndas: Set to not deallocate blocks after sanitizing + * @emvs: Set to enter media verification state + * @ovrpat: Overwrite pattern + * @result: The command completion result from CQE dword0 * * A sanitize operation alters all user data in the NVM subsystem such that * recovery of any previous user data from any cache, the non-volatile media, @@ -3989,14 +4372,38 @@ int nvme_get_property(struct nvme_get_property_args *args); * operations are processed in the background, i.e., completion of the sanitize * command does not indicate completion of the sanitize operation. * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_sanitize_nvm(struct nvme_sanitize_nvm_args *args); +static inline int nvme_sanitize_nvm(nvme_link_t l, + enum nvme_sanitize_sanact sanact, + bool ause, __u8 owpass, bool oipbp, + bool ndas, bool emvs, __u32 ovrpat, + __u32 *result) +{ + __u32 cdw10 = NVME_SET(sanact, SANITIZE_CDW10_SANACT) | + NVME_SET(ause, SANITIZE_CDW10_AUSE) | + NVME_SET(owpass, SANITIZE_CDW10_OWPASS) | + NVME_SET(oipbp, SANITIZE_CDW10_OIPBP) | + NVME_SET(ndas, SANITIZE_CDW10_NDAS) | + NVME_SET(emvs, SANITIZE_CDW10_EMVS); + __u32 cdw11 = ovrpat; + + struct nvme_passthru_cmd cmd = { + .opcode = nvme_admin_sanitize_nvm, + .cdw10 = cdw10, + .cdw11 = cdw11, + }; + + return nvme_submit_admin_passthru(l, &cmd, result); +} /** * nvme_dev_self_test() - Start or abort a self test - * @args: &struct nvme_dev_self_test argument structure + * @l: Link handle + * @nsid: Namespace ID to test + * @stc: Self test code, see &enum nvme_dst_stc + * @result: The command completion result from CQE dword0 * * The Device Self-test command starts a device self-test operation or abort a * device self-test operation. A device self-test operation is a diagnostic @@ -4009,14 +4416,32 @@ int nvme_sanitize_nvm(struct nvme_sanitize_nvm_args *args); * 0xffffffff to test all namespaces. All other values tests a specific * namespace, if present. * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_dev_self_test(struct nvme_dev_self_test_args *args); +static inline int nvme_dev_self_test(nvme_link_t l, __u32 nsid, + enum nvme_dst_stc stc, + __u32 *result) +{ + __u32 cdw10 = NVME_SET(stc, DEVICE_SELF_TEST_CDW10_STC); + + struct nvme_passthru_cmd cmd = { + .opcode = nvme_admin_dev_self_test, + .nsid = nsid, + .cdw10 = cdw10, + }; + + return nvme_submit_admin_passthru(l, &cmd, result); +} /** * nvme_virtual_mgmt() - Virtualization resource management - * @args: &struct nvme_virtual_mgmt_args argument structure + * @l: Link handle + * @act: Virtual resource action, see &enum nvme_virt_mgmt_act + * @rt: Resource type to modify, see &enum nvme_virt_mgmt_rt + * @cntlid: Controller id for which resources are bing modified + * @nr: Number of resources being allocated or assigned + * @result: If successful, the CQE dword0 * * The Virtualization Management command is supported by primary controllers * that support the Virtualization Enhancements capability. This command is @@ -4026,131 +4451,481 @@ int nvme_dev_self_test(struct nvme_dev_self_test_args *args); * - Assigning Flexible Resources for secondary controllers * - Setting the Online and Offline state for secondary controllers * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_virtual_mgmt(struct nvme_virtual_mgmt_args *args); +static inline int nvme_virtual_mgmt(nvme_link_t l, enum nvme_virt_mgmt_act act, + enum nvme_virt_mgmt_rt rt, __u16 cntlid, + __u16 nr, __u32 *result) +{ + __u32 cdw10 = NVME_SET(act, VIRT_MGMT_CDW10_ACT) | + NVME_SET(rt, VIRT_MGMT_CDW10_RT) | + NVME_SET(cntlid, VIRT_MGMT_CDW10_CNTLID); + __u32 cdw11 = NVME_SET(nr, VIRT_MGMT_CDW11_NR); + + struct nvme_passthru_cmd cmd = { + .opcode = nvme_admin_virtual_mgmt, + .cdw10 = cdw10, + .cdw11 = cdw11, + }; + + return nvme_submit_admin_passthru(l, &cmd, result); +} /** * nvme_flush() - Send an nvme flush command - * @fd: File descriptor of nvme device + * @l: Link handle * @nsid: Namespace identifier * * The Flush command requests that the contents of volatile write cache be made * non-volatile. * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_flush(int fd, __u32 nsid) +static inline int nvme_flush(nvme_link_t l, __u32 nsid) { struct nvme_passthru_cmd cmd = {}; cmd.opcode = nvme_cmd_flush; cmd.nsid = nsid; - return nvme_submit_io_passthru(fd, &cmd, NULL); + return nvme_submit_io_passthru(l, &cmd, NULL); +} + +static inline int nvme_set_var_size_tags(__u8 pif, __u8 sts, __u64 reftag, __u64 storage_tag, + __u32 *cmd_dw2, __u32 *cmd_dw3, __u32 *cmd_dw14) +{ + __u32 cdw2 = 0, cdw3 = 0, cdw14; + + switch (pif) { + case NVME_NVM_PIF_16B_GUARD: + cdw14 = NVME_SET(reftag, NVM_CDW14_ELBTL); + cdw14 |= NVME_SET(storage_tag << (32 - sts), NVM_CDW14_ELBTL); + break; + case NVME_NVM_PIF_32B_GUARD: + cdw14 = NVME_SET(reftag, NVM_CDW14_ELBTL); + cdw3 = NVME_SET(reftag >> 32, NVM_CDW3_ELBTU); + cdw14 |= NVME_SET((storage_tag << (80 - sts)) & 0xffff0000, NVM_CDW14_ELBTL); + if (sts >= 48) + cdw3 |= NVME_SET(storage_tag >> (sts - 48), NVM_CDW3_ELBTU); + else + cdw3 |= NVME_SET(storage_tag << (48 - sts), NVM_CDW3_ELBTU); + cdw2 = NVME_SET(storage_tag >> (sts - 16), NVM_CDW2_ELBTU); + break; + case NVME_NVM_PIF_64B_GUARD: + cdw14 = NVME_SET(reftag, NVM_CDW14_ELBTL); + cdw3 = NVME_SET((reftag >> 32) & 0xffff, NVM_CDW3_ELBTU); + cdw14 |= NVME_SET(storage_tag << (48 - sts), NVM_CDW14_ELBTL); + if (sts >= 16) + cdw3 |= NVME_SET((storage_tag >> (sts - 16)) & 0xffff, NVM_CDW3_ELBTU); + else + cdw3 |= NVME_SET((storage_tag << (16 - sts)) & 0xffff, NVM_CDW3_ELBTU); + break; + default: + perror("Unsupported Protection Information Format"); + return -EINVAL; + } + + *cmd_dw2 = cdw2; + *cmd_dw3 = cdw3; + *cmd_dw14 = cdw14; + return 0; } /** * nvme_io() - Submit an nvme user I/O command - * @args: &struct nvme_io_args argument structure + * @l: Link handle * @opcode: Opcode to execute + * @nsid: Namespace ID + * @slba: Starting logical block + * @storage_tag: This filed specifies Variable Sized Expected Logical Block + * Storage Tag (ELBST) or Logical Block Storage Tag (LBST) + * @nlb: Number of logical blocks to send (0's based value) + * @control: Command control flags, see &enum nvme_io_control_flags. + * @apptag: This field specifies the Application Tag Mask expected value. + * Used only if the namespace is formatted to use end-to-end + * protection information. + * @appmask: This field specifies the Application Tag expected value. Used + * only if the namespace is formatted to use end-to-end protection + * information. + * @reftag: This field specifies the variable sized Expected Initial + * Logical Block Reference Tag (EILBRT) or Initial Logical Block + * Reference Tag (ILBRT). Used only if the namespace is formatted + * to use end-to-end protection information. + * @dspec: Directive specific value + * @dsm: Data set management attributes, see &enum nvme_io_dsm_flags + * @reftag_u64: This field specifies the variable sized Expected Initial + * Logical Block Reference Tag (EILBRT) or Initial Logical Block + * Reference Tag (ILBRT). It is the 8 byte version required for + * enhanced protection information. Used only if the namespace is + * formatted to use end-to-end protection information. + * @sts: Storage tag size in bits, set by namespace Extended LBA Format + * @pif: Protection information format, determines how variable sized + * storage_tag and reftag are put into dwords 2, 3, and 14. Set by + * namespace Extended LBA Format. + * @data: Pointer to user address of the data buffer + * @data_len: Length of user buffer, @data, in bytes + * @metadata: Pointer to user address of the metadata buffer + * @metadata_len:Length of user buffer, @metadata, in bytes + * @result: The command completion result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_io(struct nvme_io_args *args, __u8 opcode); +static inline int nvme_io(nvme_link_t l, __u8 opcode, __u32 nsid, __u64 slba, __u64 storage_tag, + __u32 reftag, __u16 nlb, __u16 control, __u16 apptag, __u16 appmask, + __u16 dspec, __u8 dsm, __u64 reftag_u64, __u8 sts, __u8 pif, void *data, + __u32 data_len, void *metadata, __u32 metadata_len, __u32 *result) +{ + __u32 cdw10 = NVME_SET(slba, NVM_CDW10_SLBAL); + __u32 cdw11 = NVME_SET(slba >> 32, NVM_CDW11_SLBAU); + __u32 cdw12 = NVME_SET(nlb, NVM_CDW12_NLB) | NVME_SET(control, NVM_CDW12_CONTROL); + __u32 cdw13 = NVME_SET(dsm, NVM_CDW13_DSM) | NVME_SET(dspec, NVM_CDW13_DSPEC); + __u32 cdw15 = NVME_SET(apptag, NVM_CDW15_ELBAT) | NVME_SET(appmask, NVM_CDW15_ELBATM); + + struct nvme_passthru_cmd cmd = { + .opcode = opcode, + .nsid = nsid, + .metadata = (__u64)(uintptr_t)metadata, + .addr = (__u64)(uintptr_t)data, + .metadata_len = metadata_len, + .data_len = data_len, + .cdw10 = cdw10, + .cdw11 = cdw11, + .cdw12 = cdw12, + .cdw13 = cdw13, + .cdw15 = cdw15, + }; + + if (nvme_set_var_size_tags(pif, sts, reftag_u64, storage_tag, &cmd.cdw2, &cmd.cdw3, + &cmd.cdw14)) + return -EINVAL; + + + return nvme_submit_io_passthru(l, &cmd, result); +} /** * nvme_read() - Submit an nvme user read command - * @args: &struct nvme_io_args argument structure + * @l: Link handle + * @nsid: Namespace ID + * @slba: Starting logical block + * @storage_tag: This filed specifies Variable Sized Expected Logical Block + * Storage Tag (ELBST) or Logical Block Storage Tag (LBST) + * @nlb: Number of logical blocks to send (0's based value) + * @control: Command control flags, see &enum nvme_io_control_flags. + * @apptag: This field specifies the Application Tag Mask expected value. + * Used only if the namespace is formatted to use end-to-end + * protection information. + * @appmask: This field specifies the Application Tag expected value. Used + * only if the namespace is formatted to use end-to-end protection + * information. + * @reftag: This field specifies the variable sized Expected Initial + * Logical Block Reference Tag (EILBRT) or Initial Logical Block + * Reference Tag (ILBRT). Used only if the namespace is formatted + * to use end-to-end protection information. + * @dspec: Directive specific value + * @dsm: Data set management attributes, see &enum nvme_io_dsm_flags + * @reftag_u64: This field specifies the variable sized Expected Initial + * Logical Block Reference Tag (EILBRT) or Initial Logical Block + * Reference Tag (ILBRT). It is the 8 byte version required for + * enhanced protection information. Used only if the namespace is + * formatted to use end-to-end protection information. + * @sts: Storage tag size in bits, set by namespace Extended LBA Format + * @pif: Protection information format, determines how variable sized + * storage_tag and reftag are put into dwords 2, 3, and 14. Set by + * namespace Extended LBA Format. + * @data: Pointer to user address of the data buffer + * @data_len: Length of user buffer, @data, in bytes + * @metadata: Pointer to user address of the metadata buffer + * @metadata_len:Length of user buffer, @metadata, in bytes + * @result: The command completion result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_read(struct nvme_io_args *args) +static inline int nvme_read(nvme_link_t l, __u32 nsid, __u64 slba, __u64 storage_tag, __u32 reftag, + __u16 nlb, __u16 control, __u16 apptag, __u16 appmask, __u16 dspec, + __u8 dsm, __u64 reftag_u64, __u8 sts, __u8 pif, void *data, + __u32 data_len, void *metadata, __u32 metadata_len, __u32 *result) { - return nvme_io(args, nvme_cmd_read); + return nvme_io(l, nvme_cmd_read, nsid, slba, storage_tag, reftag, nlb, control, apptag, + appmask, dspec, dsm, reftag_u64, sts, pif, data, data_len, metadata, + metadata_len, result); } /** * nvme_write() - Submit an nvme user write command - * @args: &struct nvme_io_args argument structure + * @l: Link handle + * @nsid: Namespace ID + * @slba: Starting logical block + * @storage_tag: This filed specifies Variable Sized Expected Logical Block + * Storage Tag (ELBST) or Logical Block Storage Tag (LBST) + * @nlb: Number of logical blocks to send (0's based value) + * @control: Command control flags, see &enum nvme_io_control_flags. + * @apptag: This field specifies the Application Tag Mask expected value. + * Used only if the namespace is formatted to use end-to-end + * protection information. + * @appmask: This field specifies the Application Tag expected value. Used + * only if the namespace is formatted to use end-to-end protection + * information. + * @reftag: This field specifies the variable sized Expected Initial + * Logical Block Reference Tag (EILBRT) or Initial Logical Block + * Reference Tag (ILBRT). Used only if the namespace is formatted + * to use end-to-end protection information. + * @dspec: Directive specific value + * @dsm: Data set management attributes, see &enum nvme_io_dsm_flags + * @reftag_u64: This field specifies the variable sized Expected Initial + * Logical Block Reference Tag (EILBRT) or Initial Logical Block + * Reference Tag (ILBRT). It is the 8 byte version required for + * enhanced protection information. Used only if the namespace is + * formatted to use end-to-end protection information. + * @sts: Storage tag size in bits, set by namespace Extended LBA Format + * @pif: Protection information format, determines how variable sized + * storage_tag and reftag are put into dwords 2, 3, and 14. Set by + * namespace Extended LBA Format. + * @data: Pointer to user address of the data buffer + * @data_len: Length of user buffer, @data, in bytes + * @metadata: Pointer to user address of the metadata buffer + * @metadata_len:Length of user buffer, @metadata, in bytes + * @result: The command completion result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_write(struct nvme_io_args *args) +static inline int nvme_write(nvme_link_t l, __u32 nsid, __u64 slba, __u64 storage_tag, __u32 reftag, + __u16 nlb, __u16 control, __u16 apptag, __u16 appmask, __u16 dspec, + __u8 dsm, __u64 reftag_u64, __u8 sts, __u8 pif, void *data, + __u32 data_len, void *metadata, __u32 metadata_len, __u32 *result) { - return nvme_io(args, nvme_cmd_write); + return nvme_io(l, nvme_cmd_write, nsid, slba, storage_tag, reftag, nlb, control, apptag, + appmask, dspec, dsm, reftag_u64, sts, pif, data, data_len, metadata, + metadata_len, result); } /** * nvme_compare() - Submit an nvme user compare command - * @args: &struct nvme_io_args argument structure + * @l: Link handle + * @nsid: Namespace ID + * @slba: Starting logical block + * @storage_tag: This filed specifies Variable Sized Expected Logical Block + * Storage Tag (ELBST) or Logical Block Storage Tag (LBST) + * @nlb: Number of logical blocks to send (0's based value) + * @control: Command control flags, see &enum nvme_io_control_flags. + * @apptag: This field specifies the Application Tag Mask expected value. + * Used only if the namespace is formatted to use end-to-end + * protection information. + * @appmask: This field specifies the Application Tag expected value. Used + * only if the namespace is formatted to use end-to-end protection + * information. + * @reftag: This field specifies the variable sized Expected Initial + * Logical Block Reference Tag (EILBRT) or Initial Logical Block + * Reference Tag (ILBRT). Used only if the namespace is formatted + * to use end-to-end protection information. + * @dspec: Directive specific value + * @dsm: Data set management attributes, see &enum nvme_io_dsm_flags + * @reftag_u64: This field specifies the variable sized Expected Initial + * Logical Block Reference Tag (EILBRT) or Initial Logical Block + * Reference Tag (ILBRT). It is the 8 byte version required for + * enhanced protection information. Used only if the namespace is + * formatted to use end-to-end protection information. + * @sts: Storage tag size in bits, set by namespace Extended LBA Format + * @pif: Protection information format, determines how variable sized + * storage_tag and reftag are put into dwords 2, 3, and 14. Set by + * namespace Extended LBA Format. + * @data: Pointer to user address of the data buffer + * @data_len: Length of user buffer, @data, in bytes + * @metadata: Pointer to user address of the metadata buffer + * @metadata_len:Length of user buffer, @metadata, in bytes + * @result: The command completion result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_compare(struct nvme_io_args *args) +static inline int nvme_compare(nvme_link_t l, __u32 nsid, __u64 slba, __u64 storage_tag, + __u32 reftag, __u16 nlb, __u16 control, __u16 apptag, __u16 appmask, + __u16 dspec, __u8 dsm, __u64 reftag_u64, __u8 sts, __u8 pif, + void *data, __u32 data_len, void *metadata, __u32 metadata_len, + __u32 *result) { - return nvme_io(args, nvme_cmd_compare); + return nvme_io(l, nvme_cmd_compare, nsid, slba, storage_tag, reftag, nlb, control, apptag, + appmask, dspec, dsm, reftag_u64, sts, pif, data, data_len, metadata, + metadata_len, result); } /** * nvme_write_zeros() - Submit an nvme write zeroes command - * @args: &struct nvme_io_args argument structure + * @l: Link handle + * @nsid: Namespace ID + * @slba: Starting logical block + * @storage_tag: This filed specifies Variable Sized Expected Logical Block + * Storage Tag (ELBST) or Logical Block Storage Tag (LBST) + * @nlb: Number of logical blocks to send (0's based value) + * @control: Command control flags, see &enum nvme_io_control_flags. + * @apptag: This field specifies the Application Tag Mask expected value. + * Used only if the namespace is formatted to use end-to-end + * protection information. + * @appmask: This field specifies the Application Tag expected value. Used + * only if the namespace is formatted to use end-to-end protection + * information. + * @reftag: This field specifies the variable sized Expected Initial + * Logical Block Reference Tag (EILBRT) or Initial Logical Block + * Reference Tag (ILBRT). Used only if the namespace is formatted + * to use end-to-end protection information. + * @dspec: Directive specific value + * @dsm: Data set management attributes, see &enum nvme_io_dsm_flags + * @reftag_u64: This field specifies the variable sized Expected Initial + * Logical Block Reference Tag (EILBRT) or Initial Logical Block + * Reference Tag (ILBRT). It is the 8 byte version required for + * enhanced protection information. Used only if the namespace is + * formatted to use end-to-end protection information. + * @sts: Storage tag size in bits, set by namespace Extended LBA Format + * @pif: Protection information format, determines how variable sized + * storage_tag and reftag are put into dwords 2, 3, and 14. Set by + * namespace Extended LBA Format. + * @data: Pointer to user address of the data buffer + * @data_len: Length of user buffer, @data, in bytes + * @metadata: Pointer to user address of the metadata buffer + * @metadata_len:Length of user buffer, @metadata, in bytes + * @result: The command completion result from CQE dword0 * * The Write Zeroes command sets a range of logical blocks to zero. After * successful completion of this command, the value returned by subsequent * reads of logical blocks in this range shall be all bytes cleared to 0h until * a write occurs to this LBA range. * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_write_zeros(struct nvme_io_args *args) +static inline int nvme_write_zeros(nvme_link_t l, __u32 nsid, __u64 slba, __u64 storage_tag, + __u32 reftag, __u16 nlb, __u16 control, __u16 apptag, + __u16 appmask, __u16 dspec, __u8 dsm, __u64 reftag_u64, __u8 sts, + __u8 pif, void *data, __u32 data_len, void *metadata, + __u32 metadata_len, __u32 *result) { - return nvme_io(args, nvme_cmd_write_zeroes); + return nvme_io(l, nvme_cmd_write_zeroes, nsid, slba, storage_tag, reftag, nlb, control, + apptag, appmask, dspec, dsm, reftag_u64, sts, pif, data, data_len, metadata, + metadata_len, result); } /** * nvme_write_uncorrectable() - Submit an nvme write uncorrectable command - * @args: &struct nvme_io_args argument structure + * @l: Link handle + * @nsid: Namespace ID + * @slba: Starting logical block + * @storage_tag: This filed specifies Variable Sized Expected Logical Block + * Storage Tag (ELBST) or Logical Block Storage Tag (LBST) + * @nlb: Number of logical blocks to send (0's based value) + * @control: Command control flags, see &enum nvme_io_control_flags. + * @apptag: This field specifies the Application Tag Mask expected value. + * Used only if the namespace is formatted to use end-to-end + * protection information. + * @appmask: This field specifies the Application Tag expected value. Used + * only if the namespace is formatted to use end-to-end protection + * information. + * @reftag: This field specifies the variable sized Expected Initial + * Logical Block Reference Tag (EILBRT) or Initial Logical Block + * Reference Tag (ILBRT). Used only if the namespace is formatted + * to use end-to-end protection information. + * @dspec: Directive specific value + * @dsm: Data set management attributes, see &enum nvme_io_dsm_flags + * @reftag_u64: This field specifies the variable sized Expected Initial + * Logical Block Reference Tag (EILBRT) or Initial Logical Block + * Reference Tag (ILBRT). It is the 8 byte version required for + * enhanced protection information. Used only if the namespace is + * formatted to use end-to-end protection information. + * @sts: Storage tag size in bits, set by namespace Extended LBA Format + * @pif: Protection information format, determines how variable sized + * storage_tag and reftag are put into dwords 2, 3, and 14. Set by + * namespace Extended LBA Format. + * @data: Pointer to user address of the data buffer + * @data_len: Length of user buffer, @data, in bytes + * @metadata: Pointer to user address of the metadata buffer + * @metadata_len:Length of user buffer, @metadata, in bytes + * @result: The command completion result from CQE dword0 * * The Write Uncorrectable command marks a range of logical blocks as invalid. * When the specified logical block(s) are read after this operation, a failure * is returned with Unrecovered Read Error status. To clear the invalid logical * block status, a write operation on those logical blocks is required. * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_write_uncorrectable(struct nvme_io_args *args) +static inline int nvme_write_uncorrectable(nvme_link_t l, __u32 nsid, __u64 slba, __u64 storage_tag, + __u32 reftag, __u16 nlb, __u16 control, __u16 apptag, + __u16 appmask, __u16 dspec, __u8 dsm, __u64 reftag_u64, + __u8 sts, __u8 pif, void *data, __u32 data_len, + void *metadata, __u32 metadata_len, __u32 *result) { - return nvme_io(args, nvme_cmd_write_uncor); + return nvme_io(l, nvme_cmd_write_uncor, nsid, slba, storage_tag, reftag, nlb, control, + apptag, appmask, dspec, dsm, reftag_u64, sts, pif, data, data_len, metadata, + metadata_len, result); } /** * nvme_verify() - Send an nvme verify command - * @args: &struct nvme_io_args argument structure + * @l: Link handle + * @nsid: Namespace ID + * @slba: Starting logical block + * @storage_tag: This filed specifies Variable Sized Expected Logical Block + * Storage Tag (ELBST) or Logical Block Storage Tag (LBST) + * @nlb: Number of logical blocks to send (0's based value) + * @control: Command control flags, see &enum nvme_io_control_flags. + * @apptag: This field specifies the Application Tag Mask expected value. + * Used only if the namespace is formatted to use end-to-end + * protection information. + * @appmask: This field specifies the Application Tag expected value. Used + * only if the namespace is formatted to use end-to-end protection + * information. + * @reftag: This field specifies the variable sized Expected Initial + * Logical Block Reference Tag (EILBRT) or Initial Logical Block + * Reference Tag (ILBRT). Used only if the namespace is formatted + * to use end-to-end protection information. + * @dspec: Directive specific value + * @dsm: Data set management attributes, see &enum nvme_io_dsm_flags + * @reftag_u64: This field specifies the variable sized Expected Initial + * Logical Block Reference Tag (EILBRT) or Initial Logical Block + * Reference Tag (ILBRT). It is the 8 byte version required for + * enhanced protection information. Used only if the namespace is + * formatted to use end-to-end protection information. + * @sts: Storage tag size in bits, set by namespace Extended LBA Format + * @pif: Protection information format, determines how variable sized + * storage_tag and reftag are put into dwords 2, 3, and 14. Set by + * namespace Extended LBA Format. + * @data: Pointer to user address of the data buffer + * @data_len: Length of user buffer, @data, in bytes + * @metadata: Pointer to user address of the metadata buffer + * @metadata_len:Length of user buffer, @metadata, in bytes + * @result: The command completion result from CQE dword0 * * The Verify command verifies integrity of stored information by reading data * and metadata, if applicable, for the LBAs indicated without transferring any * data or metadata to the host. * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_verify(struct nvme_io_args *args) +static inline int nvme_verify(nvme_link_t l, __u32 nsid, __u64 slba, __u64 storage_tag, + __u32 reftag, __u16 nlb, __u16 control, __u16 apptag, __u16 appmask, + __u16 dspec, __u8 dsm, __u64 reftag_u64, __u8 sts, __u8 pif, + void *data, __u32 data_len, void *metadata, __u32 metadata_len, + __u32 *result) { - return nvme_io(args, nvme_cmd_verify); + return nvme_io(l, nvme_cmd_verify, nsid, slba, storage_tag, reftag, nlb, control, apptag, + appmask, dspec, dsm, reftag_u64, sts, pif, data, data_len, metadata, + metadata_len, result); } /** * nvme_dsm() - Send an nvme data set management command - * @args: &struct nvme_dsm_args argument structure + * @l: Link handle + * @nsid: Namespace identifier + * @nr_ranges: Number of block ranges in the data set management attributes + * @attrs: DSM attributes, see &enum nvme_dsm_attributes + * @dsm: The data set management attributes + * @result: The command completion result from CQE dword0 * * The Dataset Management command is used by the host to indicate attributes * for ranges of logical blocks. This includes attributes like frequency that @@ -4158,162 +4933,446 @@ static inline int nvme_verify(struct nvme_io_args *args) * to optimize performance and reliability, and may be used to * deallocate/unmap/trim those logical blocks. * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_dsm(struct nvme_dsm_args *args); +static inline int nvme_dsm(nvme_link_t l, __u32 nsid, __u16 nr_ranges, + __u32 attrs, struct nvme_dsm_range *dsm, + __u32 *result) +{ + __u32 cdw10 = NVME_SET(nr_ranges - 1, DSM_CDW10_NR); + __u32 cdw11 = NVME_SET(attrs, DSM_CDW11_ATTRS); + + struct nvme_passthru_cmd cmd = { + .opcode = nvme_cmd_dsm, + .nsid = nsid, + .addr = (__u64)(uintptr_t)dsm, + .data_len = (__u32)(nr_ranges * sizeof(*dsm)), + .cdw10 = cdw10, + .cdw11 = cdw11, + }; + + return nvme_submit_io_passthru(l, &cmd, result); +} /** * nvme_copy() - Copy command + * @l: Link handle + * @nsid: Namespace identifier + * @sdlba: Start destination LBA + * @nr: Number of ranges + * @desfmt: Descriptor format + * @prinfor: Protection information field for read + * @prinfow: Protection information field for write + * @cetype: Command Extension Type + * @dtype: Directive Type + * @stcw: Storage Tag Check Write + * @stcr: Storage Tag Check Read + * @fua: Force unit access + * @lr: Limited retry + * @cev: Command Extension Value + * @dspec: Directive specific value + * @sts: Storage tag size in bits, set by namespace Extended LBA Format + * @pif: Protection information format, determines how variable sized + * storage_tag and reftag are put into dwords 2, 3, and 14. Set by + * namespace Extended LBA Format. + * @storage_tag: This filed specifies Variable Sized Expected Logical Block + * Storage Tag (ELBST) or Logical Block Storage Tag (LBST) + * @reftag: This field specifies the variable sized Expected Initial + * Logical Block Reference Tag (EILBRT) or Initial Logical Block + * Reference Tag (ILBRT). Used only if the namespace is formatted + * to use end-to-end protection information. + * @lbat: Logical block application tag + * @lbatm: Logical block application tag mask + * @cpydsc: Range description + * @result: The command completion result from CQE dword0 * - * @args: &struct nvme_copy_args argument structure - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_copy(struct nvme_copy_args *args); +static inline int nvme_copy(nvme_link_t l, __u32 nsid, __u64 sdlba, __u16 nr, __u8 desfmt, + __u8 prinfor, __u8 prinfow, __u8 cetype, __u8 dtype, bool stcw, + bool stcr, bool fua, bool lr, __u16 cev, __u16 dspec, + __u8 sts, __u8 pif, __u64 storage_tag, __u32 reftag, + __u16 lbat, __u16 lbatm, void *cpydsc, __u32 *result) +{ + __u32 cdw10 = NVME_SET(sdlba, COPY_CDW10_SDLBAL); + __u32 cdw11 = NVME_SET(sdlba >> 32, COPY_CDW11_SDLBAU); + __u32 cdw12 = NVME_SET(nr - 1, COPY_CDW12_NR) | + NVME_SET(desfmt, COPY_CDW12_DESFMT) | + NVME_SET(prinfor, COPY_CDW12_PRINFOR) | + NVME_SET(cetype, COPY_CDW12_CETYPE) | + NVME_SET(dtype, COPY_CDW12_DTYPE) | + NVME_SET(stcw, COPY_CDW12_STCW) | + NVME_SET(stcr, COPY_CDW12_STCR) | + NVME_SET(prinfow, COPY_CDW12_PRINFOW) | + NVME_SET(fua, COPY_CDW12_FUA) | + NVME_SET(lr, COPY_CDW12_LR); + __u32 cdw13 = NVME_SET(cev, NVM_CDW13_CEV) | + NVME_SET(dspec, NVM_CDW13_DSPEC); + __u32 cdw15 = NVME_SET(lbat, COPY_CDW15_LBAT) | + NVME_SET(lbatm, COPY_CDW15_LBATM); + __u32 data_len; + + switch (desfmt) { + case 1: + data_len = nr * sizeof(struct nvme_copy_range_f1); + break; + case 2: + data_len = nr * sizeof(struct nvme_copy_range_f2); + break; + case 3: + data_len = nr * sizeof(struct nvme_copy_range_f3); + break; + default: + data_len = nr * sizeof(struct nvme_copy_range); + } + + struct nvme_passthru_cmd cmd = { + .opcode = nvme_cmd_copy, + .nsid = nsid, + .addr = (__u64)(uintptr_t)cpydsc, + .data_len = data_len, + .cdw10 = cdw10, + .cdw11 = cdw11, + .cdw12 = cdw12, + .cdw13 = cdw13, + .cdw15 = cdw15, + }; + + if (nvme_set_var_size_tags(pif, sts, reftag, storage_tag, &cmd.cdw2, &cmd.cdw3, + &cmd.cdw14)) + return -EINVAL; + + return nvme_submit_io_passthru(l, &cmd, result); +} /** * nvme_resv_acquire() - Send an nvme reservation acquire - * @args: &struct nvme_resv_acquire argument structure + * @l: Link handle + * @nsid: Namespace identifier + * @racqa: The action that is performed by the command, see &enum nvme_resv_racqa + * @iekey: Set to ignore the existing key + * @disnsrs: Disperse Namespace Reservation Support + * @rtype: The type of reservation to be create, see &enum nvme_resv_rtype + * @crkey: The current reservation key associated with the host + * @prkey: Preempt Reserveration Key + * @nrkey: The reservation key to be unregistered from the namespace if + * the action is preempt + * @result: The command completion result from CQE dword0 * * The Reservation Acquire command acquires a reservation on a namespace, * preempt a reservation held on a namespace, and abort a reservation held on a * namespace. * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_resv_acquire(struct nvme_resv_acquire_args *args); +static inline int nvme_resv_acquire(nvme_link_t l, __u32 nsid, enum nvme_resv_racqa racqa, + bool iekey, bool disnsrs, enum nvme_resv_rtype rtype, + __u16 prkey, __u64 crkey, __u64 nrkey, + __u32 *result) + +{ + __le64 payload[2] = { + htole64(crkey), + htole64(nrkey) + }; + __u32 cdw10 = (racqa & 0x7) | (iekey ? 1 << 3 : 0) | (rtype << 8); + + struct nvme_passthru_cmd cmd = { + .opcode = nvme_cmd_resv_acquire, + .nsid = nsid, + .addr = (__u64)(uintptr_t)(payload), + .data_len = sizeof(payload), + .cdw10 = cdw10, + }; + + return nvme_submit_io_passthru(l, &cmd, result); +} /** * nvme_resv_register() - Send an nvme reservation register - * @args: &struct nvme_resv_register_args argument structure + * @l: Link handle + * @nsid: Namespace identifier + * @rrega: The registration action, see &enum nvme_resv_rrega + * @iekey: Set to ignore the existing key + * @disnsrs: Disperse Namespace Reservation Support + * @cptpl: Change persist through power loss, see &enum nvme_resv_cptpl + * @crkey: The current reservation key associated with the host + * @nrkey: The new reservation key to be register if action is register or + * replace + * @result: The command completion result from CQE dword0 * * The Reservation Register command registers, unregisters, or replaces a * reservation key. * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_resv_register(struct nvme_resv_register_args *args); +static inline int nvme_resv_register(nvme_link_t l, __u32 nsid, enum nvme_resv_rrega rrega, + bool iekey, bool disnsrs, enum nvme_resv_cptpl cptpl, + __u64 crkey, __u64 nrkey, __u32 *result) +{ + __le64 payload[2] = { + htole64(crkey), + htole64(nrkey) + }; + __u32 cdw10 = (rrega & 0x7) | (iekey ? 1 << 3 : 0) | (cptpl << 30); + + struct nvme_passthru_cmd cmd = { + .opcode = nvme_cmd_resv_register, + .nsid = nsid, + .addr = (__u64)(uintptr_t)(payload), + .data_len = sizeof(payload), + .cdw10 = cdw10, + }; + + return nvme_submit_io_passthru(l, &cmd, result); +} /** * nvme_resv_release() - Send an nvme reservation release - * @args: &struct nvme_resv_release_args argument structure + * @l: Link handle + * @nsid: Namespace identifier + * @rrela: Reservation release action, see &enum nvme_resv_rrela + * @crkey: The current reservation key to release + * @iekey: Set to ignore the existing key + * @disnsrs: Disperse Namespace Reservation Support + * @rtype: The type of reservation to be create, see &enum nvme_resv_rtype + * @result: The command completion result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_resv_release(struct nvme_resv_release_args *args); +static inline int nvme_resv_release(nvme_link_t l, __u32 nsid, enum nvme_resv_rrela rrela, + __u64 crkey, bool iekey, bool disnsrs, + enum nvme_resv_rtype rtype, __u32 *result) +{ + __le64 payload[1] = { htole64(crkey) }; + __u32 cdw10 = (rrela & 0x7) | (iekey ? 1 << 3 : 0) | (rtype << 8); + + struct nvme_passthru_cmd cmd = { + .opcode = nvme_cmd_resv_release, + .nsid = nsid, + .addr = (__u64)(uintptr_t)(payload), + .data_len = sizeof(payload), + .cdw10 = cdw10, + }; + + return nvme_submit_io_passthru(l, &cmd, result); +} /** * nvme_resv_report() - Send an nvme reservation report - * @args: struct nvme_resv_report_args argument structure + * @l: Link handle + * @nsid: Namespace identifier + * @eds: Request extended Data Structure + * @report: The user space destination address to store the reservation + * report + * @len: Number of bytes to request transferred with this command + * @result: The command completion result from CQE dword0 * * Returns a Reservation Status data structure to memory that describes the * registration and reservation status of a namespace. See the definition for * the returned structure, &struct nvme_reservation_status, for more details. * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_resv_report(struct nvme_resv_report_args *args); +static inline int nvme_resv_report(nvme_link_t l, __u32 nsid, bool eds, + struct nvme_resv_status *report, __u32 len, __u32 *result) +{ + struct nvme_passthru_cmd cmd = { + .opcode = nvme_cmd_resv_report, + .nsid = nsid, + .addr = (__u64)(uintptr_t)report, + .data_len = len, + .cdw10 = (len >> 2) - 1, + .cdw11 = (__u32)(eds ? 1 : 0), + }; + + return nvme_submit_io_passthru(l, &cmd, result); +} /** * nvme_io_mgmt_recv() - I/O Management Receive command - * @args: &struct nvme_io_mgmt_recv_args argument structure + * @l: Link handle + * @nsid: Namespace identifier + * @mo: Management Operation + * @mos: Management Operation Specific + * @data: Userspace address of the data + * @data_len: Length of @data * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_io_mgmt_recv(struct nvme_io_mgmt_recv_args *args); +static inline int nvme_io_mgmt_recv(nvme_link_t l, __u32 nsid, __u8 mo, + __u16 mos, void *data, __u32 data_len) +{ + __u32 cdw10 = mo | (mos << 16); + __u32 cdw11 = (data_len >> 2) - 1; + + struct nvme_passthru_cmd cmd = { + .opcode = nvme_cmd_io_mgmt_recv, + .nsid = nsid, + .addr = (__u64)(uintptr_t)data, + .data_len = data_len, + .cdw10 = cdw10, + .cdw11 = cdw11, + }; + + return nvme_submit_io_passthru(l, &cmd, NULL); +} /** * nvme_fdp_reclaim_unit_handle_status() - Get reclaim unit handle status - * @fd: File descriptor of nvme device + * @l: Link handle * @nsid: Namespace identifier * @data_len: Length of response buffer * @data: Response buffer * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_fdp_reclaim_unit_handle_status(int fd, __u32 nsid, +static inline int nvme_fdp_reclaim_unit_handle_status(nvme_link_t l, __u32 nsid, __u32 data_len, void *data) { - struct nvme_io_mgmt_recv_args args = { - .data = data, - .args_size = sizeof(args), - .fd = fd, - .nsid = nsid, - .data_len = data_len, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .mos = 0, - .mo = NVME_IO_MGMT_RECV_RUH_STATUS, - }; - - return nvme_io_mgmt_recv(&args); + return nvme_io_mgmt_recv(l, nsid, NVME_IO_MGMT_RECV_RUH_STATUS, 0, + data, data_len); } /** * nvme_io_mgmt_send() - I/O Management Send command - * @args: &struct nvme_io_mgmt_send_args argument structure + * @l: Link handle + * @nsid: Namespace identifier + * @mo: Management Operation + * @mos: Management Operation Specific + * @data: Userspace address of the data + * @data_len: Length of @data * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_io_mgmt_send(struct nvme_io_mgmt_send_args *args); +static inline int nvme_io_mgmt_send(nvme_link_t l, __u32 nsid, __u8 mo, __u16 mos, + void *data, __u32 data_len) +{ + __u32 cdw10 = mo | (mos << 16); + + struct nvme_passthru_cmd cmd = { + .opcode = nvme_cmd_io_mgmt_send, + .nsid = nsid, + .addr = (__u64)(uintptr_t)data, + .data_len = data_len, + .cdw10 = cdw10, + }; + + return nvme_submit_io_passthru(l, &cmd, NULL); +} /** * nvme_fdp_reclaim_unit_handle_update() - Update a list of reclaim unit handles - * @fd: File descriptor of nvme device + * @l: Link handle * @nsid: Namespace identifier * @npids: Number of placement identifiers * @pids: List of placement identifiers * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_fdp_reclaim_unit_handle_update(int fd, __u32 nsid, +static inline int nvme_fdp_reclaim_unit_handle_update(nvme_link_t l, __u32 nsid, unsigned int npids, __u16 *pids) { - struct nvme_io_mgmt_send_args args = { - .data = (void *)pids, - .args_size = sizeof(args), - .fd = fd, - .nsid = nsid, - .data_len = (__u32)(npids * sizeof(__u16)), - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .mos = (__u16)(npids - 1), - .mo = NVME_IO_MGMT_SEND_RUH_UPDATE, - }; - - return nvme_io_mgmt_send(&args); + return nvme_io_mgmt_send(l, nsid, NVME_IO_MGMT_SEND_RUH_UPDATE, + (__u16)(npids - 1), + (void *)pids, + (__u32)(npids * sizeof(__u16))); } /** * nvme_zns_mgmt_send() - ZNS management send command - * @args: &struct nvme_zns_mgmt_send_args argument structure + * @l: Link handle + * @nsid: Namespace ID + * @slba: Starting logical block address + * @zsa: Zone send action + * @selall: Select all flag + * @zsaso: Zone Send Action Specific Option + * @zm: Zone Management + * @data: Userspace address of the data + * @data_len: Length of @data + * @result: The command completion result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_zns_mgmt_send(struct nvme_zns_mgmt_send_args *args); +static inline int nvme_zns_mgmt_send(nvme_link_t l, __u32 nsid, __u64 slba, + enum nvme_zns_send_action zsa, bool selall, + __u8 zsaso, __u8 zm, void *data, __u32 data_len, + __u32 *result) +{ + __u32 cdw10 = slba & 0xffffffff; + __u32 cdw11 = slba >> 32; + __u32 cdw13 = NVME_SET(zsa, ZNS_MGMT_SEND_ZSA) | + NVME_SET(selall, ZNS_MGMT_SEND_SEL) | + NVME_SET(zsaso, ZNS_MGMT_SEND_ZSASO); + + struct nvme_passthru_cmd cmd = { + .opcode = nvme_zns_cmd_mgmt_send, + .nsid = nsid, + .addr = (__u64)(uintptr_t)data, + .data_len = data_len, + .cdw10 = cdw10, + .cdw11 = cdw11, + .cdw13 = cdw13, + }; + return nvme_submit_io_passthru(l, &cmd, result); +} /** * nvme_zns_mgmt_recv() - ZNS management receive command - * @args: &struct nvme_zns_mgmt_recv_args argument structure + * @l: Link handle + * @nsid: Namespace ID + * @slba: Starting logical block address + * @zra: zone receive action + * @zras: Zone receive action specific field + * @zraspf: Zone receive action specific features + * @data: Userspace address of the data + * @data_len: Length of @data + * @result: The command completion result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_zns_mgmt_recv(struct nvme_zns_mgmt_recv_args *args); +static inline int nvme_zns_mgmt_recv(nvme_link_t l, __u32 nsid, __u64 slba, + enum nvme_zns_recv_action zra, __u16 zras, + bool zraspf, void *data, __u32 data_len, + __u32 *result) +{ + __u32 cdw10 = slba & 0xffffffff; + __u32 cdw11 = slba >> 32; + __u32 cdw12 = (data_len >> 2) - 1; + __u32 cdw13 = NVME_SET(zra, ZNS_MGMT_RECV_ZRA) | + NVME_SET(zras, ZNS_MGMT_RECV_ZRAS) | + NVME_SET(zraspf, ZNS_MGMT_RECV_ZRASPF); + + struct nvme_passthru_cmd cmd = { + .opcode = nvme_zns_cmd_mgmt_recv, + .nsid = nsid, + .addr = (__u64)(uintptr_t)data, + .data_len = data_len, + .cdw10 = cdw10, + .cdw11 = cdw11, + .cdw12 = cdw12, + .cdw13 = cdw13, + }; + + return nvme_submit_io_passthru(l, &cmd, result); +} /** * nvme_zns_report_zones() - Return the list of zones - * @fd: File descriptor of nvme device + * @l: Link handle * @nsid: Namespace ID * @slba: Starting LBA * @opts: Reporting options @@ -4321,116 +5380,347 @@ int nvme_zns_mgmt_recv(struct nvme_zns_mgmt_recv_args *args); * @partial: Partial report requested * @data_len: Length of the data buffer * @data: Userspace address of the report zones data - * @timeout: timeout in ms * @result: The command completion result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -static inline int nvme_zns_report_zones(int fd, __u32 nsid, __u64 slba, - enum nvme_zns_report_options opts, - bool extended, bool partial, - __u32 data_len, void *data, - __u32 timeout, __u32 *result) -{ - struct nvme_zns_mgmt_recv_args args = { - .slba = slba, - .result = result, - .data = data, - .args_size = sizeof(args), - .fd = fd, - .timeout = timeout, - .nsid = nsid, - .zra = extended ? NVME_ZNS_ZRA_EXTENDED_REPORT_ZONES : - NVME_ZNS_ZRA_REPORT_ZONES, - .data_len = data_len, - .zrasf = (__u16)opts, - .zras_feat = partial, - }; - - return nvme_zns_mgmt_recv(&args); +static inline int nvme_zns_report_zones(nvme_link_t l, __u32 nsid, __u64 slba, + enum nvme_zns_report_options opts, bool extended, + bool partial, __u32 data_len, void *data, __u32 *result) +{ + return nvme_zns_mgmt_recv(l, nsid, slba, extended ? NVME_ZNS_ZRA_EXTENDED_REPORT_ZONES : + NVME_ZNS_ZRA_REPORT_ZONES, (__u16)opts, partial, data, data_len, + result); } /** * nvme_zns_append() - Append data to a zone - * @args: &struct nvme_zns_append_args argument structure + * @l: Link handle + * @nsid: Namespace ID + * @zslba: Zone start logical block address + * @nlb: Number of logical blocks + * @control: Upper 16 bits of cdw12 + * @cev: Command Extension Value + * @dspec: Directive Specific + * @lbatm: Logical block application tag mask + * @lbat: Logical block application tag + * @ilbrt_u64: Initial logical block reference tag - 8 byte + * version required for enhanced protection info + * @metadata: Userspace address of the metadata + * @metadata_len: Length of @metadata + * @data: Userspace address of the data + * @data_len: Length of @data + * @result: The command completion result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_zns_append(struct nvme_zns_append_args *args); +static inline int nvme_zns_append(nvme_link_t l, __u32 nsid, __u64 zslba, __u16 nlb, + __u16 control, __u16 cev, __u16 dspec, + __u16 lbat, __u16 lbatm, __u64 ilbrt_u64, + void *metadata, __u32 metadata_len, + void *data, __u32 data_len, __u64 *result) +{ + __u32 cdw3 = (ilbrt_u64 >> 32) & 0xffffffff; + __u32 cdw10 = zslba & 0xffffffff; + __u32 cdw11 = zslba >> 32; + __u32 cdw12 = nlb | (control << 16); + __u32 cdw14 = ilbrt_u64 & 0xffffffff; + __u32 cdw15 = lbat | (lbatm << 16); + + struct nvme_passthru_cmd64 cmd = { + .opcode = nvme_zns_cmd_append, + .nsid = nsid, + .cdw3 = cdw3, + .metadata = (__u64)(uintptr_t)metadata, + .addr = (__u64)(uintptr_t)data, + .metadata_len = metadata_len, + .data_len = data_len, + .cdw10 = cdw10, + .cdw11 = cdw11, + .cdw12 = cdw12, + .cdw14 = cdw14, + .cdw15 = cdw15, + }; + + return nvme_submit_io_passthru64(l, &cmd, result); +} /** * nvme_dim_send - Send a Discovery Information Management (DIM) command - * @args: &struct nvme_dim_args argument structure + * @l: Link handle + * @tas: Task field of the Command Dword 10 (cdw10) + * @data: Pointer to the DIM data + * @data_len: Length of @data + * @result: Set on completion to the command's CQE DWORD 0 controller response. * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_dim_send(struct nvme_dim_args *args); +static inline int nvme_dim_send(nvme_link_t l, __u8 tas, void *data, + __u32 data_len, __u32 *result) +{ + __u32 cdw10 = NVME_SET(tas, DIM_TAS); + + struct nvme_passthru_cmd cmd = { + .opcode = nvme_admin_discovery_info_mgmt, + .addr = (__u64)(uintptr_t)data, + .data_len = data_len, + .cdw10 = cdw10, + }; + + return nvme_submit_admin_passthru(l, &cmd, result); +} /** * nvme_lm_cdq() - Controller Data Queue - Controller Data Queue command - * @args: &struct nvme_lm_cdq_args argument structure + * @l: Link handle + * @sel: Select (SEL): This field specifies the type of management operation to perform. + * @mos: Management Operation Specific (MOS): This field is specific to the SEL type + * @cntlid: Controller ID: For Create CDQ, specifies the target migratable controller + * @sz: For Create CDQ, specifies the size of CDQ, in dwords - 4 byte + * @data: Pointer to data + * @cdqid: Controller Data Queue ID (CDQID): For Create CDQ, this field is the CDQID created + * by the controller if no error is present. For Delete CDQ, this field is the CDQID + * to delete. + * @result: Set on completion to the command's CQE DWORD 0 controller response * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise.) */ -int nvme_lm_cdq(struct nvme_lm_cdq_args *args); +static inline int nvme_lm_cdq(nvme_link_t l, __u8 sel, __u16 mos, __u16 cntlid, + __u32 sz, void *data, __u16 *cdqid, __u32 *result) +{ + __u32 cdw10 = NVME_SET(sel, LM_CDQ_SEL) | + NVME_SET(mos, LM_CDQ_MOS); + __u32 cdw11 = 0, data_len = 0; + int err; + + if (sel == NVME_LM_SEL_CREATE_CDQ) { + cdw11 = NVME_SET(NVME_SET(cntlid, LM_CREATE_CDQ_CNTLID), LM_CQS) | + NVME_LM_CREATE_CDQ_PC; + data_len = sz << 2; + } else if (sel == NVME_LM_SEL_DELETE_CDQ) { + cdw11 = NVME_SET(*cdqid, LM_DELETE_CDQ_CDQID); + } + + struct nvme_passthru_cmd cmd = { + .opcode = nvme_admin_ctrl_data_queue, + .addr = (__u64)(uintptr_t)data, + .data_len = data_len, + .cdw10 = cdw10, + .cdw11 = cdw11, + .cdw12 = sz, + }; + + err = nvme_submit_admin_passthru(l, &cmd, result); + + if (!err) + *cdqid = NVME_GET(cmd.result, LM_CREATE_CDQ_CDQID); + + return err; +} /** * nvme_lm_track_send() - Track Send command - * @args: &struct nvme_lm_track_send_args argument structure + * @l: Link handle + * @sel: Select (SEL): This field specifies the type of + * management operation to perform + * @mos: Management Operation Specific (MOS): This field + * is specific to the SEL type + * @cdqid: Controller Data Queue ID (CDQID) + * @result: Set on completion to the command's CQE DWORD 0 + * controller response * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_lm_track_send(struct nvme_lm_track_send_args *args); +static inline int nvme_lm_track_send(nvme_link_t l, __u8 sel, __u16 mos, + __u16 cdqid, __u32 *result) + +{ + __u32 cdw10 = NVME_SET(sel, LM_TRACK_SEND_SEL) | + NVME_SET(mos, LM_TRACK_SEND_MOS); + + struct nvme_passthru_cmd cmd = { + .opcode = nvme_admin_track_send, + .cdw10 = cdw10, + .cdw11 = cdqid, + }; + + return nvme_submit_admin_passthru(l, &cmd, result); +} /** * nvme_lm_migration_send() - Migration Send command - * @args: &struct nvme_lm_migration_send_args argument structure + * @l: Link handle + * @sel: Select (SEL): This field specifies the type of management + * operation to perform. + * @mos: Management Operation Specific (MOS): This field is specific + * to the SEL type + * @cntlid: Controller ID: This field specifies the identifier of the + * controller to which the operation is performed. + * @stype: Suspend Type (STYPE): This field specifies the type of suspend. + * @dudmq: Delete User Data Migration Queue (DUDMQ): If set, the migration + * queue is deleted is deleted as part of the Suspend operation. + * If cleared, it is retained. + * @csvi: Controller State Version Index (CSVI): A non-zero value in this + * field specifies the index to a specific entry in the NVMe + * Controller State Version list of the Supported Controller State + * Formats data structure. + * @csuuidi: Controller State UUID Index (CSUUIDI): A non-zero value in this + * field specifies the index to a specific entry in the + * Vendor Specific Controller State UUID Supported. + * list of the Supported Controller State Formats data structure. + * @cso: Offset: This field specifies the offset, in bytes, within + * the data available to be returned and specifies the starting + * point for that data for what is actually returned to the host. + * @uidx: UUID Index (UIDX): If this field is set to a non-zero value, + * then the value of this field is the index of a UUID in the + * UUID List (refer to Figure 320) that is used by the command. + * @data: Pointer to data + * @data_len: Length of @data + * @result: Set on completion to the command's CQE DWORD 0 controller response * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_lm_migration_send(struct nvme_lm_migration_send_args *args); +static inline int nvme_lm_migration_send(nvme_link_t l, __u16 sel, __u16 mos, + __u16 cntlid, __u8 stype, bool dudmq, + __u8 csvi, __u16 csuuidi, __u64 cso, + __u8 uidx, void *data, __u32 data_len, + __u32 *result) +{ + __u32 cdw10 = NVME_SET(sel, LM_MIGRATION_SEND_SEL) | + NVME_SET(mos, LM_MIGRATION_SEND_MOS); + __u32 cdw11 = 0; + __u32 cdw14 = NVME_SET(uidx, LM_MIGRATION_SEND_UIDX); + + if (sel == NVME_LM_SEL_SUSPEND) { + cdw11 = NVME_SET(stype, LM_STYPE) | + NVME_SET(cntlid, LM_SUSPEND_CNTLID); + if (dudmq) + cdw11 |= NVME_LM_DUDMQ; + } else if (sel == NVME_LM_SEL_RESUME) { + cdw11 = NVME_SET(cntlid, LM_RESUME_CNTLID); + } else if (sel == NVME_LM_SEL_SET_CONTROLLER_STATE) { + cdw11 = NVME_SET(csuuidi, LM_SET_CONTROLLER_STATE_CSUUIDI) | + NVME_SET(csvi, LM_SET_CONTROLLER_STATE_CSVI) | + NVME_SET(cntlid, LM_SET_CONTROLLER_STATE_CNTLID); + } + + struct nvme_passthru_cmd cmd = { + .opcode = nvme_admin_migration_send, + .addr = (__u64)(uintptr_t)data, + .data_len = data_len, + .cdw10 = cdw10, + .cdw11 = cdw11, + .cdw12 = (__u32)cso, + .cdw13 = (__u32)(cso >> 32), + .cdw14 = cdw14, + .cdw15 = (__u32)(data_len / sizeof(__u32)), + }; + + return nvme_submit_admin_passthru(l, &cmd, result); +} /** * nvme_lm_migration_recv - Migration Receive command - * @args: &struct nvme_lm_migration_rev_args argument structure + * @l: Link handle + * @offset: Offset: This field specifies the offset, in bytes, within the data available to be + * returned and specifies the starting point for that data for what is actually + * returned to the host. + * @mos: Management Operation Specific (MOS): This field is specific to the SEL type + * @cntlid: Controller ID: This field specifies the identifier of the controller to which the + * operation is performed. + * @csuuidi: Controller State UUID Index (CSUUIDI): A non-zero value in this field specifies the + * index to a specific entry in the Vendor Specific Controller State UUID Supported. + * list of the Supported Controller State Formats data structure. + * @sel: Select (SEL): This field specifies the type of management operation to perform + * @uidx: UUID Index (UIDX): If this field is set to a non-zero value, then the value of this + * field is the index of a UUID in the UUID List (refer to Figure 320) that is used by + * the command. + * @csuidxp: Controller State UUID Index Parameter (CSUIDXP): This field is vendor specific. + * @data: Pointer to data + * @len: Length of @data + * @result: Set on completion to the command's CQE DWORD 0 controller response * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_lm_migration_recv(struct nvme_lm_migration_recv_args *args); +static inline int nvme_lm_migration_recv(nvme_link_t l, __u64 offset, __u16 mos, __u16 cntlid, + __u16 csuuidi, __u8 sel, __u8 uidx, __u8 csuidxp, + void *data, __u32 len, __u32 *result) +{ + __u32 cdw10 = NVME_SET(sel, LM_MIGRATION_RECV_SEL) | NVME_SET(mos, LM_MIGRATION_RECV_MOS); + __u32 cdw11 = 0, data_len = 0; + + if (sel == NVME_LM_SEL_GET_CONTROLLER_STATE) { + cdw11 = NVME_SET(csuidxp, LM_GET_CONTROLLER_STATE_CSUIDXP) | + NVME_SET(csuuidi, LM_GET_CONTROLLER_STATE_CSUUIDI) | + NVME_SET(cntlid, LM_GET_CONTROLLER_STATE_CNTLID); + data_len = len; + } + + struct nvme_passthru_cmd cmd = { + .opcode = nvme_admin_migration_receive, + .addr = (__u64)(uintptr_t)data, + .data_len = data_len, + .cdw10 = cdw10, + .cdw11 = cdw11, + .cdw12 = (__u32)offset, + .cdw13 = (__u32)(offset >> 32), + .cdw14 = NVME_SET(uidx, LM_MIGRATION_RECV_UIDX), + .cdw15 = len ? (__u32)((len - 1) / sizeof(__u32)) : 0, /* 0's based */ + }; + + return nvme_submit_admin_passthru(l, &cmd, result); +} /** * nvme_lm_set_features_ctrl_data_queue - Set Controller Datea Queue feature - * @fd: File descriptor of nvme device + * @l: Link handle * @cdqid: Controller Data Queue ID (CDQID) * @hp: Head Pointer * @tpt: Tail Pointer Trigger * @etpt: Enable Tail Pointer Trigger * @result: The command completions result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_lm_set_features_ctrl_data_queue(int fd, __u16 cdqid, __u32 hp, __u32 tpt, bool etpt, - __u32 *result); +static inline int nvme_lm_set_features_ctrl_data_queue(nvme_link_t l, __u16 cdqid, __u32 hp, + __u32 tpt, bool etpt, __u32 *result) +{ + __u32 cdw11 = cdqid | NVME_SET(etpt, LM_CTRL_DATA_QUEUE_ETPT); + + return nvme_set_features(l, NVME_NSID_NONE, + NVME_FEAT_FID_CTRL_DATA_QUEUE, false, + cdw11, hp, tpt, 0, + NVME_UUID_NONE, NULL, 0, result); +} /** * nvme_lm_get_features_ctrl_data_queue - Get Controller Data Queue feature - * @fd: File descriptor of nvme device + * @l: Link handle + * @sel: Select which type of attribute to return, + * see &enum nvme_get_features_sel * @cdqid: Controller Data Queue ID (CDQID) - * @data: Get Controller Data Queue feature data + * @qfd: Get Controller Data Queue feature data * @result: The command completions result from CQE dword0 * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_lm_get_features_ctrl_data_queue(int fd, __u16 cdqid, - struct nvme_lm_ctrl_data_queue_fid_data *data, - __u32 *result); +static inline int nvme_lm_get_features_ctrl_data_queue(nvme_link_t l, + enum nvme_get_features_sel sel, + __u16 cdqid, + struct nvme_lm_ctrl_data_queue_fid_data *qfd, + __u32 *result) +{ + return nvme_get_features(l, NVME_NSID_NONE, NVME_FEAT_FID_CTRL_DATA_QUEUE, + sel, cdqid, NVME_UUID_NONE, + qfd, sizeof(*qfd), result); +} #endif /* _LIBNVME_IOCTL_H */ diff --git a/src/nvme/json.c b/src/nvme/json.c index 992a54373..8a611d8f2 100644 --- a/src/nvme/json.c +++ b/src/nvme/json.c @@ -248,15 +248,12 @@ int json_read_config(nvme_root_t r, const char *config_file) } json_root = parse_json(r, fd); close(fd); - if (!json_root) { - errno = EPROTO; - return -1; - } + if (!json_root) + return -EPROTO; if (!json_object_is_type(json_root, json_type_array)) { nvme_msg(r, LOG_DEBUG, "Wrong format, expected array\n"); json_object_put(json_root); - errno = EPROTO; - return -1; + return -EPROTO; } for (h = 0; h < json_object_array_length(json_root); h++) { host_obj = json_object_array_get_idx(json_root, h); @@ -448,8 +445,7 @@ int json_update_config(nvme_root_t r, const char *config_file) nvme_msg(r, LOG_ERR, "Failed to write to %s, %s\n", config_file ? "stdout" : config_file, json_util_get_last_err()); - ret = -1; - errno = EIO; + ret = -EIO; } json_object_put(json_root); @@ -675,8 +671,7 @@ int json_dump_tree(nvme_root_t r) if (ret < 0) { nvme_msg(r, LOG_ERR, "Failed to write, %s\n", json_util_get_last_err()); - ret = -1; - errno = EIO; + ret = -EIO; } json_object_put(json_root); diff --git a/src/nvme/linux.c b/src/nvme/linux.c index ae4aa526f..f330b84d2 100644 --- a/src/nvme/linux.c +++ b/src/nvme/linux.c @@ -7,6 +7,8 @@ * Chaitanya Kulkarni */ +#include "nvme/api-types.h" +#include "nvme/types.h" #include #include #include @@ -41,97 +43,176 @@ #include "base64.h" #include "crc32.h" -static int __nvme_open(const char *name) +static int __nvme_link_open_direct(nvme_link_t l, const char *devname) { _cleanup_free_ char *path = NULL; - int ret; + char *name = basename(devname); + int ret, id, ns; + bool c; + + l->type = NVME_LINK_TYPE_DIRECT; + + ret = sscanf(name, "nvme%dn%d", &id, &ns); + if (ret != 1 && ret != 2) + return -EINVAL; + c = ret == 1; ret = asprintf(&path, "%s/%s", "/dev", name); - if (ret < 0) { - errno = ENOMEM; - return -1; + if (ret < 0) + return -ENOMEM; + + l->fd = open(path, O_RDONLY); + if (l->fd < 0) + return -errno; + + ret = fstat(l->fd, &l->stat); + if (ret < 0) + return -errno; + + if (c) { + if (!S_ISCHR(l->stat.st_mode)) + return -EINVAL; + } else if (!S_ISBLK(l->stat.st_mode)) { + return -EINVAL; } - return open(path, O_RDONLY); + return 0; } -int nvme_open(const char *name) +void __nvme_link_close_direct(nvme_link_t l) { - int ret, fd, id, ns; - struct stat stat; - bool c; + close(l->fd); + free(l); +} - ret = sscanf(name, "nvme%dn%d", &id, &ns); - if (ret != 1 && ret != 2) { - errno = EINVAL; - return -1; +nvme_link_t __nvme_create_link(nvme_root_t r) +{ + nvme_link_t l; + + l = calloc(1, sizeof(*l)); + if (!l) + return NULL; + + l->root = r; + + return l; +} + +int nvme_open(nvme_root_t r, const char *name, nvme_link_t *lp) +{ + nvme_link_t l; + int ret; + + l = __nvme_create_link(r); + if (!l) + return -ENOMEM; + + l->name = strdup(name); + if (!l->name) { + free(l); + return -ENOMEM; } - c = ret == 1; - fd = __nvme_open(name); - if (fd < 0) - return fd; + if (!strcmp(name, "NVME_TEST_FD")) { + l->type = NVME_LINK_TYPE_DIRECT; + l->fd = 0xFD; + *lp = l; + return 0; + } - ret = fstat(fd, &stat); - if (ret < 0) - goto close_fd; + if (!strncmp(name, "mctp:", strlen("mctp:"))) + ret = __nvme_link_open_mi(l, name); + else + ret = __nvme_link_open_direct(l, name); - if (c) { - if (!S_ISCHR(stat.st_mode)) { - errno = EINVAL; - goto close_fd; - } - } else if (!S_ISBLK(stat.st_mode)) { - errno = EINVAL; - goto close_fd; + if (ret) { + nvme_close(l); + return ret; } - return fd; + *lp = l; -close_fd: - close(fd); - return -1; + return 0; +} + +void nvme_close(nvme_link_t l) +{ + if (!l) + return; + + free(l->name); + + switch (l->type) { + case NVME_LINK_TYPE_DIRECT: + __nvme_link_close_direct(l); + break; + case NVME_LINK_TYPE_MI: + __nvme_link_close_mi(l); + break; + case NVME_LINK_TYPE_UNKNOWN: + free(l); + } +} + +int nvme_link_get_fd(nvme_link_t l) +{ + return l->fd; +} + +bool nvme_link_is_blkdev(nvme_link_t l) +{ + return S_ISBLK(l->stat.st_mode); +} + +bool nvme_link_is_chardev(nvme_link_t l) +{ + return S_ISCHR(l->stat.st_mode); } -int nvme_fw_download_seq(int fd, __u32 size, __u32 xfer, __u32 offset, +bool nvme_link_is_direct(nvme_link_t l) +{ + return l->type == NVME_LINK_TYPE_DIRECT; +} + +bool nvme_link_is_mi(nvme_link_t l) +{ + return l->type == NVME_LINK_TYPE_MI; +} + +const char *nvme_link_get_name(nvme_link_t l) +{ + return l->name; +} + +int nvme_fw_download_seq(nvme_link_t l, __u32 size, __u32 xfer, __u32 offset, void *buf) { - int err = 0; - struct nvme_fw_download_args args = { - .args_size = sizeof(args), - .fd = fd, - .offset = offset, - .data_len = xfer, - .data = buf, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .result = NULL, - }; + int err; while (size > 0) { - args.data_len = MIN(xfer, size); - err = nvme_fw_download(&args); + err = nvme_fw_download(l, buf, MIN(xfer, size), + offset, NULL); if (err) - break; + return err; - args.data += xfer; + buf += xfer; size -= xfer; - args.offset += xfer; + offset += xfer; } - return err; + return 0; } -int nvme_get_telemetry_max(int fd, enum nvme_telemetry_da *da, size_t *data_tx) +int nvme_get_telemetry_max(nvme_link_t l, enum nvme_telemetry_da *da, size_t *data_tx) { _cleanup_free_ struct nvme_id_ctrl *id_ctrl = NULL; int err; id_ctrl = __nvme_alloc(sizeof(*id_ctrl)); - if (!id_ctrl) { - errno = ENOMEM; - return -1; - } - err = nvme_identify_ctrl(fd, id_ctrl); + if (!id_ctrl) + return -ENOMEM; + + err = nvme_identify_ctrl(l, id_ctrl); if (err) return err; @@ -154,7 +235,7 @@ int nvme_get_telemetry_max(int fd, enum nvme_telemetry_da *da, size_t *data_tx) return err; } -int nvme_get_telemetry_log(int fd, bool create, bool ctrl, bool rae, size_t max_data_tx, +int nvme_get_telemetry_log(nvme_link_t l, bool create, bool ctrl, bool rae, size_t max_data_tx, enum nvme_telemetry_da da, struct nvme_telemetry_log **buf, size_t *size) { @@ -166,37 +247,22 @@ int nvme_get_telemetry_log(int fd, bool create, bool ctrl, bool rae, size_t max_ void *tmp; int err; size_t dalb; - struct nvme_get_log_args args = { - .args_size = sizeof(args), - .fd = fd, - .nsid = NVME_NSID_NONE, - .lsp = NVME_LOG_LSP_NONE, - .lsi = NVME_LOG_LSI_NONE, - .uuidx = NVME_UUID_NONE, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .result = NULL, - .csi = NVME_CSI_NVM, - .rae = rae, - .ot = false, - }; *size = 0; log = __nvme_alloc(xfer); - if (!log) { - errno = ENOMEM; - return -1; - } + if (!log) + return -ENOMEM; if (ctrl) { - err = nvme_get_log_telemetry_ctrl(fd, true, 0, xfer, log); + err = nvme_get_log_telemetry_ctrl(l, true, 0, log, xfer); lid = NVME_LOG_LID_TELEMETRY_CTRL; } else { lid = NVME_LOG_LID_TELEMETRY_HOST; if (create) - err = nvme_get_log_create_telemetry_host_mcda(fd, da, log); + err = nvme_get_log_create_telemetry_host_mcda(l, da, log); else - err = nvme_get_log_telemetry_host(fd, 0, xfer, log); + err = nvme_get_log_telemetry_host(l, 0, log, xfer); } if (err) @@ -225,27 +291,23 @@ int nvme_get_telemetry_log(int fd, bool create, bool ctrl, bool rae, size_t max_ dalb = le32_to_cpu(telem->dalb4); break; default: - errno = EINVAL; - return -1; + return -EINVAL; } - if (dalb == 0) { - errno = ENOENT; - return -1; - } + if (dalb == 0) + return -ENOENT; *size = (dalb + 1) * xfer; tmp = __nvme_realloc(log, *size); - if (!tmp) { - errno = ENOMEM; - return -1; - } + if (!tmp) + return -ENOMEM; log = tmp; - args.lid = lid; - args.log = log; - args.len = *size; - err = nvme_get_log_page(fd, max_data_tx, &args); + err = nvme_get_log(l, NVME_NSID_NONE, rae, NVME_LOG_LSP_NONE, + lid, NVME_LOG_LSI_NONE, NVME_CSI_NVM, + false, NVME_UUID_NONE, + 0, log, *size, + max_data_tx, NULL); if (err) return err; @@ -255,66 +317,52 @@ int nvme_get_telemetry_log(int fd, bool create, bool ctrl, bool rae, size_t max_ } -static int nvme_check_get_telemetry_log(int fd, bool create, bool ctrl, bool rae, +static int nvme_check_get_telemetry_log(nvme_link_t l, bool create, bool ctrl, bool rae, struct nvme_telemetry_log **log, enum nvme_telemetry_da da, size_t *size) { enum nvme_telemetry_da max_da = 0; - int err = nvme_get_telemetry_max(fd, &max_da, NULL); + int err = nvme_get_telemetry_max(l, &max_da, NULL); if (err) return err; - if (da > max_da) { - errno = ENOENT; - return -1; - } - return nvme_get_telemetry_log(fd, create, ctrl, rae, 4096, da, log, size); + if (da > max_da) + return -ENOENT; + + return nvme_get_telemetry_log(l, create, ctrl, rae, 4096, da, log, size); } -int nvme_get_ctrl_telemetry(int fd, bool rae, struct nvme_telemetry_log **log, +int nvme_get_ctrl_telemetry(nvme_link_t l, bool rae, struct nvme_telemetry_log **log, enum nvme_telemetry_da da, size_t *size) { - return nvme_check_get_telemetry_log(fd, false, true, rae, log, da, size); + return nvme_check_get_telemetry_log(l, false, true, rae, log, da, size); } -int nvme_get_host_telemetry(int fd, struct nvme_telemetry_log **log, +int nvme_get_host_telemetry(nvme_link_t l, struct nvme_telemetry_log **log, enum nvme_telemetry_da da, size_t *size) { - return nvme_check_get_telemetry_log(fd, false, false, false, log, da, size); + return nvme_check_get_telemetry_log(l, false, false, false, log, da, size); } -int nvme_get_new_host_telemetry(int fd, struct nvme_telemetry_log **log, +int nvme_get_new_host_telemetry(nvme_link_t l, struct nvme_telemetry_log **log, enum nvme_telemetry_da da, size_t *size) { - return nvme_check_get_telemetry_log(fd, true, false, false, log, da, size); + return nvme_check_get_telemetry_log(l, true, false, false, log, da, size); } -int nvme_get_lba_status_log(int fd, bool rae, struct nvme_lba_status_log **log) +int nvme_get_lba_status_log(nvme_link_t l, bool rae, struct nvme_lba_status_log **log) { _cleanup_free_ struct nvme_lba_status_log *buf = NULL; __u32 size; void *tmp; int err; - struct nvme_get_log_args args = { - .args_size = sizeof(args), - .fd = fd, - .nsid = NVME_NSID_NONE, - .lsp = NVME_LOG_LSP_NONE, - .lsi = NVME_LOG_LSI_NONE, - .uuidx = NVME_UUID_NONE, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .result = NULL, - .csi = NVME_CSI_NVM, - .rae = rae, - .ot = false, - }; buf = malloc(sizeof(*buf)); if (!buf) - return -1; + return -ENOMEM; - err = nvme_get_log_lba_status(fd, true, 0, sizeof(*buf), buf); + err = nvme_get_log_lba_status(l, true, 0, buf, sizeof(*buf)); if (err) { *log = NULL; return err; @@ -330,14 +378,15 @@ int nvme_get_lba_status_log(int fd, bool rae, struct nvme_lba_status_log **log) tmp = realloc(buf, size); if (!tmp) { *log = NULL; - return -1; + return -ENOMEM; } buf = tmp; - args.lid = NVME_LOG_LID_LBA_STATUS; - args.log = buf; - args.len = size; - err = nvme_get_log_page(fd, 4096, &args); + err = nvme_get_log(l, NVME_NSID_NONE, rae, NVME_LOG_LSP_NONE, + NVME_LOG_LID_LBA_STATUS, NVME_LOG_LSI_NONE, NVME_CSI_NVM, + false, NVME_UUID_NONE, + 0, buf, size, + NVME_LOG_PAGE_PDU_SIZE, NULL); if (err) { *log = NULL; return err; @@ -348,38 +397,29 @@ int nvme_get_lba_status_log(int fd, bool rae, struct nvme_lba_status_log **log) return 0; } -static int nvme_ns_attachment(int fd, __u32 nsid, __u16 num_ctrls, - __u16 *ctrlist, bool attach, __u32 timeout) +static int nvme_ns_attachment(nvme_link_t l, __u32 nsid, __u16 num_ctrls, + __u16 *ctrlist, bool attach) { struct nvme_ctrl_list cntlist = { 0 }; - struct nvme_ns_attach_args args = { - .args_size = sizeof(args), - .fd = fd, - .nsid = nsid, - .sel = NVME_NS_ATTACH_SEL_CTRL_DEATTACH, - .ctrlist = &cntlist, - .timeout = timeout, - }; + enum nvme_ns_attach_sel sel = NVME_NS_ATTACH_SEL_CTRL_DEATTACH; if (attach) - args.sel = NVME_NS_ATTACH_SEL_CTRL_ATTACH; + sel = NVME_NS_ATTACH_SEL_CTRL_ATTACH; - nvme_init_ctrl_list(args.ctrlist, num_ctrls, ctrlist); - return nvme_ns_attach(&args); + nvme_init_ctrl_list(&cntlist, num_ctrls, ctrlist); + return nvme_ns_attach(l, nsid, sel, &cntlist, NULL); } -int nvme_namespace_attach_ctrls(int fd, __u32 nsid, __u16 num_ctrls, +int nvme_namespace_attach_ctrls(nvme_link_t l, __u32 nsid, __u16 num_ctrls, __u16 *ctrlist) { - return nvme_ns_attachment(fd, nsid, num_ctrls, ctrlist, true, - NVME_DEFAULT_IOCTL_TIMEOUT); + return nvme_ns_attachment(l, nsid, num_ctrls, ctrlist, true); } -int nvme_namespace_detach_ctrls(int fd, __u32 nsid, __u16 num_ctrls, +int nvme_namespace_detach_ctrls(nvme_link_t l, __u32 nsid, __u16 num_ctrls, __u16 *ctrlist) { - return nvme_ns_attachment(fd, nsid, num_ctrls, ctrlist, false, - NVME_DEFAULT_IOCTL_TIMEOUT); + return nvme_ns_attachment(l, nsid, num_ctrls, ctrlist, false); } size_t nvme_get_ana_log_len_from_id_ctrl(const struct nvme_id_ctrl *id_ctrl, @@ -392,17 +432,16 @@ size_t nvme_get_ana_log_len_from_id_ctrl(const struct nvme_id_ctrl *id_ctrl, return rgo ? size : size + le32_to_cpu(id_ctrl->mnan) * sizeof(__le32); } -int nvme_get_ana_log_len(int fd, size_t *analen) +int nvme_get_ana_log_len(nvme_link_t l, size_t *analen) { _cleanup_free_ struct nvme_id_ctrl *ctrl = NULL; int ret; ctrl = __nvme_alloc(sizeof(*ctrl)); - if (!ctrl) { - errno = ENOMEM; - return -1; - } - ret = nvme_identify_ctrl(fd, ctrl); + if (!ctrl) + return -ENOMEM; + + ret = nvme_identify_ctrl(l, ctrl); if (ret) return ret; @@ -410,18 +449,17 @@ int nvme_get_ana_log_len(int fd, size_t *analen) return 0; } -int nvme_get_logical_block_size(int fd, __u32 nsid, int *blksize) +int nvme_get_logical_block_size(nvme_link_t l, __u32 nsid, int *blksize) { _cleanup_free_ struct nvme_id_ns *ns = NULL; __u8 flbas; int ret; ns = __nvme_alloc(sizeof(*ns)); - if (!ns) { - errno = ENOMEM; - return -1; - } - ret = nvme_identify_ns(fd, nsid, ns); + if (!ns) + return -ENOMEM; + + ret = nvme_identify_ns(l, nsid, ns); if (ret) return ret; @@ -441,7 +479,7 @@ static int __nvme_set_attr(const char *path, const char *value) nvme_msg(LOG_DEBUG, "Failed to open %s: %s\n", path, strerror(errno)); #endif - return -1; + return -errno; } return write(fd, value, strlen(value)); } @@ -453,7 +491,7 @@ int nvme_set_attr(const char *dir, const char *attr, const char *value) ret = asprintf(&path, "%s/%s", dir, attr); if (ret < 0) - return -1; + return -ENOMEM; return __nvme_set_attr(path, value); } @@ -493,10 +531,8 @@ char *nvme_get_attr(const char *dir, const char *attr) int ret; ret = asprintf(&path, "%s/%s", dir, attr); - if (ret < 0) { - errno = ENOMEM; + if (ret < 0) return NULL; - } return __nvme_get_attr(path); } @@ -534,8 +570,7 @@ int nvme_gen_dhchap_key(char *hostnqn, enum nvme_hmac_alg hmac, if (hmac != NVME_HMAC_ALG_NONE) { nvme_msg(NULL, LOG_ERR, "HMAC transformation not supported; " \ "recompile with OpenSSL support.\n"); - errno = -EINVAL; - return -1; + return -EINVAL; } memcpy(key, secret, key_len); @@ -549,8 +584,7 @@ static int derive_retained_key(int hmac, const char *hostnqn, { nvme_msg(NULL, LOG_ERR, "NVMe TLS is not supported; " "recompile with OpenSSL support.\n"); - errno = ENOTSUP; - return -1; + return -ENOTSUP; } static int derive_psk_digest(const char *hostnqn, const char *subsysnqn, @@ -560,8 +594,7 @@ static int derive_psk_digest(const char *hostnqn, const char *subsysnqn, { nvme_msg(NULL, LOG_ERR, "NVMe TLS 2.0 is not supported; " "recompile with OpenSSL support.\n"); - errno = ENOTSUP; - return -1; + return -ENOTSUP; } static int derive_tls_key(int version, int cipher, const char *context, @@ -570,8 +603,7 @@ static int derive_tls_key(int version, int cipher, const char *context, { nvme_msg(NULL, LOG_ERR, "NVMe TLS is not supported; " "recompile with OpenSSL support.\n"); - errno = ENOTSUP; - return -1; + return -ENOTSUP; } #else /* CONFIG_OPENSSL */ static unsigned char default_hmac(size_t key_len) @@ -662,54 +694,40 @@ static int derive_retained_key(int hmac, const char *hostnqn, } md = select_hmac(hmac, &hmac_len); - if (!md || !hmac_len) { - errno = EINVAL; - return -1; - } + if (!md || !hmac_len) + return -EINVAL; ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL); - if (!ctx) { - errno = ENOMEM; - return -1; - } + if (!ctx) + return -ENOMEM; + + if (EVP_PKEY_derive_init(ctx) <= 0) + return -ENOMEM; + + if (EVP_PKEY_CTX_set_hkdf_md(ctx, md) <= 0) + return -ENOKEY; + + if (EVP_PKEY_CTX_set1_hkdf_key(ctx, configured, key_len) <= 0) + return -ENOKEY; - if (EVP_PKEY_derive_init(ctx) <= 0) { - errno = ENOMEM; - return -1; - } - if (EVP_PKEY_CTX_set_hkdf_md(ctx, md) <= 0) { - errno = ENOKEY; - return -1; - } - if (EVP_PKEY_CTX_set1_hkdf_key(ctx, configured, key_len) <= 0) { - errno = ENOKEY; - return -1; - } if (EVP_PKEY_CTX_add1_hkdf_info(ctx, - (const unsigned char *)&length, 2) <= 0) { - errno = ENOKEY; - return -1; - } + (const unsigned char *)&length, 2) <= 0) + return -ENOKEY; + if (EVP_PKEY_CTX_add1_hkdf_info(ctx, - (const unsigned char *)"tls13 ", 6) <= 0) { - errno = ENOKEY; - return -1; - } + (const unsigned char *)"tls13 ", 6) <= 0) + return -ENOKEY; + if (EVP_PKEY_CTX_add1_hkdf_info(ctx, - (const unsigned char *)"HostNQN", 7) <= 0) { - errno = ENOKEY; - return -1; - } + (const unsigned char *)"HostNQN", 7) <= 0) + return -ENOKEY; + if (EVP_PKEY_CTX_add1_hkdf_info(ctx, - (const unsigned char *)hostnqn, strlen(hostnqn)) <= 0) { - errno = ENOKEY; - return -1; - } + (const unsigned char *)hostnqn, strlen(hostnqn)) <= 0) + return -ENOKEY; - if (EVP_PKEY_derive(ctx, retained, &key_len) <= 0) { - errno = ENOKEY; - return -1; - } + if (EVP_PKEY_derive(ctx, retained, &key_len) <= 0) + return -ENOKEY; return key_len; } @@ -746,66 +764,51 @@ static int derive_tls_key(int version, unsigned char cipher, size_t hmac_len; md = select_hmac(cipher, &hmac_len); - if (!md || !hmac_len) { - errno = EINVAL; - return -1; - } + if (!md || !hmac_len) + return -EINVAL; ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL); - if (!ctx) { - errno = ENOMEM; - return -1; - } + if (!ctx) + return -ENOMEM; + + if (EVP_PKEY_derive_init(ctx) <= 0) + return -ENOMEM; + + if (EVP_PKEY_CTX_set_hkdf_md(ctx, md) <= 0) + return -ENOKEY; + + if (EVP_PKEY_CTX_set1_hkdf_key(ctx, retained, key_len) <= 0) + return -ENOKEY; - if (EVP_PKEY_derive_init(ctx) <= 0) { - errno = ENOMEM; - return -1; - } - if (EVP_PKEY_CTX_set_hkdf_md(ctx, md) <= 0) { - errno = ENOKEY; - return -1; - } - if (EVP_PKEY_CTX_set1_hkdf_key(ctx, retained, key_len) <= 0) { - errno = ENOKEY; - return -1; - } if (EVP_PKEY_CTX_add1_hkdf_info(ctx, - (const unsigned char *)&length, 2) <= 0) { - errno = ENOKEY; - return -1; - } + (const unsigned char *)&length, 2) <= 0) + return -ENOKEY; + if (EVP_PKEY_CTX_add1_hkdf_info(ctx, - (const unsigned char *)"tls13 ", 6) <= 0) { - errno = ENOKEY; - return -1; - } + (const unsigned char *)"tls13 ", 6) <= 0) + return -ENOKEY; + if (EVP_PKEY_CTX_add1_hkdf_info(ctx, - (const unsigned char *)"nvme-tls-psk", 12) <= 0) { - errno = ENOKEY; - return -1; - } + (const unsigned char *)"nvme-tls-psk", 12) <= 0) + return -ENOKEY; + if (version == 1) { char hash_str[5]; sprintf(hash_str, "%02d ", cipher); if (EVP_PKEY_CTX_add1_hkdf_info(ctx, (const unsigned char *)hash_str, - strlen(hash_str)) <= 0) { - errno = ENOKEY; - return -1; - } + strlen(hash_str)) <= 0) + return -ENOKEY; } + if (EVP_PKEY_CTX_add1_hkdf_info(ctx, (const unsigned char *)context, - strlen(context)) <= 0) { - errno = ENOKEY; - return -1; - } + strlen(context)) <= 0) + return -ENOKEY; - if (EVP_PKEY_derive(ctx, psk, &key_len) <= 0) { - errno = ENOKEY; - return -1; - } + if (EVP_PKEY_derive(ctx, psk, &key_len) <= 0) + return -ENOKEY; return key_len; } @@ -832,22 +835,16 @@ int nvme_gen_dhchap_key(char *hostnqn, enum nvme_hmac_alg hmac, size_t len; lib_ctx = OSSL_LIB_CTX_new(); - if (!lib_ctx) { - errno = ENOMEM; - return -1; - } + if (!lib_ctx) + return -ENOMEM; mac = EVP_MAC_fetch(lib_ctx, OSSL_MAC_NAME_HMAC, progq); - if (!mac) { - errno = ENOMEM; - return -1; - } + if (!mac) + return -ENOMEM; mac_ctx = EVP_MAC_CTX_new(mac); - if (!mac_ctx) { - errno = ENOMEM; - return -1; - } + if (!mac_ctx) + return -ENOMEM; switch (hmac) { case NVME_HMAC_ALG_NONE: @@ -863,40 +860,29 @@ int nvme_gen_dhchap_key(char *hostnqn, enum nvme_hmac_alg hmac, digest = OSSL_DIGEST_NAME_SHA2_512; break; default: - errno = EINVAL; - return -1; + return -EINVAL; } *p++ = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_DIGEST, digest, 0); *p = OSSL_PARAM_construct_end(); - if (!EVP_MAC_init(mac_ctx, secret, key_len, params)) { - errno = ENOKEY; - return -1; - } + if (!EVP_MAC_init(mac_ctx, secret, key_len, params)) + return -ENOKEY; if (!EVP_MAC_update(mac_ctx, (unsigned char *)hostnqn, - strlen(hostnqn))) { - errno = ENOKEY; - return -1; - } + strlen(hostnqn))) + return -ENOKEY; if (!EVP_MAC_update(mac_ctx, (unsigned char *)hmac_seed, - strlen(hmac_seed))) { - errno = ENOKEY; - return -1; - } + strlen(hmac_seed))) + return -ENOKEY; - if (!EVP_MAC_final(mac_ctx, key, &len, key_len)) { - errno = ENOKEY; - return -1; - } + if (!EVP_MAC_final(mac_ctx, key, &len, key_len)) + return -ENOKEY; - if (len != key_len) { - errno = EMSGSIZE; - return -1; - } + if (len != key_len) + return -EMSGSIZE; return 0; } @@ -918,21 +904,17 @@ static int derive_psk_digest(const char *hostnqn, const char *subsysnqn, size_t len; lib_ctx = OSSL_LIB_CTX_new(); - if (!lib_ctx) { - errno = ENOMEM; - return -1; - } + if (!lib_ctx) + return -ENOMEM; + mac = EVP_MAC_fetch(lib_ctx, OSSL_MAC_NAME_HMAC, progq); - if (!mac) { - errno = ENOMEM; - return -1; - } + if (!mac) + return -ENOMEM; mac_ctx = EVP_MAC_CTX_new(mac); - if (!mac_ctx) { - errno = ENOMEM; - return -1; - } + if (!mac_ctx) + return -ENOMEM; + switch (cipher) { case NVME_HMAC_ALG_SHA2_256: dig = OSSL_DIGEST_NAME_SHA2_256; @@ -941,66 +923,52 @@ static int derive_psk_digest(const char *hostnqn, const char *subsysnqn, dig = OSSL_DIGEST_NAME_SHA2_384; break; default: - errno = EINVAL; - break; + return -EINVAL; } - if (!dig) - return -1; + *p++ = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_DIGEST, dig, 0); *p = OSSL_PARAM_construct_end(); psk_ctx = malloc(key_len); - if (!psk_ctx) { - errno = ENOMEM; - return -1; - } + if (!psk_ctx) + return -ENOMEM; + + if (!EVP_MAC_init(mac_ctx, retained, key_len, params)) + return -ENOKEY; - if (!EVP_MAC_init(mac_ctx, retained, key_len, params)) { - errno = ENOKEY; - return -1; - } if (!EVP_MAC_update(mac_ctx, (unsigned char *)hostnqn, - strlen(hostnqn))) { - errno = ENOKEY; - return -1; - } - if (!EVP_MAC_update(mac_ctx, (unsigned char *)" ", 1)) { - errno = ENOKEY; - return -1; - } + strlen(hostnqn))) + return -ENOKEY; + + if (!EVP_MAC_update(mac_ctx, (unsigned char *)" ", 1)) + return -ENOKEY; + if (!EVP_MAC_update(mac_ctx, (unsigned char *)subsysnqn, - strlen(subsysnqn))) { - errno = ENOKEY; - return -1; - } - if (!EVP_MAC_update(mac_ctx, (unsigned char *)" ", 1)) { - errno = ENOKEY; - return -1; - } + strlen(subsysnqn))) + return -ENOKEY; + + if (!EVP_MAC_update(mac_ctx, (unsigned char *)" ", 1)) + return -ENOKEY; + if (!EVP_MAC_update(mac_ctx, (unsigned char *)hmac_seed, - strlen(hmac_seed))) { - errno = ENOKEY; - return -1; - } - if (!EVP_MAC_final(mac_ctx, psk_ctx, &hmac_len, key_len)) { - errno = ENOKEY; - return -1; - } - if (hmac_len > key_len) { - errno = EMSGSIZE; - return -1; - } - if (hmac_len * 2 > digest_len) { - errno = EINVAL; - return -1; - } + strlen(hmac_seed))) + return -ENOKEY; + + if (!EVP_MAC_final(mac_ctx, psk_ctx, &hmac_len, key_len)) + return -ENOKEY; + + if (hmac_len > key_len) + return -EMSGSIZE; + + if (hmac_len * 2 > digest_len) + return -EINVAL; + memset(digest, 0, digest_len); len = base64_encode(psk_ctx, hmac_len, digest); - if (len < 0) { - errno = ENOKEY; + if (len < 0) return len; - } + return strlen(digest); } #endif /* !CONFIG_OPENSSL */ @@ -1014,10 +982,8 @@ static int gen_tls_identity(const char *hostnqn, const char *subsysnqn, version, cipher, hostnqn, subsysnqn); return strlen(identity); } - if (version > 1) { - errno = EINVAL; - return -1; - } + if (version > 1) + return -EINVAL; sprintf(identity, "NVMe%01dR%02d %s %s %s", version, cipher, hostnqn, subsysnqn, digest); @@ -1035,16 +1001,13 @@ static int derive_nvme_keys(const char *hostnqn, const char *subsysnqn, unsigned char cipher; int ret = -1; - if (!hostnqn || !subsysnqn || !identity || !psk) { - errno = EINVAL; - return -1; - } + if (!hostnqn || !subsysnqn || !identity || !psk) + return -EINVAL; retained = malloc(key_len); - if (!retained) { - errno = ENOMEM; - return -1; - } + if (!retained) + return -ENOMEM; + ret = derive_retained_key(hmac, hostnqn, configured, retained, key_len); if (ret < 0) return ret; @@ -1058,10 +1021,9 @@ static int derive_nvme_keys(const char *hostnqn, const char *subsysnqn, size_t digest_len = 2 * key_len; digest = malloc(digest_len); - if (!digest) { - errno = ENOMEM; - return -1; - } + if (!digest) + return -ENOMEM; + ret = derive_psk_digest(hostnqn, subsysnqn, version, cipher, retained, key_len, digest, digest_len); @@ -1082,10 +1044,8 @@ static ssize_t nvme_identity_len(int hmac, int version, const char *hostnqn, { ssize_t len; - if (!hostnqn || !subsysnqn) { - errno = EINVAL; - return -1; - } + if (!hostnqn || !subsysnqn) + return -EINVAL; len = strlen(hostnqn) + strlen(subsysnqn) + 12; if (version == 1) { @@ -1093,46 +1053,52 @@ static ssize_t nvme_identity_len(int hmac, int version, const char *hostnqn, if (hmac == NVME_HMAC_ALG_SHA2_384) len += 32; } else if (version > 1) { - errno = EINVAL; - return -1; + return -EINVAL; } + return len; } -char *nvme_generate_tls_key_identity(const char *hostnqn, const char *subsysnqn, +int nvme_generate_tls_key_identity(const char *hostnqn, const char *subsysnqn, int version, int hmac, - unsigned char *configured_key, int key_len) + unsigned char *configured_key, int key_len, + char **identityp) { _cleanup_free_ unsigned char *psk = NULL; char *identity; ssize_t identity_len; - int ret = -1; + int ret; identity_len = nvme_identity_len(hmac, version, hostnqn, subsysnqn); if (identity_len < 0) - return NULL; + return identity_len; identity = malloc(identity_len); if (!identity) - return NULL; + return -ENOMEM; psk = malloc(key_len); - if (!psk) - goto out_free_identity; + if (!psk) { + ret = -ENOMEM; + goto err; + } memset(psk, 0, key_len); ret = derive_nvme_keys(hostnqn, subsysnqn, identity, version, hmac, configured_key, psk, key_len); -out_free_identity: - if (ret < 0) { - free(identity); - identity = NULL; - } - return identity; + if (ret) + goto err; + + *identityp = identity; + return 0; + +err: + free(identity); + return -ret; } #ifdef CONFIG_KEYUTILS -long nvme_lookup_keyring(const char *keyring) +int nvme_lookup_keyring(const char *keyring, long *key) { key_serial_t keyring_id; @@ -1140,8 +1106,10 @@ long nvme_lookup_keyring(const char *keyring) keyring = NVME_TLS_DEFAULT_KEYRING; keyring_id = find_key_by_type_and_desc("keyring", keyring, 0); if (keyring_id < 0) - return 0; - return keyring_id; + return -errno; + + *key = keyring_id; + return 0; } char *nvme_describe_key_serial(long key_id) @@ -1163,13 +1131,13 @@ char *nvme_describe_key_serial(long key_id) return strdup(last); } -long nvme_lookup_key(const char *type, const char *identity) +int nvme_lookup_key(const char *type, const char *identity, long *keyp) { key_serial_t key; key = keyctl_search(KEY_SPEC_SESSION_KEYRING, type, identity, 0); if (key < 0) - return 0; + return -errno; return key; } @@ -1178,55 +1146,53 @@ int nvme_set_keyring(long key_id) long err; if (key_id == 0) { - key_id = nvme_lookup_keyring(NULL); - if (key_id == 0) { - errno = ENOKEY; - return -1; - } + if (nvme_lookup_keyring(NULL, &key_id)) + return -ENOKEY; } err = keyctl_link(key_id, KEY_SPEC_SESSION_KEYRING); if (err < 0) - return -1; + return -errno; return 0; } -unsigned char *nvme_read_key(long keyring_id, long key_id, int *len) +int nvme_read_key(long keyring_id, long key_id, int *len, + unsigned char **key) { void *buffer; int ret; ret = nvme_set_keyring(keyring_id); - if (ret < 0) { - errno = -ret; - return NULL; - } + if (ret < 0) + return ret; + ret = keyctl_read_alloc(key_id, &buffer); - if (ret < 0) { - errno = -ret; - buffer = NULL; - } else - *len = ret; + if (ret < 0) + return ret; - return buffer; + *len = ret; + *key = buffer; + return 0; } -long nvme_update_key(long keyring_id, const char *key_type, - const char *identity, unsigned char *key_data, - int key_len) +int nvme_update_key(long keyring_id, const char *key_type, + const char *identity, unsigned char *key_data, + int key_len, long *keyp) { long key; key = keyctl_search(keyring_id, key_type, identity, 0); if (key > 0) { if (keyctl_revoke(key) < 0) - return 0; + return -errno; } key = add_key(key_type, identity, key_data, key_len, keyring_id); if (key < 0) - key = 0; - return key; + return -errno; + + *keyp = key; + return 0; } struct __scan_keys_data { @@ -1272,13 +1238,16 @@ int nvme_scan_tls_keys(const char *keyring, nvme_scan_tls_keys_cb_t cb, void *data) { struct __scan_keys_data d; - key_serial_t keyring_id = nvme_lookup_keyring(keyring); + long keyring_id; int ret; - if (!keyring_id) { - errno = EINVAL; - return -1; - } + ret = nvme_lookup_keyring(keyring, &keyring_id); + if (ret) + return ret; + + if (!keyring_id) + return -EINVAL; + ret = nvme_set_keyring(keyring_id); if (ret < 0) return ret; @@ -1290,99 +1259,109 @@ int nvme_scan_tls_keys(const char *keyring, nvme_scan_tls_keys_cb_t cb, return ret; } -static long __nvme_insert_tls_key_versioned(key_serial_t keyring_id, const char *key_type, - const char *hostnqn, const char *subsysnqn, - int version, int hmac, - unsigned char *configured_key, int key_len) +static int __nvme_insert_tls_key_versioned(key_serial_t keyring_id, const char *key_type, + const char *hostnqn, const char *subsysnqn, + int version, int hmac, + unsigned char *configured_key, int key_len, + long *key) { _cleanup_free_ unsigned char *psk = NULL; _cleanup_free_ char *identity = NULL; ssize_t identity_len; - key_serial_t key; int ret; identity_len = nvme_identity_len(hmac, version, hostnqn, subsysnqn); if (identity_len < 0) - return 0; + return identity_len; identity = malloc(identity_len); - if (!identity) { - errno = ENOMEM; - return 0; - } + if (!identity) + return -ENOMEM; + memset(identity, 0, identity_len); psk = malloc(key_len); - if (!psk) { - errno = ENOMEM; - return 0; - } + if (!psk) + return -ENOMEM; + memset(psk, 0, key_len); ret = derive_nvme_keys(hostnqn, subsysnqn, identity, version, hmac, configured_key, psk, key_len); - if (ret != key_len) { - errno = ENOKEY; - return 0; - } + if (ret != key_len) + return -ENOKEY; - key = nvme_update_key(keyring_id, key_type, identity, - psk, key_len); - return key; + return nvme_update_key(keyring_id, key_type, identity, + psk, key_len, key); } -long nvme_insert_tls_key_versioned(const char *keyring, const char *key_type, - const char *hostnqn, const char *subsysnqn, - int version, int hmac, - unsigned char *configured_key, int key_len) +int nvme_insert_tls_key_versioned(const char *keyring, const char *key_type, + const char *hostnqn, const char *subsysnqn, + int version, int hmac, + unsigned char *configured_key, int key_len, + long *key) { - key_serial_t keyring_id; + long keyring_id; int ret; - keyring_id = nvme_lookup_keyring(keyring); - if (keyring_id == 0) { - errno = ENOKEY; - return 0; - } + ret = nvme_lookup_keyring(keyring, &keyring_id); + if (ret) + return ret; + + if (keyring_id == 0) + return -ENOKEY; ret = nvme_set_keyring(keyring_id); if (ret < 0) - return 0; + return ret; + return __nvme_insert_tls_key_versioned(keyring_id, key_type, hostnqn, subsysnqn, version, hmac, - configured_key, key_len); + configured_key, key_len, + key); } -long nvme_revoke_tls_key(const char *keyring, const char *key_type, - const char *identity) +int nvme_revoke_tls_key(const char *keyring, const char *key_type, + const char *identity) { - key_serial_t keyring_id; + long keyring_id; long key; + int ret; - keyring_id = nvme_lookup_keyring(keyring); - if (keyring_id == 0) { - errno = ENOKEY; - return 0; - } + ret = nvme_lookup_keyring(keyring, &keyring_id); + if (ret) + return ret; + + if (keyring_id == 0) + return -ENOKEY; key = keyctl_search(keyring_id, key_type, identity, 0); if (key < 0) - return -1; + return -errno; - return keyctl_revoke(key); + if (keyctl_revoke(key)) + return -errno; + + return 0; } -static long __nvme_insert_tls_key(long keyring_id, - const char *hostnqn, const char *subsysnqn, - const char *identity, const char *key) +static int __nvme_insert_tls_key(long keyring_id, + const char *hostnqn, const char *subsysnqn, + const char *identity, const char *key, long *keyp) { _cleanup_free_ unsigned char *key_data = NULL; unsigned char version; unsigned char hmac; size_t key_len; + long lkey; + int ret; + + ret = nvme_import_tls_key_versioned(key, &version, + &hmac, &key_len, + &key_data); + if (ret) + return ret; - key_data = nvme_import_tls_key_versioned(key, &version, - &hmac, &key_len); if (!key_data) return -EINVAL; @@ -1393,14 +1372,21 @@ static long __nvme_insert_tls_key(long keyring_id, * configured key. Derive a new key and load the newly * created key into the keystore. */ - return __nvme_insert_tls_key_versioned(keyring_id, "psk", - hostnqn, subsysnqn, - version, hmac, - key_data, key_len); + ret = __nvme_insert_tls_key_versioned(keyring_id, "psk", + hostnqn, subsysnqn, + version, hmac, + key_data, key_len, + &lkey); + } else { + ret = nvme_update_key(keyring_id, "psk", identity, + key_data, key_len, &lkey); } - return nvme_update_key(keyring_id, "psk", identity, - key_data, key_len); + if (ret) + return ret; + + *keyp = lkey; + return 0; } int __nvme_import_keys_from_config(nvme_host_t h, nvme_ctrl_t c, @@ -1410,6 +1396,7 @@ int __nvme_import_keys_from_config(nvme_host_t h, nvme_ctrl_t c, const char *subsysnqn = nvme_ctrl_get_subsysnqn(c); const char *keyring, *key, *identity; long kr_id = 0, id = 0; + int ret; if (!hostnqn || !subsysnqn) { nvme_msg(h->r, LOG_ERR, "Invalid NQNs (%s, %s)\n", @@ -1424,9 +1411,9 @@ int __nvme_import_keys_from_config(nvme_host_t h, nvme_ctrl_t c, keyring = nvme_ctrl_get_keyring(c); if (keyring) { - kr_id = nvme_lookup_keyring(keyring); - if (kr_id == 0) - return -errno; + ret = nvme_lookup_keyring(keyring, &kr_id); + if (ret) + return ret; } else kr_id = c->cfg.keyring; @@ -1436,9 +1423,9 @@ int __nvme_import_keys_from_config(nvme_host_t h, nvme_ctrl_t c, * That means we are explicitly selecting the keyring. */ if (!kr_id) { - kr_id = nvme_lookup_keyring(".nvme"); - if (kr_id == 0) - return -errno; + ret = nvme_lookup_keyring(".nvme", &kr_id); + if (ret) + return ret; } if (nvme_set_keyring(kr_id) < 0) { @@ -1448,16 +1435,16 @@ int __nvme_import_keys_from_config(nvme_host_t h, nvme_ctrl_t c, identity = nvme_ctrl_get_tls_key_identity(c); if (identity) - id = nvme_lookup_key("psk", identity); + ret = nvme_lookup_key("psk", identity, &id); if (!id) - id = __nvme_insert_tls_key(kr_id, hostnqn, - subsysnqn, identity, key); + ret = __nvme_insert_tls_key(kr_id, hostnqn, + subsysnqn, identity, key, &id); - if (id <= 0) { + if (ret) { nvme_msg(h->r, LOG_ERR, "Failed to insert TLS KEY, error %d\n", - errno); - return -errno; + ret); + return ret; } out: @@ -1467,77 +1454,70 @@ int __nvme_import_keys_from_config(nvme_host_t h, nvme_ctrl_t c, return 0; } #else -long nvme_lookup_keyring(const char *keyring) +int nvme_lookup_keyring(const char *keyring, long *key) { nvme_msg(NULL, LOG_ERR, "key operations not supported; "\ "recompile with keyutils support.\n"); - errno = ENOTSUP; - return 0; + return -ENOTSUP; } char *nvme_describe_key_serial(long key_id) { nvme_msg(NULL, LOG_ERR, "key operations not supported; "\ "recompile with keyutils support.\n"); - errno = ENOTSUP; return NULL; } -long nvme_lookup_key(const char *type, const char *identity) +int nvme_lookup_key(const char *type, const char *identity, long *key) { nvme_msg(NULL, LOG_ERR, "key operations not supported; "\ "recompile with keyutils support.\n"); - errno = ENOTSUP; - return 0; + return -ENOTSUP; } int nvme_set_keyring(long key_id) { nvme_msg(NULL, LOG_ERR, "key operations not supported; "\ "recompile with keyutils support.\n"); - errno = ENOTSUP; - return -1; + return -ENOTSUP; } -unsigned char *nvme_read_key(long keyring_id, long key_id, int *len) +int nvme_read_key(long keyring_id, long key_id, int *len, + unsigned char **key) { - errno = ENOTSUP; - return NULL; + return -ENOTSUP; } -long nvme_update_key(long keyring_id, const char *key_type, - const char *identity, unsigned char *key_data, - int key_len) +int nvme_update_key(long keyring_id, const char *key_type, + const char *identity, unsigned char *key_data, + int key_len, long *key) { - errno = ENOTSUP; - return 0; + return -ENOTSUP; } int nvme_scan_tls_keys(const char *keyring, nvme_scan_tls_keys_cb_t cb, void *data) { - errno = ENOTSUP; - return -1; + return -ENOTSUP; } -long nvme_insert_tls_key_versioned(const char *keyring, const char *key_type, - const char *hostnqn, const char *subsysnqn, - int version, int hmac, - unsigned char *configured_key, int key_len) +int nvme_insert_tls_key_versioned(const char *keyring, const char *key_type, + const char *hostnqn, const char *subsysnqn, + int version, int hmac, + unsigned char *configured_key, int key_len, + long *key) { nvme_msg(NULL, LOG_ERR, "key operations not supported; " "recompile with keyutils support.\n"); - errno = ENOTSUP; - return -1; + return -ENOTSUP; } -long nvme_revoke_tls_key(const char *keyring, const char *key_type, - const char *identity) +int nvme_revoke_tls_key(const char *keyring, const char *key_type, + const char *identity) { nvme_msg(NULL, LOG_ERR, "key operations not supported; " "recompile with keyutils support.\n"); - errno = ENOTSUP; - return -1; + return -ENOTSUP; } int __nvme_import_keys_from_config(nvme_host_t h, nvme_ctrl_t c, @@ -1550,13 +1530,13 @@ int __nvme_import_keys_from_config(nvme_host_t h, nvme_ctrl_t c, } #endif -long nvme_insert_tls_key(const char *keyring, const char *key_type, +int nvme_insert_tls_key(const char *keyring, const char *key_type, const char *hostnqn, const char *subsysnqn, int hmac, - unsigned char *configured_key, int key_len) + unsigned char *configured_key, int key_len, long *key) { return nvme_insert_tls_key_versioned(keyring, key_type, hostnqn, subsysnqn, 0, hmac, - configured_key, key_len); + configured_key, key_len, key); } /* @@ -1571,9 +1551,9 @@ long nvme_insert_tls_key(const char *keyring, const char *key_type, * s: 32 or 48 bytes binary followed by a CRC-32 of the configured PSK * (4 bytes) encoded as base64 */ -char *nvme_export_tls_key_versioned(unsigned char version, unsigned char hmac, - const unsigned char *key_data, - size_t key_len) +int nvme_export_tls_key_versioned(unsigned char version, unsigned char hmac, + const unsigned char *key_data, + size_t key_len, char **encoded_keyp) { unsigned int raw_len, encoded_len, len; unsigned long crc = crc32(0L, NULL, 0); @@ -1583,18 +1563,18 @@ char *nvme_export_tls_key_versioned(unsigned char version, unsigned char hmac, switch (hmac) { case NVME_HMAC_ALG_NONE: if (key_len != 32 && key_len != 48) - goto err_inval; + return -EINVAL; break; case NVME_HMAC_ALG_SHA2_256: if (key_len != 32) - goto err_inval; + return -EINVAL; break; case NVME_HMAC_ALG_SHA2_384: if (key_len != 48) - goto err_inval; + return -EINVAL; break; default: - goto err_inval; + return -EINVAL; } raw_len = key_len; @@ -1607,25 +1587,20 @@ char *nvme_export_tls_key_versioned(unsigned char version, unsigned char hmac, encoded_len = (raw_len * 2) + 20; encoded_key = malloc(encoded_len); - if (!encoded_key) { - errno = ENOMEM; - return NULL; - } + if (!encoded_key) + return -ENOMEM; + memset(encoded_key, 0, encoded_len); len = sprintf(encoded_key, "NVMeTLSkey-%x:%02x:", version, hmac); len += base64_encode(raw_secret, raw_len, encoded_key + len); encoded_key[len++] = ':'; encoded_key[len++] = '\0'; - return encoded_key; - -err_inval: - errno = EINVAL; - return NULL; - + *encoded_keyp = encoded_key; + return 0; } -char *nvme_export_tls_key(const unsigned char *key_data, int key_len) +int nvme_export_tls_key(const unsigned char *key_data, int key_len, char **key) { unsigned char hmac; @@ -1634,13 +1609,14 @@ char *nvme_export_tls_key(const unsigned char *key_data, int key_len) else hmac = NVME_HMAC_ALG_SHA2_384; - return nvme_export_tls_key_versioned(1, hmac, key_data, key_len); + return nvme_export_tls_key_versioned(1, hmac, key_data, key_len, key); } -unsigned char *nvme_import_tls_key_versioned(const char *encoded_key, - unsigned char *version, - unsigned char *hmac, - size_t *key_len) +int nvme_import_tls_key_versioned(const char *encoded_key, + unsigned char *version, + unsigned char *hmac, + size_t *key_len, + unsigned char **keyp) { unsigned char decoded_key[128], *key_data; unsigned int crc = crc32(0L, NULL, 0); @@ -1649,48 +1625,42 @@ unsigned char *nvme_import_tls_key_versioned(const char *encoded_key, size_t len; if (sscanf(encoded_key, "NVMeTLSkey-%d:%02x:*s", - &_version, &_hmac) != 2) { - errno = EINVAL; - return NULL; - } + &_version, &_hmac) != 2) + return -EINVAL; + + if (_version != 1) + return -EINVAL; - if (_version != 1) { - errno = EINVAL; - return NULL; - } *version = _version; len = strlen(encoded_key); switch (_hmac) { case NVME_HMAC_ALG_NONE: if (len != 65 && len != 89) - goto err_inval; + return -EINVAL; break; case NVME_HMAC_ALG_SHA2_256: if (len != 65) - goto err_inval; + return -EINVAL; break; case NVME_HMAC_ALG_SHA2_384: if (len != 89) - goto err_inval; + return -EINVAL; break; default: - errno = EINVAL; - return NULL; + return -EINVAL; } *hmac = _hmac; err = base64_decode(encoded_key + 16, len - 17, decoded_key); - if (err < 0) { - errno = ENOKEY; - return NULL; - } + if (err < 0) + return -ENOKEY; + decoded_len = err; decoded_len -= 4; - if (decoded_len != 32 && decoded_len != 48) { - errno = ENOKEY; - return NULL; - } + if (decoded_len != 32 && decoded_len != 48) + return -ENOKEY; + crc = crc32(crc, decoded_key, decoded_len); key_crc = ((uint32_t)decoded_key[decoded_len]) | ((uint32_t)decoded_key[decoded_len + 1] << 8) | @@ -1699,38 +1669,34 @@ unsigned char *nvme_import_tls_key_versioned(const char *encoded_key, if (key_crc != crc) { nvme_msg(NULL, LOG_ERR, "CRC mismatch (key %08x, crc %08x)", key_crc, crc); - errno = ENOKEY; - return NULL; + return -ENOKEY; } key_data = malloc(decoded_len); - if (!key_data) { - errno = ENOMEM; - return NULL; - } + if (!key_data) + return -ENOMEM; memcpy(key_data, decoded_key, decoded_len); *key_len = decoded_len; - return key_data; - -err_inval: - errno = EINVAL; - return NULL; + *keyp = key_data; + return 0; } -unsigned char *nvme_import_tls_key(const char *encoded_key, int *key_len, - unsigned int *hmac) +int nvme_import_tls_key(const char *encoded_key, int *key_len, + unsigned int *hmac, unsigned char **keyp) { unsigned char version, _hmac; unsigned char *psk; size_t len; + int ret; - psk = nvme_import_tls_key_versioned(encoded_key, &version, - &_hmac, &len); - if (!psk) - return NULL; + ret = nvme_import_tls_key_versioned(encoded_key, &version, + &_hmac, &len, &psk); + if (ret) + return ret; *hmac = _hmac; *key_len = len; - return psk; + *keyp = psk; + return 0; } diff --git a/src/nvme/linux.h b/src/nvme/linux.h index e865a8c8a..c750cddc5 100644 --- a/src/nvme/linux.h +++ b/src/nvme/linux.h @@ -10,6 +10,7 @@ #define _LIBNVME_LINUX_H #include +#include #include #include @@ -22,32 +23,32 @@ /** * nvme_fw_download_seq() - Firmware download sequence - * @fd: File descriptor of nvme device + * @l: Link handle * @size: Total size of the firmware image to transfer * @xfer: Maximum size to send with each partial transfer * @offset: Starting offset to send with this firmware download * @buf: Address of buffer containing all or part of the firmware image. * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_fw_download_seq(int fd, __u32 size, __u32 xfer, __u32 offset, +int nvme_fw_download_seq(nvme_link_t l, __u32 size, __u32 xfer, __u32 offset, void *buf); /** * nvme_get_telemetry_max() - Get telemetry limits - * @fd: File descriptor of nvme device + * @l: Link handle * @da: On success return max supported data area * @max_data_tx: On success set to max transfer chunk supported by the controller * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_get_telemetry_max(int fd, enum nvme_telemetry_da *da, size_t *max_data_tx); +int nvme_get_telemetry_max(nvme_link_t l, enum nvme_telemetry_da *da, size_t *max_data_tx); /** * nvme_get_telemetry_log() - Get specified telemetry log - * @fd: File descriptor of nvme device + * @l: Link handle * @create: Generate new host initated telemetry capture * @ctrl: Get controller Initiated log * @rae: Retain asynchronous events @@ -59,15 +60,15 @@ int nvme_get_telemetry_max(int fd, enum nvme_telemetry_da *da, size_t *max_data_ * The total size allocated can be calculated as: * (nvme_telemetry_log da size + 1) * NVME_LOG_TELEM_BLOCK_SIZE. * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_get_telemetry_log(int fd, bool create, bool ctrl, bool rae, size_t max_data_tx, +int nvme_get_telemetry_log(nvme_link_t l, bool create, bool ctrl, bool rae, size_t max_data_tx, enum nvme_telemetry_da da, struct nvme_telemetry_log **log, size_t *size); /** * nvme_get_ctrl_telemetry() - Get controller telemetry log - * @fd: File descriptor of nvme device + * @l: Link handle * @rae: Retain asynchronous events * @log: On success, set to the value of the allocated and retrieved log. * @da: Log page data area, valid values: &enum nvme_telemetry_da @@ -76,15 +77,15 @@ int nvme_get_telemetry_log(int fd, bool create, bool ctrl, bool rae, size_t max_ * The total size allocated can be calculated as: * (nvme_telemetry_log da size + 1) * NVME_LOG_TELEM_BLOCK_SIZE. * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_get_ctrl_telemetry(int fd, bool rae, struct nvme_telemetry_log **log, +int nvme_get_ctrl_telemetry(nvme_link_t l, bool rae, struct nvme_telemetry_log **log, enum nvme_telemetry_da da, size_t *size); /** * nvme_get_host_telemetry() - Get host telemetry log - * @fd: File descriptor of nvme device + * @l: Link handle * @log: On success, set to the value of the allocated and retrieved log. * @da: Log page data area, valid values: &enum nvme_telemetry_da * @size: Ptr to the telemetry log size, so it can be returned @@ -92,15 +93,15 @@ int nvme_get_ctrl_telemetry(int fd, bool rae, struct nvme_telemetry_log **log, * The total size allocated can be calculated as: * (nvme_telemetry_log da size + 1) * NVME_LOG_TELEM_BLOCK_SIZE. * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_get_host_telemetry(int fd, struct nvme_telemetry_log **log, +int nvme_get_host_telemetry(nvme_link_t l, struct nvme_telemetry_log **log, enum nvme_telemetry_da da, size_t *size); /** * nvme_get_new_host_telemetry() - Get new host telemetry log - * @fd: File descriptor of nvme device + * @l: Link handle * @log: On success, set to the value of the allocated and retrieved log. * @da: Log page data area, valid values: &enum nvme_telemetry_da * @size: Ptr to the telemetry log size, so it can be returned @@ -108,10 +109,10 @@ int nvme_get_host_telemetry(int fd, struct nvme_telemetry_log **log, * The total size allocated can be calculated as: * (nvme_telemetry_log da size + 1) * NVME_LOG_TELEM_BLOCK_SIZE. * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_get_new_host_telemetry(int fd, struct nvme_telemetry_log **log, +int nvme_get_new_host_telemetry(nvme_link_t l, struct nvme_telemetry_log **log, enum nvme_telemetry_da da, size_t *size); /** @@ -126,71 +127,129 @@ size_t nvme_get_ana_log_len_from_id_ctrl(const struct nvme_id_ctrl *id_ctrl, /** * nvme_get_ana_log_len() - Retrieve size of the current ANA log - * @fd: File descriptor of nvme device + * @l: Link handle * @analen: Pointer to where the length will be set on success * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_get_ana_log_len(int fd, size_t *analen); +int nvme_get_ana_log_len(nvme_link_t l, size_t *analen); /** * nvme_get_logical_block_size() - Retrieve block size - * @fd: File descriptor of nvme device + * @l: Link handle * @nsid: Namespace id * @blksize: Pointer to where the block size will be set on success * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_get_logical_block_size(int fd, __u32 nsid, int *blksize); +int nvme_get_logical_block_size(nvme_link_t l, __u32 nsid, int *blksize); /** * nvme_get_lba_status_log() - Retrieve the LBA Status log page - * @fd: File descriptor of the nvme device + * @l: Link handle * @rae: Retain asynchronous events * @log: On success, set to the value of the allocated and retrieved log. * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_get_lba_status_log(int fd, bool rae, struct nvme_lba_status_log **log); +int nvme_get_lba_status_log(nvme_link_t l, bool rae, struct nvme_lba_status_log **log); /** * nvme_namespace_attach_ctrls() - Attach namespace to controller(s) - * @fd: File descriptor of nvme device + * @l: Link handle * @nsid: Namespace ID to attach * @num_ctrls: Number of controllers in ctrlist * @ctrlist: List of controller IDs to perform the attach action * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_namespace_attach_ctrls(int fd, __u32 nsid, __u16 num_ctrls, __u16 *ctrlist); +int nvme_namespace_attach_ctrls(nvme_link_t l, __u32 nsid, __u16 num_ctrls, __u16 *ctrlist); /** * nvme_namespace_detach_ctrls() - Detach namespace from controller(s) - * @fd: File descriptor of nvme device + * @l: Link handle * @nsid: Namespace ID to detach * @num_ctrls: Number of controllers in ctrlist * @ctrlist: List of controller IDs to perform the detach action * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. + * Return: 0 on success, the nvme command status if a response was + * received (see &enum nvme_status_field) or a negative error otherwise. */ -int nvme_namespace_detach_ctrls(int fd, __u32 nsid, __u16 num_ctrls, __u16 *ctrlist); +int nvme_namespace_detach_ctrls(nvme_link_t l, __u32 nsid, __u16 num_ctrls, __u16 *ctrlist); /** * nvme_open() - Open an nvme controller or namespace device + * @r: &nvme_root_t object * @name: The basename of the device to open + * @l: Link object to return * * This will look for the handle in /dev/ and validate the name and filetype * match linux conventions. * - * Return: A file descriptor for the device on a successful open, or -1 with - * errno set otherwise. + * Return: 0 on success or negative error code otherwise */ -int nvme_open(const char *name); +int nvme_open(nvme_root_t r, const char *name, nvme_link_t *l); + +/** + * nvme_close() - Close link handle + * @l: Link handle + */ +void nvme_close(nvme_link_t l); + +/** + * nvme_link_get_fd - Return file descriptor for link handle + * @l: Link handle + * + * If the device handle is for a ioctl based device, nvme_link_get_fd + * will return a valid file descriptor. + * + * Return: File descriptor for an IOCTL based link handle, otherwise -1. + */ +int nvme_link_get_fd(nvme_link_t l); + +/** + * nvme_link_is_blkdev - Check if link handle is a block device + * @l: Link handle + * + * Return: Return true if link handle is a block device, otherwise false. + */ +bool nvme_link_is_blkdev(nvme_link_t l); + +/** + * nvme_link_is_chardev - Check if link handle is a char device + * @l: Link handle + * + * Return: Return true if link handle is a char device, otherwise false. + */ +bool nvme_link_is_chardev(nvme_link_t l); + +/** + * nvme_link_is_direct - Check if link handle is using IOCTL interface + * @l: Link handle + * + * Return: Return true if link handle is using IOCTL itnerface, otherwise false. + */ +bool nvme_link_is_direct(nvme_link_t l); + +/** + * nvme_link_is_mi - Check if link handle is a using MI interface + * @l: Link handle + * + * Return: Return true if link handle is using MI interface, otherwise false. + */ +bool nvme_link_is_mi(nvme_link_t l); + +/** + * nvme_link_get_name - Return name of the device link handle + * @l: Link handle + * + * Return: Device file name, otherwise -1. + */ +const char *nvme_link_get_name(nvme_link_t l); /** * enum nvme_hmac_alg - HMAC algorithm @@ -215,7 +274,7 @@ enum nvme_hmac_alg { * @key: Generated DH-HMAC-CHAP key * * Return: If key generation was successful the function returns 0 or - * -1 with errno set otherwise. + * a negative error code otherwise. */ int nvme_gen_dhchap_key(char *hostnqn, enum nvme_hmac_alg hmac, unsigned int key_len, unsigned char *secret, @@ -224,13 +283,13 @@ int nvme_gen_dhchap_key(char *hostnqn, enum nvme_hmac_alg hmac, /** * nvme_lookup_keyring() - Lookup keyring serial number * @keyring: Keyring name + * @key: Key serial number to return * * Looks up the serial number of the keyring @keyring. * - * Return: The key serial number of the keyring - * or 0 with errno set otherwise. + * Return: 0 on success or negative error code otherwise */ -long nvme_lookup_keyring(const char *keyring); +int nvme_lookup_keyring(const char *keyring, long *key); /** * nvme_describe_key_serial() - Return key description @@ -246,16 +305,16 @@ char *nvme_describe_key_serial(long key_id); /** * nvme_lookup_key() - Lookup key serial number - * @type: Key type - * @identity: Key description + * @type: Key type + * @identity: Key description + * @key: Key serial number to return * * Looks up the serial number of the key @identity * with type %type in the current session keyring. * - * Return: The key serial number of the key - * or 0 with errno set otherwise. + * Return: 0 on success or negative error code otherwise */ -long nvme_lookup_key(const char *type, const char *identity); +int nvme_lookup_key(const char *type, const char *identity, long *key); /** * nvme_set_keyring() - Link keyring for lookup @@ -264,45 +323,46 @@ long nvme_lookup_key(const char *type, const char *identity); * Links @keyring_id into the session keyring such that * its keys are available for further key lookups. * - * Return: 0 on success, a negative number on error - * with errno set. + * Return: 0 on success or negative error code otherwise */ int nvme_set_keyring(long keyring_id); /** * nvme_read_key() - Read key raw data - * @keyring_id: Id of the keyring holding %key_id - * @key_id: Key id - * @len: Length of the returned data + * @keyring_id: Id of the keyring holding %key_id + * @key_id: Key id + * @len: Length of the returned data + * @key: Key serial to return * * Links the keyring specified by @keyring_id into the session * keyring and reads the payload of the key specified by @key_id. * @len holds the size of the returned buffer. * If @keyring is 0 the default keyring '.nvme' is used. * - * Return: Pointer to the payload on success, - * or NULL with errno set otherwise. + * Return: 0 on success or negative error code otherwise */ -unsigned char *nvme_read_key(long keyring_id, long key_id, int *len); +int nvme_read_key(long keyring_id, long key_id, int *len, + unsigned char **key); /** * nvme_update_key() - Update key raw data - * @keyring_id: Id of the keyring holding %key_id - * @key_type: Type of the key to insert - * @identity: Key identity string - * @key_data: Raw data of the key - * @key_len: Length of @key_data + * @keyring_id: Id of the keyring holding %key_id + * @key_type: Type of the key to insert + * @identity: Key identity string + * @key_data: Raw data of the key + * @key_len: Length of @key_data + * @key: Key serial to return * * Links the keyring specified by @keyring_id into the session * keyring and updates the key reference by @identity with @key_data. * The old key with identity @identity will be revoked to make it * inaccessible. * - * Return: Key id of the new key or 0 with errno set otherwise. + * Return: 0 on success or negative error code otherwise */ -long nvme_update_key(long keyring_id, const char *key_type, - const char *identity, unsigned char *key_data, - int key_len); +int nvme_update_key(long keyring_id, const char *key_type, + const char *identity, unsigned char *key_data, + int key_len, long *key); /** * typedef nvme_scan_tls_keys_cb_t - Callback for iterating TLS keys @@ -329,31 +389,30 @@ typedef void (*nvme_scan_tls_keys_cb_t)(long keyring, long key, * form 'NVMe<0|1>0<1|2> ', otherwise it will be skipped * during iteration. * - * Return: Number of keys for which @cb was called, or -1 with errno set - * on error. + * Return: Number of keys for which @cb was called, or negative error code */ int nvme_scan_tls_keys(const char *keyring, nvme_scan_tls_keys_cb_t cb, void *data); /** * nvme_insert_tls_key() - Derive and insert TLS key - * @keyring: Keyring to use + * @keyring: Keyring to use * @key_type: Type of the resulting key * @hostnqn: Host NVMe Qualified Name * @subsysnqn: Subsystem NVMe Qualified Name * @hmac: HMAC algorithm * @configured_key: Configured key data to derive the key from * @key_len: Length of @configured_key + * @key: Key serial to return * * Derives a 'retained' TLS key as specified in NVMe TCP 1.0a and * stores it as type @key_type in the keyring specified by @keyring. * - * Return: The key serial number if the key could be inserted into - * the keyring or 0 with errno otherwise. + * Return: 0 on success or negative error code otherwise */ -long nvme_insert_tls_key(const char *keyring, const char *key_type, +int nvme_insert_tls_key(const char *keyring, const char *key_type, const char *hostnqn, const char *subsysnqn, int hmac, - unsigned char *configured_key, int key_len); + unsigned char *configured_key, int key_len, long *key); /** * nvme_insert_tls_key_versioned() - Derive and insert TLS key @@ -365,18 +424,19 @@ long nvme_insert_tls_key(const char *keyring, const char *key_type, * @hmac: HMAC algorithm * @configured_key: Configured key data to derive the key from * @key_len: Length of @configured_key + * @key: Key serial to return * * Derives a 'retained' TLS key as specified in NVMe TCP 1.0a (if * @version s set to '0') or NVMe TP8028 (if @version is set to '1) and * stores it as type @key_type in the keyring specified by @keyring. * - * Return: The key serial number if the key could be inserted into - * the keyring or 0 with errno otherwise. + * Return: 0 on success or negative error code otherwise */ -long nvme_insert_tls_key_versioned(const char *keyring, const char *key_type, - const char *hostnqn, const char *subsysnqn, - int version, int hmac, - unsigned char *configured_key, int key_len); +int nvme_insert_tls_key_versioned(const char *keyring, const char *key_type, + const char *hostnqn, const char *subsysnqn, + int version, int hmac, + unsigned char *configured_key, int key_len, + long *key); /** * nvme_generate_tls_key_identity() - Generate the TLS key identity @@ -386,16 +446,19 @@ long nvme_insert_tls_key_versioned(const char *keyring, const char *key_type, * @hmac: HMAC algorithm * @configured_key: Configured key data to derive the key from * @key_len: Length of @configured_key + * @identity: TLS identity to return * * Derives a 'retained' TLS key as specified in NVMe TCP and * generate the corresponding TLs identity. * - * Return: The string containing the TLS identity. It is the responsibility - * of the caller to free the returned string. + * It is the responsibility of the caller to free the returned string. + * + * Return: 0 on success or negative error code otherwise */ -char *nvme_generate_tls_key_identity(const char *hostnqn, const char *subsysnqn, - int version, int hmac, - unsigned char *configured_key, int key_len); +int nvme_generate_tls_key_identity(const char *hostnqn, const char *subsysnqn, + int version, int hmac, + unsigned char *configured_key, int key_len, + char **identity); /** * nvme_revoke_tls_key() - Revoke TLS key from keyring @@ -403,24 +466,26 @@ char *nvme_generate_tls_key_identity(const char *hostnqn, const char *subsysnqn, * @key_type: Type of the key to revoke * @identity: Key identity string * - * Return: 0 on success or on failure -1 with errno set. + * Return: 0 on success or negative error code otherwise */ -long nvme_revoke_tls_key(const char *keyring, const char *key_type, - const char *identity); +int nvme_revoke_tls_key(const char *keyring, const char *key_type, + const char *identity); /** * nvme_export_tls_key() - Export a TLS key * @key_data: Raw data of the key * @key_len: Length of @key_data + * @identity: TLS identity * * Returns @key_data in the PSK Interchange format as defined in section * 3.6.1.5 of the NVMe TCP Transport specification. * - * Return: The string containing the TLS identity or NULL with errno set - * on error. It is the responsibility of the caller to free the returned + * It is the responsibility of the caller to free the returned * string. + * + * Return: 0 on success or negative error code otherwise */ -char *nvme_export_tls_key(const unsigned char *key_data, int key_len); +int nvme_export_tls_key(const unsigned char *key_data, int key_len, char **identity); /** * nvme_export_tls_key_versioned() - Export a TLS pre-shared key @@ -429,32 +494,36 @@ char *nvme_export_tls_key(const unsigned char *key_data, int key_len); * in a retained PSK * @key_data: Raw data of the key * @key_len: Length of @key_data + * @identity: TLS identity to return * * Returns @key_data in the PSK Interchange format as defined in section * 3.6.1.5 of the NVMe TCP Transport specification. * - * Return: The string containing the TLS identity or NULL with errno set - * on error. It is the responsibility of the caller to free the returned + * It is the responsibility of the caller to free the returned * string. + * + * Return: 0 on success or negative error code otherwise */ -char *nvme_export_tls_key_versioned(unsigned char version, unsigned char hmac, - const unsigned char *key_data, - size_t key_len); +int nvme_export_tls_key_versioned(unsigned char version, unsigned char hmac, + const unsigned char *key_data, + size_t key_len, char **identity); /** * nvme_import_tls_key() - Import a TLS key * @encoded_key: TLS key in PSK interchange format * @key_len: Length of the resulting key data * @hmac: HMAC algorithm + * @key: Key serial to return * * Imports @key_data in the PSK Interchange format as defined in section * 3.6.1.5 of the NVMe TCP Transport specification. * - * Return: The raw data of the PSK or NULL with errno set on error. It is - * the responsibility of the caller to free the returned string. + * It is the responsibility of the caller to free the returned string. + * + * Return: 0 on success or negative error code otherwise */ -unsigned char *nvme_import_tls_key(const char *encoded_key, int *key_len, - unsigned int *hmac); +int nvme_import_tls_key(const char *encoded_key, int *key_len, + unsigned int *hmac, unsigned char **key); /** * nvme_import_tls_key_versioned() - Import a TLS key @@ -463,20 +532,23 @@ unsigned char *nvme_import_tls_key(const char *encoded_key, int *key_len, * @hmac: HMAC algorithm used to transfor the configured * PSK in a retained PSK * @key_len: Length of the resulting key data + * @key: Key serial to return * * Imports @key_data in the PSK Interchange format as defined in section * 3.6.1.5 of the NVMe TCP Transport specification. * - * Return: The raw data of the PSK or NULL with errno set on error. It is - * the responsibility of the caller to free the returned string. + * It is the responsibility of the caller to free the returned string. + * + * Return: 0 on success or negative error code otherwise */ -unsigned char *nvme_import_tls_key_versioned(const char *encoded_key, - unsigned char *version, - unsigned char *hmac, - size_t *key_len); +int nvme_import_tls_key_versioned(const char *encoded_key, + unsigned char *version, + unsigned char *hmac, + size_t *key_len, + unsigned char **key); /** * nvme_submit_passthru - Low level ioctl wrapper for passthru commands - * @fd: File descriptor of the nvme device + * @l: Link handle * @ioctl_cmd: IOCTL command id * @cmd: Passhtru command * @result: Optional field to return the result @@ -485,15 +557,16 @@ unsigned char *nvme_import_tls_key_versioned(const char *encoded_key, * exposed as weak symbol so that the user application is able to provide their own * implementation of this function with additional debugging or logging code. * - * Return: The value from the ioctl system call (see ioctl documentation) + * Return: The value from the ioctl system call (see ioctl documentation) or + * a negative error code otherwise. */ __attribute__((weak)) -int nvme_submit_passthru(int fd, unsigned long ioctl_cmd, +int nvme_submit_passthru(nvme_link_t l, unsigned long ioctl_cmd, struct nvme_passthru_cmd *cmd, __u32 *result); /** * nvme_submit_passthru64 - Low level ioctl wrapper for passthru commands - * @fd: File descriptor of the nvme device + * @l: Link handle * @ioctl_cmd: IOCTL command id * @cmd: Passhtru command * @result: Optional field to return the result @@ -502,10 +575,11 @@ int nvme_submit_passthru(int fd, unsigned long ioctl_cmd, * exposed as weak symbol so that the user application is able to provide their own * implementation of this function with additional debugging or logging code. * - * Return: The value from the ioctl system call (see ioctl documentation) + * Return: The value from the ioctl system call (see ioctl documentation) or + * a negative error code otherwise. */ __attribute__((weak)) -int nvme_submit_passthru64(int fd, unsigned long ioctl_cmd, +int nvme_submit_passthru64(nvme_link_t l, unsigned long ioctl_cmd, struct nvme_passthru_cmd64 *cmd, __u64 *result); diff --git a/src/nvme/log.h b/src/nvme/log.h index 5a2f81c1b..cd0d5f8de 100644 --- a/src/nvme/log.h +++ b/src/nvme/log.h @@ -69,7 +69,7 @@ int nvme_get_logging_level(nvme_root_t r, bool *log_pid, bool *log_tstamp); * via the arguments use the the default one which can be set via this call. * When creating a new root object with @nvme_create_root the global root object * will be set as well. This means the global root object is always pointing to - * the latest created root object. Note the first @nvme_free_tree call will reset + * the latest created root object. Note the first @nvme_free_root call will reset * the global root object. * * This function is deprecated. Use nvme_init_default_logging or/and diff --git a/src/nvme/mi.c b/src/nvme/mi.c index 14c71d75e..43511bf5e 100644 --- a/src/nvme/mi.c +++ b/src/nvme/mi.c @@ -19,6 +19,7 @@ #include "log.h" #include "mi.h" +#include "linux.h" #include "private.h" #define NUM_ENABLES (256u) @@ -56,6 +57,61 @@ static bool nvme_mi_probe_enabled_default(void) } +static int parse_devname(const char *dev, unsigned int *net, uint8_t *eid, + unsigned int *ctrl) +{ + int rc; + + /* ,: form */ + rc = sscanf(dev, "mctp:%u,%hhu:%u", net, eid, ctrl); + if (rc == 3) + return 0; + + /* , form, implicit ctrl-id = 0 */ + *ctrl = 0; + rc = sscanf(dev, "mctp:%u,%hhu", net, eid); + if (rc == 2) + return 0; + + return -EINVAL; +} + +int __nvme_link_init_mi(nvme_link_t l) +{ + if (l->type != NVME_LINK_TYPE_UNKNOWN) + return -EALREADY; + + l->type = NVME_LINK_TYPE_MI; + + return 0; +} + +int __nvme_link_open_mi(nvme_link_t l, const char *devname) +{ + unsigned int rc, net, ctrl_id; + unsigned char eid; + struct nvme_mi_ep *ep; + + rc = __nvme_link_init_mi(l); + if (rc) + return rc; + + rc = parse_devname(devname, &net, &eid, &ctrl_id); + return rc; + + ep = nvme_mi_open_mctp(l->root, net, eid); + if (!ep) + return -EINVAL; + + return 0; +} + +void __nvme_link_close_mi(nvme_link_t link) +{ + list_del(&link->ep_entry); + free(link); +} + /* MI-equivalent of nvme_create_root, but avoids clashing symbol names * when linking against both libnvme and libnvme-mi. */ @@ -65,10 +121,8 @@ nvme_root_t nvme_mi_create_root(FILE *fp, int log_level) int fd; r = calloc(1, sizeof(*r)); - if (!r) { - errno = ENOMEM; + if (!r) return NULL; - } if (fp) { fd = fileno(fp); @@ -157,9 +211,8 @@ static void __nvme_mi_format_mn(struct nvme_id_ctrl *id, void nvme_mi_ep_probe(struct nvme_mi_ep *ep) { - struct nvme_identify_args id_args = { 0 }; struct nvme_id_ctrl id = { 0 }; - struct nvme_mi_ctrl *ctrl; + struct nvme_link *link; int rc; /* Ensure the probe occurs at most once. This isn't just to mitigate doubling @@ -182,8 +235,8 @@ void nvme_mi_ep_probe(struct nvme_mi_ep *ep) /* start with no quirks, detect as we go */ ep->quirks = 0; - ctrl = nvme_mi_init_ctrl(ep, 0); - if (!ctrl) + link = nvme_mi_init_link(ep, 0); + if (!link) return; /* Do enough of an identify (assuming controller 0) to retrieve @@ -198,15 +251,9 @@ void nvme_mi_ep_probe(struct nvme_mi_ep *ep) * * all other fields - rab and onwards - will be zero! */ - id_args.args_size = sizeof(id_args); - id_args.data = &id; - id_args.cns = NVME_IDENTIFY_CNS_CTRL; - id_args.nsid = NVME_NSID_NONE; - id_args.cntid = 0; - id_args.csi = NVME_CSI_NVM; - - rc = nvme_mi_admin_identify_partial(ctrl, &id_args, 0, - offsetof(struct nvme_id_ctrl, rab)); + rc = nvme_identify_partial(link, NVME_NSID_NONE, 0, NVME_IDENTIFY_CNS_CTRL, + NVME_CSI_NVM, 0, 0, &id, + offsetof(struct nvme_id_ctrl, rab), NULL); if (rc) { nvme_msg(ep->root, LOG_WARNING, "Identify Controller failed, no quirks applied\n"); @@ -238,7 +285,7 @@ void nvme_mi_ep_probe(struct nvme_mi_ep *ep) } out_close: - nvme_mi_close_ctrl(ctrl); + nvme_close(link); } static const int nsec_per_sec = 1000 * 1000 * 1000; @@ -337,25 +384,27 @@ static bool nvme_mi_ep_has_quirk(nvme_mi_ep_t ep, unsigned long quirk) return ep->quirks & quirk; } -struct nvme_mi_ctrl *nvme_mi_init_ctrl(nvme_mi_ep_t ep, __u16 ctrl_id) +struct nvme_link *nvme_mi_init_link(nvme_mi_ep_t ep, __u16 ctrl_id) { - struct nvme_mi_ctrl *ctrl; + struct nvme_link *link; - ctrl = malloc(sizeof(*ctrl)); - if (!ctrl) - return NULL; + link = __nvme_create_link(ep->root); + if (!link) + NULL; - ctrl->ep = ep; - ctrl->id = ctrl_id; + __nvme_link_init_mi(link); - list_add_tail(&ep->controllers, &ctrl->ep_entry); + link->ep = ep; + link->id = ctrl_id; - return ctrl; + list_add_tail(&ep->controllers, &link->ep_entry); + + return link; } -__u16 nvme_mi_ctrl_id(nvme_mi_ctrl_t ctrl) +__u16 nvme_mi_ctrl_id(nvme_link_t link) { - return ctrl->id; + return link->id; } int nvme_mi_scan_ep(nvme_mi_ep_t ep, bool force_rescan) @@ -366,9 +415,9 @@ int nvme_mi_scan_ep(nvme_mi_ep_t ep, bool force_rescan) if (ep->controllers_scanned) { if (force_rescan) { - struct nvme_mi_ctrl *ctrl, *tmp; - nvme_mi_for_each_ctrl_safe(ep, ctrl, tmp) - nvme_mi_close_ctrl(ctrl); + struct nvme_link *link, *tmp; + nvme_mi_for_each_link_safe(ep, link, tmp) + nvme_close(link); } else { return 0; } @@ -379,19 +428,17 @@ int nvme_mi_scan_ep(nvme_mi_ep_t ep, bool force_rescan) return rc; n_ctrl = le16_to_cpu(list.num); - if (n_ctrl > NVME_ID_CTRL_LIST_MAX) { - errno = EPROTO; - return -1; - } + if (n_ctrl > NVME_ID_CTRL_LIST_MAX) + return -EPROTO; for (i = 0; i < n_ctrl; i++) { - struct nvme_mi_ctrl *ctrl; + struct nvme_link *link; __u16 id; id = le16_to_cpu(list.identifier[i]); - ctrl = nvme_mi_init_ctrl(ep, id); - if (!ctrl) + link = nvme_mi_init_link(ep, id); + if (!link) break; } @@ -450,7 +497,7 @@ int nvme_mi_async_read(nvme_mi_ep_t ep, struct nvme_mi_resp *resp) int rc = ep->transport->aem_read(ep, resp); - if (rc && errno == EWOULDBLOCK) { + if (rc == EWOULDBLOCK) { //Sometimes we might get owned tag data from the wrong endpoint. //This isn't an error, but we shouldn't process it here resp->data_len = 0;//No data to process @@ -464,8 +511,7 @@ int nvme_mi_async_read(nvme_mi_ep_t ep, struct nvme_mi_resp *resp) rc = nvme_mi_verify_resp_mic(resp); if (rc) { nvme_msg(ep->root, LOG_WARNING, "crc mismatch\n"); - errno = EBADMSG; - return -1; + return -EBADMSG; } } @@ -475,22 +521,19 @@ int nvme_mi_async_read(nvme_mi_ep_t ep, struct nvme_mi_resp *resp) if (resp->hdr_len < sizeof(struct nvme_mi_msg_hdr)) { nvme_msg(ep->root, LOG_DEBUG, "Bad response header len: %zd\n", resp->hdr_len); - errno = EPROTO; - return -1; + return -EPROTO; } if (resp->hdr->type != NVME_MI_MSGTYPE_NVME) { nvme_msg(ep->root, LOG_DEBUG, "Invalid message type 0x%02x\n", resp->hdr->type); - errno = EPROTO; - return -1; + return -EPROTO; } if (!(resp->hdr->nmp & ~(NVME_MI_ROR_REQ << 7))) { nvme_msg(ep->root, LOG_DEBUG, "ROR value in response indicates a response\n"); - errno = EIO; - return -1; + return -EIO; } if (!(resp->hdr->nmp & (NVME_MI_MT_AE << 3))) { @@ -513,25 +556,17 @@ int nvme_mi_submit(nvme_mi_ep_t ep, struct nvme_mi_req *req, user_data = nvme_mi_submit_entry(req->hdr->type, req->hdr, req->hdr_len, req->data, req->data_len); - if (req->hdr_len < sizeof(struct nvme_mi_msg_hdr)) { - errno = EINVAL; - return -1; - } + if (req->hdr_len < sizeof(struct nvme_mi_msg_hdr)) + return -EINVAL; - if (req->hdr_len & 0x3) { - errno = EINVAL; - return -1; - } + if (req->hdr_len & 0x3) + return -EINVAL; - if (resp->hdr_len < sizeof(struct nvme_mi_msg_hdr)) { - errno = EINVAL; - return -1; - } + if (resp->hdr_len < sizeof(struct nvme_mi_msg_hdr)) + return -EINVAL; - if (resp->hdr_len & 0x3) { - errno = EINVAL; - return -1; - } + if (resp->hdr_len & 0x3) + return -EINVAL; nvme_mi_ep_probe(ep); @@ -555,8 +590,7 @@ int nvme_mi_submit(nvme_mi_ep_t ep, struct nvme_mi_req *req, rc = nvme_mi_verify_resp_mic(resp); if (rc) { nvme_msg(ep->root, LOG_WARNING, "crc mismatch\n"); - errno = EBADMSG; - return -1; + return -EBADMSG; } } @@ -564,22 +598,19 @@ int nvme_mi_submit(nvme_mi_ep_t ep, struct nvme_mi_req *req, if (resp->hdr_len < sizeof(struct nvme_mi_msg_hdr)) { nvme_msg(ep->root, LOG_DEBUG, "Bad response header len: %zd\n", resp->hdr_len); - errno = EPROTO; - return -1; + return -EPROTO; } if (resp->hdr->type != NVME_MI_MSGTYPE_NVME) { nvme_msg(ep->root, LOG_DEBUG, "Invalid message type 0x%02x\n", resp->hdr->type); - errno = EPROTO; - return -1; + return -EPROTO; } if (!(resp->hdr->nmp & (NVME_MI_ROR_RSP << 7))) { nvme_msg(ep->root, LOG_DEBUG, "ROR value in response indicates a request\n"); - errno = EIO; - return -1; + return -EIO; } if ((resp->hdr->nmp & 0x1) != (req->hdr->nmp & 0x1)) { @@ -587,8 +618,7 @@ int nvme_mi_submit(nvme_mi_ep_t ep, struct nvme_mi_req *req, "Command slot mismatch: req %d, resp %d\n", req->hdr->nmp & 0x1, resp->hdr->nmp & 0x1); - errno = EIO; - return -1; + return -EIO; } nvme_mi_submit_exit(resp->hdr->type, resp->hdr, resp->hdr_len, resp->data, resp->data_len, @@ -676,10 +706,8 @@ static int nvme_mi_admin_parse_status(struct nvme_mi_resp *resp, __u32 *result) * the former two generate return values here */ - if (resp->hdr_len < sizeof(*resp_hdr)) { - errno = -EPROTO; - return -1; - } + if (resp->hdr_len < sizeof(*resp_hdr)) + return -EPROTO; resp_hdr = (struct nvme_mi_msg_resp *)resp->hdr; /* If we have a MI error, we can't be sure there's an admin header @@ -693,10 +721,8 @@ static int nvme_mi_admin_parse_status(struct nvme_mi_resp *resp, __u32 *result) /* We shouldn't hit this, as we'd have an error reported earlier. * However, for pointer safety, ensure we have a full admin header */ - if (resp->hdr_len < sizeof(*admin_hdr)) { - errno = EPROTO; - return -1; - } + if (resp->hdr_len < sizeof(*admin_hdr)) + return -EPROTO; admin_hdr = (struct nvme_mi_admin_resp_hdr *)resp->hdr; nvme_result = le32_to_cpu(admin_hdr->cdw0); @@ -718,10 +744,8 @@ static int nvme_mi_control_parse_status(struct nvme_mi_resp *resp, __u16 *cpsr) { struct nvme_mi_control_resp *control_resp; - if (resp->hdr_len < sizeof(*control_resp)) { - errno = -EPROTO; - return -1; - } + if (resp->hdr_len < sizeof(*control_resp)) + return -EPROTO; control_resp = (struct nvme_mi_control_resp *)resp->hdr; if (control_resp->status) @@ -756,7 +780,7 @@ static int nvme_mi_get_async_message(nvme_mi_ep_t ep, } -int nvme_mi_admin_xfer(nvme_mi_ctrl_t ctrl, +int nvme_mi_admin_xfer(nvme_link_t link, struct nvme_mi_admin_req_hdr *admin_req, size_t req_data_size, struct nvme_mi_admin_resp_hdr *admin_resp, @@ -774,42 +798,32 @@ int nvme_mi_admin_xfer(nvme_mi_ctrl_t ctrl, */ /* NVMe-MI v1.2 imposes a limit of 4096 bytes on the dlen field */ - if (*resp_data_size > 4096) { - errno = EINVAL; - return -1; - } + if (*resp_data_size > 4096) + return -EINVAL; /* we only have 32 bits of offset */ - if (resp_data_offset > 0xffffffff) { - errno = EINVAL; - return -1; - } + if (resp_data_offset > 0xffffffff) + return -EINVAL; /* request and response lengths & offset must be aligned */ if ((req_data_size & 0x3) || (*resp_data_size & 0x3) || - (resp_data_offset & 0x3)) { - errno = EINVAL; - return -1; - } + (resp_data_offset & 0x3)) + return -EINVAL; /* bidirectional not permitted (see DLEN definition) */ - if (req_data_size && *resp_data_size) { - errno = EINVAL; - return -1; - } + if (req_data_size && *resp_data_size) + return -EINVAL; - if (!*resp_data_size && resp_data_offset) { - errno = EINVAL; - return -1; - } + if (!*resp_data_size && resp_data_offset) + return -EINVAL; admin_req->hdr.type = NVME_MI_MSGTYPE_NVME; admin_req->hdr.nmp = (NVME_MI_ROR_REQ << 7) | (NVME_MI_MT_ADMIN << 3) | - (ctrl->ep->csi & 1); + (link->ep->csi & 1); - admin_req->ctrl_id = cpu_to_le16(ctrl->id); + admin_req->ctrl_id = cpu_to_le16(link->id); memset(&req, 0, sizeof(req)); req.hdr = &admin_req->hdr; req.hdr_len = sizeof(*admin_req); @@ -836,7 +850,7 @@ int nvme_mi_admin_xfer(nvme_mi_ctrl_t ctrl, admin_req->dlen = cpu_to_le32(dlen); admin_req->doff = cpu_to_le32(doff); - rc = nvme_mi_submit(ctrl->ep, &req, &resp); + rc = nvme_mi_submit(link->ep, &req, &resp); if (rc) return rc; @@ -845,7 +859,7 @@ int nvme_mi_admin_xfer(nvme_mi_ctrl_t ctrl, return 0; } -int nvme_mi_admin_admin_passthru(nvme_mi_ctrl_t ctrl, __u8 opcode, __u8 flags, +int nvme_mi_admin_admin_passthru(nvme_link_t link, __u8 opcode, __u8 flags, __u16 rsvd, __u32 nsid, __u32 cdw2, __u32 cdw3, __u32 cdw10, __u32 cdw11, __u32 cdw12, __u32 cdw13, __u32 cdw14, __u32 cdw15, @@ -864,17 +878,15 @@ int nvme_mi_admin_admin_passthru(nvme_mi_ctrl_t ctrl, __u8 opcode, __u8 flags, bool has_read_data = false; if (direction == NVME_DATA_TFR_BIDIRECTIONAL) { - nvme_msg(ctrl->ep->root, LOG_ERR, + nvme_msg(link->root, LOG_ERR, "nvme_mi_admin_admin_passthru doesn't support bidirectional commands\n"); - errno = EINVAL; - return -1; + return -EINVAL; } if (data_len > 4096) { - nvme_msg(ctrl->ep->root, LOG_ERR, + nvme_msg(link->root, LOG_ERR, "nvme_mi_admin_admin_passthru doesn't support data_len over 4096 bytes.\n"); - errno = EINVAL; - return -1; + return -EINVAL; } if (data != NULL && data_len != 0) { @@ -884,7 +896,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(ctrl->ep, &req, &req_hdr, ctrl->id, opcode); + nvme_mi_admin_init_req(link->ep, &req, &req_hdr, link->id, opcode); req_hdr.cdw1 = cpu_to_le32(nsid); req_hdr.cdw2 = cpu_to_le32(cdw2); req_hdr.cdw3 = cpu_to_le32(cdw3); @@ -917,12 +929,12 @@ int nvme_mi_admin_admin_passthru(nvme_mi_ctrl_t ctrl, __u8 opcode, __u8 flags, * timeout and override */ if (timeout_ms != 0) { - timeout_save = nvme_mi_ep_get_timeout(ctrl->ep); - nvme_mi_ep_set_timeout(ctrl->ep, timeout_ms); + timeout_save = nvme_mi_ep_get_timeout(link->ep); + nvme_mi_ep_set_timeout(link->ep, timeout_ms); } - rc = nvme_mi_submit(ctrl->ep, &req, &resp); + rc = nvme_mi_submit(link->ep, &req, &resp); if (timeout_ms != 0) - nvme_mi_ep_set_timeout(ctrl->ep, timeout_save); + nvme_mi_ep_set_timeout(link->ep, timeout_save); if (rc) return rc; @@ -931,65 +943,8 @@ int nvme_mi_admin_admin_passthru(nvme_mi_ctrl_t ctrl, __u8 opcode, __u8 flags, if (rc) return rc; - if (has_read_data && (resp.data_len != data_len)) { - errno = EPROTO; - return -1; - } - - return 0; -} - -int nvme_mi_admin_identify_partial(nvme_mi_ctrl_t ctrl, - struct nvme_identify_args *args, - off_t offset, size_t size) -{ - struct nvme_mi_admin_resp_hdr resp_hdr; - struct nvme_mi_admin_req_hdr req_hdr; - struct nvme_mi_resp resp; - struct nvme_mi_req req; - int rc; - - if (args->args_size < sizeof(*args)) { - errno = EINVAL; - return -1; - } - - if (!size || size > 0xffffffff) { - errno = EINVAL; - return -1; - } - - 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 | - args->cns_specific_id); - req_hdr.cdw14 = cpu_to_le32(args->uuidx); - req_hdr.dlen = cpu_to_le32(size & 0xffffffff); - req_hdr.flags = 0x1; - if (offset) { - req_hdr.flags |= 0x2; - req_hdr.doff = cpu_to_le32(offset); - } - - nvme_mi_admin_init_resp(&resp, &resp_hdr); - resp.data = args->data; - resp.data_len = size; - - rc = nvme_mi_submit(ctrl->ep, &req, &resp); - if (rc) - return rc; - - rc = nvme_mi_admin_parse_status(&resp, args->result); - if (rc) - return rc; - - /* callers will expect a full response; if the data buffer isn't - * fully valid, return an error */ - if (resp.data_len != size) { - errno = EPROTO; - return -1; - } + if (has_read_data && (resp.data_len != data_len)) + return -EPROTO; return 0; } @@ -1017,714 +972,6 @@ int nvme_mi_control(nvme_mi_ep_t ep, __u8 opcode, return 0; } -/* retrieves a MCTP-messsage-sized chunk of log page data. offset and len are - * specified within the args->data area. The `offset` parameter is a relative - * offset to the args->lpo ! - * - * What's more, we change the LPO of original command to chunk the request - * message into proper size which is allowed by MI interface. One reason is that - * this option seems to be supported better by devices. For more information - * about this option, please check https://github.com/linux-nvme/libnvme/pull/539 - * */ -static int __nvme_mi_admin_get_log(nvme_mi_ctrl_t ctrl, - const struct nvme_get_log_args *args, - off_t offset, size_t *lenp, bool final) -{ - __u64 log_page_offset = args->lpo + offset; - struct nvme_mi_admin_resp_hdr resp_hdr; - struct nvme_mi_admin_req_hdr req_hdr; - struct nvme_mi_resp resp; - struct nvme_mi_req req; - size_t len; - __u32 ndw; - int rc; - - /* MI spec requires that the data length field is less than or equal - * to 4096 */ - len = *lenp; - if (!len || len > 4096 || len < 4) { - errno = EINVAL; - return -1; - } - - if (offset < 0 || offset >= args->len || offset + len > args->len) { - errno = EINVAL; - return -1; - } - - ndw = (len >> 2) - 1; - - 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 | - args->lsp << 8 | - (args->lid & 0xff)); - req_hdr.cdw11 = cpu_to_le32(args->lsi << 16 | - ndw >> 16); - req_hdr.cdw12 = cpu_to_le32(log_page_offset & 0xffffffff); - req_hdr.cdw13 = cpu_to_le32(log_page_offset >> 32); - req_hdr.cdw14 = cpu_to_le32(args->csi << 24 | - (args->ot ? 1 : 0) << 23 | - args->uuidx); - req_hdr.flags = 0x1; - req_hdr.dlen = cpu_to_le32(len & 0xffffffff); - - nvme_mi_admin_init_resp(&resp, &resp_hdr); - resp.data = args->log + offset; - resp.data_len = len; - - rc = nvme_mi_submit(ctrl->ep, &req, &resp); - if (rc) - return rc; - - rc = nvme_mi_admin_parse_status(&resp, args->result); - if (!rc) - *lenp = resp.data_len; - - return rc; -} - -int nvme_mi_admin_get_log_page(nvme_mi_ctrl_t ctrl, __u32 xfer_size, - struct nvme_get_log_args *args) -{ - const size_t max_xfer_size = xfer_size; - off_t xfer_offset; - int rc = 0; - - if (args->args_size < sizeof(*args)) { - errno = EINVAL; - return -1; - } - - if (args->ot && (args->len > max_xfer_size)) { - errno = EINVAL; - return -1; - } - - for (xfer_offset = 0; xfer_offset < args->len;) { - size_t xfered_size, cur_xfer_size = max_xfer_size; - bool final; - - if (xfer_offset + cur_xfer_size > args->len) - cur_xfer_size = args->len - xfer_offset; - - xfered_size = cur_xfer_size; - - final = xfer_offset + cur_xfer_size >= args->len; - - /* xfered_size is used as both input and output parameter */ - rc = __nvme_mi_admin_get_log(ctrl, args, xfer_offset, - &xfered_size, final); - if (rc) - break; - - xfer_offset += xfered_size; - /* if we returned less data than expected, consider that - * the end of the log page */ - if (xfered_size != cur_xfer_size) - break; - } - - if (!rc) - args->len = xfer_offset; - - return rc; -} - -int nvme_mi_admin_get_log(nvme_mi_ctrl_t ctrl, struct nvme_get_log_args *args) -{ - return nvme_mi_admin_get_log_page(ctrl, 4096, args); -} - -static int read_ana_chunk(nvme_mi_ctrl_t ctrl, enum nvme_log_ana_lsp lsp, bool rae, - __u8 *log, __u8 **read, __u8 *to_read, __u8 *log_end) -{ - if (to_read > log_end) { - errno = ENOSPC; - return -1; - } - - while (*read < to_read) { - __u32 len = min_t(__u32, log_end - *read, NVME_LOG_PAGE_PDU_SIZE); - int ret; - - ret = nvme_mi_admin_get_log_ana(ctrl, lsp, rae, - *read - log, len, *read); - if (ret) - return ret; - - *read += len; - } - return 0; -} - -static int try_read_ana(nvme_mi_ctrl_t ctrl, enum nvme_log_ana_lsp lsp, bool rae, - struct nvme_ana_log *log, __u8 *log_end, - __u8 *read, __u8 **to_read, bool *may_retry) -{ - __u16 ngrps = le16_to_cpu(log->ngrps); - - while (ngrps--) { - __u8 *group = *to_read; - int ret; - __le32 nnsids; - - *to_read += sizeof(*log->descs); - ret = read_ana_chunk(ctrl, lsp, rae, - (__u8 *)log, &read, *to_read, log_end); - if (ret) { - /* - * If the provided buffer isn't long enough, - * the log page may have changed while reading it - * and the computed length was inaccurate. - * Have the caller check chgcnt and retry. - */ - *may_retry = errno == ENOSPC; - return ret; - } - - /* - * struct nvme_ana_group_desc has 8-byte alignment - * but the group pointer is only 4-byte aligned. - * Don't dereference the misaligned pointer. - */ - memcpy(&nnsids, - group + offsetof(struct nvme_ana_group_desc, nnsids), - sizeof(nnsids)); - *to_read += le32_to_cpu(nnsids) * sizeof(__le32); - ret = read_ana_chunk(ctrl, lsp, rae, - (__u8 *)log, &read, *to_read, log_end); - if (ret) { - *may_retry = errno == ENOSPC; - return ret; - } - } - - *may_retry = true; - return 0; -} - -int nvme_mi_admin_get_ana_log_atomic(nvme_mi_ctrl_t ctrl, bool rgo, bool rae, - unsigned int retries, - struct nvme_ana_log *log, __u32 *len) -{ - const enum nvme_log_ana_lsp lsp = - rgo ? NVME_LOG_ANA_LSP_RGO_GROUPS_ONLY : 0; - /* Get Log Page can only fetch multiples of dwords */ - __u8 * const log_end = (__u8 *)log + (*len & -4); - __u8 *read = (__u8 *)log; - __u8 *to_read; - int ret; - - if (!retries) { - errno = EINVAL; - return -1; - } - - to_read = (__u8 *)log->descs; - ret = read_ana_chunk(ctrl, lsp, rae, - (__u8 *)log, &read, to_read, log_end); - if (ret) - return ret; - - do { - bool may_retry = false; - int saved_ret; - int saved_errno; - __le64 chgcnt; - - saved_ret = try_read_ana(ctrl, lsp, rae, log, log_end, - read, &to_read, &may_retry); - /* - * If the log page was read with multiple Get Log Page commands, - * chgcnt must be checked afterwards to ensure atomicity - */ - *len = to_read - (__u8 *)log; - if (*len <= NVME_LOG_PAGE_PDU_SIZE || !may_retry) - return saved_ret; - - saved_errno = errno; - chgcnt = log->chgcnt; - read = (__u8 *)log; - to_read = (__u8 *)log->descs; - ret = read_ana_chunk(ctrl, lsp, rae, - (__u8 *)log, &read, to_read, log_end); - if (ret) - return ret; - - if (log->chgcnt == chgcnt) { - /* Log hasn't changed; return try_read_ana() result */ - errno = saved_errno; - return saved_ret; - } - } while (--retries); - - errno = EAGAIN; - return -1; -} - -int nvme_mi_admin_security_send(nvme_mi_ctrl_t ctrl, - struct nvme_security_send_args *args) -{ - - struct nvme_mi_admin_resp_hdr resp_hdr; - struct nvme_mi_admin_req_hdr req_hdr; - struct nvme_mi_resp resp; - struct nvme_mi_req req; - int rc; - - if (args->args_size < sizeof(*args)) { - errno = EINVAL; - return -1; - } - - if (args->data_len > 4096) { - errno = EINVAL; - return -1; - } - - 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 | - args->spsp1 << 16 | - args->spsp0 << 8 | - args->nssf); - - req_hdr.cdw11 = cpu_to_le32(args->data_len & 0xffffffff); - - req_hdr.flags = 0x1; - req_hdr.dlen = cpu_to_le32(args->data_len & 0xffffffff); - req.data = args->data; - req.data_len = args->data_len; - - nvme_mi_admin_init_resp(&resp, &resp_hdr); - - rc = nvme_mi_submit(ctrl->ep, &req, &resp); - if (rc) - return rc; - - return nvme_mi_admin_parse_status(&resp, args->result); -} - -int nvme_mi_admin_security_recv(nvme_mi_ctrl_t ctrl, - struct nvme_security_receive_args *args) -{ - - struct nvme_mi_admin_resp_hdr resp_hdr; - struct nvme_mi_admin_req_hdr req_hdr; - struct nvme_mi_resp resp; - struct nvme_mi_req req; - int rc; - - if (args->args_size < sizeof(*args)) { - errno = EINVAL; - return -1; - } - - if (args->data_len > 4096) { - errno = EINVAL; - return -1; - } - - 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 | - args->spsp1 << 16 | - args->spsp0 << 8 | - args->nssf); - - req_hdr.cdw11 = cpu_to_le32(args->data_len & 0xffffffff); - - req_hdr.flags = 0x1; - req_hdr.dlen = cpu_to_le32(args->data_len & 0xffffffff); - - nvme_mi_admin_init_resp(&resp, &resp_hdr); - resp.data = args->data; - resp.data_len = args->data_len; - - rc = nvme_mi_submit(ctrl->ep, &req, &resp); - if (rc) - return rc; - - rc = nvme_mi_admin_parse_status(&resp, args->result); - if (rc) - return rc; - - args->data_len = resp.data_len; - - return 0; -} - -int nvme_mi_admin_get_features(nvme_mi_ctrl_t ctrl, - struct nvme_get_features_args *args) -{ - struct nvme_mi_admin_resp_hdr resp_hdr; - struct nvme_mi_admin_req_hdr req_hdr; - struct nvme_mi_resp resp; - struct nvme_mi_req req; - int rc; - - if (args->args_size < sizeof(*args)) { - errno = EINVAL; - return -1; - } - - nvme_mi_admin_init_req(ctrl->ep, &req, &req_hdr, ctrl->id, - nvme_admin_get_features); - - req_hdr.cdw1 = cpu_to_le32(args->nsid); - req_hdr.cdw10 = cpu_to_le32((args->sel & 0x7) << 8 | args->fid); - req_hdr.cdw14 = cpu_to_le32(args->uuidx & 0x7f); - req_hdr.cdw11 = cpu_to_le32(args->cdw11); - - nvme_mi_admin_init_resp(&resp, &resp_hdr); - resp.data = args->data; - resp.data_len = args->data_len; - - rc = nvme_mi_submit(ctrl->ep, &req, &resp); - if (rc) - return rc; - - rc = nvme_mi_admin_parse_status(&resp, args->result); - if (rc) - return rc; - - args->data_len = resp.data_len; - - return 0; -} - -static int __nvme_mi_admin_get_features(nvme_mi_ctrl_t ctrl, enum nvme_features_id fid, - enum nvme_get_features_sel sel, __u32 *result) -{ - struct nvme_get_features_args args = { - .args_size = sizeof(args), - .fid = fid, - .nsid = NVME_NSID_NONE, - .sel = sel, - .cdw11 = 0, - .uuidx = NVME_UUID_NONE, - .data_len = 0, - .data = NULL, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .result = result, - }; - - return nvme_mi_admin_get_features(ctrl, &args); -} - -int nvme_mi_admin_get_features_arbitration(nvme_mi_ctrl_t ctrl, enum nvme_get_features_sel sel, - __u32 *result) -{ - return __nvme_mi_admin_get_features(ctrl, NVME_FEAT_FID_ARBITRATION, sel, result); -} - -int nvme_mi_admin_get_features_power_mgmt(nvme_mi_ctrl_t ctrl, enum nvme_get_features_sel sel, - __u32 *result) -{ - return __nvme_mi_admin_get_features(ctrl, NVME_FEAT_FID_POWER_MGMT, sel, result); -} - -int nvme_mi_admin_set_features(nvme_mi_ctrl_t ctrl, - struct nvme_set_features_args *args) -{ - struct nvme_mi_admin_resp_hdr resp_hdr; - struct nvme_mi_admin_req_hdr req_hdr; - struct nvme_mi_resp resp; - struct nvme_mi_req req; - int rc; - - if (args->args_size < sizeof(*args)) { - errno = EINVAL; - return -1; - } - - nvme_mi_admin_init_req(ctrl->ep, &req, &req_hdr, ctrl->id, - nvme_admin_set_features); - - req_hdr.cdw1 = cpu_to_le32(args->nsid); - req_hdr.cdw10 = cpu_to_le32((__u32)!!args->save << 31 | - (args->fid & 0xff)); - req_hdr.cdw14 = cpu_to_le32(args->uuidx & 0x7f); - req_hdr.cdw11 = cpu_to_le32(args->cdw11); - req_hdr.cdw12 = cpu_to_le32(args->cdw12); - req_hdr.cdw13 = cpu_to_le32(args->cdw13); - req_hdr.cdw15 = cpu_to_le32(args->cdw15); - - req.data_len = args->data_len; - req.data = args->data; - - nvme_mi_admin_init_resp(&resp, &resp_hdr); - - rc = nvme_mi_submit(ctrl->ep, &req, &resp); - if (rc) - return rc; - - rc = nvme_mi_admin_parse_status(&resp, args->result); - if (rc) - return rc; - - args->data_len = resp.data_len; - - return 0; -} - -static int __nvme_mi_admin_set_features(nvme_mi_ctrl_t ctrl, __u8 fid, __u32 cdw11, bool save, - __u32 *result) -{ - struct nvme_set_features_args args = { - .args_size = sizeof(args), - .nsid = NVME_NSID_NONE, - .cdw11 = cdw11, - .cdw12 = 0, - .save = save, - .uuidx = NVME_UUID_NONE, - .cdw15 = 0, - .data_len = 0, - .data = NULL, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .result = result, - }; - return nvme_mi_admin_set_features(ctrl, &args); -} - -int nvme_mi_admin_set_features_power_mgmt(nvme_mi_ctrl_t ctrl, __u8 ps, __u8 wh, bool save, - __u32 *result) -{ - __u32 value = NVME_SET(ps, FEAT_PWRMGMT_PS) | NVME_SET(wh, FEAT_PWRMGMT_WH); - - return __nvme_mi_admin_set_features(ctrl, NVME_FEAT_FID_POWER_MGMT, value, save, result); -} - -int nvme_mi_admin_ns_mgmt(nvme_mi_ctrl_t ctrl, - struct nvme_ns_mgmt_args *args) -{ - const size_t size_v1 = sizeof_args(struct nvme_ns_mgmt_args, csi, __u64); - const size_t size_v2 = sizeof_args(struct nvme_ns_mgmt_args, data, __u64); - struct nvme_mi_admin_resp_hdr resp_hdr; - struct nvme_mi_admin_req_hdr req_hdr; - struct nvme_mi_resp resp; - struct nvme_mi_req req; - int rc; - size_t data_len; - - if (args->args_size < size_v1 || args->args_size > size_v2) { - errno = EINVAL; - return -1; - } - - nvme_mi_admin_init_req(ctrl->ep, &req, &req_hdr, ctrl->id, - nvme_admin_ns_mgmt); - - req_hdr.cdw1 = cpu_to_le32(args->nsid); - req_hdr.cdw10 = cpu_to_le32(args->sel & 0xf); - req_hdr.cdw11 = cpu_to_le32(args->csi << 24); - - if (args->args_size == size_v2) { - if (args->data) { - req.data = args->data; - data_len = sizeof(*args->data); - } - } - else { - if (args->ns) { - req.data = args->ns; - data_len = sizeof(*args->ns); - } - } - - if (req.data) { - req.data_len = data_len; - req_hdr.dlen = cpu_to_le32(data_len); - req_hdr.flags = 0x1; - } - - nvme_mi_admin_init_resp(&resp, &resp_hdr); - - rc = nvme_mi_submit(ctrl->ep, &req, &resp); - if (rc) - return rc; - - return nvme_mi_admin_parse_status(&resp, args->result); -} - -int nvme_mi_admin_ns_attach(nvme_mi_ctrl_t ctrl, - struct nvme_ns_attach_args *args) -{ - struct nvme_mi_admin_resp_hdr resp_hdr; - struct nvme_mi_admin_req_hdr req_hdr; - struct nvme_mi_resp resp; - struct nvme_mi_req req; - int rc; - - if (args->args_size < sizeof(*args)) { - errno = EINVAL; - return -1; - } - - nvme_mi_admin_init_req(ctrl->ep, &req, &req_hdr, ctrl->id, - nvme_admin_ns_attach); - - req_hdr.cdw1 = cpu_to_le32(args->nsid); - req_hdr.cdw10 = cpu_to_le32(args->sel & 0xf); - req.data = args->ctrlist; - req.data_len = sizeof(*args->ctrlist); - req_hdr.dlen = cpu_to_le32(sizeof(*args->ctrlist)); - req_hdr.flags = 0x1; - - nvme_mi_admin_init_resp(&resp, &resp_hdr); - - rc = nvme_mi_submit(ctrl->ep, &req, &resp); - if (rc) - return rc; - - return nvme_mi_admin_parse_status(&resp, args->result); -} - -int nvme_mi_admin_fw_download(nvme_mi_ctrl_t ctrl, - struct nvme_fw_download_args *args) -{ - struct nvme_mi_admin_resp_hdr resp_hdr; - struct nvme_mi_admin_req_hdr req_hdr; - struct nvme_mi_resp resp; - struct nvme_mi_req req; - int rc; - - if (args->args_size < sizeof(*args)) { - errno = EINVAL; - return -1; - } - - if ((args->data_len & 0x3) || (!args->data_len)) { - errno = EINVAL; - return -1; - } - - if (args->offset & 0x3) { - errno = EINVAL; - return -1; - } - - 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); - req_hdr.cdw11 = cpu_to_le32(args->offset >> 2); - req.data = args->data; - req.data_len = args->data_len; - req_hdr.dlen = cpu_to_le32(args->data_len); - req_hdr.flags = 0x1; - - nvme_mi_admin_init_resp(&resp, &resp_hdr); - - rc = nvme_mi_submit(ctrl->ep, &req, &resp); - if (rc) - return rc; - - return nvme_mi_admin_parse_status(&resp, NULL); -} - -int nvme_mi_admin_fw_commit(nvme_mi_ctrl_t ctrl, - struct nvme_fw_commit_args *args) -{ - struct nvme_mi_admin_resp_hdr resp_hdr; - struct nvme_mi_admin_req_hdr req_hdr; - struct nvme_mi_resp resp; - struct nvme_mi_req req; - int rc; - - if (args->args_size < sizeof(*args)) { - errno = EINVAL; - return -1; - } - - 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_admin_init_resp(&resp, &resp_hdr); - - rc = nvme_mi_submit(ctrl->ep, &req, &resp); - if (rc) - return rc; - - return nvme_mi_admin_parse_status(&resp, NULL); -} - -int nvme_mi_admin_format_nvm(nvme_mi_ctrl_t ctrl, - struct nvme_format_nvm_args *args) -{ - struct nvme_mi_admin_resp_hdr resp_hdr; - struct nvme_mi_admin_req_hdr req_hdr; - struct nvme_mi_resp resp; - struct nvme_mi_req req; - int rc; - - if (args->args_size < sizeof(*args)) { - errno = EINVAL; - return -1; - } - - nvme_mi_admin_init_req(ctrl->ep, &req, &req_hdr, ctrl->id, - nvme_admin_format_nvm); - - req_hdr.cdw1 = cpu_to_le32(args->nsid); - req_hdr.cdw10 = cpu_to_le32(((args->lbafu & 0x3) << 12) - | ((args->ses & 0x7) << 9) - | ((args->pil & 0x1) << 8) - | ((args->pi & 0x7) << 5) - | ((args->mset & 0x1) << 4) - | ((args->lbaf & 0xf) << 0)); - - nvme_mi_admin_init_resp(&resp, &resp_hdr); - - rc = nvme_mi_submit(ctrl->ep, &req, &resp); - if (rc) - return rc; - - return nvme_mi_admin_parse_status(&resp, args->result); -} - -int nvme_mi_admin_sanitize_nvm(nvme_mi_ctrl_t ctrl, - struct nvme_sanitize_nvm_args *args) -{ - struct nvme_mi_admin_resp_hdr resp_hdr; - struct nvme_mi_admin_req_hdr req_hdr; - struct nvme_mi_resp resp; - struct nvme_mi_req req; - int rc; - - if (args->args_size < sizeof(*args)) { - errno = EINVAL; - return -1; - } - - 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) - | ((args->oipbp ? 1 : 0) << 8) - | ((args->owpass & 0xf) << 4) - | ((args->ause ? 1 : 0) << 3) - | ((args->sanact & 0x7) << 0)); - req_hdr.cdw11 = cpu_to_le32(args->ovrpat); - - nvme_mi_admin_init_resp(&resp, &resp_hdr); - - rc = nvme_mi_submit(ctrl->ep, &req, &resp); - if (rc) - return rc; - - 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, @@ -1795,10 +1042,8 @@ int nvme_mi_mi_xfer(nvme_mi_ep_t ep, * to the requirements of the particular command set */ - if (*resp_data_size > mi_data_xfer_size_limit) { - errno = EINVAL; - return -1; - } + if (*resp_data_size > mi_data_xfer_size_limit) + return -EINVAL; mi_req->hdr.type = NVME_MI_MSGTYPE_NVME; mi_req->hdr.nmp = (NVME_MI_ROR_REQ << 7) | @@ -1845,8 +1090,7 @@ int nvme_mi_mi_read_mi_data_subsys(nvme_mi_ep_t ep, "MI read data length mismatch: " "got %zd bytes, expected %zd\n", len, sizeof(*s)); - errno = EPROTO; - return -1; + return -EPROTO; } return 0; @@ -1866,10 +1110,8 @@ int nvme_mi_mi_read_mi_data_port(nvme_mi_ep_t ep, __u8 portid, if (rc) return rc; - if (len != sizeof(*p)) { - errno = EPROTO; - return -1; - } + if (len != sizeof(*p)) + return -EPROTO; return 0; } @@ -1905,10 +1147,8 @@ int nvme_mi_mi_read_mi_data_ctrl(nvme_mi_ep_t ep, __u16 ctrl_id, if (rc) return rc; - if (len != sizeof(*ctrl)) { - errno = EPROTO; - return -1; - } + if (len != sizeof(*ctrl)) + return -EPROTO; return 0; } @@ -1944,8 +1184,7 @@ int nvme_mi_mi_subsystem_health_status_poll(nvme_mi_ep_t ep, bool clear, "MI Subsystem Health Status length mismatch: " "got %zd bytes, expected %zd\n", resp.data_len, sizeof(*sshs)); - errno = EPROTO; - return -1; + return -EPROTO; } return 0; @@ -2066,22 +1305,17 @@ int nvme_mi_mi_config_set_async_event(nvme_mi_ep_t ep, ((__u32)aemd << 16) | ((__u16) aerd << 8) | NVME_MI_CONFIG_AE; - //Basic checks here on lengths + // Basic checks here on lengths if (enable_list_size < sizeof(struct nvme_mi_aem_enable_list) || - (sizeof(struct nvme_mi_aem_enable_list) + - enable_list->hdr.numaee * sizeof(struct nvme_mi_aem_enable_item) - > enable_list_size) - ) { - errno = EINVAL; - return -1; - } + (sizeof(struct nvme_mi_aem_enable_list) + + enable_list->hdr.numaee * sizeof(struct nvme_mi_aem_enable_item) + > enable_list_size)) + return -EINVAL; - //Some very baseic header checks + // Some very baseic header checks if (enable_list->hdr.aeelhl != sizeof(struct nvme_mi_aem_enable_list_header) || - enable_list->hdr.aeelver != 0) { - errno = EINVAL; - return -1; - } + enable_list->hdr.aeelver != 0) + return -EINVAL; return nvme_mi_mi_config_set_get_ex(ep, nvme_mi_mi_opcode_configuration_set, @@ -2097,13 +1331,13 @@ int nvme_mi_mi_config_set_async_event(nvme_mi_ep_t ep, void nvme_mi_close(nvme_mi_ep_t ep) { - struct nvme_mi_ctrl *ctrl, *tmp; + struct nvme_link *link, *tmp; /* don't look for controllers during destruction */ ep->controllers_scanned = true; - nvme_mi_for_each_ctrl_safe(ep, ctrl, tmp) - nvme_mi_close_ctrl(ctrl); + nvme_mi_for_each_link_safe(ep, link, tmp) + nvme_close(link); if (ep->transport && ep->transport->close) ep->transport->close(ep); @@ -2111,12 +1345,6 @@ void nvme_mi_close(nvme_mi_ep_t ep) free(ep); } -void nvme_mi_close_ctrl(nvme_mi_ctrl_t ctrl) -{ - list_del(&ctrl->ep_entry); - free(ctrl); -} - char *nvme_mi_endpoint_desc(nvme_mi_ep_t ep) { char tsbuf[101], *s = NULL; @@ -2157,17 +1385,16 @@ nvme_mi_ep_t nvme_mi_next_endpoint(nvme_root_t m, nvme_mi_ep_t ep) return ep ? list_next(&m->endpoints, ep, root_entry) : NULL; } -nvme_mi_ctrl_t nvme_mi_first_ctrl(nvme_mi_ep_t ep) +nvme_link_t nvme_mi_first_link(nvme_mi_ep_t ep) { - return list_top(&ep->controllers, struct nvme_mi_ctrl, ep_entry); + return list_top(&ep->controllers, struct nvme_link, ep_entry); } -nvme_mi_ctrl_t nvme_mi_next_ctrl(nvme_mi_ep_t ep, nvme_mi_ctrl_t c) +nvme_link_t nvme_mi_next_link(nvme_mi_ep_t ep, nvme_link_t l) { - return c ? list_next(&ep->controllers, c, ep_entry) : NULL; + return l ? list_next(&ep->controllers, l, ep_entry) : NULL; } - static const char *const mi_status[] = { [NVME_MI_RESP_MPR] = "More Processing Required: The command message is in progress and requires more time to complete processing", [NVME_MI_RESP_INTERNAL_ERR] = "Internal Error: The request message could not be processed due to a vendor-specific error", @@ -2273,19 +1500,14 @@ void nvme_mi_aem_aeolli_set_aeoltl(struct nvme_mi_aem_occ_list_hdr *hdr, __u32 a static int validate_enabled_list(struct nvme_mi_aem_supported_list *list, size_t len) { - if (list->hdr.aeslver != 0) { - errno = EPROTO; - return -1; - } - if (list->hdr.aeslhl != sizeof(struct nvme_mi_aem_supported_list)) { - errno = EPROTO; - return -1; - } + if (list->hdr.aeslver != 0) + return -EPROTO; + if (list->hdr.aeslhl != sizeof(struct nvme_mi_aem_supported_list)) + return -EPROTO; if (list->hdr.aest > len || list->hdr.aest != list->hdr.aeslhl + list->hdr.numaes * sizeof(struct nvme_mi_aem_supported_item)) { - errno = EPROTO; - return -1; + return -EPROTO; } return 0; } @@ -2295,18 +1517,20 @@ static int validate_occ_list_update_ctx( struct nvme_mi_aem_ctx *ctx, bool check_generation_num) { + int err; + //Make sure header fields have valid data if (len < sizeof(*occ_header)) { - errno = EPROTO; + err = -EPROTO; goto err_cleanup; } else if (occ_header->aelver != 0 || occ_header->aeolhl != sizeof(*occ_header)) { //Make sure header is the right version and length - errno = EPROTO; + err = -EPROTO; goto err_cleanup; } else if (nvme_mi_aem_aeolli_get_aeoltl(occ_header->aeolli) > len) { //Full length is bigger than the data that was received - errno = EPROTO; + err = -EPROTO; goto err_cleanup; } else if (check_generation_num && ctx->last_generation_num == @@ -2334,11 +1558,11 @@ static int validate_occ_list_update_ctx( for (int i = 0; i < occ_header->numaeo; i++) { //Validate this item if (current->aelhlen != sizeof(*current)) { - errno = EPROTO; + err = -EPROTO; goto err_cleanup; } else if (!ctx->callbacks.enabled_map.enabled[current->aeoui.aeoi]) { //This is unexpected as this AE shouldn't be enabled - errno = EPROTO; + err = -EPROTO; goto err_cleanup; } @@ -2347,7 +1571,7 @@ static int validate_occ_list_update_ctx( bytes_so_far += offset; if (bytes_so_far > nvme_mi_aem_aeolli_get_aeoltl(occ_header->aeolli)) { - errno = EPROTO; + err = -EPROTO; goto err_cleanup; } @@ -2357,7 +1581,7 @@ static int validate_occ_list_update_ctx( return 0; err_cleanup: - return -1; + return err; } int nvme_mi_aem_get_fd(nvme_mi_ep_t ep) diff --git a/src/nvme/mi.h b/src/nvme/mi.h index 52190636d..958296573 100644 --- a/src/nvme/mi.h +++ b/src/nvme/mi.h @@ -89,6 +89,7 @@ #include #include +#include /** * NVME_MI_MSGTYPE_NVME - MCTP message type for NVMe-MI messages. @@ -791,42 +792,33 @@ void nvme_mi_ep_set_mprt_max(nvme_mi_ep_t ep, unsigned int mprt_max_ms); */ unsigned int nvme_mi_ep_get_timeout(nvme_mi_ep_t ep); -struct nvme_mi_ctrl; - -/** - * typedef nvme_mi_ctrl_t - NVMe-MI Controller object. - * - * Provides NVMe command functionality, through the MI interface. - */ -typedef struct nvme_mi_ctrl * nvme_mi_ctrl_t; - /** - * nvme_mi_first_ctrl - Start controller iterator + * nvme_mi_first_link - Start link iterator * @ep: &nvme_mi_ep_t object * - * Return: first MI controller object under this root, or NULL if no controllers - * are present. + * Return: first link to a MI controller object under this root, or NULL + * if no controllers are present. * - * See: &nvme_mi_next_ctrl, &nvme_mi_for_each_ctrl + * See: &nvme_mi_next_link, &nvme_mi_for_each_link */ -nvme_mi_ctrl_t nvme_mi_first_ctrl(nvme_mi_ep_t ep); +nvme_link_t nvme_mi_first_link(nvme_mi_ep_t ep); /** - * nvme_mi_next_ctrl - Continue ctrl iterator + * nvme_mi_next_link - Continue link iterator * @ep: &nvme_mi_ep_t object - * @c: &nvme_mi_ctrl_t current position of iterator + * @l: &nvme_mi_link_t current position of iterator * - * Return: next MI controller object after @c under this endpoint, or NULL - * if no further controllers are present. + * Return: next link to MI controller object after @c under this + * endpoint, or NULL if no further controllers are present. * - * See: &nvme_mi_first_ctrl, &nvme_mi_for_each_ctrl + * See: &nvme_mi_first_link, &nvme_mi_for_each_link */ -nvme_mi_ctrl_t nvme_mi_next_ctrl(nvme_mi_ep_t ep, nvme_mi_ctrl_t c); +nvme_link_t nvme_mi_next_link(nvme_mi_ep_t ep, nvme_link_t l); /** - * nvme_mi_for_each_ctrl - Iterator for NVMe-MI controllers. + * nvme_mi_for_each_link - Iterator for link to NVMe-MI controllers. * @ep: &nvme_mi_ep_t containing endpoints - * @c: &nvme_mi_ctrl_t object, set on each iteration + * @l: &nvme_link_t object, set on each iteration * * Allows iteration of the list of controllers behind an endpoint. Unless the * controllers have already been created explicitly, you'll probably want to @@ -834,16 +826,16 @@ nvme_mi_ctrl_t nvme_mi_next_ctrl(nvme_mi_ep_t ep, nvme_mi_ctrl_t c); * * See: &nvme_mi_scan_ep() */ -#define nvme_mi_for_each_ctrl(ep, c) \ - for (c = nvme_mi_first_ctrl(ep); c != NULL; \ - c = nvme_mi_next_ctrl(ep, c)) +#define nvme_mi_for_each_link(ep, l) \ + for (l = nvme_mi_first_link(ep); l != NULL; \ + l = nvme_mi_next_link(ep, l)) /** - * nvme_mi_for_each_ctrl_safe - Iterator for NVMe-MI controllers, allowing + * nvme_mi_for_each_link_safe - Iterator for link to NVMe-MI controllers, allowing * deletion during traversal * @ep: &nvme_mi_ep_t containing controllers - * @c: &nvme_mi_ctrl_t object, set on each iteration - * @_c: &nvme_mi_ctrl_t object used as temporary storage + * @l: &nvme_link_t object, set on each iteration + * @_l: &nvme_link_t object used as temporary storage * * Allows iteration of the list of controllers behind an endpoint, safe against * deletion during iteration. Unless the controllers have already been created @@ -852,10 +844,10 @@ nvme_mi_ctrl_t nvme_mi_next_ctrl(nvme_mi_ep_t ep, nvme_mi_ctrl_t c); * * See: &nvme_mi_scan_ep() */ -#define nvme_mi_for_each_ctrl_safe(ep, c, _c) \ - for (c = nvme_mi_first_ctrl(ep), _c = nvme_mi_next_ctrl(ep, c); \ - c != NULL; \ - c = _c, _c = nvme_mi_next_ctrl(ep, c)) +#define nvme_mi_for_each_link_safe(ep, l, _l) \ + for (l = nvme_mi_first_link(ep), _l = nvme_mi_next_link(ep, l); \ + l != NULL; \ + l = _l, _l = nvme_mi_next_link(ep, l)) /** * nvme_mi_open_mctp() - Create an endpoint using a MCTP connection. @@ -924,7 +916,7 @@ nvme_root_t nvme_mi_scan_mctp(void); int nvme_mi_scan_ep(nvme_mi_ep_t ep, bool force_rescan); /** - * nvme_mi_init_ctrl() - initialise a NVMe controller. + * nvme_mi_init_link() - initialise a link to NVMe controller. * @ep: Endpoint to create under * @ctrl_id: ID of controller to initialize. * @@ -934,29 +926,22 @@ int nvme_mi_scan_ep(nvme_mi_ep_t ep, bool force_rescan); * * Return: New controller object, or NULL on failure. * - * See &nvme_mi_close_ctrl - */ -nvme_mi_ctrl_t nvme_mi_init_ctrl(nvme_mi_ep_t ep, __u16 ctrl_id); - -/** - * nvme_mi_close_ctrl() - free a controller - * @ctrl: controller to free + * See &nvme_mi_close_link */ -void nvme_mi_close_ctrl(nvme_mi_ctrl_t ctrl); +nvme_link_t nvme_mi_init_link(nvme_mi_ep_t ep, __u16 ctrl_id); /** * nvme_mi_ctrl_id() - get the ID of a controller - * @ctrl: controller to query + * @link: link to controller to query * * Retrieve the ID of the controller, as defined by hardware, and available * in the Identify (Controller List) data. This is the value passed to - * @nvme_mi_init_ctrl, but may have been created internally via + * @nvme_mi_init_link, but may have been created internally via * @nvme_mi_scan_ep. * * Return: the (locally-stored) ID of this controller. */ -__u16 nvme_mi_ctrl_id(nvme_mi_ctrl_t ctrl); - +__u16 nvme_mi_ctrl_id(nvme_link_t link); /** * nvme_mi_endpoint_desc - Get a string describing a MI endpoint. @@ -1342,7 +1327,7 @@ static inline int nvme_mi_aem_ack(nvme_mi_ep_t ep, /** * nvme_mi_admin_xfer() - Raw admin transfer interface. - * @ctrl: controller to send the admin command to + * @link: link to send the admin command to * @admin_req: request data * @req_data_size: size of request data payload * @admin_resp: buffer for response data @@ -1367,7 +1352,7 @@ static inline int nvme_mi_aem_ack(nvme_mi_ep_t ep, * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise.. */ -int nvme_mi_admin_xfer(nvme_mi_ctrl_t ctrl, +int nvme_mi_admin_xfer(nvme_link_t link, struct nvme_mi_admin_req_hdr *admin_req, size_t req_data_size, struct nvme_mi_admin_resp_hdr *admin_resp, @@ -1376,7 +1361,7 @@ int nvme_mi_admin_xfer(nvme_mi_ctrl_t ctrl, /** * nvme_mi_admin_admin_passthru() - Submit an nvme admin passthrough command - * @ctrl: Controller to send command to + * @link: Link to send command to * @opcode: The nvme admin command to send * @flags: NVMe command flags (not used) * @rsvd: Reserved for future use @@ -1407,68 +1392,13 @@ int nvme_mi_admin_xfer(nvme_mi_ctrl_t ctrl, * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise. */ -int nvme_mi_admin_admin_passthru(nvme_mi_ctrl_t ctrl, __u8 opcode, __u8 flags, +int nvme_mi_admin_admin_passthru(nvme_link_t link, __u8 opcode, __u8 flags, __u16 rsvd, __u32 nsid, __u32 cdw2, __u32 cdw3, __u32 cdw10, __u32 cdw11, __u32 cdw12, __u32 cdw13, __u32 cdw14, __u32 cdw15, __u32 data_len, void *data, __u32 metadata_len, void *metadata, __u32 timeout_ms, __u32 *result); -/** - * nvme_mi_admin_identify_partial() - Perform an Admin identify command, - * and retrieve partial response data. - * @ctrl: Controller to process identify command - * @args: Identify command arguments - * @offset: offset of identify data to retrieve from response - * @size: size of identify data to return - * - * Perform an Identify command, using the Identify command parameters in @args. - * The @offset and @size arguments allow the caller to retrieve part of - * the identify response. See NVMe-MI section 6.2 for the semantics (and some - * handy diagrams) of the offset & size parameters. - * - * Will return an error if the length of the response data (from the controller) - * did not match @size. - * - * Unless you're performing a vendor-unique identify command, You'll probably - * want to use one of the identify helpers (nvme_mi_admin_identify, - * nvme_mi_admin_identify_cns_nsid, or nvme_mi_admin_identify_) instead - * of this. If the type of your identify command is standardized but not - * yet supported by libnvme-mi, please contact the maintainers. - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. - * - * See: &struct nvme_identify_args - */ -int nvme_mi_admin_identify_partial(nvme_mi_ctrl_t ctrl, - struct nvme_identify_args *args, - off_t offset, size_t size); - -/** - * nvme_mi_admin_identify() - Perform an Admin identify command. - * @ctrl: Controller to process identify command - * @args: Identify command arguments - * - * Perform an Identify command, using the Identify command parameters in @args. - * Stores the identify data in ->data, and (if set) the result from cdw0 - * into args->result. - * - * Will return an error if the length of the response data (from the - * controller) is not a full &NVME_IDENTIFY_DATA_SIZE. - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. - * - * See: &struct nvme_identify_args - */ -static inline int nvme_mi_admin_identify(nvme_mi_ctrl_t ctrl, - struct nvme_identify_args *args) -{ - return nvme_mi_admin_identify_partial(ctrl, args, - 0, NVME_IDENTIFY_DATA_SIZE); -} - /** * nvme_mi_control() - Perform a Control Primitive command * @ep: endpoint for MI communication @@ -1487,1961 +1417,6 @@ static inline int nvme_mi_admin_identify(nvme_mi_ctrl_t ctrl, int nvme_mi_control(nvme_mi_ep_t ep, __u8 opcode, __u16 cpsp, __u16 *result_cpsr); -/** - * nvme_mi_admin_identify_cns_nsid() - Perform an Admin identify command using - * specific CNS/NSID parameters. - * @ctrl: Controller to process identify command - * @cns: Controller or Namespace Structure, specifying identified object - * @nsid: namespace ID - * @data: buffer for identify data response - * - * Perform an Identify command, using the CNS specifier @cns, and the - * namespace ID @nsid if required by the CNS type. - * - * Stores the identify data in @data, which is expected to be a buffer of - * &NVME_IDENTIFY_DATA_SIZE bytes. - * - * Will return an error if the length of the response data (from the - * controller) is not a full &NVME_IDENTIFY_DATA_SIZE. - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. - */ -static inline int nvme_mi_admin_identify_cns_nsid(nvme_mi_ctrl_t ctrl, - enum nvme_identify_cns cns, - __u32 nsid, void *data) -{ - struct nvme_identify_args args = { - .result = NULL, - .data = data, - .args_size = sizeof(args), - .cns = cns, - .csi = NVME_CSI_NVM, - .nsid = nsid, - .cntid = NVME_CNTLID_NONE, - .cns_specific_id = NVME_CNSSPECID_NONE, - .uuidx = NVME_UUID_NONE, - }; - - return nvme_mi_admin_identify(ctrl, &args); -} - -/** - * nvme_mi_admin_identify_ns() - Perform an Admin identify command for a - * namespace - * @ctrl: Controller to process identify command - * @nsid: namespace ID - * @ns: Namespace identification to populate - * - * Perform an Identify (namespace) command, setting the namespace id data - * in @ns. The namespace is expected to active and allocated. - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. - */ -static inline int nvme_mi_admin_identify_ns(nvme_mi_ctrl_t ctrl, __u32 nsid, - struct nvme_id_ns *ns) -{ - return nvme_mi_admin_identify_cns_nsid(ctrl, NVME_IDENTIFY_CNS_NS, - nsid, ns); -} - -/** - * nvme_mi_admin_identify_ns_descs() - Perform an Admin identify Namespace - * Identification Descriptor list command for a namespace - * @ctrl: Controller to process identify command - * @nsid: Namespace ID - * @descs: Namespace Identification Descriptor list to populate - * - * Perform an Identify namespace identification description list command, - * setting the namespace identification description list in @descs - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. - */ -static inline int nvme_mi_admin_identify_ns_descs(nvme_mi_ctrl_t ctrl, - __u32 nsid, - struct nvme_ns_id_desc *descs) -{ - return nvme_mi_admin_identify_cns_nsid(ctrl, NVME_IDENTIFY_CNS_NS_DESC_LIST, - nsid, descs); -} - -/** - * nvme_mi_admin_identify_allocated_ns() - Perform an Admin identify command - * for an allocated namespace - * @ctrl: Controller to process identify command - * @nsid: namespace ID - * @ns: Namespace identification to populate - * - * Perform an Identify (namespace) command, setting the namespace id data - * in @ns. - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. - */ -static inline int nvme_mi_admin_identify_allocated_ns(nvme_mi_ctrl_t ctrl, - __u32 nsid, - struct nvme_id_ns *ns) -{ - return nvme_mi_admin_identify_cns_nsid(ctrl, - NVME_IDENTIFY_CNS_ALLOCATED_NS, - nsid, ns); -} - -/** - * nvme_mi_admin_identify_ctrl() - Perform an Admin identify for a controller - * @ctrl: Controller to process identify command - * @id: Controller identify data to populate - * - * Perform an Identify command, for the controller specified by @ctrl, - * writing identify data to @id. - * - * Will return an error if the length of the response data (from the - * controller) is not a full &NVME_IDENTIFY_DATA_SIZE, so @id will be - * fully populated on success. - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. - * - * See: &struct nvme_id_ctrl - */ -static inline int nvme_mi_admin_identify_ctrl(nvme_mi_ctrl_t ctrl, - struct nvme_id_ctrl *id) -{ - return nvme_mi_admin_identify_cns_nsid(ctrl, NVME_IDENTIFY_CNS_CTRL, - NVME_NSID_NONE, id); -} - -/** - * nvme_mi_admin_identify_ctrl_list() - Perform an Admin identify for a - * controller list. - * @ctrl: Controller to process identify command - * @cntid: Controller ID to specify list start - * @list: List data to populate - * - * Perform an Identify command, for the controller list starting with - * IDs greater than or equal to @cntid. - * - * Will return an error if the length of the response data (from the - * controller) is not a full &NVME_IDENTIFY_DATA_SIZE, so @id will be - * fully populated on success. - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. - * - * See: &struct nvme_ctrl_list - */ -static inline int nvme_mi_admin_identify_ctrl_list(nvme_mi_ctrl_t ctrl, - __u16 cntid, - struct nvme_ctrl_list *list) -{ - struct nvme_identify_args args = { - .result = NULL, - .data = list, - .args_size = sizeof(args), - .cns = NVME_IDENTIFY_CNS_CTRL_LIST, - .csi = NVME_CSI_NVM, - .nsid = NVME_NSID_NONE, - .cntid = cntid, - .cns_specific_id = NVME_CNSSPECID_NONE, - .uuidx = NVME_UUID_NONE, - }; - - return nvme_mi_admin_identify(ctrl, &args); -} - -/** - * nvme_mi_admin_identify_nsid_ctrl_list() - Perform an Admin identify for a - * controller list with specific namespace ID - * @ctrl: Controller to process identify command - * @nsid: Namespace identifier - * @cntid: Controller ID to specify list start - * @list: List data to populate - * - * Perform an Identify command, for the controller list for @nsid, starting - * with IDs greater than or equal to @cntid. - * - * Will return an error if the length of the response data (from the - * controller) is not a full &NVME_IDENTIFY_DATA_SIZE, so @id will be - * fully populated on success. - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. - * - * See: &struct nvme_ctrl_list - */ -static inline int nvme_mi_admin_identify_nsid_ctrl_list(nvme_mi_ctrl_t ctrl, - __u32 nsid, __u16 cntid, - struct nvme_ctrl_list *list) -{ - struct nvme_identify_args args = { - .result = NULL, - .data = list, - .args_size = sizeof(args), - .cns = NVME_IDENTIFY_CNS_NS_CTRL_LIST, - .csi = NVME_CSI_NVM, - .nsid = nsid, - .cntid = cntid, - .cns_specific_id = NVME_CNSSPECID_NONE, - .uuidx = NVME_UUID_NONE, - }; - - return nvme_mi_admin_identify(ctrl, &args); -} - -/** - * nvme_mi_admin_identify_allocated_ns_list() - Perform an Admin identify for - * an allocated namespace list - * @ctrl: Controller to process identify command - * @nsid: Namespace ID to specify list start - * @list: List data to populate - * - * Perform an Identify command, for the allocated namespace list starting with - * IDs greater than or equal to @nsid. Specify &NVME_NSID_NONE for the start - * of the list. - * - * Will return an error if the length of the response data (from the - * controller) is not a full &NVME_IDENTIFY_DATA_SIZE, so @list will be - * be fully populated on success. - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. - * - * See: &struct nvme_ns_list - */ -static inline int nvme_mi_admin_identify_allocated_ns_list(nvme_mi_ctrl_t ctrl, - __u32 nsid, - struct nvme_ns_list *list) -{ - struct nvme_identify_args args = { - .result = NULL, - .data = list, - .args_size = sizeof(args), - .cns = NVME_IDENTIFY_CNS_ALLOCATED_NS_LIST, - .csi = NVME_CSI_NVM, - .nsid = nsid, - .cns_specific_id = NVME_CNSSPECID_NONE, - .uuidx = NVME_UUID_NONE, - }; - - return nvme_mi_admin_identify(ctrl, &args); -} - -/** - * nvme_mi_admin_identify_active_ns_list() - Perform an Admin identify for an - * active namespace list - * @ctrl: Controller to process identify command - * @nsid: Namespace ID to specify list start - * @list: List data to populate - * - * Perform an Identify command, for the active namespace list starting with - * IDs greater than or equal to @nsid. Specify &NVME_NSID_NONE for the start - * of the list. - * - * Will return an error if the length of the response data (from the - * controller) is not a full &NVME_IDENTIFY_DATA_SIZE, so @list will be - * be fully populated on success. - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. - * - * See: &struct nvme_ns_list - */ -static inline int nvme_mi_admin_identify_active_ns_list(nvme_mi_ctrl_t ctrl, - __u32 nsid, - struct nvme_ns_list *list) -{ - struct nvme_identify_args args = { - .result = NULL, - .data = list, - .args_size = sizeof(args), - .cns = NVME_IDENTIFY_CNS_NS_ACTIVE_LIST, - .csi = NVME_CSI_NVM, - .nsid = nsid, - .cns_specific_id = NVME_CNSSPECID_NONE, - .uuidx = NVME_UUID_NONE, - }; - - return nvme_mi_admin_identify(ctrl, &args); -} - -/** - * nvme_mi_admin_identify_primary_ctrl() - Perform an Admin identify for - * primary controller capabilities data structure. - * @ctrl: Controller to process identify command - * @cntid: Controller ID to specify - * @cap: Primary Controller Capabilities data structure to populate - * - * Perform an Identify command to get the Primary Controller Capabilities data - * for the controller specified by @cntid - * - * Will return an error if the length of the response data (from the - * controller) is not a full &NVME_IDENTIFY_DATA_SIZE, so @cap will be - * be fully populated on success. - * - * Return: 0 on success, non-zero on failure - * - * See: &struct nvme_primary_ctrl_cap - */ -static inline int nvme_mi_admin_identify_primary_ctrl(nvme_mi_ctrl_t ctrl, - __u16 cntid, - struct nvme_primary_ctrl_cap *cap) -{ - struct nvme_identify_args args = { - .result = NULL, - .data = cap, - .args_size = sizeof(args), - .cns = NVME_IDENTIFY_CNS_PRIMARY_CTRL_CAP, - .csi = NVME_CSI_NVM, - .nsid = NVME_NSID_NONE, - .cntid = cntid, - .cns_specific_id = NVME_CNSSPECID_NONE, - .uuidx = NVME_UUID_NONE, - }; - - return nvme_mi_admin_identify(ctrl, &args); -} - -/** - * nvme_mi_admin_identify_secondary_ctrl_list() - Perform an Admin identify for - * a secondary controller list. - * @ctrl: Controller to process identify command - * @cntid: Controller ID to specify list start - * @list: List data to populate - * - * Perform an Identify command, for the secondary controllers associated with - * the current primary controller. Only entries with IDs greater than or - * equal to @cntid are returned. - * - * Will return an error if the length of the response data (from the - * controller) is not a full &NVME_IDENTIFY_DATA_SIZE, so @list will be - * be fully populated on success. - * - * Return: 0 on success, non-zero on failure - * - * See: &struct nvme_secondary_ctrl_list - */ -static inline int nvme_mi_admin_identify_secondary_ctrl_list(nvme_mi_ctrl_t ctrl, - __u16 cntid, - struct nvme_secondary_ctrl_list *list) -{ - struct nvme_identify_args args = { - .result = NULL, - .data = list, - .args_size = sizeof(args), - .cns = NVME_IDENTIFY_CNS_SECONDARY_CTRL_LIST, - .csi = NVME_CSI_NVM, - .nsid = NVME_NSID_NONE, - .cntid = cntid, - .cns_specific_id = NVME_CNSSPECID_NONE, - .uuidx = NVME_UUID_NONE, - }; - - return nvme_mi_admin_identify(ctrl, &args); -} - -/** - * nvme_mi_admin_get_log_page() - Retrieve log page data from controller - * @ctrl: Controller to query - * @xfer_len: The chunk size of the read - * @args: Get Log Page command arguments - * - * Performs a Get Log Page Admin command as specified by @args. Response data - * is stored in @args->data, which should be a buffer of @args->data_len bytes. - * Resulting data length is stored in @args->data_len on successful - * command completion. - * - * This request may be implemented as multiple log page commands, in order - * to fit within MI message-size limits. - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. - * - * See: &struct nvme_get_log_args - */ -int nvme_mi_admin_get_log_page(nvme_mi_ctrl_t ctrl, __u32 xfer_len, - struct nvme_get_log_args *args); - -/** - * nvme_mi_admin_get_log() - Retrieve log page data from controller - * @ctrl: Controller to query - * @args: Get Log Page command arguments - * - * Performs a Get Log Page Admin command as specified by @args. Response data - * is stored in @args->data, which should be a buffer of @args->data_len bytes. - * Resulting data length is stored in @args->data_len on successful - * command completion. - * - * This request may be implemented as multiple log page commands, in order - * to fit within MI message-size limits. - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. - * - * See: &struct nvme_get_log_args - */ -int nvme_mi_admin_get_log(nvme_mi_ctrl_t ctrl, struct nvme_get_log_args *args); - -/** - * nvme_mi_admin_get_nsid_log() - Helper for Get Log Page functions - * @ctrl: Controller to query - * @rae: Retain Asynchronous Events - * @lid: Log identifier - * @nsid: Namespace ID - * @len: length of log buffer - * @log: pointer for resulting log data - * - * Performs a Get Log Page Admin command for a specific log ID @lid and - * namespace ID @nsid. Log data is expected to be @len bytes, and is stored - * in @log on success. The @rae flag is passed as-is to the Get Log Page - * command, and is specific to the Log Page requested. - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. - */ -static inline int nvme_mi_admin_get_nsid_log(nvme_mi_ctrl_t ctrl, bool rae, - enum nvme_cmd_get_log_lid lid, - __u32 nsid, __u32 len, void *log) -{ - struct nvme_get_log_args args = { - .lpo = 0, - .result = NULL, - .log = log, - .args_size = sizeof(args), - .lid = lid, - .len = len, - .nsid = nsid, - .csi = NVME_CSI_NVM, - .lsi = NVME_LOG_LSI_NONE, - .lsp = NVME_LOG_LSP_NONE, - .uuidx = NVME_UUID_NONE, - .rae = rae, - .ot = false, - }; - - return nvme_mi_admin_get_log(ctrl, &args); -} - -/** - * nvme_mi_admin_get_endgid_log() - Helper for Get Endurance Group ID Log Page functions - * @ctrl: Controller to query - * @rae: Retain Asynchronous Events - * @lid: Log identifier - * @endgid: Endurance Group ID - * @len: length of log buffer - * @log: pointer for resulting log data - * - * Performs a Get Log Page Admin command for a specific log ID @lid and - * endurance group ID @endgid. Log data is expected to be @len bytes, and is stored - * in @log on success. The @rae flag is passed as-is to the Get Log Page - * command, and is specific to the Log Page requested. - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. - */ -static inline int nvme_mi_admin_get_endgid_log(nvme_mi_ctrl_t ctrl, bool rae, - enum nvme_cmd_get_log_lid lid, __u16 endgid, - __u32 len, void *log) -{ - struct nvme_get_log_args args = { - .lpo = 0, - .result = NULL, - .log = log, - .args_size = sizeof(args), - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .lid = lid, - .len = len, - .nsid = NVME_NSID_NONE, - .csi = NVME_CSI_NVM, - .lsi = endgid, - .lsp = NVME_LOG_LSP_NONE, - .uuidx = NVME_LOG_LSP_NONE, - .rae = rae, - .ot = false, - }; - - return nvme_mi_admin_get_log(ctrl, &args); -} - -/** - * nvme_mi_admin_get_log_simple() - Helper for Get Log Page functions with no - * NSID or RAE requirements - * @ctrl: Controller to query - * @lid: Log identifier - * @len: length of log buffer - * @log: pointer for resulting log data - * - * Performs a Get Log Page Admin command for a specific log ID @lid, using - * NVME_NSID_ALL for the namespace identifier, and rae set to false. - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. - */ -static inline int nvme_mi_admin_get_log_simple(nvme_mi_ctrl_t ctrl, - enum nvme_cmd_get_log_lid lid, - __u32 len, void *log) -{ - return nvme_mi_admin_get_nsid_log(ctrl, false, lid, NVME_NSID_ALL, - len, log); -} - -/** - * nvme_mi_admin_get_log_supported_log_pages() - Retrieve nmve supported log - * pages - * @ctrl: Controller to query - * @rae: Retain asynchronous events - * @log: Array of LID supported and Effects data structures - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. - */ -static inline int nvme_mi_admin_get_log_supported_log_pages(nvme_mi_ctrl_t ctrl, - bool rae, - struct nvme_supported_log_pages *log) -{ - return nvme_mi_admin_get_nsid_log(ctrl, rae, - NVME_LOG_LID_SUPPORTED_LOG_PAGES, - NVME_NSID_ALL, sizeof(*log), log); -} - -/** - * nvme_mi_admin_get_log_error() - Retrieve nvme error log - * @ctrl: Controller to query - * @nr_entries: Number of error log entries allocated - * @rae: Retain asynchronous events - * @err_log: Array of error logs of size 'entries' - * - * This log page describes extended error information for a command that - * completed with error, or may report an error that is not specific to a - * particular command. - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. - */ -static inline int nvme_mi_admin_get_log_error(nvme_mi_ctrl_t ctrl, - unsigned int nr_entries, bool rae, - struct nvme_error_log_page *err_log) -{ - return nvme_mi_admin_get_nsid_log(ctrl, rae, NVME_LOG_LID_ERROR, - NVME_NSID_ALL, sizeof(*err_log) * nr_entries, - err_log); -} - -/** - * nvme_mi_admin_get_log_smart() - Retrieve nvme smart log - * @ctrl: Controller to query - * @nsid: Optional namespace identifier - * @rae: Retain asynchronous events - * @smart_log: User address to store the smart log - * - * This log page provides SMART and general health information. The information - * provided is over the life of the controller and is retained across power - * cycles. To request the controller log page, the namespace identifier - * specified is FFFFFFFFh. The controller may also support requesting the log - * page on a per namespace basis, as indicated by bit 0 of the LPA field in the - * Identify Controller data structure. - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. - */ -static inline int nvme_mi_admin_get_log_smart(nvme_mi_ctrl_t ctrl, __u32 nsid, - bool rae, - struct nvme_smart_log *smart_log) -{ - return nvme_mi_admin_get_nsid_log(ctrl, rae, NVME_LOG_LID_SMART, - nsid, sizeof(*smart_log), smart_log); -} - -/** - * nvme_mi_admin_get_log_fw_slot() - Retrieves the controller firmware log - * @ctrl: Controller to query - * @rae: Retain asynchronous events - * @fw_log: User address to store the log page - * - * This log page describes the firmware revision stored in each firmware slot - * supported. The firmware revision is indicated as an ASCII string. The log - * page also indicates the active slot number. - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. - */ -static inline int nvme_mi_admin_get_log_fw_slot(nvme_mi_ctrl_t ctrl, bool rae, - struct nvme_firmware_slot *fw_log) -{ - return nvme_mi_admin_get_nsid_log(ctrl, rae, NVME_LOG_LID_FW_SLOT, - NVME_NSID_ALL, sizeof(*fw_log), fw_log); -} - -/** - * nvme_mi_admin_get_log_changed_ns_list() - Retrieve namespace changed list - * @ctrl: Controller to query - * @rae: Retain asynchronous events - * @ns_log: User address to store the log page - * - * This log page describes namespaces attached to this controller that have - * changed since the last time the namespace was identified, been added, or - * deleted. - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. - */ -static inline int nvme_mi_admin_get_log_changed_ns_list(nvme_mi_ctrl_t ctrl, - bool rae, - struct nvme_ns_list *ns_log) -{ - return nvme_mi_admin_get_nsid_log(ctrl, rae, NVME_LOG_LID_CHANGED_NS, - NVME_NSID_ALL, sizeof(*ns_log), ns_log); -} - -/** - * nvme_mi_admin_get_log_cmd_effects() - Retrieve nvme command effects log - * @ctrl: Controller to query - * @csi: Command Set Identifier - * @effects_log: User address to store the effects log - * - * This log page describes the commands that the controller supports and the - * effects of those commands on the state of the NVM subsystem. - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. - */ -static inline int nvme_mi_admin_get_log_cmd_effects(nvme_mi_ctrl_t ctrl, - enum nvme_csi csi, - struct nvme_cmd_effects_log *effects_log) -{ - struct nvme_get_log_args args = { - .lpo = 0, - .result = NULL, - .log = effects_log, - .args_size = sizeof(args), - .lid = NVME_LOG_LID_CMD_EFFECTS, - .len = sizeof(*effects_log), - .nsid = NVME_NSID_ALL, - .csi = csi, - .lsi = NVME_LOG_LSI_NONE, - .lsp = NVME_LOG_LSP_NONE, - .uuidx = NVME_UUID_NONE, - .rae = false, - .ot = false, - }; - return nvme_mi_admin_get_log(ctrl, &args); -} - -/** - * nvme_mi_admin_get_log_device_self_test() - Retrieve the device self test log - * @ctrl: Controller to query - * @log: Userspace address of the log payload - * - * The log page indicates the status of an in progress self test and the - * percent complete of that operation, and the results of the previous 20 - * self-test operations. - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. - */ -static inline int nvme_mi_admin_get_log_device_self_test(nvme_mi_ctrl_t ctrl, - struct nvme_self_test_log *log) -{ - return nvme_mi_admin_get_nsid_log(ctrl, false, - NVME_LOG_LID_DEVICE_SELF_TEST, - NVME_NSID_ALL, sizeof(*log), log); -} - -/** - * nvme_mi_admin_get_log_create_telemetry_host_mcda() - Create host telemetry log - * @ctrl: Controller to query - * @mcda: Maximum Created Data Area - * @log: Userspace address of the log payload - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. - */ -static inline int nvme_mi_admin_get_log_create_telemetry_host_mcda(nvme_mi_ctrl_t ctrl, - enum nvme_telemetry_da mcda, - struct nvme_telemetry_log *log) -{ - struct nvme_get_log_args args = { - .lpo = 0, - .result = NULL, - .log = log, - .args_size = sizeof(args), - .lid = NVME_LOG_LID_TELEMETRY_HOST, - .len = sizeof(*log), - .nsid = NVME_NSID_NONE, - .csi = NVME_CSI_NVM, - .lsi = NVME_LOG_LSI_NONE, - .lsp = (__u8)((mcda << 1) | NVME_LOG_TELEM_HOST_LSP_CREATE), - .uuidx = NVME_UUID_NONE, - .rae = false, - .ot = false, - }; - return nvme_mi_admin_get_log(ctrl, &args); -} - -/** - * nvme_mi_admin_get_log_create_telemetry_host() - Create host telemetry log - * @ctrl: Controller to query - * @log: Userspace address of the log payload - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. - */ -static inline int nvme_mi_admin_get_log_create_telemetry_host(nvme_mi_ctrl_t ctrl, - struct nvme_telemetry_log *log) -{ - return nvme_mi_admin_get_log_create_telemetry_host_mcda(ctrl, NVME_TELEMETRY_DA_CTRL_DETERMINE, log); -} - -/** - * nvme_mi_admin_get_log_telemetry_host() - Get Telemetry Host-Initiated log - * page - * @ctrl: Controller to query - * @offset: Offset into the telemetry data - * @len: Length of provided user buffer to hold the log data in bytes - * @log: User address for log page data - * - * Retrieves the Telemetry Host-Initiated log page at the requested offset - * using the previously existing capture. - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. - */ -static inline int nvme_mi_admin_get_log_telemetry_host(nvme_mi_ctrl_t ctrl, - __u64 offset, __u32 len, - void *log) -{ - struct nvme_get_log_args args = { - .lpo = offset, - .result = NULL, - .log = log, - .args_size = sizeof(args), - .lid = NVME_LOG_LID_TELEMETRY_HOST, - .len = len, - .nsid = NVME_NSID_NONE, - .csi = NVME_CSI_NVM, - .lsi = NVME_LOG_LSI_NONE, - .lsp = NVME_LOG_TELEM_HOST_LSP_RETAIN, - .uuidx = NVME_UUID_NONE, - .rae = false, - .ot = false, - }; - return nvme_mi_admin_get_log(ctrl, &args); -} - -/** - * nvme_mi_admin_get_log_telemetry_ctrl() - Get Telemetry Controller-Initiated - * log page - * @ctrl: Controller to query - * @rae: Retain asynchronous events - * @offset: Offset into the telemetry data - * @len: Length of provided user buffer to hold the log data in bytes - * @log: User address for log page data - * - * Retrieves the Telemetry Controller-Initiated log page at the requested offset - * using the previously existing capture. - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. - */ -static inline int nvme_mi_admin_get_log_telemetry_ctrl(nvme_mi_ctrl_t ctrl, - bool rae, - __u64 offset, __u32 len, - void *log) -{ - struct nvme_get_log_args args = { - .lpo = offset, - .result = NULL, - .log = log, - .args_size = sizeof(args), - .lid = NVME_LOG_LID_TELEMETRY_CTRL, - .len = len, - .nsid = NVME_NSID_NONE, - .csi = NVME_CSI_NVM, - .lsi = NVME_LOG_LSI_NONE, - .lsp = NVME_LOG_LSP_NONE, - .uuidx = NVME_UUID_NONE, - .rae = rae, - .ot = false, - }; - return nvme_mi_admin_get_log(ctrl, &args); -} - -/** - * nvme_mi_admin_get_log_endurance_group() - Get Endurance Group log - * @ctrl: Controller to query - * @endgid: Starting group identifier to return in the list - * @log: User address to store the endurance log - * - * This log page indicates if an Endurance Group Event has occurred for a - * particular Endurance Group. If an Endurance Group Event has occurred, the - * details of the particular event are included in the Endurance Group - * Information log page for that Endurance Group. An asynchronous event is - * generated when an entry for an Endurance Group is newly added to this log - * page. - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. - */ -static inline int nvme_mi_admin_get_log_endurance_group(nvme_mi_ctrl_t ctrl, - __u16 endgid, - struct nvme_endurance_group_log *log) -{ - struct nvme_get_log_args args = { - .lpo = 0, - .result = NULL, - .log = log, - .args_size = sizeof(args), - .lid = NVME_LOG_LID_ENDURANCE_GROUP, - .len = sizeof(*log), - .nsid = NVME_NSID_NONE, - .csi = NVME_CSI_NVM, - .lsi = endgid, - .lsp = NVME_LOG_LSP_NONE, - .uuidx = NVME_UUID_NONE, - .rae = false, - .ot = false, - }; - return nvme_mi_admin_get_log(ctrl, &args); -} - -/** - * nvme_mi_admin_get_log_predictable_lat_nvmset() - Predictable Latency Per NVM - * Set - * @ctrl: Controller to query - * @nvmsetid: NVM set id - * @log: User address to store the predictable latency log - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. - */ -static inline int nvme_mi_admin_get_log_predictable_lat_nvmset(nvme_mi_ctrl_t ctrl, - __u16 nvmsetid, - struct nvme_nvmset_predictable_lat_log *log) -{ - struct nvme_get_log_args args = { - .lpo = 0, - .result = NULL, - .log = log, - .args_size = sizeof(args), - .lid = NVME_LOG_LID_PREDICTABLE_LAT_NVMSET, - .len = sizeof(*log), - .nsid = NVME_NSID_NONE, - .csi = NVME_CSI_NVM, - .lsi = nvmsetid, - .lsp = NVME_LOG_LSP_NONE, - .uuidx = NVME_UUID_NONE, - .rae = false, - .ot = false, - }; - return nvme_mi_admin_get_log(ctrl, &args); -} - -/** - * nvme_mi_admin_get_log_predictable_lat_event() - Retrieve Predictable Latency - * Event Aggregate Log Page - * @ctrl: Controller to query - * @rae: Retain asynchronous events - * @offset: Offset into the predictable latency event - * @len: Length of provided user buffer to hold the log data in bytes - * @log: User address for log page data - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. - */ -static inline int nvme_mi_admin_get_log_predictable_lat_event(nvme_mi_ctrl_t ctrl, - bool rae, - __u32 offset, - __u32 len, - void *log) -{ - struct nvme_get_log_args args = { - .lpo = offset, - .result = NULL, - .log = log, - .args_size = sizeof(args), - .lid = NVME_LOG_LID_PREDICTABLE_LAT_AGG, - .len = len, - .nsid = NVME_NSID_NONE, - .csi = NVME_CSI_NVM, - .lsi = NVME_LOG_LSI_NONE, - .lsp = NVME_LOG_LSP_NONE, - .uuidx = NVME_UUID_NONE, - .rae = rae, - .ot = false, - }; - return nvme_mi_admin_get_log(ctrl, &args); -} - -/** - * nvme_mi_admin_get_log_ana() - Retrieve Asymmetric Namespace Access log page - * @ctrl: Controller to query - * @lsp: Log specific, see &enum nvme_get_log_ana_lsp - * @rae: Retain asynchronous events - * @offset: Offset to the start of the log page - * @len: The allocated length of the log page - * @log: User address to store the ana log - * - * This log consists of a header describing the log and descriptors containing - * the asymmetric namespace access information for ANA Groups that contain - * namespaces that are attached to the controller processing the command. - * - * See &struct nvme_ana_log for the definition of the returned structure. - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. - */ -static inline int nvme_mi_admin_get_log_ana(nvme_mi_ctrl_t ctrl, - enum nvme_log_ana_lsp lsp, bool rae, - __u64 offset, __u32 len, void *log) -{ - struct nvme_get_log_args args = { - .lpo = offset, - .result = NULL, - .log = log, - .args_size = sizeof(args), - .lid = NVME_LOG_LID_ANA, - .len = len, - .nsid = NVME_NSID_NONE, - .csi = NVME_CSI_NVM, - .lsi = NVME_LOG_LSI_NONE, - .lsp = (__u8)lsp, - .uuidx = NVME_UUID_NONE, - .rae = rae, - .ot = false, - }; - return nvme_mi_admin_get_log(ctrl, &args); -} - -/** - * nvme_mi_admin_get_log_ana_groups() - Retrieve Asymmetric Namespace Access - * groups only log page - * @ctrl: Controller to query - * @rae: Retain asynchronous events - * @len: The allocated length of the log page - * @log: User address to store the ana group log - * - * See &struct nvme_ana_group_desc for the definition of the returned structure. - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. - */ -static inline int nvme_mi_admin_get_log_ana_groups(nvme_mi_ctrl_t ctrl, - bool rae, __u32 len, - struct nvme_ana_group_desc *log) -{ - return nvme_mi_admin_get_log_ana(ctrl, NVME_LOG_ANA_LSP_RGO_GROUPS_ONLY, rae, 0, - len, log); -} - -/** - * nvme_mi_admin_get_ana_log_atomic() - Retrieve Asymmetric Namespace Access - * log page atomically - * @ctrl: Controller to query - * @rgo: Whether to retrieve ANA groups only (no NSIDs) - * @rae: Whether to retain asynchronous events - * @retries: The maximum number of times to retry on log page changes - * @log: Pointer to a buffer to receive the ANA log page - * @len: Input: the length of the log page buffer. - * Output: the actual length of the ANA log page. - * - * See &struct nvme_ana_log for the definition of the returned structure. - * - * Return: If successful, returns 0 and sets *len to the actual log page length. - * If unsuccessful, returns the nvme command status if a response was received - * (see &enum nvme_status_field) or -1 with errno set otherwise. - * Sets errno = EINVAL if retries == 0. - * Sets errno = EAGAIN if unable to read the log page atomically - * because chgcnt changed during each of the retries attempts. - * Sets errno = ENOSPC if the full log page does not fit in the provided buffer. - */ -int nvme_mi_admin_get_ana_log_atomic(nvme_mi_ctrl_t ctrl, bool rgo, bool rae, - unsigned int retries, - struct nvme_ana_log *log, __u32 *len); - -/** - * nvme_mi_admin_get_log_lba_status() - Retrieve LBA Status - * @ctrl: Controller to query - * @rae: Retain asynchronous events - * @offset: Offset to the start of the log page - * @len: The allocated length of the log page - * @log: User address to store the log page - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. - */ -static inline int nvme_mi_admin_get_log_lba_status(nvme_mi_ctrl_t ctrl, bool rae, - __u64 offset, __u32 len, - void *log) -{ - struct nvme_get_log_args args = { - .lpo = offset, - .result = NULL, - .log = log, - .args_size = sizeof(args), - .lid = NVME_LOG_LID_LBA_STATUS, - .len = len, - .nsid = NVME_NSID_NONE, - .csi = NVME_CSI_NVM, - .lsi = NVME_LOG_LSI_NONE, - .lsp = NVME_LOG_LSP_NONE, - .uuidx = NVME_UUID_NONE, - .rae = rae, - .ot = false, - }; - return nvme_mi_admin_get_log(ctrl, &args); -} - -/** - * nvme_mi_admin_get_log_endurance_grp_evt() - Retrieve Rotational Media - * Information - * @ctrl: Controller to query - * @rae: Retain asynchronous events - * @offset: Offset to the start of the log page - * @len: The allocated length of the log page - * @log: User address to store the log page - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. - */ -static inline int nvme_mi_admin_get_log_endurance_grp_evt(nvme_mi_ctrl_t ctrl, - bool rae, - __u32 offset, - __u32 len, - void *log) -{ - struct nvme_get_log_args args = { - .lpo = offset, - .result = NULL, - .log = log, - .args_size = sizeof(args), - .lid = NVME_LOG_LID_ENDURANCE_GRP_EVT, - .len = len, - .nsid = NVME_NSID_NONE, - .csi = NVME_CSI_NVM, - .lsi = NVME_LOG_LSI_NONE, - .lsp = NVME_LOG_LSP_NONE, - .uuidx = NVME_UUID_NONE, - .rae = rae, - .ot = false, - }; - return nvme_mi_admin_get_log(ctrl, &args); -} - -/** - * nvme_mi_admin_get_log_fid_supported_effects() - Retrieve Feature Identifiers - * Supported and Effects - * @ctrl: Controller to query - * @rae: Retain asynchronous events - * @log: FID Supported and Effects data structure - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. - */ -static inline int nvme_mi_admin_get_log_fid_supported_effects(nvme_mi_ctrl_t ctrl, - bool rae, - struct nvme_fid_supported_effects_log *log) -{ - return nvme_mi_admin_get_nsid_log(ctrl, rae, - NVME_LOG_LID_FID_SUPPORTED_EFFECTS, - NVME_NSID_NONE, sizeof(*log), log); -} - -/** - * nvme_mi_admin_get_log_mi_cmd_supported_effects() - displays the MI Commands - * Supported by the controller - * @ctrl: Controller to query - * @rae: Retain asynchronous events - * @log: MI Command Supported and Effects data structure - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. - */ -static inline int nvme_mi_admin_get_log_mi_cmd_supported_effects(nvme_mi_ctrl_t ctrl, - bool rae, - struct nvme_mi_cmd_supported_effects_log *log) -{ - return nvme_mi_admin_get_nsid_log(ctrl, rae, NVME_LOG_LID_MI_CMD_SUPPORTED_EFFECTS, - NVME_NSID_NONE, sizeof(*log), log); -} - -/** - * nvme_mi_admin_get_log_boot_partition() - Retrieve Boot Partition - * @ctrl: Controller to query - * @rae: Retain asynchronous events - * @lsp: The log specified field of LID - * @len: The allocated size, minimum - * struct nvme_boot_partition - * @part: User address to store the log page - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. - */ -static inline int nvme_mi_admin_get_log_boot_partition(nvme_mi_ctrl_t ctrl, - bool rae, __u8 lsp, - __u32 len, - struct nvme_boot_partition *part) -{ - struct nvme_get_log_args args = { - .lpo = 0, - .result = NULL, - .log = part, - .args_size = sizeof(args), - .lid = NVME_LOG_LID_BOOT_PARTITION, - .len = len, - .nsid = NVME_NSID_NONE, - .csi = NVME_CSI_NVM, - .lsi = NVME_LOG_LSI_NONE, - .lsp = NVME_LOG_LSP_NONE, - .uuidx = NVME_UUID_NONE, - .rae = rae, - .ot = false, - }; - return nvme_mi_admin_get_log(ctrl, &args); -} - -/** - * nvme_mi_admin_get_log_rotational_media_info() - Retrieve Rotational Media Information Log - * @ctrl: Controller to query - * @endgid: Endurance Group Identifier - * @len: The allocated length of the log page - * @log: User address to store the log page - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise - */ -static inline int nvme_mi_admin_get_log_rotational_media_info(nvme_mi_ctrl_t ctrl, __u16 endgid, - __u32 len, - struct nvme_rotational_media_info_log *log) -{ - return nvme_mi_admin_get_endgid_log(ctrl, false, NVME_LOG_LID_ROTATIONAL_MEDIA_INFO, endgid, - len, log); -} - -/** - * nvme_mi_admin_get_log_dispersed_ns_participating_nss() - Retrieve Dispersed Namespace - * Participating NVM Subsystems Log - * @ctrl: Controller to query - * @nsid: Namespace Identifier - * @len: The allocated length of the log page - * @log: User address to store the log page - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise - */ -static inline int nvme_mi_admin_get_log_dispersed_ns_participating_nss(nvme_mi_ctrl_t ctrl, - __u32 nsid, __u32 len, - struct nvme_dispersed_ns_participating_nss_log *log) -{ - return nvme_mi_admin_get_nsid_log(ctrl, false, NVME_LOG_LID_DISPERSED_NS_PARTICIPATING_NSS, - nsid, len, log); -} - -/** - * nvme_mi_admin_get_log_mgmt_addr_list() - Retrieve Management Address List Log - * @ctrl: Controller to query - * @len: The allocated length of the log page - * @log: User address to store the log page - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise - */ -static inline int nvme_mi_admin_get_log_mgmt_addr_list(nvme_mi_ctrl_t ctrl, __u32 len, - struct nvme_mgmt_addr_list_log *log) -{ - return nvme_mi_admin_get_log_simple(ctrl, NVME_LOG_LID_MGMT_ADDR_LIST, len, log); -} - -/** - * nvme_mi_admin_get_log_phy_rx_eom() - Retrieve Physical Interface Receiver Eye Opening Measurement Log - * @ctrl: Controller to query - * @lsp: Log specific, controls action and measurement quality - * @controller: Target controller ID - * @len: The allocated size, minimum - * struct nvme_phy_rx_eom_log - * @log: User address to store the log page - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise - */ -static inline int nvme_mi_admin_get_log_phy_rx_eom(nvme_mi_ctrl_t ctrl, - __u8 lsp, __u16 controller, - __u32 len, - struct nvme_phy_rx_eom_log *log) -{ - struct nvme_get_log_args args = { - .lpo = 0, - .result = NULL, - .log = log, - .args_size = sizeof(args), - .lid = NVME_LOG_LID_PHY_RX_EOM, - .len = len, - .nsid = NVME_NSID_NONE, - .csi = NVME_CSI_NVM, - .lsi = controller, - .lsp = lsp, - .uuidx = NVME_UUID_NONE, - .rae = false, - .ot = false, - }; - return nvme_mi_admin_get_log(ctrl, &args); -} - -/** - * nvme_mi_admin_get_log_reachability_groups() - Retrieve Reachability Groups Log - * @ctrl: Controller to query - * @rgo: Return groups only - * @rae: Retain asynchronous events - * @len: The allocated length of the log page - * @log: User address to store the log page - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise - */ -static inline int nvme_mi_admin_get_log_reachability_groups(nvme_mi_ctrl_t ctrl, bool rgo, bool rae, - __u32 len, struct nvme_reachability_groups_log *log) -{ - struct nvme_get_log_args args = { - .lpo = 0, - .result = NULL, - .log = log, - .args_size = sizeof(args), - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .lid = NVME_LOG_LID_REACHABILITY_GROUPS, - .len = len, - .nsid = NVME_NSID_ALL, - .csi = NVME_CSI_NVM, - .lsi = NVME_LOG_LSI_NONE, - .lsp = rgo, - .uuidx = NVME_LOG_LSP_NONE, - .rae = rae, - .ot = false, - }; - - return nvme_mi_admin_get_log_page(ctrl, NVME_LOG_PAGE_PDU_SIZE, &args); -} - -/** - * nvme_mi_admin_get_log_reachability_associations() - Retrieve Reachability Associations Log - * @ctrl: Controller to query - * @rao: Return associations only - * @rae: Retain asynchronous events - * @len: The allocated length of the log page - * @log: User address to store the log page - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise - */ -static inline int nvme_mi_admin_get_log_reachability_associations(nvme_mi_ctrl_t ctrl, bool rao, - bool rae, __u32 len, - struct nvme_reachability_associations_log *log) -{ - struct nvme_get_log_args args = { - .lpo = 0, - .result = NULL, - .log = log, - .args_size = sizeof(args), - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .lid = NVME_LOG_LID_REACHABILITY_ASSOCIATIONS, - .len = len, - .nsid = NVME_NSID_ALL, - .csi = NVME_CSI_NVM, - .lsi = NVME_LOG_LSI_NONE, - .lsp = rao, - .uuidx = NVME_LOG_LSP_NONE, - .rae = rae, - .ot = false, - }; - - return nvme_mi_admin_get_log_page(ctrl, NVME_LOG_PAGE_PDU_SIZE, &args); -} - -/** - * nvme_mi_admin_get_log_changed_alloc_ns_list() - Retrieve Changed Allocated Namespace List Log - * @ctrl: Controller to query - * @rae: Retain asynchronous events - * @len: The allocated length of the log page - * @log: User address to store the log page - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise - */ -static inline int nvme_mi_admin_get_log_changed_alloc_ns_list(nvme_mi_ctrl_t ctrl, bool rae, - __u32 len, struct nvme_ns_list *log) -{ - return nvme_mi_admin_get_nsid_log(ctrl, rae, NVME_LOG_LID_CHANGED_ALLOC_NS_LIST, - NVME_NSID_ALL, len, log); -} - -/** - * nvme_mi_admin_get_log_discovery() - Retrieve Discovery log page - * @ctrl: Controller to query - * @rae: Retain asynchronous events - * @offset: Offset of this log to retrieve - * @len: The allocated size for this portion of the log - * @log: User address to store the discovery log - * - * Supported only by fabrics discovery controllers, returning discovery - * records. - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. - */ -static inline int nvme_mi_admin_get_log_discovery(nvme_mi_ctrl_t ctrl, bool rae, - __u32 offset, __u32 len, - void *log) -{ - struct nvme_get_log_args args = { - .lpo = offset, - .result = NULL, - .log = log, - .args_size = sizeof(args), - .lid = NVME_LOG_LID_DISCOVER, - .len = len, - .nsid = NVME_NSID_NONE, - .csi = NVME_CSI_NVM, - .lsi = NVME_LOG_LSI_NONE, - .lsp = NVME_LOG_LSP_NONE, - .uuidx = NVME_UUID_NONE, - .rae = rae, - .ot = false, - }; - return nvme_mi_admin_get_log(ctrl, &args); -} - -/** - * nvme_mi_admin_get_log_host_discover() - Retrieve Host Discovery Log - * @ctrl: Controller to query - * @allhoste: All host entries - * @rae: Retain asynchronous events - * @len: The allocated length of the log page - * @log: User address to store the log page - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise - */ -static inline int nvme_mi_admin_get_log_host_discover(nvme_mi_ctrl_t ctrl, bool allhoste, bool rae, - __u32 len, struct nvme_host_discover_log *log) -{ - struct nvme_get_log_args args = { - .lpo = 0, - .result = NULL, - .log = log, - .args_size = sizeof(args), - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .lid = NVME_LOG_LID_HOST_DISCOVER, - .len = len, - .nsid = NVME_NSID_ALL, - .csi = NVME_CSI_NVM, - .lsi = NVME_LOG_LSI_NONE, - .lsp = allhoste, - .uuidx = NVME_LOG_LSP_NONE, - .rae = rae, - .ot = false, - }; - - return nvme_mi_admin_get_log_page(ctrl, NVME_LOG_PAGE_PDU_SIZE, &args); -} - -/** - * nvme_mi_admin_get_log_ave_discover() - Retrieve AVE Discovery Log - * @ctrl: Controller to query - * @rae: Retain asynchronous events - * @len: The allocated length of the log page - * @log: User address to store the log page - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise - */ -static inline int nvme_mi_admin_get_log_ave_discover(nvme_mi_ctrl_t ctrl, bool rae, __u32 len, - struct nvme_ave_discover_log *log) -{ - return nvme_mi_admin_get_nsid_log(ctrl, rae, NVME_LOG_LID_AVE_DISCOVER, NVME_NSID_ALL, len, - log); -} - -/** - * nvme_mi_admin_get_log_pull_model_ddc_req() - Retrieve Pull Model DDC Request Log - * @ctrl: Controller to query - * @rae: Retain asynchronous events - * @len: The allocated length of the log page - * @log: User address to store the log page - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise - */ -static inline int nvme_mi_admin_get_log_pull_model_ddc_req(nvme_mi_ctrl_t ctrl, bool rae, __u32 len, - struct nvme_pull_model_ddc_req_log *log) -{ - return nvme_mi_admin_get_nsid_log(ctrl, rae, NVME_LOG_LID_PULL_MODEL_DDC_REQ, NVME_NSID_ALL, - len, log); -} - -/** - * nvme_mi_admin_get_log_media_unit_stat() - Retrieve Media Unit Status - * @ctrl: Controller to query - * @domid: Domain Identifier selection, if supported - * @mus: User address to store the Media Unit statistics log - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. - */ -static inline int nvme_mi_admin_get_log_media_unit_stat(nvme_mi_ctrl_t ctrl, - __u16 domid, - struct nvme_media_unit_stat_log *mus) -{ - struct nvme_get_log_args args = { - .lpo = 0, - .result = NULL, - .log = mus, - .args_size = sizeof(args), - .lid = NVME_LOG_LID_MEDIA_UNIT_STATUS, - .len = sizeof(*mus), - .nsid = NVME_NSID_NONE, - .csi = NVME_CSI_NVM, - .lsi = domid, - .lsp = NVME_LOG_LSP_NONE, - .uuidx = NVME_UUID_NONE, - .rae = false, - .ot = false, - }; - return nvme_mi_admin_get_log(ctrl, &args); -} - -/** - * nvme_mi_admin_get_log_support_cap_config_list() - Retrieve Supported - * Capacity Configuration List - * @ctrl: Controller to query - * @domid: Domain Identifier selection, if supported - * @cap: User address to store supported capabilities config list - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. - */ -static inline int nvme_mi_admin_get_log_support_cap_config_list(nvme_mi_ctrl_t ctrl, - __u16 domid, - struct nvme_supported_cap_config_list_log *cap) -{ - struct nvme_get_log_args args = { - .lpo = 0, - .result = NULL, - .log = cap, - .args_size = sizeof(args), - .lid = NVME_LOG_LID_SUPPORTED_CAP_CONFIG_LIST, - .len = sizeof(*cap), - .nsid = NVME_NSID_NONE, - .csi = NVME_CSI_NVM, - .lsi = domid, - .lsp = NVME_LOG_LSP_NONE, - .uuidx = NVME_UUID_NONE, - .rae = false, - .ot = false, - }; - return nvme_mi_admin_get_log(ctrl, &args); -} - -/** - * nvme_mi_admin_get_log_reservation() - Retrieve Reservation Notification - * @ctrl: Controller to query - * @rae: Retain asynchronous events - * @log: User address to store the reservation log - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. - */ -static inline int nvme_mi_admin_get_log_reservation(nvme_mi_ctrl_t ctrl, - bool rae, - struct nvme_resv_notification_log *log) -{ - return nvme_mi_admin_get_nsid_log(ctrl, rae, NVME_LOG_LID_RESERVATION, - NVME_NSID_ALL, sizeof(*log), log); -} - -/** - * nvme_mi_admin_get_log_sanitize() - Retrieve Sanitize Status - * @ctrl: Controller to query - * @rae: Retain asynchronous events - * @log: User address to store the sanitize log - * - * The Sanitize Status log page reports sanitize operation time estimates and - * information about the most recent sanitize operation. - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. - */ -static inline int nvme_mi_admin_get_log_sanitize(nvme_mi_ctrl_t ctrl, bool rae, - struct nvme_sanitize_log_page *log) -{ - return nvme_mi_admin_get_nsid_log(ctrl, rae, NVME_LOG_LID_SANITIZE, - NVME_NSID_ALL, sizeof(*log), log); -} - -/** - * nvme_mi_admin_get_log_zns_changed_zones() - Retrieve list of zones that have - * changed - * @ctrl: Controller to query - * @nsid: Namespace ID - * @rae: Retain asynchronous events - * @log: User address to store the changed zone log - * - * The list of zones that have changed state due to an exceptional event. - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. - */ -static inline int nvme_mi_admin_get_log_zns_changed_zones(nvme_mi_ctrl_t ctrl, - __u32 nsid, bool rae, - struct nvme_zns_changed_zone_log *log) -{ - struct nvme_get_log_args args = { - .lpo = 0, - .result = NULL, - .log = log, - .args_size = sizeof(args), - .lid = NVME_LOG_LID_ZNS_CHANGED_ZONES, - .len = sizeof(*log), - .nsid = nsid, - .csi = NVME_CSI_ZNS, - .lsi = NVME_LOG_LSI_NONE, - .lsp = NVME_LOG_LSP_NONE, - .uuidx = NVME_UUID_NONE, - .rae = rae, - .ot = false, - }; - return nvme_mi_admin_get_log(ctrl, &args); -} - -/** - * nvme_mi_admin_get_log_persistent_event() - Retrieve Persistent Event Log - * @ctrl: Controller to query - * @action: Action the controller should take during processing this command - * @size: Size of @pevent_log - * @pevent_log: User address to store the persistent event log - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. - */ -static inline int nvme_mi_admin_get_log_persistent_event(nvme_mi_ctrl_t ctrl, - enum nvme_pevent_log_action action, - __u32 size, void *pevent_log) -{ - struct nvme_get_log_args args = { - .lpo = 0, - .result = NULL, - .log = pevent_log, - .args_size = sizeof(args), - .lid = NVME_LOG_LID_PERSISTENT_EVENT, - .len = size, - .nsid = NVME_NSID_ALL, - .csi = NVME_CSI_NVM, - .lsi = NVME_LOG_LSI_NONE, - .lsp = (__u8)action, - .uuidx = NVME_UUID_NONE, - .rae = false, - .ot = false, - }; - return nvme_mi_admin_get_log(ctrl, &args); -} - -/** - * nvme_mi_admin_get_log_lockdown() - Retrieve lockdown Log - * @ctrl: Controller to query - * @cnscp: Contents and Scope of Command and Feature Identifier Lists - * @lockdown_log: Buffer to store the lockdown log - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. - */ -static inline int nvme_mi_admin_get_log_lockdown(nvme_mi_ctrl_t ctrl, - __u8 cnscp, struct nvme_lockdown_log *lockdown_log) -{ - struct nvme_get_log_args args = { - .lpo = 0, - .result = NULL, - .log = lockdown_log, - .args_size = sizeof(args), - .lid = NVME_LOG_LID_CMD_AND_FEAT_LOCKDOWN, - .len = sizeof(*lockdown_log), - .nsid = NVME_NSID_ALL, - .csi = NVME_CSI_NVM, - .lsi = NVME_LOG_LSI_NONE, - .lsp = cnscp, - .uuidx = NVME_UUID_NONE, - .rae = false, - .ot = false, - }; - return nvme_mi_admin_get_log(ctrl, &args); -} - -/** - * nvme_mi_admin_security_send() - Perform a Security Send command on a - * controller. - * @ctrl: Controller to send command to - * @args: Security Send command arguments - * - * Performs a Security Send Admin command as specified by @args. Response data - * is stored in @args->data, which should be a buffer of @args->data_len bytes. - * Resulting data length is stored in @args->data_len on successful - * command completion. - * - * Security Send data length should not be greater than 4096 bytes to - * comply with specification limits. - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. - * - * See: &struct nvme_get_log_args - */ -int nvme_mi_admin_security_send(nvme_mi_ctrl_t ctrl, - struct nvme_security_send_args *args); - -/** - * nvme_mi_admin_security_recv() - Perform a Security Receive command on a - * controller. - * @ctrl: Controller to send command to - * @args: Security Receive command arguments - * - * Performs a Security Receive Admin command as specified by @args. Response - * data is stored in @args->data, which should be a buffer of @args->data_len - * bytes. Resulting data length is stored in @args->data_len on successful - * command completion. - * - * Security Receive data length should not be greater than 4096 bytes to - * comply with specification limits. - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. - * - * See: &struct nvme_get_log_args - */ -int nvme_mi_admin_security_recv(nvme_mi_ctrl_t ctrl, - struct nvme_security_receive_args *args); - -/** - * nvme_mi_admin_get_features - Perform a Get Feature command on a controller - * @ctrl: Controller to send command to - * @args: Get Features command arguments - * - * Performs a Get Features Admin command as specified by @args. Returned - * feature data will be stored in @args->result and @args->data, depending - * on the specification of the feature itself; most features do not return - * additional data. See section 5.27.1 of the NVMe spec (v2.0b) for - * feature-specific information. - * - * On success, @args->data_len will be updated with the actual data length - * received. - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. - */ -int nvme_mi_admin_get_features(nvme_mi_ctrl_t ctrl, - struct nvme_get_features_args *args); - -/** - * nvme_mi_admin_get_features_arbitration() - Get arbitration feature - * @ctrl: Controller to send command to - * @sel: Select which type of attribute to return, see &enum nvme_get_features_sel - * @result: The feature data is returned in this argument - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. - */ -int nvme_mi_admin_get_features_arbitration(nvme_mi_ctrl_t ctrl, enum nvme_get_features_sel sel, - __u32 *result); - -/** - * nvme_mi_admin_get_features_power_mgmt() - Get power management feature - * @ctrl: Controller to send command to - * @sel: Select which type of attribute to return, see &enum nvme_get_features_sel - * @result: The feature data is returned in this argument - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. - */ -int nvme_mi_admin_get_features_power_mgmt(nvme_mi_ctrl_t ctrl, enum nvme_get_features_sel sel, - __u32 *result); - -/** - * nvme_mi_admin_get_features_data() - Helper function for &nvme_mi_admin_get_features() - * @ctrl: Controller to send command to - * @fid: Feature identifier - * @nsid: Namespace ID, if applicable for @fid - * @data_len: Length of feature data, if applicable for @fid, in bytes - * @data: User address of feature data, if applicable - * @result: The command completion result from CQE dword0 - * - * Helper for optionally features that optionally return data, using the - * SEL_CURRENT selector value. - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. - */ -static inline int nvme_mi_admin_get_features_data(nvme_mi_ctrl_t ctrl, - enum nvme_features_id fid, - __u32 nsid, __u32 data_len, - void *data, __u32 *result) -{ - struct nvme_get_features_args args = { - .result = result, - .data = data, - .args_size = sizeof(args), - .nsid = nsid, - .sel = NVME_GET_FEATURES_SEL_CURRENT, - .cdw11 = 0, - .data_len = data_len, - .fid = (__u8)fid, - .uuidx = NVME_UUID_NONE, - }; - - return nvme_mi_admin_get_features(ctrl, &args); -} - -/** - * nvme_mi_admin_get_features_simple - Get a simple feature value with no data - * @ctrl: Controller to send command to - * @fid: Feature identifier - * @nsid: Namespace id, if required by @fid - * @result: output feature data - */ -static inline int nvme_mi_admin_get_features_simple(nvme_mi_ctrl_t ctrl, - enum nvme_features_id fid, - __u32 nsid, - __u32 *result) -{ - return nvme_mi_admin_get_features_data(ctrl, fid, nsid, - 0, NULL, result); -} - -/** - * nvme_mi_admin_set_features - Perform a Set Features command on a controller - * @ctrl: Controller to send command to - * @args: Set Features command arguments - * - * Performs a Set Features Admin command as specified by @args. Result - * data will be stored in @args->result. - * on the specification of the feature itself; most features do not return - * additional data. See section 5.27.1 of the NVMe spec (v2.0b) for - * feature-specific information. - * - * On success, @args->data_len will be updated with the actual data length - * received. - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. - */ -int nvme_mi_admin_set_features(nvme_mi_ctrl_t ctrl, - struct nvme_set_features_args *args); - -/** - * nvme_mi_admin_set_features_power_mgmt() - Set power management feature - * @ctrl: Controller to send command to - * @ps: Power State - * @wh: Workload Hint - * @save: Save value across power states - * @result: The feature data is returned in this argument - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. - */ -int nvme_mi_admin_set_features_power_mgmt(nvme_mi_ctrl_t ctrl, __u8 ps, __u8 wh, bool save, - __u32 *result); - -/** - * nvme_mi_admin_ns_mgmt - Issue a Namespace Management command - * @ctrl: Controller to send command to - * @args: Namespace management command arguments - * - * Issues a Namespace Management command to @ctrl, with arguments specified - * from @args. - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. - */ -int nvme_mi_admin_ns_mgmt(nvme_mi_ctrl_t ctrl, - struct nvme_ns_mgmt_args *args); - -/** - * nvme_mi_admin_ns_mgmt_create - Helper for Namespace Management Create command - * @ctrl: Controller to send command to - * @ns: New namespace parameters - * @csi: Command Set Identifier for new NS - * @nsid: Set to new namespace ID on create - * @data: Host Software Specified Fields that defines ns creation parameters - * - * Issues a Namespace Management (Create) command to @ctrl, to create a - * new namespace specified by @ns, using command set @csi. On success, - * the new namespace ID will be written to @nsid. - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. - */ -static inline int nvme_mi_admin_ns_mgmt_create(nvme_mi_ctrl_t ctrl, - struct nvme_id_ns *ns, __u8 csi, __u32 *nsid, - struct nvme_ns_mgmt_host_sw_specified *data) -{ - struct nvme_ns_mgmt_args args = { - .result = nsid, - .ns = ns, - .args_size = sizeof(args), - .nsid = NVME_NSID_NONE, - .sel = NVME_NS_MGMT_SEL_CREATE, - .csi = csi, - .data = data, - }; - - return nvme_mi_admin_ns_mgmt(ctrl, &args); -} - -/** - * nvme_mi_admin_ns_mgmt_delete - Helper for Namespace Management Delete command - * @ctrl: Controller to send command to - * @nsid: Namespace ID to delete - * - * Issues a Namespace Management (Delete) command to @ctrl, to delete the - * namespace with id @nsid. - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. - */ -static inline int nvme_mi_admin_ns_mgmt_delete(nvme_mi_ctrl_t ctrl, __u32 nsid) -{ - struct nvme_ns_mgmt_args args = { - .args_size = sizeof(args), - .nsid = nsid, - .sel = NVME_NS_MGMT_SEL_DELETE, - }; - - return nvme_mi_admin_ns_mgmt(ctrl, &args); -} - -/** - * nvme_mi_admin_ns_attach() - Attach or detach namespace to controller(s) - * @ctrl: Controller to send command to - * @args: Namespace Attach command arguments - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. - */ -int nvme_mi_admin_ns_attach(nvme_mi_ctrl_t ctrl, - struct nvme_ns_attach_args *args); - -/** - * nvme_mi_admin_ns_attach_ctrls() - Attach namespace to controllers - * @ctrl: Controller to send command to - * @nsid: Namespace ID to attach - * @ctrlist: Controller list to modify attachment state of nsid - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. - */ -static inline int nvme_mi_admin_ns_attach_ctrls(nvme_mi_ctrl_t ctrl, __u32 nsid, - struct nvme_ctrl_list *ctrlist) -{ - struct nvme_ns_attach_args args = { - .result = NULL, - .ctrlist = ctrlist, - .args_size = sizeof(args), - .nsid = nsid, - .sel = NVME_NS_ATTACH_SEL_CTRL_ATTACH, - }; - - return nvme_mi_admin_ns_attach(ctrl, &args); -} - -/** - * nvme_mi_admin_ns_detach_ctrls() - Detach namespace from controllers - * @ctrl: Controller to send command to - * @nsid: Namespace ID to detach - * @ctrlist: Controller list to modify attachment state of nsid - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. - */ -static inline int nvme_mi_admin_ns_detach_ctrls(nvme_mi_ctrl_t ctrl, __u32 nsid, - struct nvme_ctrl_list *ctrlist) -{ - struct nvme_ns_attach_args args = { - .result = NULL, - .ctrlist = ctrlist, - .args_size = sizeof(args), - .nsid = nsid, - .sel = NVME_NS_ATTACH_SEL_CTRL_DEATTACH, - }; - - return nvme_mi_admin_ns_attach(ctrl, &args); -} - -/** - * nvme_mi_admin_fw_download() - Download part or all of a firmware image to - * the controller - * @ctrl: Controller to send firmware data to - * @args: &struct nvme_fw_download_args argument structure - * - * The Firmware Image Download command downloads all or a portion of an image - * for a future update to the controller. The Firmware Image Download command - * downloads a new image (in whole or in part) to the controller. - * - * The image may be constructed of multiple pieces that are individually - * downloaded with separate Firmware Image Download commands. Each Firmware - * Image Download command includes a Dword Offset and Number of Dwords that - * specify a dword range. - * - * The new firmware image is not activated as part of the Firmware Image - * Download command. Use the nvme_mi_admin_fw_commit() to activate a newly - * downloaded image. - * - * Return: 0 on success, non-zero on failure - */ -int nvme_mi_admin_fw_download(nvme_mi_ctrl_t ctrl, - struct nvme_fw_download_args *args); - -/** - * nvme_mi_admin_fw_commit() - Commit firmware using the specified action - * @ctrl: Controller to send firmware data to - * @args: &struct nvme_fw_download_args argument structure - * - * The Firmware Commit command modifies the firmware image or Boot Partitions. - * - * Return: 0 on success, non-zero on failure - */ -int nvme_mi_admin_fw_commit(nvme_mi_ctrl_t ctrl, - struct nvme_fw_commit_args *args); - -/** - * nvme_mi_admin_format_nvm() - Format NVMe namespace - * @ctrl: Controller to send command to - * @args: Format NVM command arguments - * - * Perform a low-level format to set the LBA data & metadata size. May destroy - * data & metadata on the specified namespaces - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. - */ -int nvme_mi_admin_format_nvm(nvme_mi_ctrl_t ctrl, - struct nvme_format_nvm_args *args); - -/** - * nvme_mi_admin_sanitize_nvm() - Start a subsystem Sanitize operation - * @ctrl: Controller to send command to - * @args: Sanitize command arguments - * - * A sanitize operation alters all user data in the NVM subsystem such that - * recovery of any previous user data from any cache, the non-volatile media, - * or any Controller Memory Buffer is not possible. - * - * The Sanitize command starts a sanitize operation or to recover from a - * previously failed sanitize operation. The sanitize operation types that may - * be supported are Block Erase, Crypto Erase, and Overwrite. All sanitize - * operations are processed in the background, i.e., completion of the sanitize - * command does not indicate completion of the sanitize operation. - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. - */ -int nvme_mi_admin_sanitize_nvm(nvme_mi_ctrl_t ctrl, - struct nvme_sanitize_nvm_args *args); - /** * enum nvme_mi_aem_handler_next_action - Next action for the AEM state machine handler * @NVME_MI_AEM_HNA_ACK: Send an ack for the AEM diff --git a/src/nvme/nbft.c b/src/nvme/nbft.c index b7d0dc84d..fd94a450e 100644 --- a/src/nvme/nbft.c +++ b/src/nvme/nbft.c @@ -700,8 +700,7 @@ int nvme_nbft_read(struct nbft_info **nbft, const char *filename) if (raw_nbft_fp == NULL) { nvme_msg(NULL, LOG_ERR, "Failed to open %s: %s\n", filename, strerror(errno)); - errno = EINVAL; - return 1; + return -EINVAL; } i = fseek(raw_nbft_fp, 0L, SEEK_END); @@ -709,8 +708,7 @@ int nvme_nbft_read(struct nbft_info **nbft, const char *filename) nvme_msg(NULL, LOG_ERR, "Failed to read from %s: %s\n", filename, strerror(errno)); fclose(raw_nbft_fp); - errno = EINVAL; - return 1; + return -EINVAL; } raw_nbft_size = ftell(raw_nbft_fp); @@ -720,8 +718,7 @@ int nvme_nbft_read(struct nbft_info **nbft, const char *filename) if (!raw_nbft) { nvme_msg(NULL, LOG_ERR, "Failed to allocate memory for NBFT table"); fclose(raw_nbft_fp); - errno = ENOMEM; - return 1; + return -ENOMEM; } i = fread(raw_nbft, sizeof(*raw_nbft), raw_nbft_size, raw_nbft_fp); @@ -730,8 +727,7 @@ int nvme_nbft_read(struct nbft_info **nbft, const char *filename) filename, strerror(errno)); fclose(raw_nbft_fp); free(raw_nbft); - errno = EINVAL; - return 1; + return -EINVAL; } fclose(raw_nbft_fp); @@ -742,8 +738,7 @@ int nvme_nbft_read(struct nbft_info **nbft, const char *filename) if (!*nbft) { nvme_msg(NULL, LOG_ERR, "Could not allocate memory for NBFT\n"); free(raw_nbft); - errno = ENOMEM; - return 1; + return -ENOMEM; } (*nbft)->filename = strdup(filename); @@ -753,8 +748,7 @@ int nvme_nbft_read(struct nbft_info **nbft, const char *filename) if (parse_raw_nbft(*nbft)) { nvme_msg(NULL, LOG_ERR, "Failed to parse %s\n", filename); nvme_nbft_free(*nbft); - errno = EINVAL; - return 1; + return -EINVAL; } return 0; } diff --git a/src/nvme/private.h b/src/nvme/private.h index ac5949678..6162aa9aa 100644 --- a/src/nvme/private.h +++ b/src/nvme/private.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -23,6 +24,36 @@ const char *nvme_slots_sysfs_dir(void); const char *nvme_uuid_ibm_filename(void); const char *nvme_dmi_entries_dir(void); +struct nvme_log { + int fd; + int level; + bool pid; + bool timestamp; +}; + +enum nvme_link_type { + NVME_LINK_TYPE_UNKNOWN = 0, + NVME_LINK_TYPE_DIRECT, + NVME_LINK_TYPE_MI, +}; + +struct nvme_link { + struct nvme_root *root; + enum nvme_link_type type; + char *name; + + /* direct */ + int fd; + struct stat stat; + + /* mi */ + struct nvme_mi_ep *ep; + __u16 id; + struct list_node ep_entry; + + struct nvme_log *log; +}; + struct nvme_path { struct list_node entry; struct list_node nentry; @@ -52,7 +83,7 @@ struct nvme_ns { struct nvme_ctrl *c; struct nvme_ns_head *head; - int fd; + struct nvme_link *l; __u32 nsid; char *name; char *generic_name; @@ -76,7 +107,7 @@ struct nvme_ctrl { struct list_head namespaces; struct nvme_subsystem *s; - int fd; + struct nvme_link *l; char *name; char *sysfs_dir; char *address; @@ -171,13 +202,6 @@ struct nvme_fabric_options { bool trsvcid; }; -struct nvme_log { - int fd; - int level; - bool pid; - bool timestamp; -}; - struct nvme_root { char *config_file; char *application; @@ -198,6 +222,12 @@ int json_update_config(nvme_root_t r, const char *config_file); int json_dump_tree(nvme_root_t r); +nvme_link_t __nvme_open(nvme_root_t r, const char *name); +nvme_link_t __nvme_create_link(nvme_root_t root); +int __nvme_link_open_mi(nvme_link_t l, const char *devname); +int __nvme_link_init_mi(nvme_link_t l); +void __nvme_link_close_mi(nvme_link_t link); + nvme_ctrl_t __nvme_lookup_ctrl(nvme_subsystem_t s, const char *transport, const char *traddr, const char *host_traddr, const char *host_iface, const char *trsvcid, @@ -303,12 +333,6 @@ struct nvme_mi_ep { struct nvme_mi_aem_ctx *aem_ctx; }; -struct nvme_mi_ctrl { - struct nvme_mi_ep *ep; - __u16 id; - struct list_node ep_entry; -}; - struct nvme_mi_ep *nvme_mi_init_ep(struct nvme_root *root); void nvme_mi_ep_probe(struct nvme_mi_ep *ep); diff --git a/src/nvme/tree.c b/src/nvme/tree.c index 9aaaa1b50..208c468ff 100644 --- a/src/nvme/tree.c +++ b/src/nvme/tree.c @@ -29,6 +29,7 @@ #include "ioctl.h" #include "linux.h" #include "filters.h" +#include "nvme/api-types.h" #include "tree.h" #include "filters.h" #include "util.h" @@ -166,10 +167,8 @@ int nvme_host_get_ids(nvme_root_t r, */ if (!hid) { hid = nvmf_hostid_generate(); - if (!hid) { - errno = -ENOMEM; - return -1; - } + if (!hid) + return -ENOMEM; nvme_msg(r, LOG_DEBUG, "warning: using auto generated hostid and hostnqn\n"); @@ -178,10 +177,8 @@ int nvme_host_get_ids(nvme_root_t r, /* incomplete configuration, thus derive hostnqn from hostid */ if (!hnqn) { hnqn = nvmf_hostnqn_generate_from_hostid(hid); - if (!hnqn) { - errno = -ENOMEM; - return -1; - } + if (!hnqn) + return -ENOMEM; } /* sanity checks */ @@ -200,21 +197,24 @@ int nvme_host_get_ids(nvme_root_t r, return 0; } -nvme_host_t nvme_default_host(nvme_root_t r) +int nvme_default_host(nvme_root_t r, nvme_host_t *hp) { _cleanup_free_ char *hostnqn = NULL; _cleanup_free_ char *hostid = NULL; struct nvme_host *h; + int err; - if (nvme_host_get_ids(r, NULL, NULL, &hostnqn, &hostid)) - return NULL; + err = nvme_host_get_ids(r, NULL, NULL, &hostnqn, &hostid); + if (err) + return err; h = nvme_lookup_host(r, hostnqn, hostid); nvme_host_set_hostsymname(h, NULL); default_host = h; - return h; + *hp = h; + return 0; } static void nvme_filter_subsystem(nvme_root_t r, nvme_subsystem_t s, @@ -290,15 +290,17 @@ int nvme_scan_topology(struct nvme_root *r, nvme_scan_filter_t f, void *f_args) ctrls.num = nvme_scan_ctrls(&ctrls.ents); if (ctrls.num < 0) { nvme_msg(r, LOG_DEBUG, "failed to scan ctrls: %s\n", - strerror(errno)); + strerror(ctrls.num)); return ctrls.num; } for (i = 0; i < ctrls.num; i++) { - nvme_ctrl_t c = nvme_scan_ctrl(r, ctrls.ents[i]->d_name); - if (!c) { + nvme_ctrl_t c; + + ret = nvme_scan_ctrl(r, ctrls.ents[i]->d_name, &c); + if (!ret) { nvme_msg(r, LOG_DEBUG, "failed to scan ctrl %s: %s\n", - ctrls.ents[i]->d_name, strerror(errno)); + ctrls.ents[i]->d_name, strerror(ret)); continue; } } @@ -306,7 +308,7 @@ int nvme_scan_topology(struct nvme_root *r, nvme_scan_filter_t f, void *f_args) subsys.num = nvme_scan_subsystems(&subsys.ents); if (subsys.num < 0) { nvme_msg(r, LOG_DEBUG, "failed to scan subsystems: %s\n", - strerror(errno)); + strerror(subsys.num)); return subsys.num; } @@ -315,7 +317,7 @@ int nvme_scan_topology(struct nvme_root *r, nvme_scan_filter_t f, void *f_args) if (ret < 0) { nvme_msg(r, LOG_DEBUG, "failed to scan subsystem %s: %s\n", - subsys.ents[i]->d_name, strerror(errno)); + subsys.ents[i]->d_name, strerror(ret)); } } @@ -334,10 +336,8 @@ nvme_root_t nvme_create_root(FILE *fp, int log_level) int fd; r = calloc(1, sizeof(*r)); - if (!r) { - errno = ENOMEM; + if (!r) return NULL; - } if (fp) { fd = fileno(fp); @@ -358,42 +358,51 @@ nvme_root_t nvme_create_root(FILE *fp, int log_level) } int nvme_read_config(nvme_root_t r, const char *config_file) + { - int err = -1; - int tmp; + int err; - if (!r || !config_file) { - errno = ENODEV; - return err; - } + if (!r || !config_file) + return -ENODEV; r->config_file = strdup(config_file); - if (!r->config_file) { - errno = ENOMEM; - return err; - } + if (!r->config_file) + return -ENOMEM; - tmp = errno; err = json_read_config(r, config_file); /* * The json configuration file is optional, * so ignore errors when opening the file. */ - if (err < 0 && errno != EPROTO) { - errno = tmp; + if (err < 0 && err != -EPROTO) return 0; - } return err; } -nvme_root_t nvme_scan(const char *config_file) +int nvme_scan(const char *config_file, nvme_root_t *rp) { nvme_root_t r = nvme_create_root(NULL, DEFAULT_LOGLEVEL); + int ret; - nvme_scan_topology(r, NULL, NULL); - nvme_read_config(r, config_file); - return r; + if (!r) + return -ENOMEM; + + ret = nvme_scan_topology(r, NULL, NULL); + if (ret) + goto err; + if (config_file) { + ret = nvme_read_config(r, config_file); + if (ret) + goto err; + } + + *rp = r; + return 0; + +err: + nvme_free_root(r); + return ret; } int nvme_update_config(nvme_root_t r) @@ -518,7 +527,7 @@ void nvme_refresh_topology(nvme_root_t r) nvme_scan_topology(r, NULL, NULL); } -void nvme_free_tree(nvme_root_t r) +void nvme_free_root(nvme_root_t r) { struct nvme_host *h, *_h; @@ -633,7 +642,7 @@ nvme_path_t nvme_namespace_next_path(nvme_ns_t ns, nvme_path_t p) static void __nvme_free_ns(struct nvme_ns *n) { list_del_init(&n->entry); - nvme_ns_release_fd(n); + nvme_ns_release_link(n); free(n->generic_name); free(n->name); free(n->sysfs_dir); @@ -678,10 +687,10 @@ void nvme_subsystem_release_fds(struct nvme_subsystem *s) struct nvme_ns *n, *_n; nvme_subsystem_for_each_ctrl_safe(s, c, _c) - nvme_ctrl_release_fd(c); + nvme_ctrl_release_link(c); nvme_subsystem_for_each_ns_safe(s, n, _n) - nvme_ns_release_fd(n); + nvme_ns_release_link(n); } /* @@ -811,7 +820,7 @@ static int nvme_subsystem_scan_namespaces(nvme_root_t r, nvme_subsystem_t s) if (namespaces.num < 0) { nvme_msg(r, LOG_DEBUG, "failed to scan namespaces for subsys %s: %s\n", - s->subsysnqn, strerror(errno)); + s->subsysnqn, strerror(namespaces.num)); return namespaces.num; } @@ -821,7 +830,7 @@ static int nvme_subsystem_scan_namespaces(nvme_root_t r, nvme_subsystem_t s) if (ret < 0) nvme_msg(r, LOG_DEBUG, "failed to scan namespace %s: %s\n", - namespaces.ents[i]->d_name, strerror(errno)); + namespaces.ents[i]->d_name, strerror(ret)); } return 0; @@ -865,13 +874,11 @@ static int nvme_scan_subsystem(struct nvme_root *r, const char *name) nvme_msg(r, LOG_DEBUG, "scan subsystem %s\n", name); ret = asprintf(&path, "%s/%s", nvme_subsys_sysfs_dir(), name); if (ret < 0) - return ret; + return -errno; subsysnqn = nvme_get_attr(path, "subsysnqn"); - if (!subsysnqn) { - errno = ENODEV; - return -1; - } + if (!subsysnqn) + return -ENODEV; nvme_for_each_host(r, h) { nvme_for_each_subsystem(h, _s) { /* @@ -883,10 +890,8 @@ static int nvme_scan_subsystem(struct nvme_root *r, const char *name) continue; if (strcmp(_s->name, name)) continue; - if (!nvme_subsystem_scan_namespaces(r, _s)) { - errno = EINVAL; - return -1; - } + if (!nvme_subsystem_scan_namespaces(r, _s)) + return -EINVAL; s = _s; } } @@ -898,21 +903,18 @@ static int nvme_scan_subsystem(struct nvme_root *r, const char *name) */ nvme_msg(r, LOG_DEBUG, "creating detached subsystem '%s'\n", name); - h = nvme_default_host(r); + ret = nvme_default_host(r, &h); + if (ret) + return ret; s = nvme_alloc_subsystem(h, name, subsysnqn); - if (!s) { - errno = ENOMEM; - return -1; - } - if (!nvme_subsystem_scan_namespaces(r, s)) { - errno = EINVAL; - return -1; - } + if (!s) + return -ENOMEM; + if (!nvme_subsystem_scan_namespaces(r, s)) + return -EINVAL; } else if (strcmp(s->subsysnqn, subsysnqn)) { nvme_msg(r, LOG_DEBUG, "NQN mismatch for subsystem '%s'\n", name); - errno = EINVAL; - return -1; + return -EINVAL; } return 0; @@ -979,21 +981,16 @@ static int nvme_ctrl_scan_path(nvme_root_t r, struct nvme_ctrl *c, char *name) nvme_msg(r, LOG_DEBUG, "scan controller %s path %s\n", c->name, name); - if (!c->s) { - errno = ENXIO; - return -1; - } + if (!c->s) + return -ENXIO; + ret = asprintf(&path, "%s/%s", c->sysfs_dir, name); - if (ret < 0) { - errno = ENOMEM; - return -1; - } + if (ret < 0) + return -ENOMEM; p = calloc(1, sizeof(*p)); - if (!p) { - errno = ENOMEM; - return -1; - } + if (!p) + return -ENOMEM; p->c = c; p->name = strdup(name); @@ -1023,25 +1020,28 @@ static int nvme_ctrl_scan_path(nvme_root_t r, struct nvme_ctrl *c, char *name) return 0; } -int nvme_ctrl_get_fd(nvme_ctrl_t c) +nvme_link_t nvme_ctrl_get_link(nvme_ctrl_t c) { - if (c->fd < 0) { - c->fd = nvme_open(c->name); - if (c->fd < 0) - nvme_msg(root_from_ctrl(c), LOG_ERR, - "Failed to open ctrl %s, errno %d\n", - c->name, errno); + if (!c->l) { + nvme_root_t r = root_from_ctrl(c); + int err; + + err = nvme_open(r, c->name, &c->l); + if (err) + nvme_msg(r, LOG_ERR, + "Failed to open ctrl %s, error %d\n", + c->name, err); } - return c->fd; + return c->l; } -void nvme_ctrl_release_fd(nvme_ctrl_t c) +void nvme_ctrl_release_link(nvme_ctrl_t c) { - if (c->fd < 0) + if (!c->l) return; - close(c->fd); - c->fd = -1; + nvme_close(c->l); + c->l = NULL; } nvme_subsystem_t nvme_ctrl_get_subsystem(nvme_ctrl_t c) @@ -1286,7 +1286,7 @@ bool nvme_ctrl_is_unique_discovery_ctrl(nvme_ctrl_t c) int nvme_ctrl_identify(nvme_ctrl_t c, struct nvme_id_ctrl *id) { - return nvme_identify_ctrl(nvme_ctrl_get_fd(c), id); + return nvme_identify_ctrl(nvme_ctrl_get_link(c), id); } nvme_ns_t nvme_ctrl_first_ns(nvme_ctrl_t c) @@ -1313,7 +1313,7 @@ nvme_path_t nvme_ctrl_next_path(nvme_ctrl_t c, nvme_path_t p) do { free(a); (a) = NULL; } while (0) void nvme_deconfigure_ctrl(nvme_ctrl_t c) { - nvme_ctrl_release_fd(c); + nvme_ctrl_release_link(c); FREE_CTRL_ATTR(c->name); FREE_CTRL_ATTR(c->sysfs_dir); FREE_CTRL_ATTR(c->firmware); @@ -1404,36 +1404,32 @@ static bool traddr_is_hostname(const char *transport, const char *traddr) return true; } -struct nvme_ctrl *nvme_create_ctrl(nvme_root_t r, - const char *subsysnqn, const char *transport, - const char *traddr, const char *host_traddr, - const char *host_iface, const char *trsvcid) +int nvme_create_ctrl(nvme_root_t r, + const char *subsysnqn, const char *transport, + const char *traddr, const char *host_traddr, + const char *host_iface, const char *trsvcid, + nvme_ctrl_t *cp) { struct nvme_ctrl *c; if (!transport) { nvme_msg(r, LOG_ERR, "No transport specified\n"); - errno = EINVAL; - return NULL; + return -EINVAL; } if (strncmp(transport, "loop", 4) && strncmp(transport, "pcie", 4) && !traddr) { nvme_msg(r, LOG_ERR, "No transport address for '%s'\n", transport); - errno = EINVAL; - return NULL; + return -EINVAL; } if (!subsysnqn) { nvme_msg(r, LOG_ERR, "No subsystem NQN specified\n"); - errno = EINVAL; - return NULL; + return -EINVAL; } c = calloc(1, sizeof(*c)); - if (!c) { - errno = ENOMEM; - return NULL; - } - c->fd = -1; + if (!c) + return -ENOMEM; + c->l = NULL; nvmf_default_config(&c->cfg); list_head_init(&c->namespaces); list_head_init(&c->paths); @@ -1444,7 +1440,7 @@ struct nvme_ctrl *nvme_create_ctrl(nvme_root_t r, c->traddr = strdup(traddr); if (host_traddr) { if (traddr_is_hostname(transport, host_traddr)) - c->cfg.host_traddr = hostname2traddr(r, host_traddr); + hostname2traddr(r, host_traddr, &c->cfg.host_traddr); if (!c->cfg.host_traddr) c->cfg.host_traddr = strdup(host_traddr); } @@ -1453,7 +1449,8 @@ struct nvme_ctrl *nvme_create_ctrl(nvme_root_t r, if (trsvcid) c->trsvcid = strdup(trsvcid); - return c; + *cp = c; + return 0; } /** @@ -1850,6 +1847,7 @@ nvme_ctrl_t nvme_lookup_ctrl(nvme_subsystem_t s, const char *transport, { nvme_root_t r; struct nvme_ctrl *c; + int ret; if (!s || !transport) return NULL; @@ -1860,13 +1858,15 @@ nvme_ctrl_t nvme_lookup_ctrl(nvme_subsystem_t s, const char *transport, return c; r = s->h ? s->h->r : NULL; - c = nvme_create_ctrl(r, s->subsysnqn, transport, traddr, - host_traddr, host_iface, trsvcid); - if (c) { - c->s = s; - list_add_tail(&s->ctrls, &c->entry); - s->h->r->modified = true; - } + ret = nvme_create_ctrl(r, s->subsysnqn, transport, traddr, + host_traddr, host_iface, trsvcid, &c); + if (ret) + return NULL; + + c->s = s; + list_add_tail(&s->ctrls, &c->entry); + s->h->r->modified = true; + return c; } @@ -1907,8 +1907,9 @@ static int nvme_ctrl_scan_namespaces(nvme_root_t r, struct nvme_ctrl *c) return 0; } -static char *nvme_ctrl_lookup_subsystem_name(nvme_root_t r, - const char *ctrl_name) +static int nvme_ctrl_lookup_subsystem_name(nvme_root_t r, + const char *ctrl_name, + char **name) { const char *subsys_dir = nvme_subsys_sysfs_dir(); _cleanup_dirents_ struct dirents subsys = {}; @@ -1916,26 +1917,30 @@ static char *nvme_ctrl_lookup_subsystem_name(nvme_root_t r, subsys.num = nvme_scan_subsystems(&subsys.ents); if (subsys.num < 0) - return NULL; + return subsys.num; + for (i = 0; i < subsys.num; i++) { struct stat st; _cleanup_free_ char *path = NULL; if (asprintf(&path, "%s/%s/%s", subsys_dir, - subsys.ents[i]->d_name, ctrl_name) < 0) { - errno = ENOMEM; - return NULL; - } + subsys.ents[i]->d_name, ctrl_name) < 0) + return -ENOMEM; nvme_msg(r, LOG_DEBUG, "lookup subsystem %s\n", path); if (stat(path, &st) < 0) { continue; } - return strdup(subsys.ents[i]->d_name); + + *name = strdup(subsys.ents[i]->d_name); + if (!*name) + return -ENOMEM; + + return 0; } - return NULL; + return -ENOENT; } -static char *nvme_ctrl_lookup_phy_slot(nvme_root_t r, const char *address) +static int nvme_ctrl_lookup_phy_slot(nvme_root_t r, const char *address, char **slot) { const char *slots_sysfs_dir = nvme_slots_sysfs_dir(); _cleanup_free_ char *target_addr = NULL; @@ -1944,13 +1949,13 @@ static char *nvme_ctrl_lookup_phy_slot(nvme_root_t r, const char *address) struct dirent *entry; if (!address) - return NULL; + return -EINVAL; slots_dir = opendir(slots_sysfs_dir); if (!slots_dir) { nvme_msg(r, LOG_WARNING, "failed to open slots dir %s\n", slots_sysfs_dir); - return NULL; + return -errno; } target_addr = strndup(address, 10); @@ -1963,20 +1968,24 @@ static char *nvme_ctrl_lookup_phy_slot(nvme_root_t r, const char *address) ret = asprintf(&path, "%s/%s", slots_sysfs_dir, entry->d_name); - if (ret < 0) { - errno = ENOMEM; - return NULL; - } + if (ret < 0) + return -ENOMEM; addr = nvme_get_attr(path, "address"); /* some directories don't have an address entry */ if (!addr) continue; - if (strcmp(addr, target_addr) == 0) - return strdup(entry->d_name); + if (strcmp(addr, target_addr)) + continue; + + *slot = strdup(entry->d_name); + if (*slot) + return -ENOMEM; + + return 0; } } - return NULL; + return -ENOENT; } static void nvme_read_sysfs_dhchap(nvme_root_t r, nvme_ctrl_t c) @@ -2049,7 +2058,7 @@ static int nvme_reconfigure_ctrl(nvme_root_t r, nvme_ctrl_t c, const char *path, * It's necesssary to release any resources first because a ctrl * can be reused. */ - nvme_ctrl_release_fd(c); + nvme_ctrl_release_link(c); FREE_CTRL_ATTR(c->name); FREE_CTRL_ATTR(c->sysfs_dir); FREE_CTRL_ATTR(c->firmware); @@ -2068,11 +2077,11 @@ static int nvme_reconfigure_ctrl(nvme_root_t r, nvme_ctrl_t c, const char *path, if (!d) { nvme_msg(r, LOG_ERR, "Failed to open ctrl dir %s, error %d\n", path, errno); - errno = ENODEV; - return -1; + return -ENODEV; } closedir(d); + c->l = NULL; c->name = strdup(name); c->sysfs_dir = strdup(path); c->firmware = nvme_get_ctrl_attr(c, "firmware_rev"); @@ -2085,11 +2094,10 @@ static int nvme_reconfigure_ctrl(nvme_root_t r, nvme_ctrl_t c, const char *path, c->cntrltype = nvme_get_ctrl_attr(c, "cntrltype"); c->cntlid = nvme_get_ctrl_attr(c, "cntlid"); c->dctype = nvme_get_ctrl_attr(c, "dctype"); - c->phy_slot = nvme_ctrl_lookup_phy_slot(r, c->address); + nvme_ctrl_lookup_phy_slot(r, c->address, &c->phy_slot); nvme_read_sysfs_dhchap(r, c); nvme_read_sysfs_tls(r, c); - errno = 0; /* cleanup after nvme_get_ctrl_attr() */ return 0; } @@ -2100,48 +2108,45 @@ int nvme_init_ctrl(nvme_host_t h, nvme_ctrl_t c, int instance) int ret; ret = asprintf(&name, "nvme%d", instance); - if (ret < 0) { - errno = ENOMEM; - return -1; - } + if (ret < 0) + return -ENOMEM; + ret = asprintf(&path, "%s/%s", nvme_ctrl_sysfs_dir(), name); - if (ret < 0) { - errno = ENOMEM; - return ret; - } + if (ret < 0) + return -ENOMEM; ret = nvme_reconfigure_ctrl(h->r, c, path, name); if (ret < 0) return ret; c->address = nvme_get_attr(path, "address"); - if (!c->address && strcmp(c->transport, "loop")) { - errno = ENVME_CONNECT_INVAL_TR; - return -1; - } + if (!c->address && strcmp(c->transport, "loop")) + return -ENVME_CONNECT_INVAL_TR; - subsys_name = nvme_ctrl_lookup_subsystem_name(h->r, name); - if (!subsys_name) { + ret = nvme_ctrl_lookup_subsystem_name(h->r, name, &subsys_name); + if (ret) { nvme_msg(h->r, LOG_ERR, "Failed to lookup subsystem name for %s\n", c->name); - errno = ENVME_CONNECT_LOOKUP_SUBSYS_NAME; - return -1; + return ENVME_CONNECT_LOOKUP_SUBSYS_NAME; } + s = nvme_lookup_subsystem(h, subsys_name, c->subsysnqn); - if (!s) { - errno = ENVME_CONNECT_LOOKUP_SUBSYS; - return -1; - } + if (!s) + return -ENVME_CONNECT_LOOKUP_SUBSYS; + if (s->subsystype && !strcmp(s->subsystype, "discovery")) c->discovery_ctrl = true; + c->s = s; list_add_tail(&s->ctrls, &c->entry); + return ret; } -static nvme_ctrl_t nvme_ctrl_alloc(nvme_root_t r, nvme_subsystem_t s, - const char *path, const char *name) +int nvme_ctrl_alloc(nvme_root_t r, nvme_subsystem_t s, + const char *path, const char *name, + nvme_ctrl_t *cp) { _cleanup_free_ char *addr = NULL, *address = NULL, *transport = NULL; char *host_traddr = NULL, *host_iface = NULL; @@ -2151,10 +2156,9 @@ static nvme_ctrl_t nvme_ctrl_alloc(nvme_root_t r, nvme_subsystem_t s, int ret; transport = nvme_get_attr(path, "transport"); - if (!transport) { - errno = ENXIO; - return NULL; - } + if (!transport) + return -ENXIO; + /* Parse 'address' string into components */ addr = nvme_get_attr(path, "address"); if (!addr) { @@ -2166,16 +2170,12 @@ static nvme_ctrl_t nvme_ctrl_alloc(nvme_root_t r, nvme_subsystem_t s, goto skip_address; /* Older kernel don't support pcie transport addresses */ - if (strcmp(transport, "pcie")) { - errno = ENXIO; - return NULL; - } + if (strcmp(transport, "pcie")) + return -ENXIO; /* Figure out the PCI address from the attribute path */ rpath = realpath(path, NULL); - if (!rpath) { - errno = ENOMEM; - return NULL; - } + if (!rpath) + return -ENOMEM; a = strtok_r(rpath, "/", &e); while(a && strlen(a)) { if (_a) @@ -2226,18 +2226,23 @@ static nvme_ctrl_t nvme_ctrl_alloc(nvme_root_t r, nvme_subsystem_t s, c = p; if (!c && !p) { nvme_msg(r, LOG_ERR, "failed to lookup ctrl\n"); - errno = ENODEV; - return NULL; + return -ENODEV; } FREE_CTRL_ATTR(c->address); c->address = strdup(addr); if (s->subsystype && !strcmp(s->subsystype, "discovery")) c->discovery_ctrl = true; + ret = nvme_reconfigure_ctrl(r, c, path, name); - return (ret < 0) ? NULL : c; + if (ret) { + nvme_free_ctrl(c); + return ret; + } + *cp = c; + return 0; } -nvme_ctrl_t nvme_scan_ctrl(nvme_root_t r, const char *name) +int nvme_scan_ctrl(nvme_root_t r, const char *name, nvme_ctrl_t *cp) { _cleanup_free_ char *subsysnqn = NULL, *subsysname = NULL; _cleanup_free_ char *hostnqn = NULL, *hostid = NULL; @@ -2249,10 +2254,8 @@ nvme_ctrl_t nvme_scan_ctrl(nvme_root_t r, const char *name) nvme_msg(r, LOG_DEBUG, "scan controller %s\n", name); ret = asprintf(&path, "%s/%s", nvme_ctrl_sysfs_dir(), name); - if (ret < 0) { - errno = ENOMEM; - return NULL; - } + if (ret < 0) + return -ENOMEM; hostnqn = nvme_get_attr(path, "hostnqn"); hostid = nvme_get_attr(path, "hostid"); @@ -2266,40 +2269,36 @@ nvme_ctrl_t nvme_scan_ctrl(nvme_root_t r, const char *name) } } if (!h) { - h = nvme_default_host(r); - if (!h) { - errno = ENOMEM; - return NULL; - } + ret = nvme_default_host(r, &h); + if (ret) + return ret; } subsysnqn = nvme_get_attr(path, "subsysnqn"); - if (!subsysnqn) { - errno = ENXIO; - return NULL; - } - subsysname = nvme_ctrl_lookup_subsystem_name(r, name); - if (!subsysname) { + if (!subsysnqn) + return -ENXIO; + + ret = nvme_ctrl_lookup_subsystem_name(r, name, &subsysname); + if (ret) { nvme_msg(r, LOG_DEBUG, "failed to lookup subsystem for controller %s\n", name); - errno = ENXIO; - return NULL; + return ret; } - s = nvme_lookup_subsystem(h, subsysname, subsysnqn); - if (!s) { - errno = ENOMEM; - return NULL; - } + s = nvme_lookup_subsystem(h, subsysname, subsysnqn); + if (!s) + return -ENOMEM; - c = nvme_ctrl_alloc(r, s, path, name); - if (!c) - return NULL; + ret = nvme_ctrl_alloc(r, s, path, name, &c); + if (ret) + return ret; nvme_ctrl_scan_paths(r, c); nvme_ctrl_scan_namespaces(r, c); - return c; + + *cp = c; + return 0; } void nvme_rescan_ctrl(struct nvme_ctrl *c) @@ -2318,36 +2317,38 @@ static int nvme_bytes_to_lba(nvme_ns_t n, off_t offset, size_t count, int bs; bs = nvme_ns_get_lba_size(n); - if (!count || offset & (bs - 1) || count & (bs - 1)) { - errno = EINVAL; - return -1; - } + if (!count || offset & (bs - 1) || count & (bs - 1)) + return -EINVAL; *lba = offset >> n->lba_shift; *nlb = (count >> n->lba_shift) - 1; + return 0; } -int nvme_ns_get_fd(nvme_ns_t n) +nvme_link_t nvme_ns_get_link(nvme_ns_t n) { - if (n->fd < 0) { - n->fd = nvme_open(n->name); - if (n->fd < 0) - nvme_msg(root_from_ns(n), LOG_ERR, - "Failed to open ns %s, errno %d\n", - n->name, errno); + if (!n->l) { + nvme_root_t r = root_from_ns(n); + int err; + + err = nvme_open(r, n->name, &n->l); + if (err) + nvme_msg(r, LOG_ERR, + "Failed to open ns %s, error %d\n", + n->name, err); } - return n->fd; + return n->l; } -void nvme_ns_release_fd(nvme_ns_t n) +void nvme_ns_release_link(nvme_ns_t n) { - if (n->fd < 0) + if (!n->l) return; - close(n->fd); - n->fd = -1; + nvme_close(n->l); + n->l = NULL; } nvme_subsystem_t nvme_ns_get_subsystem(nvme_ns_t n) @@ -2442,179 +2443,89 @@ void nvme_ns_get_uuid(nvme_ns_t n, unsigned char out[NVME_UUID_LEN]) int nvme_ns_identify(nvme_ns_t n, struct nvme_id_ns *ns) { - return nvme_identify_ns(nvme_ns_get_fd(n), nvme_ns_get_nsid(n), ns); + return nvme_identify_ns(nvme_ns_get_link(n), nvme_ns_get_nsid(n), ns); } int nvme_ns_identify_descs(nvme_ns_t n, struct nvme_ns_id_desc *descs) { - return nvme_identify_ns_descs(nvme_ns_get_fd(n), nvme_ns_get_nsid(n), descs); + return nvme_identify_ns_descs(nvme_ns_get_link(n), nvme_ns_get_nsid(n), descs); } int nvme_ns_verify(nvme_ns_t n, off_t offset, size_t count) { - struct nvme_io_args args = { - .args_size = sizeof(args), - .fd = nvme_ns_get_fd(n), - .nsid = nvme_ns_get_nsid(n), - .control = 0, - .dsm = 0, - .dspec = 0, - .reftag = 0, - .apptag = 0, - .appmask = 0, - .storage_tag = 0, - .data_len = 0, - .data = NULL, - .metadata_len = 0, - .metadata = NULL, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .result = NULL, - }; + __u64 slba; + __u16 nlb; - if (nvme_bytes_to_lba(n, offset, count, &args.slba, &args.nlb)) + if (nvme_bytes_to_lba(n, offset, count, &slba, &nlb)) return -1; - return nvme_verify(&args); + return nvme_verify(nvme_ns_get_link(n), nvme_ns_get_nsid(n), slba, 0, 0, nlb, 0, 0, 0, 0, 0, + 0, 0, 0, NULL, 0, NULL, 0, NULL); } int nvme_ns_write_uncorrectable(nvme_ns_t n, off_t offset, size_t count) { - struct nvme_io_args args = { - .args_size = sizeof(args), - .fd = nvme_ns_get_fd(n), - .nsid = nvme_ns_get_nsid(n), - .control = 0, - .dsm = 0, - .dspec = 0, - .reftag = 0, - .apptag = 0, - .appmask = 0, - .storage_tag = 0, - .data_len = 0, - .data = NULL, - .metadata_len = 0, - .metadata = NULL, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .result = NULL, - }; + __u64 slba; + __u16 nlb; - if (nvme_bytes_to_lba(n, offset, count, &args.slba, &args.nlb)) + if (nvme_bytes_to_lba(n, offset, count, &slba, &nlb)) return -1; - return nvme_write_uncorrectable(&args); + return nvme_write_uncorrectable(nvme_ns_get_link(n), nvme_ns_get_nsid(n), slba, 0, 0, nlb, + 0, 0, 0, 0, 0, 0, 0, 0, NULL, 0, NULL, 0, NULL); } int nvme_ns_write_zeros(nvme_ns_t n, off_t offset, size_t count) { - struct nvme_io_args args = { - .args_size = sizeof(args), - .fd = nvme_ns_get_fd(n), - .nsid = nvme_ns_get_nsid(n), - .control = 0, - .dsm = 0, - .dspec = 0, - .reftag = 0, - .apptag = 0, - .appmask = 0, - .storage_tag = 0, - .data_len = 0, - .data = NULL, - .metadata_len = 0, - .metadata = NULL, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .result = NULL, - }; + __u64 slba; + __u16 nlb; - if (nvme_bytes_to_lba(n, offset, count, &args.slba, &args.nlb)) + if (nvme_bytes_to_lba(n, offset, count, &slba, &nlb)) return -1; - return nvme_write_zeros(&args); + return nvme_write_zeros(nvme_ns_get_link(n), nvme_ns_get_nsid(n), slba, 0, 0, nlb, 0, 0, 0, + 0, 0, 0, 0, 0, NULL, 0, NULL, 0, NULL); } int nvme_ns_write(nvme_ns_t n, void *buf, off_t offset, size_t count) { - struct nvme_io_args args = { - .args_size = sizeof(args), - .fd = nvme_ns_get_fd(n), - .nsid = nvme_ns_get_nsid(n), - .control = 0, - .dsm = 0, - .dspec = 0, - .reftag = 0, - .apptag = 0, - .appmask = 0, - .storage_tag = 0, - .data_len = count, - .data = buf, - .metadata_len = 0, - .metadata = NULL, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .result = NULL, - }; + __u64 slba; + __u16 nlb; - if (nvme_bytes_to_lba(n, offset, count, &args.slba, &args.nlb)) + if (nvme_bytes_to_lba(n, offset, count, &slba, &nlb)) return -1; - return nvme_write(&args); + return nvme_write(nvme_ns_get_link(n), nvme_ns_get_nsid(n), slba, 0, 0, nlb, 0, 0, 0, 0, 0, + 0, 0, 0, NULL, 0, NULL, 0, NULL); } int nvme_ns_read(nvme_ns_t n, void *buf, off_t offset, size_t count) { - struct nvme_io_args args = { - .args_size = sizeof(args), - .fd = nvme_ns_get_fd(n), - .nsid = nvme_ns_get_nsid(n), - .control = 0, - .dsm = 0, - .dspec = 0, - .reftag = 0, - .apptag = 0, - .appmask = 0, - .storage_tag = 0, - .data_len = count, - .data = buf, - .metadata_len = 0, - .metadata = NULL, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .result = NULL, - }; + __u64 slba; + __u16 nlb; - if (nvme_bytes_to_lba(n, offset, count, &args.slba, &args.nlb)) + if (nvme_bytes_to_lba(n, offset, count, &slba, &nlb)) return -1; - return nvme_read(&args); + return nvme_read(nvme_ns_get_link(n), nvme_ns_get_nsid(n), slba, 0, 0, nlb, 0, 0, 0, 0, 0, + 0, 0, 0, NULL, 0, NULL, 0, NULL); } int nvme_ns_compare(nvme_ns_t n, void *buf, off_t offset, size_t count) { - struct nvme_io_args args = { - .args_size = sizeof(args), - .fd = nvme_ns_get_fd(n), - .nsid = nvme_ns_get_nsid(n), - .control = 0, - .dsm = 0, - .dspec = 0, - .reftag = 0, - .apptag = 0, - .appmask = 0, - .storage_tag = 0, - .data_len = count, - .data = buf, - .metadata_len = 0, - .metadata = NULL, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .result = NULL, - }; + __u64 slba; + __u16 nlb; - if (nvme_bytes_to_lba(n, offset, count, &args.slba, &args.nlb)) + if (nvme_bytes_to_lba(n, offset, count, &slba, &nlb)) return -1; - return nvme_compare(&args); + return nvme_compare(nvme_ns_get_link(n), nvme_ns_get_nsid(n), slba, 0, 0, nlb, 0, 0, 0, 0, + 0, 0, 0, 0, NULL, 0, NULL, 0, NULL); } int nvme_ns_flush(nvme_ns_t n) { - return nvme_flush(nvme_ns_get_fd(n), nvme_ns_get_nsid(n)); + return nvme_flush(nvme_ns_get_link(n), nvme_ns_get_nsid(n)); } static int nvme_strtou64(const char *str, void *res) @@ -2750,7 +2661,8 @@ static int nvme_ns_init(const char *path, struct nvme_ns *ns) ns->lba_count = size >> (ns->lba_shift - SECTOR_SHIFT); if (asprintf(&attr, "%s/csi", path) < 0) - return -errno; + return -ENOMEM; + ret = stat(attr, &sb); if (ret == 0) { /* only available on kernels >= 6.8 */ @@ -2799,7 +2711,7 @@ static void nvme_ns_set_generic_name(struct nvme_ns *n, const char *name) n->generic_name = strdup(generic_name); } -static nvme_ns_t nvme_ns_open(const char *sys_path, const char *name) +int nvme_ns_open(const char *sys_path, const char *name, nvme_ns_t *ns) { int ret; struct nvme_ns *n; @@ -2808,25 +2720,21 @@ static nvme_ns_t nvme_ns_open(const char *sys_path, const char *name) _cleanup_free_ char *path = NULL; n = calloc(1, sizeof(*n)); - if (!n) { - errno = ENOMEM; - return NULL; - } + if (!n) + return -ENOMEM; head = calloc(1, sizeof(*head)); if (!head) { - errno = ENOMEM; free(n); - return NULL; + return -ENOMEM; } head->n = n; list_head_init(&head->paths); ret = asprintf(&path, "%s/%s", sys_path, "multipath"); - if (ret < 0) { - errno = ENOMEM; + if (ret < 0) goto free_ns_head; - } + /* * The sysfs-dir "multipath" is available only when nvme multipath * is configured and we're running kernel version >= 6.14. @@ -2839,19 +2747,21 @@ static nvme_ns_t nvme_ns_open(const char *sys_path, const char *name) head->sysfs_dir = NULL; n->head = head; - n->fd = -1; + n->l = NULL; n->name = strdup(name); nvme_ns_set_generic_name(n, name); - if (nvme_ns_init(sys_path, n) != 0) + ret = nvme_ns_init(sys_path, n); + if (ret) goto free_ns; list_node_init(&n->entry); - nvme_ns_release_fd(n); /* Do not leak fds */ + nvme_ns_release_link(n); - return n; + *ns = n; + return 0; free_ns: free(n->generic_name); @@ -2859,7 +2769,7 @@ static nvme_ns_t nvme_ns_open(const char *sys_path, const char *name) free_ns_head: free(head); free(n); - return NULL; + return ret; } static inline bool nvme_ns_is_generic(const char *name) @@ -2886,38 +2796,35 @@ static char *nvme_ns_generic_to_blkdev(const char *generic) return strdup(blkdev); } -static struct nvme_ns *__nvme_scan_namespace(const char *sysfs_dir, const char *name) +static int __nvme_scan_namespace(const char *sysfs_dir, const char *name, nvme_ns_t *ns) { - struct nvme_ns *n; + _cleanup_free_ char *blkdev = NULL; _cleanup_free_ char *path = NULL; + struct nvme_ns *n; int ret; - _cleanup_free_ char *blkdev = NULL; blkdev = nvme_ns_generic_to_blkdev(name); - if (!blkdev) { - errno = ENOMEM; - return NULL; - } + if (!blkdev) + return -ENOMEM; ret = asprintf(&path, "%s/%s", sysfs_dir, blkdev); - if (ret < 0) { - errno = ENOMEM; - return NULL; - } + if (ret < 0) + return -ENOMEM; - n = nvme_ns_open(path, blkdev); - if (!n) - return NULL; + ret = nvme_ns_open(path, blkdev, &n); + if (ret) + return ret; n->sysfs_dir = path; path = NULL; - return n; + *ns = n; + return 0; } -nvme_ns_t nvme_scan_namespace(const char *name) +int nvme_scan_namespace(const char *name, nvme_ns_t *ns) { - return __nvme_scan_namespace(nvme_ns_sysfs_dir(), name); + return __nvme_scan_namespace(nvme_ns_sysfs_dir(), name, ns); } @@ -2989,18 +2896,18 @@ static int nvme_ctrl_scan_namespace(nvme_root_t r, struct nvme_ctrl *c, char *name) { struct nvme_ns *n, *_n, *__n; + int ret; nvme_msg(r, LOG_DEBUG, "scan controller %s namespace %s\n", c->name, name); if (!c->s) { nvme_msg(r, LOG_DEBUG, "no subsystem for %s\n", name); - errno = EINVAL; - return -1; + return -EINVAL; } - n = __nvme_scan_namespace(c->sysfs_dir, name); - if (!n) { + ret = __nvme_scan_namespace(c->sysfs_dir, name, &n); + if (ret) { nvme_msg(r, LOG_DEBUG, "failed to scan namespace %s\n", name); - return -1; + return ret; } nvme_ctrl_for_each_ns_safe(c, _n, __n) { if (strcmp(n->name, _n->name)) @@ -3019,13 +2926,14 @@ static int nvme_subsystem_scan_namespace(nvme_root_t r, nvme_subsystem_t s, char *name) { struct nvme_ns *n, *_n, *__n; + int ret; nvme_msg(r, LOG_DEBUG, "scan subsystem %s namespace %s\n", s->name, name); - n = __nvme_scan_namespace(s->sysfs_dir, name); - if (!n) { + ret = __nvme_scan_namespace(s->sysfs_dir, name, &n); + if (ret) { nvme_msg(r, LOG_DEBUG, "failed to scan namespace %s\n", name); - return -1; + return ret; } nvme_subsystem_for_each_ns_safe(s, _n, __n) { struct nvme_path *p, *_p; diff --git a/src/nvme/tree.h b/src/nvme/tree.h index e0377b231..db5c70a07 100644 --- a/src/nvme/tree.h +++ b/src/nvme/tree.h @@ -10,7 +10,6 @@ #ifndef _LIBNVME_TREE_H #define _LIBNVME_TREE_H -#include #include #include @@ -19,6 +18,7 @@ #include #include +#include /** * DOC: tree.h @@ -32,20 +32,10 @@ typedef struct nvme_path *nvme_path_t; typedef struct nvme_ctrl *nvme_ctrl_t; typedef struct nvme_subsystem *nvme_subsystem_t; typedef struct nvme_host *nvme_host_t; -typedef struct nvme_root *nvme_root_t; typedef bool (*nvme_scan_filter_t)(nvme_subsystem_t, nvme_ctrl_t, nvme_ns_t, void *); -/** - * nvme_create_root() - Initialize root object - * @fp: File descriptor for logging messages - * @log_level: Logging level to use - * - * Return: Initialized &nvme_root_t object - */ -nvme_root_t nvme_create_root(FILE *fp, int log_level); - /** * nvme_root_set_application - Specify managing application * @r: &nvme_root_t object @@ -82,14 +72,6 @@ void nvme_root_skip_namespaces(nvme_root_t r); */ void nvme_root_release_fds(nvme_root_t r); -/** - * nvme_free_tree() - Free root object - * @r: &nvme_root_t object - * - * Free an &nvme_root_t object and all attached objects - */ -void nvme_free_tree(nvme_root_t r); - /** * nvme_first_host() - Start host iterator * @r: &nvme_root_t object @@ -169,13 +151,14 @@ bool nvme_host_is_pdc_enabled(nvme_host_t h, bool fallback); /** * nvme_default_host() - Initializes the default host * @r: &nvme_root_t object + * @h: &nvme_host_t object to return * * Initializes the default host object based on the hostnqn/hostid * values returned by nvme_host_get_ids() and attaches it to @r. * - * Return: &nvme_host_t object + * Return: 0 on success or negative error code otherwise */ -nvme_host_t nvme_default_host(nvme_root_t r); +int nvme_default_host(nvme_root_t r, nvme_host_t *h); /** * nvme_host_get_ids - Retrieve host ids from various sources @@ -206,7 +189,7 @@ nvme_host_t nvme_default_host(nvme_root_t r); * NVMe implementation expects a 1:1 matching between the IDs. * * Return: 0 on success (@hostnqn and @hostid contain valid strings - * which the caller needs to free), -1 otherwise and errno is set. + * which the caller needs to free), or negative error code otherwise. */ int nvme_host_get_ids(nvme_root_t r, char *hostnqn_arg, char *hostid_arg, @@ -406,15 +389,17 @@ bool nvme_ctrl_config_match(struct nvme_ctrl *c, const char *transport, * @host_traddr: Host transport address * @host_iface: Host interface name * @trsvcid: Transport service ID + * @c: @nvme_ctrl_t object to return * * Creates an unconnected controller to be used for nvme_add_ctrl(). * - * Return: Controller instance + * Return: 0 on success or negative error code otherwise */ -nvme_ctrl_t nvme_create_ctrl(nvme_root_t r, - const char *subsysnqn, const char *transport, - const char *traddr, const char *host_traddr, - const char *host_iface, const char *trsvcid); +int nvme_create_ctrl(nvme_root_t r, + const char *subsysnqn, const char *transport, + const char *traddr, const char *host_traddr, + const char *host_iface, const char *trsvcid, + nvme_ctrl_t *c); /** @@ -582,26 +567,26 @@ nvme_ns_t nvme_subsystem_next_ns(nvme_subsystem_t s, nvme_ns_t n); p = nvme_namespace_next_path(n, p)) /** - * nvme_ns_get_fd() - Get associated file descriptor + * nvme_ns_get_link() - Get associated link handle * @n: Namespace instance * * libnvme will open() the file (if not already opened) and keep - * an internal copy of the file descriptor. Following calls to - * this API retrieve the internal cached copy of the file - * descriptor. The file will remain opened and the fd will + * an internal copy of the link handle. Following calls to + * this API retrieve the internal cached copy of the link + * handle. The file will remain opened and the device handle will * remain cached until the ns object is deleted or - * nvme_ns_release_fd() is called. + * nvme_ns_release_link() is called. * - * Return: File descriptor associated with @n or -1 + * Return: Link handle with @n or NULL */ -int nvme_ns_get_fd(nvme_ns_t n); +nvme_link_t nvme_ns_get_link(nvme_ns_t n); /** - * nvme_ns_release_fd() - Close fd and clear fd from ns object + * nvme_ns_release_link() - Free link handle from ns object * @n: Namespace instance * */ -void nvme_ns_release_fd(nvme_ns_t n); +void nvme_ns_release_link(nvme_ns_t n); /** * nvme_ns_get_nsid() - NSID of a namespace @@ -900,26 +885,25 @@ nvme_ctrl_t nvme_path_get_ctrl(nvme_path_t p); nvme_ns_t nvme_path_get_ns(nvme_path_t p); /** - * nvme_ctrl_get_fd() - Get associated file descriptor + * nvme_ctrl_get_link() - Get associated link handle * @c: Controller instance * - * libnvme will open() the file (if not already opened) and keep - * an internal copy of the file descriptor. Following calls to - * this API retrieve the internal cached copy of the file - * descriptor. The file will remain opened and the fd will - * remain cached until the controller object is deleted or - * nvme_ctrl_release_fd() is called. + * libnvme will open() the device (if not already opened) and keep an + * internal copy of the link handle. Following calls to this API retrieve + * the internal cached copy of the link handle. The file will remain + * opened and the handle will remain cached until the controller object + * is deleted or nvme_ctrl_release_link() is called. * - * Return: File descriptor associated with @c or -1 + * Return: Link handle associated with @c or NULL */ -int nvme_ctrl_get_fd(nvme_ctrl_t c); +nvme_link_t nvme_ctrl_get_link(nvme_ctrl_t c); /** - * nvme_ctrl_release_fd() - Close fd and clear fd from controller object + * nvme_ctrl_release_link() - Free link handle from controller object * @c: Controller instance * */ -void nvme_ctrl_release_fd(nvme_ctrl_t c); +void nvme_ctrl_release_link(nvme_ctrl_t c); /** * nvme_ctrl_get_name() - sysfs name of a controller @@ -1277,12 +1261,13 @@ int nvme_disconnect_ctrl(nvme_ctrl_t c); * nvme_scan_ctrl() - Scan on a controller * @r: nvme_root_t object * @name: Name of the controller + * @c: @nvme_ctrl_t object to return * * Scans a controller with sysfs name @name and add it to @r. * - * Return: nvme_ctrl_t object + * Return: 0 on success or negative error code otherwise */ -nvme_ctrl_t nvme_scan_ctrl(nvme_root_t r, const char *name); +int nvme_scan_ctrl(nvme_root_t r, const char *name, nvme_ctrl_t *c); /** * nvme_rescan_ctrl() - Rescan an existing controller @@ -1296,7 +1281,7 @@ void nvme_rescan_ctrl(nvme_ctrl_t c); * @c: nvme_ctrl_t object * @instance: Instance number (e.g. 1 for nvme1) * - * Return: The ioctl() return code. Typically 0 on success. + * Return: 0 on success or negative error code otherwise */ int nvme_init_ctrl(nvme_host_t h, nvme_ctrl_t c, int instance); @@ -1404,7 +1389,7 @@ const char *nvme_subsystem_get_fw_rev(nvme_subsystem_t s); * Scans the NVMe topology and filters out the resulting elements * by applying @f. * - * Returns: 0 on success, -1 on failure with errno set. + * Return: 0 on success, or negative error code otherwise. */ int nvme_scan_topology(nvme_root_t r, nvme_scan_filter_t f, void *f_args); @@ -1443,10 +1428,11 @@ void nvme_free_host(nvme_host_t h); /** * nvme_scan() - Scan NVMe topology * @config_file: Configuration file + * @r: &nvme_root_t object to return * - * Return: nvme_root_t object of found elements + * Return: 0 on success or negative error code otherwise */ -nvme_root_t nvme_scan(const char *config_file); +int nvme_scan(const char *config_file, nvme_root_t *r); /** * nvme_read_config() - Read NVMe JSON configuration file @@ -1456,7 +1442,7 @@ nvme_root_t nvme_scan(const char *config_file); * Read in the contents of @config_file and merge them with * the elements in @r. * - * Returns: 0 on success, -1 on failure with errno set. + * Return: 0 on success or negative error code otherwise */ int nvme_read_config(nvme_root_t r, const char *config_file); @@ -1485,7 +1471,7 @@ int nvme_update_config(nvme_root_t r); * Prints the current contents of the JSON configuration * file to stdout. * - * Return: 0 on success, -1 on failure. + * Return: 0 on success, or negative error code otherwise. */ int nvme_dump_config(nvme_root_t r); @@ -1496,7 +1482,7 @@ int nvme_dump_config(nvme_root_t r); * Prints the internal object tree in JSON format * to stdout. * - * Return: 0 on success, -1 on failure. + * Return: 0 on success or negative error code otherwise */ int nvme_dump_tree(nvme_root_t r); @@ -1505,8 +1491,8 @@ int nvme_dump_tree(nvme_root_t r); * @d: sysfs directory * @attr: sysfs attribute name * - * Return: String with the contents of @attr or %NULL in case of an empty value - * or in case of an error (indicated by non-zero errno code). + * Return: String with the contents of @attr or %NULL in case of an empty + * value or error. */ char *nvme_get_attr(const char *d, const char *attr); @@ -1515,8 +1501,8 @@ char *nvme_get_attr(const char *d, const char *attr); * @s: nvme_subsystem_t object * @attr: sysfs attribute name * - * Return: String with the contents of @attr or %NULL in case of an empty value - * or in case of an error (indicated by non-zero errno code). + * Return: String with the contents of @attr or %NULL in case of an empty + * value or error. */ char *nvme_get_subsys_attr(nvme_subsystem_t s, const char *attr); @@ -1526,7 +1512,7 @@ char *nvme_get_subsys_attr(nvme_subsystem_t s, const char *attr); * @attr: sysfs attribute name * * Return: String with the contents of @attr or %NULL in case of an empty value - * or in case of an error (indicated by non-zero errno code). + * or in case of an error. */ char *nvme_get_ctrl_attr(nvme_ctrl_t c, const char *attr); @@ -1536,7 +1522,7 @@ char *nvme_get_ctrl_attr(nvme_ctrl_t c, const char *attr); * @attr: sysfs attribute name * * Return: String with the contents of @attr or %NULL in case of an empty value - * or in case of an error (indicated by non-zero errno code). + * or in case of an error. */ char *nvme_get_ns_attr(nvme_ns_t n, const char *attr); @@ -1568,17 +1554,18 @@ void nvme_subsystem_release_fds(struct nvme_subsystem *s); * @attr: sysfs attribute name * * Return: String with the contents of @attr or %NULL in case of an empty value - * or in case of an error (indicated by non-zero errno code). + * or in case of an error. */ char *nvme_get_path_attr(nvme_path_t p, const char *attr); /** * nvme_scan_namespace() - scan namespace based on sysfs name * @name: sysfs name of the namespace to scan + * @ns: &nvme_ns_t object to return * - * Return: nvme_ns_t object or NULL if not found. + * Return: 0 on success or negative error code otherwise */ -nvme_ns_t nvme_scan_namespace(const char *name); +int nvme_scan_namespace(const char *name, nvme_ns_t *ns); /** * nvme_host_get_hostsymname() - Get the host's symbolic name diff --git a/src/nvme/util.c b/src/nvme/util.c index cde9d67ea..41d4d38ea 100644 --- a/src/nvme/util.c +++ b/src/nvme/util.c @@ -180,7 +180,7 @@ __u8 nvme_status_to_errno(int status, bool fabrics) if (!status) return 0; if (status < 0) - return errno; + return -status; sc = nvme_status_code(status); switch (nvme_status_code_type(status)) { @@ -378,7 +378,7 @@ const char *nvme_status_to_string(int status, bool fabrics) __u16 sc, sct; if (status < 0) - return strerror(errno); + return strerror(-status); sc = nvme_status_code(status); sct = nvme_status_code_type(status); @@ -574,8 +574,7 @@ int nvme_get_feature_length(int fid, __u32 cdw11, enum nvme_data_tfr dir, *len = NVME_FEAT_FDPE_NOET_MASK * sizeof(struct nvme_fdp_supported_event_desc); break; default: - errno = EINVAL; - return -1; + return -EINVAL; } return 0; } @@ -590,8 +589,7 @@ int nvme_get_directive_receive_length(enum nvme_directive_dtype dtype, *len = sizeof(struct nvme_id_directives); return 0; default: - errno = EINVAL; - return -1; + return -EINVAL; } case NVME_DIRECTIVE_DTYPE_STREAMS: switch (doper) { @@ -605,12 +603,10 @@ int nvme_get_directive_receive_length(enum nvme_directive_dtype dtype, *len = 0; return 0; default: - errno = EINVAL; - return -1; + return -EINVAL; } default: - errno = EINVAL; - return -1; + return -EINVAL; } } @@ -646,19 +642,19 @@ const char *nvme_errno_to_string(int status) } #ifdef HAVE_NETDB -char *hostname2traddr(struct nvme_root *r, const char *traddr) +int hostname2traddr(nvme_root_t r, const char *traddr, char **hostname) { - struct addrinfo *host_info, hints = {.ai_family = AF_UNSPEC}; + _cleanup_addrinfo_ struct addrinfo *host_info = NULL; + struct addrinfo hints = {.ai_family = AF_UNSPEC}; char addrstr[NVMF_TRADDR_SIZE]; const char *p; - char *ret_traddr = NULL; int ret; ret = getaddrinfo(traddr, NULL, &hints, &host_info); if (ret) { nvme_msg(r, LOG_ERR, "failed to resolve host %s info\n", traddr); - return NULL; + return -errno; } switch (host_info->ai_family) { @@ -675,28 +671,27 @@ char *hostname2traddr(struct nvme_root *r, const char *traddr) default: nvme_msg(r, LOG_ERR, "unrecognized address family (%d) %s\n", host_info->ai_family, traddr); - goto free_addrinfo; + return -EINVAL; } if (!p) { nvme_msg(r, LOG_ERR, "failed to get traddr for %s\n", traddr); - goto free_addrinfo; + return -EIO; } - ret_traddr = strdup(addrstr); + *hostname = strdup(addrstr); + if (!*hostname) + return -ENOMEM; -free_addrinfo: - freeaddrinfo(host_info); - return ret_traddr; + return 0; } #else /* HAVE_NETDB */ -char *hostname2traddr(struct nvme_root *r, const char *traddr) +int hostname2traddr(nvme_root_t r, const char *traddr, char **hostname) { - nvme_msg(NULL, LOG_ERR, "No support for hostname IP address resolution; " \ + nvme_msg(r, LOG_ERR, "No support for hostname IP address resolution; " \ "recompile with libnss support.\n"); - errno = -ENOTSUP; - return NULL; + return -ENOTSUP; } #endif /* HAVE_NETDB */ @@ -972,10 +967,8 @@ int nvme_uuid_find(struct nvme_id_uuid_list *uuid_list, const unsigned char uuid { const unsigned char uuid_end[NVME_UUID_LEN] = {0}; - if ((!uuid_list) || (!uuid)) { - errno = EINVAL; - return -1; - } + if ((!uuid_list) || (!uuid)) + return -EINVAL; for (int i = 0; i < NVME_ID_UUID_LIST_MAX; i++) { if (memcmp(uuid, &uuid_list->entry[i].uuid, NVME_UUID_LEN) == 0) @@ -983,8 +976,7 @@ int nvme_uuid_find(struct nvme_id_uuid_list *uuid_list, const unsigned char uuid if (memcmp(uuid_end, &uuid_list->entry[i].uuid, NVME_UUID_LEN) == 0) break; } - errno = ENOENT; - return -1; + return -ENOENT; } #ifdef HAVE_NETDB diff --git a/src/nvme/util.h b/src/nvme/util.h index 47f9b6642..526a4ed1c 100644 --- a/src/nvme/util.h +++ b/src/nvme/util.h @@ -503,7 +503,7 @@ static inline void nvme_id_ns_flbas_to_lbaf_inuse(__u8 flbas, __u8 *lbaf_inuse) struct nvme_root; -char *hostname2traddr(struct nvme_root *r, const char *traddr); +int hostname2traddr(struct nvme_root *r, const char *traddr, char **hostname); /** * get_entity_name - Get Entity Name (ENAME). diff --git a/test/config/config-dump.c b/test/config/config-dump.c index c0c8e7313..06eb43390 100644 --- a/test/config/config-dump.c +++ b/test/config/config-dump.c @@ -4,6 +4,7 @@ * Copyright (c) 2024 Daniel Wagner, SUSE LLC */ +#include "nvme/log.h" #include #include #include @@ -17,15 +18,13 @@ static bool config_dump(const char *file) nvme_root_t r; int err; - r = nvme_create_root(stderr, LOG_ERR); + r = nvme_create_root(stderr, DEFAULT_LOGLEVEL); if (!r) return false; err = nvme_scan_topology(r, NULL, NULL); - if (err) { - if (errno != ENOENT) - goto out; - } + if (err < 0 && err != -ENOENT) + goto out; err = nvme_read_config(r, file); if (err) @@ -38,7 +37,7 @@ static bool config_dump(const char *file) pass = true; out: - nvme_free_tree(r); + nvme_free_root(r); return pass; } diff --git a/test/config/hostnqn-order.c b/test/config/hostnqn-order.c index 22fc2278e..27807ab60 100644 --- a/test/config/hostnqn-order.c +++ b/test/config/hostnqn-order.c @@ -23,10 +23,8 @@ static bool command_line(void) return false; err = nvme_scan_topology(r, NULL, NULL); - if (err) { - if (errno != ENOENT) - goto out; - } + if (err && err != ENOENT) + goto out; hostnqn = "nqn.2014-08.org.nvmexpress:uuid:ce4fee3e-c02c-11ee-8442-830d068a36c6"; hostid = "ce4fee3e-c02c-11ee-8442-830d068a36c6"; @@ -50,7 +48,7 @@ static bool command_line(void) pass = true; out: - nvme_free_tree(r); + nvme_free_root(r); return pass; } @@ -74,10 +72,8 @@ static bool json_config(char *file) goto out; err = nvme_scan_topology(r, NULL, NULL); - if (err) { - if (errno != ENOENT) - goto out; - } + if (err && err != ENOENT) + goto out; hostnqn = "nqn.2014-08.org.nvmexpress:uuid:2cd2c43b-a90a-45c1-a8cd-86b33ab273b5"; hostid = "2cd2c43b-a90a-45c1-a8cd-86b33ab273b5"; @@ -101,7 +97,7 @@ static bool json_config(char *file) pass = true; out: - nvme_free_tree(r); + nvme_free_root(r); return pass; } @@ -123,10 +119,8 @@ static bool from_file(void) return false; err = nvme_scan_topology(r, NULL, NULL); - if (err) { - if (errno != ENOENT) - goto out; - } + if (err && err != ENOENT) + goto out; err = nvme_host_get_ids(r, NULL, NULL, &hnqn, &hid); if (err) @@ -147,7 +141,7 @@ static bool from_file(void) pass = true; out: - nvme_free_tree(r); + nvme_free_root(r); return pass; } diff --git a/test/config/psk-json.c b/test/config/psk-json.c index a96ebf1b8..5b65a03bc 100644 --- a/test/config/psk-json.c +++ b/test/config/psk-json.c @@ -18,21 +18,23 @@ static bool import_export_key(nvme_ctrl_t c) unsigned char version, hmac, *key; char *encoded_key; size_t len; + int ret; - key = nvme_import_tls_key_versioned(nvme_ctrl_get_tls_key(c), - &version, &hmac, &len); - if (!key) { + ret = nvme_import_tls_key_versioned(nvme_ctrl_get_tls_key(c), + &version, &hmac, &len, &key); + if (ret) { printf("ERROR: nvme_import_tls_key_versioned failed with %d\n", - errno); + ret); return false; } - encoded_key = nvme_export_tls_key_versioned(version, hmac, key, len); + ret = nvme_export_tls_key_versioned(version, hmac, key, len, + &encoded_key); free(key); - if (!encoded_key) { + if (ret) { printf("ERROR: nvme_export_tls_key_versioned failed with %d\n", - errno); + ret); return false; } @@ -74,7 +76,7 @@ static bool psk_json_test(char *file) pass = true; out: - nvme_free_tree(r); + nvme_free_root(r); return pass; } diff --git a/test/cpp.cc b/test/cpp.cc index a6bbf42fd..403d77aac 100644 --- a/test/cpp.cc +++ b/test/cpp.cc @@ -19,8 +19,7 @@ int main() nvme_path_t p; nvme_ns_t n; - r = nvme_scan(NULL); - if (!r) + if (nvme_scan(NULL, &r)) return -1; nvme_for_each_host(r, h) { @@ -61,7 +60,7 @@ int main() } } std::cout << "\n"; - nvme_free_tree(r); + nvme_free_root(r); return 0; } diff --git a/test/ioctl/ana.c b/test/ioctl/ana.c index 1e2cffb79..ccd195655 100644 --- a/test/ioctl/ana.c +++ b/test/ioctl/ana.c @@ -11,20 +11,23 @@ #include #include "mock.h" +#include "nvme/api-types.h" #include "util.h" #define TEST_FD 0xFD #define PDU_SIZE NVME_LOG_PAGE_PDU_SIZE +static nvme_link_t test_link; + static void test_no_retries(void) { struct nvme_ana_log log; __u32 len = sizeof(log); /* max_retries = 0 is nonsensical */ - check(nvme_get_ana_log_atomic(TEST_FD, false, false, 0, &log, &len), + check(nvme_get_ana_log_atomic(test_link, false, false, + &log, &len, 0) == -EINVAL, "get log page succeeded"); - check(errno == EINVAL, "unexpected error: %m"); } static void test_len_too_short(void) @@ -33,9 +36,9 @@ static void test_len_too_short(void) __u32 len = sizeof(log) - 1; /* Provided buffer doesn't have enough space to read the header */ - check(nvme_get_ana_log_atomic(TEST_FD, false, false, 1, &log, &len), + check(nvme_get_ana_log_atomic(test_link, false, false, + &log, &len, 1) == -ENOSPC, "get log page succeeded"); - check(errno == ENOSPC, "unexpected error: %m"); } static void test_no_groups(void) @@ -56,8 +59,8 @@ static void test_no_groups(void) arbitrary(&header, sizeof(header)); header.ngrps = cpu_to_le16(0); set_mock_admin_cmds(&mock_admin_cmd, 1); - check(!nvme_get_ana_log_atomic(TEST_FD, false, false, 1, &log, &len), - "get log page failed: %m"); + check(!nvme_get_ana_log_atomic(test_link, false, false, &log, &len, 1), + "get log page failed"); end_mock_cmds(); cmp(&log, &header, sizeof(header), "incorrect header"); check(len == sizeof(header), @@ -76,10 +79,10 @@ static void test_one_group_rgo(void) * Since only one command was issued, chgcnt doesn't need to be checked. */ struct mock_cmd mock_admin_cmd = { - .opcode = nvme_admin_get_log_page, + .opcode= nvme_admin_get_log_page, .data_len = len_dwords * 4, .cdw10 = (len_dwords - 1) << 16 /* NUMDL */ - | NVME_LOG_ANA_LSP_RGO_GROUPS_ONLY << 8 /* LSP */ + | NVME_LOG_ANA_LSP_RGO_GROUPS_ONLY << 8 /* LSP */ | NVME_LOG_LID_ANA, /* LID */ .out_data = log_page, .out_data_len = sizeof(log_page), @@ -94,8 +97,8 @@ static void test_one_group_rgo(void) memcpy(log_page, &header, sizeof(header)); memcpy(log_page + sizeof(header), &group, sizeof(group)); set_mock_admin_cmds(&mock_admin_cmd, 1); - check(!nvme_get_ana_log_atomic(TEST_FD, true, false, 1, log, &len), - "get log page failed: %m"); + check(!nvme_get_ana_log_atomic(test_link, false, true, log, &len, 1), + "get log page failed"); end_mock_cmds(); cmp(log, log_page, sizeof(log_page), "incorrect log page"); check(len == sizeof(log_page), @@ -135,8 +138,8 @@ static void test_one_group_nsids(void) memcpy(log_page + sizeof(header), &group, sizeof(group)); memcpy(log_page + sizeof(header) + sizeof(group), nsids, sizeof(nsids)); set_mock_admin_cmds(&mock_admin_cmd, 1); - check(!nvme_get_ana_log_atomic(TEST_FD, false, false, 1, log, &len), - "get log page failed: %m"); + check(!nvme_get_ana_log_atomic(test_link, false, false, log, &len, 1), + "get log page failed"); end_mock_cmds(); cmp(log, log_page, sizeof(log_page), "incorrect log page"); check(len == sizeof(log_page), @@ -176,8 +179,8 @@ static void test_multiple_groups_rgo(void) memcpy(log_page, &header, sizeof(header)); memcpy(log_page + sizeof(header), groups, sizeof(groups)); set_mock_admin_cmds(&mock_admin_cmd, 1); - check(!nvme_get_ana_log_atomic(TEST_FD, true, true, 1, log, &len), - "get log page failed: %m"); + check(!nvme_get_ana_log_atomic(test_link, true, true, log, &len, 1), + "get log page failed"); end_mock_cmds(); cmp(log, log_page, sizeof(log_page), "incorrect log page"); check(len == sizeof(log_page), @@ -242,8 +245,8 @@ static void test_multiple_groups_nsids(void) sizeof(group2) + sizeof(nsids2) + sizeof(group3), nsids3, sizeof(nsids3)); set_mock_admin_cmds(&mock_admin_cmd, 1); - check(!nvme_get_ana_log_atomic(TEST_FD, false, false, 1, log, &len), - "get log page failed: %m"); + check(!nvme_get_ana_log_atomic(test_link, false, false, log, &len, 1), + "get log page failed"); end_mock_cmds(); cmp(log, log_page, sizeof(log_page), "incorrect log page"); check(len == sizeof(log_page), @@ -314,8 +317,8 @@ static void test_long_log(void) memcpy(log_page + sizeof(header), &group, sizeof(group)); memcpy(log_page + sizeof(header) + sizeof(group), nsids, sizeof(nsids)); set_mock_admin_cmds(mock_admin_cmds, ARRAY_SIZE(mock_admin_cmds)); - check(!nvme_get_ana_log_atomic(TEST_FD, false, true, 1, log, &len), - "get log page failed: %m"); + check(!nvme_get_ana_log_atomic(test_link, true, false, log, &len, 1), + "get log page failed"); end_mock_cmds(); cmp(log, log_page, sizeof(log_page), "incorrect log page"); check(len == sizeof(log_page), @@ -390,8 +393,8 @@ static void test_chgcnt_change(void) memcpy(log_page2, &header2, sizeof(header2)); memcpy(log_page2 + sizeof(header2), &group2, sizeof(group2)); set_mock_admin_cmds(mock_admin_cmds, ARRAY_SIZE(mock_admin_cmds)); - check(!nvme_get_ana_log_atomic(TEST_FD, true, true, 2, log, &len), - "get log page failed: %m"); + check(!nvme_get_ana_log_atomic(test_link, true, true, log, &len, 2), + "get log page failed"); end_mock_cmds(); cmp(log, log_page2, sizeof(log_page2), "incorrect log page"); check(len == sizeof(log_page2), @@ -472,8 +475,8 @@ static void test_buffer_too_short_chgcnt_change(void) memcpy(log_page2 + sizeof(header2) + sizeof(group2), &nsid2, sizeof(nsid2)); set_mock_admin_cmds(mock_admin_cmds, ARRAY_SIZE(mock_admin_cmds)); - check(!nvme_get_ana_log_atomic(TEST_FD, false, false, 2, log, &len), - "get log page failed: %m"); + check(!nvme_get_ana_log_atomic(test_link, false, false, log, &len, 2), + "get log page failed"); end_mock_cmds(); cmp(log, log_page2, sizeof(log_page2), "incorrect log page"); check(len == sizeof(log_page2), @@ -568,10 +571,9 @@ static void test_chgcnt_max_retries(void) memcpy(log_page2 + sizeof(header2) + sizeof(group), nsids, sizeof(nsids)); set_mock_admin_cmds(mock_admin_cmds, ARRAY_SIZE(mock_admin_cmds)); - check(nvme_get_ana_log_atomic(TEST_FD, false, true, 2, log, &len) == -1, + check(nvme_get_ana_log_atomic(test_link, true, false, log, &len, 2) == -EAGAIN, "get log page succeeded"); end_mock_cmds(); - check(errno == EAGAIN, "unexpected error: %m"); free(log); } @@ -609,10 +611,9 @@ static void test_buffer_too_short(void) memcpy(log_page + sizeof(header), &group, sizeof(group)); memcpy(log_page + sizeof(header) + sizeof(group), nsids, sizeof(nsids)); set_mock_admin_cmds(&mock_admin_cmd, 1); - check(nvme_get_ana_log_atomic(TEST_FD, false, true, 2, log, &len) == -1, + check(nvme_get_ana_log_atomic(test_link, true, false, log, &len, 2) == -ENOSPC, "get log page succeeded"); end_mock_cmds(); - check(errno == ENOSPC, "unexpected error: %m"); free(log); } @@ -628,7 +629,11 @@ static void run_test(const char *test_name, void (*test_fn)(void)) int main(void) { + nvme_root_t r = nvme_create_root(stdout, DEFAULT_LOGLEVEL); + set_mock_fd(TEST_FD); + check(!nvme_open(r, "NVME_TEST_FD", &test_link), "opening test link failed"); + RUN_TEST(no_retries); RUN_TEST(len_too_short); RUN_TEST(no_groups); @@ -641,4 +646,6 @@ int main(void) RUN_TEST(buffer_too_short_chgcnt_change); RUN_TEST(chgcnt_max_retries); RUN_TEST(buffer_too_short); + + nvme_free_root(r); } diff --git a/test/ioctl/discovery.c b/test/ioctl/discovery.c index 457acb0a8..c43611f39 100644 --- a/test/ioctl/discovery.c +++ b/test/ioctl/discovery.c @@ -11,11 +11,14 @@ #include #include "mock.h" +#include "nvme/log.h" #include "util.h" #define TEST_FD 0xFD #define HEADER_LEN 20 +static nvme_link_t test_link; + static void arbitrary_ascii_string(size_t max_len, char *str, char *log_str) { size_t len; @@ -72,7 +75,7 @@ static void test_no_entries(nvme_ctrl_t c) struct nvmf_discovery_log *log = NULL; set_mock_admin_cmds(mock_admin_cmds, ARRAY_SIZE(mock_admin_cmds)); - check(nvmf_get_discovery_log(c, &log, 1) == 0, "discovery failed: %m"); + check(nvmf_get_discovery_log(c, &log, 1) == 0, "discovery failed"); end_mock_cmds(); cmp(log, &header, sizeof(header), "incorrect header"); free(log); @@ -116,7 +119,7 @@ static void test_four_entries(nvme_ctrl_t c) arbitrary_entries(num_entries, entries, log_entries); set_mock_admin_cmds(mock_admin_cmds, ARRAY_SIZE(mock_admin_cmds)); - check(nvmf_get_discovery_log(c, &log, 1) == 0, "discovery failed: %m"); + check(nvmf_get_discovery_log(c, &log, 1) == 0, "discovery failed"); end_mock_cmds(); cmp(log, &header, sizeof(header), "incorrect header"); cmp(log->entries, entries, sizeof(entries), "incorrect entries"); @@ -175,7 +178,7 @@ static void test_five_entries(nvme_ctrl_t c) arbitrary_entries(num_entries, entries, log_entries); set_mock_admin_cmds(mock_admin_cmds, ARRAY_SIZE(mock_admin_cmds)); - check(nvmf_get_discovery_log(c, &log, 1) == 0, "discovery failed: %m"); + check(nvmf_get_discovery_log(c, &log, 1) == 0, "discovery failed"); end_mock_cmds(); cmp(log, &header, sizeof(header), "incorrect header"); cmp(log->entries, entries, sizeof(entries), "incorrect entries"); @@ -243,7 +246,7 @@ static void test_genctr_change(nvme_ctrl_t c) arbitrary(entries1, sizeof(entries1)); arbitrary_entries(num_entries2, entries2, log_entries2); set_mock_admin_cmds(mock_admin_cmds, ARRAY_SIZE(mock_admin_cmds)); - check(nvmf_get_discovery_log(c, &log, 2) == 0, "discovery failed: %m"); + check(nvmf_get_discovery_log(c, &log, 2) == 0, "discovery failed"); end_mock_cmds(); cmp(log, &header2, sizeof(header2), "incorrect header"); cmp(log->entries, entries2, sizeof(entries2), "incorrect entries"); @@ -306,9 +309,8 @@ static void test_max_retries(nvme_ctrl_t c) arbitrary(&entry, sizeof(entry)); set_mock_admin_cmds(mock_admin_cmds, ARRAY_SIZE(mock_admin_cmds)); - check(nvmf_get_discovery_log(c, &log, 2) == -1, "discovery succeeded"); + check(nvmf_get_discovery_log(c, &log, 2) == -EAGAIN, "discovery succeeded"); end_mock_cmds(); - check(errno == EAGAIN, "discovery failed: %m"); check(!log, "unexpected log page returned"); } @@ -321,13 +323,13 @@ static void test_header_error(nvme_ctrl_t c) .data_len = HEADER_LEN, .cdw10 = (HEADER_LEN / 4 - 1) << 16 /* NUMDL */ | NVME_LOG_LID_DISCOVER, /* LID */ - .err = NVME_SC_INVALID_OPCODE, + .err = -EAGAIN, }, }; struct nvmf_discovery_log *log = NULL; set_mock_admin_cmds(mock_admin_cmds, ARRAY_SIZE(mock_admin_cmds)); - check(nvmf_get_discovery_log(c, &log, 1) == -1, "discovery succeeded"); + check(nvmf_get_discovery_log(c, &log, 1) == -EAGAIN, "discovery succeeded"); end_mock_cmds(); check(!log, "unexpected log page returned"); } @@ -357,9 +359,8 @@ static void test_entries_error(nvme_ctrl_t c) struct nvmf_discovery_log *log = NULL; set_mock_admin_cmds(mock_admin_cmds, ARRAY_SIZE(mock_admin_cmds)); - check(nvmf_get_discovery_log(c, &log, 1) == -1, "discovery succeeded"); + check(nvmf_get_discovery_log(c, &log, 1) == -EIO, "discovery succeeded"); end_mock_cmds(); - check(errno == EIO, "discovery failed: %m"); check(!log, "unexpected log page returned"); } @@ -396,14 +397,14 @@ static void test_genctr_error(nvme_ctrl_t c) arbitrary(&entry, sizeof(entry)); set_mock_admin_cmds(mock_admin_cmds, ARRAY_SIZE(mock_admin_cmds)); - check(nvmf_get_discovery_log(c, &log, 1) == -1, "discovery succeeded"); + check(nvmf_get_discovery_log(c, &log, 1) == NVME_SC_INTERNAL, "discovery succeeded"); end_mock_cmds(); check(!log, "unexpected log page returned"); } static void run_test(const char *test_name, void (*test_fn)(nvme_ctrl_t)) { - struct nvme_ctrl c = {.fd = TEST_FD}; + struct nvme_ctrl c = { .l = test_link }; printf("Running test %s...", test_name); fflush(stdout); @@ -417,7 +418,11 @@ static void run_test(const char *test_name, void (*test_fn)(nvme_ctrl_t)) int main(void) { + nvme_root_t r = nvme_create_root(stdout, DEFAULT_LOGLEVEL); + set_mock_fd(TEST_FD); + check(!nvme_open(r, "NVME_TEST_FD", &test_link), "opening test link failed"); + RUN_TEST(no_entries); RUN_TEST(four_entries); RUN_TEST(five_entries); @@ -426,4 +431,6 @@ int main(void) RUN_TEST(header_error); RUN_TEST(entries_error); RUN_TEST(genctr_error); + + nvme_free_root(r); } diff --git a/test/ioctl/features.c b/test/ioctl/features.c index f26982c8a..c8d741441 100644 --- a/test/ioctl/features.c +++ b/test/ioctl/features.c @@ -7,6 +7,7 @@ #include "mock.h" #include "util.h" +#include #define TEST_FD 0xFD #define TEST_TIMEOUT 1234 @@ -22,26 +23,12 @@ #define TEST_SEL NVME_GET_FEATURES_SEL_SAVED #define TEST_SC NVME_SC_INVALID_FIELD +static nvme_link_t test_link; + static void test_set_features(void) { uint32_t result = 0; uint8_t data[256]; - struct nvme_set_features_args args = { - .result = &result, - .data = data, - .args_size = sizeof(args), - .fd = TEST_FD, - .timeout = TEST_TIMEOUT, - .nsid = TEST_NSID, - .cdw11 = TEST_CDW11, - .cdw12 = TEST_CDW12, - .cdw13 = TEST_CDW13, - .cdw15 = TEST_CDW15, - .data_len = sizeof(data), - .save = true, - .uuidx = TEST_UUIDX, - .fid = TEST_FID, - }; struct mock_cmd mock_admin_cmd = { .opcode = nvme_admin_set_features, .nsid = TEST_NSID, @@ -54,16 +41,17 @@ static void test_set_features(void) .cdw13 = TEST_CDW13, .cdw14 = TEST_UUIDX, .cdw15 = TEST_CDW15, - .timeout_ms = TEST_TIMEOUT, .result = TEST_RESULT, }; int err; arbitrary(data, sizeof(data)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_set_features(&args); + err = nvme_set_features(test_link, TEST_NSID, TEST_FID, true, TEST_CDW11, TEST_CDW12, TEST_CDW13, + TEST_CDW15, TEST_UUIDX, data, sizeof(data), + &result); end_mock_cmds(); - check(err == 0, "set features returned error %d, errno %m", err); + check(err == 0, "set features returned error %d", err); check(result == TEST_RESULT, "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT); } @@ -72,19 +60,6 @@ static void test_get_features(void) { uint32_t result = 0; uint8_t data[256], get_data[sizeof(data)] = {}; - struct nvme_get_features_args args = { - .result = &result, - .data = get_data, - .args_size = sizeof(args), - .fd = TEST_FD, - .timeout = TEST_TIMEOUT, - .nsid = TEST_NSID, - .sel = TEST_SEL, - .cdw11 = TEST_CDW11, - .data_len = sizeof(data), - .fid = TEST_FID, - .uuidx = TEST_UUIDX, - }; struct mock_cmd mock_admin_cmd = { .opcode = nvme_admin_get_features, .nsid = TEST_NSID, @@ -92,7 +67,6 @@ static void test_get_features(void) .cdw10 = TEST_SEL << 8 | TEST_FID, .cdw11 = TEST_CDW11, .cdw14 = TEST_UUIDX, - .timeout_ms = TEST_TIMEOUT, .out_data = data, .result = TEST_RESULT, }; @@ -100,9 +74,10 @@ static void test_get_features(void) arbitrary(data, sizeof(data)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_get_features(&args); + err = nvme_get_features(test_link, TEST_NSID, TEST_FID, TEST_SEL, TEST_CDW11, + TEST_UUIDX, get_data, sizeof(data), &result); end_mock_cmds(); - check(err == 0, "get features returned error %d, errno %m", err); + check(err == 0, "get features returned error %d", err); check(result == TEST_RESULT, "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT); cmp(get_data, data, sizeof(data), "incorrect data"); @@ -126,10 +101,10 @@ static void test_set_features_data(void) arbitrary(data, sizeof(data)); set_mock_admin_cmds(&mock_admin_cmd, 1); err = nvme_set_features_data( - TEST_FD, TEST_FID, TEST_NSID, TEST_CDW11, false, - sizeof(data), data, &result); + test_link, TEST_NSID, TEST_FID, false, TEST_CDW11, + data, sizeof(data), &result); end_mock_cmds(); - check(err == 0, "set features returned error %d, errno %m", err); + check(err == 0, "set features returned error %d", err); check(result == TEST_RESULT, "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT); } @@ -151,9 +126,9 @@ static void test_get_features_data(void) arbitrary(data, sizeof(data)); set_mock_admin_cmds(&mock_admin_cmd, 1); err = nvme_get_features_data( - TEST_FD, TEST_FID, TEST_NSID, sizeof(data), get_data, &result); + test_link, TEST_NSID, TEST_FID, get_data, sizeof(data), &result); end_mock_cmds(); - check(err == 0, "set features returned error %d, errno %m", err); + check(err == 0, "set features returned error %d", err); check(result == TEST_RESULT, "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT); cmp(get_data, data, sizeof(data), "incorrect data"); @@ -174,9 +149,9 @@ static void test_set_features_simple(void) set_mock_admin_cmds(&mock_admin_cmd, 1); err = nvme_set_features_simple( - TEST_FD, TEST_FID, TEST_NSID, TEST_CDW11, true, &result); + test_link, TEST_NSID, TEST_FID, true, TEST_CDW11, &result); end_mock_cmds(); - check(err == 0, "set features returned error %d, errno %m", err); + check(err == 0, "set features returned error %d", err); check(result == TEST_RESULT, "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT); } @@ -193,9 +168,9 @@ static void test_get_features_simple(void) int err; set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_get_features_simple(TEST_FD, TEST_FID, TEST_NSID, &result); + err = nvme_get_features_simple(test_link, TEST_NSID, TEST_FID, &result); end_mock_cmds(); - check(err == 0, "set features returned error %d, errno %m", err); + check(err == 0, "set features returned error %d", err); check(result == TEST_RESULT, "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT); } @@ -214,9 +189,9 @@ static void test_set_arbitration(void) set_mock_admin_cmds(&mock_admin_cmd, 1); err = nvme_set_features_arbitration( - TEST_FD, AB, LPW, MPW, HPW, false, &result); + test_link, false, AB, LPW, MPW, HPW, &result); end_mock_cmds(); - check(err == 0, "set features returned error %d, errno %m", err); + check(err == 0, "set features returned error %d", err); check(result == TEST_RESULT, "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT); } @@ -232,9 +207,9 @@ static void test_get_arbitration(void) int err; set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_get_features_arbitration(TEST_FD, TEST_SEL, &result); + err = nvme_get_features_arbitration(test_link, TEST_SEL, &result); end_mock_cmds(); - check(err == 0, "get features returned error %d, errno %m", err); + check(err == 0, "get features returned error %d", err); check(result == TEST_RESULT, "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT); } @@ -253,9 +228,9 @@ static void test_set_power_mgmt(void) int err; set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_set_features_power_mgmt(TEST_FD, PS, WH, true, &result); + err = nvme_set_features_power_mgmt(test_link, true, PS, WH, &result); end_mock_cmds(); - check(err == 0, "set features returned error %d, errno %m", err); + check(err == 0, "set features returned error %d", err); check(result == TEST_RESULT, "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT); } @@ -271,9 +246,9 @@ static void test_get_power_mgmt(void) int err; set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_get_features_power_mgmt(TEST_FD, TEST_SEL, &result); + err = nvme_get_features_power_mgmt(test_link, TEST_SEL, &result); end_mock_cmds(); - check(err == 0, "get features returned error %d, errno %m", err); + check(err == 0, "get features returned error %d", err); check(result == TEST_RESULT, "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT); } @@ -297,9 +272,9 @@ static void test_set_lba_range(void) arbitrary(&range_types, sizeof(range_types)); set_mock_admin_cmds(&mock_admin_cmd, 1); err = nvme_set_features_lba_range( - TEST_FD, TEST_NSID, NUM, false, &range_types, &result); + test_link, TEST_NSID, false, NUM, &range_types, &result); end_mock_cmds(); - check(err == 0, "set features returned error %d, errno %m", err); + check(err == 0, "set features returned error %d", err); check(result == TEST_RESULT, "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT); } @@ -321,9 +296,9 @@ static void test_get_lba_range(void) arbitrary(&range_types, sizeof(range_types)); set_mock_admin_cmds(&mock_admin_cmd, 1); err = nvme_get_features_lba_range( - TEST_FD, TEST_SEL, TEST_NSID, &get_range_types, &result); + test_link, TEST_NSID, TEST_SEL, &get_range_types, &result); end_mock_cmds(); - check(err == 0, "get features returned error %d, errno %m", err); + check(err == 0, "get features returned error %d", err); check(result == TEST_RESULT, "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT); cmp(&get_range_types, &range_types, sizeof(range_types), @@ -348,9 +323,9 @@ static void test_set_temp_thresh(void) set_mock_admin_cmds(&mock_admin_cmd, 1); err = nvme_set_features_temp_thresh( - TEST_FD, TMPTH, TMPSEL, THSEL, 0, true, &result); + test_link, true, TMPTH, TMPSEL, THSEL, 0, &result); end_mock_cmds(); - check(err == 0, "set features returned error %d, errno %m", err); + check(err == 0, "set features returned error %d", err); check(result == TEST_RESULT, "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT); } @@ -371,9 +346,9 @@ static void test_get_temp_thresh(void) int err; set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_get_features_temp_thresh(TEST_FD, TEST_SEL, 0, 0, &result); + err = nvme_get_features_temp_thresh(test_link, TEST_SEL, 0, 0, &result); end_mock_cmds(); - check(err == 0, "get features returned error %d, errno %m", err); + check(err == 0, "get features returned error %d", err); check(result == TEST_RESULT, "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT); } @@ -394,9 +369,9 @@ static void test_set_err_recovery(void) set_mock_admin_cmds(&mock_admin_cmd, 1); err = nvme_set_features_err_recovery( - TEST_FD, TEST_NSID, TLER, true, false, &result); + test_link, TEST_NSID, false, TLER, true, &result); end_mock_cmds(); - check(err == 0, "set features returned error %d, errno %m", err); + check(err == 0, "set features returned error %d", err); check(result == TEST_RESULT, "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT); } @@ -414,9 +389,9 @@ static void test_get_err_recovery(void) set_mock_admin_cmds(&mock_admin_cmd, 1); err = nvme_get_features_err_recovery( - TEST_FD, TEST_SEL, TEST_NSID, &result); + test_link, TEST_NSID, TEST_SEL, &result); end_mock_cmds(); - check(err == 0, "get features returned error %d, errno %m", err); + check(err == 0, "get features returned error %d", err); check(result == TEST_RESULT, "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT); } @@ -434,9 +409,9 @@ static void test_set_volatile_wc(void) int err; set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_set_features_volatile_wc(TEST_FD, true, true, &result); + err = nvme_set_features_volatile_wc(test_link, true, true, &result); end_mock_cmds(); - check(err == 0, "set features returned error %d, errno %m", err); + check(err == 0, "set features returned error %d", err); check(result == TEST_RESULT, "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT); } @@ -453,9 +428,9 @@ static void test_get_volatile_wc(void) int err; set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_get_features_volatile_wc(TEST_FD, TEST_SEL, &result); + err = nvme_get_features_volatile_wc(test_link, TEST_SEL, &result); end_mock_cmds(); - check(err == 0, "get features returned error %d, errno %m", err); + check(err == 0, "get features returned error %d", err); check(result == TEST_RESULT, "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT); } @@ -471,9 +446,9 @@ static void test_get_num_queues(void) int err; set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_get_features_num_queues(TEST_FD, TEST_SEL, &result); + err = nvme_get_features_num_queues(test_link, TEST_SEL, &result); end_mock_cmds(); - check(err == 0, "get features returned error %d, errno %m", err); + check(err == 0, "get features returned error %d", err); check(result == TEST_RESULT, "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT); } @@ -492,9 +467,9 @@ static void test_set_irq_coalesce(void) set_mock_admin_cmds(&mock_admin_cmd, 1); err = nvme_set_features_irq_coalesce( - TEST_FD, THR, TIME, false, &result); + test_link, false, THR, TIME, &result); end_mock_cmds(); - check(err == 0, "set features returned error %d, errno %m", err); + check(err == 0, "set features returned error %d", err); check(result == TEST_RESULT, "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT); } @@ -510,9 +485,9 @@ static void test_get_irq_coalesce(void) int err; set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_get_features_irq_coalesce(TEST_FD, TEST_SEL, &result); + err = nvme_get_features_irq_coalesce(test_link, TEST_SEL, &result); end_mock_cmds(); - check(err == 0, "get features returned error %d, errno %m", err); + check(err == 0, "get features returned error %d", err); check(result == TEST_RESULT, "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT); } @@ -532,9 +507,9 @@ static void test_set_irq_config(void) int err; set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_set_features_irq_config(TEST_FD, IV, true, true, &result); + err = nvme_set_features_irq_config(test_link, true, IV, true, &result); end_mock_cmds(); - check(err == 0, "set features returned error %d, errno %m", err); + check(err == 0, "set features returned error %d", err); check(result == TEST_RESULT, "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT); } @@ -542,19 +517,20 @@ static void test_set_irq_config(void) static void test_get_irq_config(void) { uint16_t IV = 0x5678; + bool CD = true; struct mock_cmd mock_admin_cmd = { .opcode = nvme_admin_get_features, .cdw10 = TEST_SEL << 8 | NVME_FEAT_FID_IRQ_CONFIG, - .cdw11 = IV, + .cdw11 = IV | (!!CD << 16), .result = TEST_RESULT, }; uint32_t result = 0; int err; set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_get_features_irq_config(TEST_FD, TEST_SEL, IV, &result); + err = nvme_get_features_irq_config(test_link, TEST_SEL, IV, CD, &result); end_mock_cmds(); - check(err == 0, "get features returned error %d, errno %m", err); + check(err == 0, "get features returned error %d", err); check(result == TEST_RESULT, "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT); } @@ -571,9 +547,9 @@ static void test_set_write_atomic(void) int err; set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_set_features_write_atomic(TEST_FD, true, false, &result); + err = nvme_set_features_write_atomic(test_link, false, true, &result); end_mock_cmds(); - check(err == 0, "set features returned error %d, errno %m", err); + check(err == 0, "set features returned error %d", err); check(result == TEST_RESULT, "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT); } @@ -589,9 +565,9 @@ static void test_get_write_atomic(void) int err; set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_get_features_write_atomic(TEST_FD, TEST_SEL, &result); + err = nvme_get_features_write_atomic(test_link, TEST_SEL, &result); end_mock_cmds(); - check(err == 0, "get features returned error %d, errno %m", err); + check(err == 0, "get features returned error %d", err); check(result == TEST_RESULT, "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT); } @@ -610,9 +586,9 @@ static void test_set_async_event(void) int err; set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_set_features_async_event(TEST_FD, EVENTS, true, &result); + err = nvme_set_features_async_event(test_link, true, EVENTS, &result); end_mock_cmds(); - check(err == 0, "set features returned error %d, errno %m", err); + check(err == 0, "set features returned error %d", err); check(result == TEST_RESULT, "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT); } @@ -628,9 +604,9 @@ static void test_get_async_event(void) int err; set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_get_features_async_event(TEST_FD, TEST_SEL, &result); + err = nvme_get_features_async_event(test_link, TEST_SEL, &result); end_mock_cmds(); - check(err == 0, "get features returned error %d, errno %m", err); + check(err == 0, "get features returned error %d", err); check(result == TEST_RESULT, "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT); } @@ -651,9 +627,9 @@ static void test_set_auto_pst(void) arbitrary(&apst, sizeof(apst)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_set_features_auto_pst(TEST_FD, true, false, &apst, &result); + err = nvme_set_features_auto_pst(test_link, false, true, &apst, &result); end_mock_cmds(); - check(err == 0, "set features returned error %d, errno %m", err); + check(err == 0, "set features returned error %d", err); check(result == TEST_RESULT, "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT); } @@ -673,9 +649,9 @@ static void test_get_auto_pst(void) arbitrary(&apst, sizeof(apst)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_get_features_auto_pst(TEST_FD, TEST_SEL, &get_apst, &result); + err = nvme_get_features_auto_pst(test_link, TEST_SEL, &get_apst, &result); end_mock_cmds(); - check(err == 0, "get features returned error %d, errno %m", err); + check(err == 0, "get features returned error %d", err); check(result == TEST_RESULT, "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT); cmp(&get_apst, &apst, sizeof(apst), "incorrect apst"); @@ -697,9 +673,9 @@ static void test_get_host_mem_buf(void) arbitrary(&attrs, sizeof(attrs)); set_mock_admin_cmds(&mock_admin_cmd, 1); err = nvme_get_features_host_mem_buf( - TEST_FD, TEST_SEL, &get_attrs, &result); + test_link, TEST_SEL, &get_attrs, &result); end_mock_cmds(); - check(err == 0, "get features returned error %d, errno %m", err); + check(err == 0, "get features returned error %d", err); check(result == TEST_RESULT, "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT); cmp(&get_attrs, &attrs, sizeof(attrs), "incorrect attrs"); @@ -724,9 +700,9 @@ static void test_set_timestamp(void) int err; set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_set_features_timestamp(TEST_FD, true, timestamp); + err = nvme_set_features_timestamp(test_link, timestamp, true); end_mock_cmds(); - check(err == 0, "set features returned error %d, errno %m", err); + check(err == 0, "set features returned error %d", err); } static void test_get_timestamp(void) @@ -742,9 +718,9 @@ static void test_get_timestamp(void) arbitrary(&ts, sizeof(ts)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_get_features_timestamp(TEST_FD, TEST_SEL, &get_ts); + err = nvme_get_features_timestamp(test_link, TEST_SEL, &get_ts); end_mock_cmds(); - check(err == 0, "get features returned error %d, errno %m", err); + check(err == 0, "get features returned error %d", err); cmp(&get_ts, &ts, sizeof(ts), "incorrect timestamp"); } @@ -759,9 +735,9 @@ static void test_get_kato(void) int err; set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_get_features_kato(TEST_FD, TEST_SEL, &result); + err = nvme_get_features_kato(test_link, TEST_SEL, &result); end_mock_cmds(); - check(err == 0, "get features returned error %d, errno %m", err); + check(err == 0, "get features returned error %d", err); check(result == TEST_RESULT, "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT); } @@ -779,9 +755,9 @@ static void test_set_hctm(void) int err; set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_set_features_hctm(TEST_FD, TMT2, TMT1, false, &result); + err = nvme_set_features_hctm(test_link, false, TMT2, TMT1, &result); end_mock_cmds(); - check(err == 0, "set features returned error %d, errno %m", err); + check(err == 0, "set features returned error %d", err); check(result == TEST_RESULT, "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT); } @@ -797,9 +773,9 @@ static void test_get_hctm(void) int err; set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_get_features_hctm(TEST_FD, TEST_SEL, &result); + err = nvme_get_features_hctm(test_link, TEST_SEL, &result); end_mock_cmds(); - check(err == 0, "get features returned error %d, errno %m", err); + check(err == 0, "get features returned error %d", err); check(result == TEST_RESULT, "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT); } @@ -817,9 +793,9 @@ static void test_set_nopsc(void) int err; set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_set_features_nopsc(TEST_FD, true, true, &result); + err = nvme_set_features_nopsc(test_link, true, true, &result); end_mock_cmds(); - check(err == 0, "set features returned error %d, errno %m", err); + check(err == 0, "set features returned error %d", err); check(result == TEST_RESULT, "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT); } @@ -835,9 +811,9 @@ static void test_get_nopsc(void) int err; set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_get_features_nopsc(TEST_FD, TEST_SEL, &result); + err = nvme_get_features_nopsc(test_link, TEST_SEL, &result); end_mock_cmds(); - check(err == 0, "get features returned error %d, errno %m", err); + check(err == 0, "get features returned error %d", err); check(result == TEST_RESULT, "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT); } @@ -857,9 +833,9 @@ static void test_set_rrl(void) int err; set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_set_features_rrl(TEST_FD, RRL, NVMSETID, false, &result); + err = nvme_set_features_rrl(test_link, false, NVMSETID, RRL, &result); end_mock_cmds(); - check(err == 0, "set features returned error %d, errno %m", err); + check(err == 0, "set features returned error %d", err); check(result == TEST_RESULT, "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT); } @@ -876,9 +852,9 @@ static void test_get_rrl(void) int err; set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_get_features_rrl(TEST_FD, TEST_SEL, &result); + err = nvme_get_features_rrl(test_link, TEST_SEL, &result); end_mock_cmds(); - check(err == 0, "get features returned error %d, errno %m", err); + check(err == 0, "get features returned error %d", err); check(result == TEST_RESULT, "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT); } @@ -903,9 +879,9 @@ static void test_set_plm_config(void) arbitrary(&config, sizeof(config)); set_mock_admin_cmds(&mock_admin_cmd, 1); err = nvme_set_features_plm_config( - TEST_FD, true, NVMSETID, true, &config, &result); + test_link, true, NVMSETID, true, &config, &result); end_mock_cmds(); - check(err == 0, "set features returned error %d, errno %m", err); + check(err == 0, "set features returned error %d", err); check(result == TEST_RESULT, "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT); } @@ -928,9 +904,9 @@ static void test_get_plm_config(void) arbitrary(&config, sizeof(config)); set_mock_admin_cmds(&mock_admin_cmd, 1); err = nvme_get_features_plm_config( - TEST_FD, TEST_SEL, NVMSETID, &get_config, &result); + test_link, TEST_SEL, NVMSETID, &get_config, &result); end_mock_cmds(); - check(err == 0, "get features returned error %d, errno %m", err); + check(err == 0, "get features returned error %d", err); check(result == TEST_RESULT, "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT); cmp(&get_config, &config, sizeof(config), "incorrect PLM config"); @@ -952,9 +928,9 @@ static void test_set_plm_window(void) set_mock_admin_cmds(&mock_admin_cmd, 1); err = nvme_set_features_plm_window( - TEST_FD, SEL, NVMSETID, false, &result); + test_link, false, NVMSETID, SEL, &result); end_mock_cmds(); - check(err == 0, "set features returned error %d, errno %m", err); + check(err == 0, "set features returned error %d", err); check(result == TEST_RESULT, "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT); } @@ -973,9 +949,9 @@ static void test_get_plm_window(void) set_mock_admin_cmds(&mock_admin_cmd, 1); err = nvme_get_features_plm_window( - TEST_FD, TEST_SEL, NVMSETID, &result); + test_link, TEST_SEL, NVMSETID, &result); end_mock_cmds(); - check(err == 0, "get features returned error %d, errno %m", err); + check(err == 0, "get features returned error %d", err); check(result == TEST_RESULT, "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT); } @@ -995,9 +971,9 @@ static void test_set_lba_sts_interval(void) set_mock_admin_cmds(&mock_admin_cmd, 1); err = nvme_set_features_lba_sts_interval( - TEST_FD, LSIRI, LSIPI, true, &result); + test_link, true, LSIRI, LSIPI, &result); end_mock_cmds(); - check(err == 0, "set features returned error %d, errno %m", err); + check(err == 0, "set features returned error %d", err); check(result == TEST_RESULT, "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT); } @@ -1013,9 +989,9 @@ static void test_get_lba_sts_interval(void) int err; set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_get_features_lba_sts_interval(TEST_FD, TEST_SEL, &result); + err = nvme_get_features_lba_sts_interval(test_link, TEST_SEL, &result); end_mock_cmds(); - check(err == 0, "get features returned error %d, errno %m", err); + check(err == 0, "get features returned error %d", err); check(result == TEST_RESULT, "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT); } @@ -1024,19 +1000,20 @@ static void test_set_host_behavior(void) { /* nvme_set_features_host_behavior() ignores SAVE */ struct nvme_feat_host_behavior behavior; + bool save = true; struct mock_cmd mock_admin_cmd = { .opcode = nvme_admin_set_features, .in_data = &behavior, .data_len = sizeof(behavior), - .cdw10 = NVME_FEAT_FID_HOST_BEHAVIOR, + .cdw10 = NVME_FEAT_FID_HOST_BEHAVIOR | (!!save << 31), }; int err; arbitrary(&behavior, sizeof(behavior)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_set_features_host_behavior(TEST_FD, true, &behavior); + err = nvme_set_features_host_behavior(test_link, save, &behavior); end_mock_cmds(); - check(err == 0, "set features returned error %d, errno %m", err); + check(err == 0, "set features returned error %d", err); } static void test_get_host_behavior(void) @@ -1055,9 +1032,9 @@ static void test_get_host_behavior(void) arbitrary(&behavior, sizeof(behavior)); set_mock_admin_cmds(&mock_admin_cmd, 1); err = nvme_get_features_host_behavior( - TEST_FD, TEST_SEL, &get_behavior, &result); + test_link, TEST_SEL, &get_behavior, &result); end_mock_cmds(); - check(err == 0, "get features returned error %d, errno %m", err); + check(err == 0, "get features returned error %d", err); check(result == TEST_RESULT, "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT); cmp(&get_behavior, &behavior, sizeof(behavior), "incorrect behavior"); @@ -1075,9 +1052,9 @@ static void test_set_sanitize(void) int err; set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_set_features_sanitize(TEST_FD, true, false, &result); + err = nvme_set_features_sanitize(test_link, false, true, &result); end_mock_cmds(); - check(err == 0, "set features returned error %d, errno %m", err); + check(err == 0, "set features returned error %d", err); check(result == TEST_RESULT, "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT); } @@ -1093,9 +1070,9 @@ static void test_get_sanitize(void) int err; set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_get_features_sanitize(TEST_FD, TEST_SEL, &result); + err = nvme_get_features_sanitize(test_link, TEST_SEL, &result); end_mock_cmds(); - check(err == 0, "get features returned error %d, errno %m", err); + check(err == 0, "get features returned error %d", err); check(result == TEST_RESULT, "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT); } @@ -1116,9 +1093,9 @@ static void test_set_endurance_evt_cfg(void) set_mock_admin_cmds(&mock_admin_cmd, 1); err = nvme_set_features_endurance_evt_cfg( - TEST_FD, ENDGID, EGWARN, true, &result); + test_link, true, ENDGID, EGWARN, &result); end_mock_cmds(); - check(err == 0, "set features returned error %d, errno %m", err); + check(err == 0, "set features returned error %d", err); check(result == TEST_RESULT, "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT); } @@ -1137,9 +1114,9 @@ static void test_get_endurance_event_cfg(void) set_mock_admin_cmds(&mock_admin_cmd, 1); err = nvme_get_features_endurance_event_cfg( - TEST_FD, TEST_SEL, ENDGID, &result); + test_link, TEST_SEL, ENDGID, &result); end_mock_cmds(); - check(err == 0, "get features returned error %d, errno %m", err); + check(err == 0, "get features returned error %d", err); check(result == TEST_RESULT, "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT); } @@ -1151,13 +1128,17 @@ static void test_set_iocs_profile(void) .opcode = nvme_admin_set_features, .cdw10 = NVME_FEAT_FID_IOCS_PROFILE, .cdw11 = IOCSI, + .result = TEST_RESULT, }; + uint32_t result = 0; int err; set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_set_features_iocs_profile(TEST_FD, IOCSI, false); + err = nvme_set_features_iocs_profile(test_link, false, IOCSI, &result); end_mock_cmds(); - check(err == 0, "set features returned error %d, errno %m", err); + check(err == 0, "set features returned error %d", err); + check(result == TEST_RESULT, + "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT); } static void test_get_iocs_profile(void) @@ -1171,9 +1152,9 @@ static void test_get_iocs_profile(void) int err; set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_get_features_iocs_profile(TEST_FD, TEST_SEL, &result); + err = nvme_get_features_iocs_profile(test_link, TEST_SEL, &result); end_mock_cmds(); - check(err == 0, "get features returned error %d, errno %m", err); + check(err == 0, "get features returned error %d", err); check(result == TEST_RESULT, "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT); } @@ -1192,9 +1173,9 @@ static void test_set_sw_progress(void) int err; set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_set_features_sw_progress(TEST_FD, PBSLC, true, &result); + err = nvme_set_features_sw_progress(test_link, true, PBSLC, &result); end_mock_cmds(); - check(err == 0, "set features returned error %d, errno %m", err); + check(err == 0, "set features returned error %d", err); check(result == TEST_RESULT, "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT); } @@ -1210,9 +1191,9 @@ static void test_get_sw_progress(void) int err; set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_get_features_sw_progress(TEST_FD, TEST_SEL, &result); + err = nvme_get_features_sw_progress(test_link, TEST_SEL, &result); end_mock_cmds(); - check(err == 0, "get features returned error %d, errno %m", err); + check(err == 0, "get features returned error %d", err); check(result == TEST_RESULT, "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT); } @@ -1232,9 +1213,9 @@ static void test_set_host_id(void) arbitrary(hostid, sizeof(hostid)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_set_features_host_id(TEST_FD, false, true, hostid); + err = nvme_set_features_host_id(test_link, true, false, hostid); end_mock_cmds(); - check(err == 0, "set features returned error %d, errno %m", err); + check(err == 0, "set features returned error %d", err); } static void test_set_host_id_extended(void) @@ -1252,9 +1233,9 @@ static void test_set_host_id_extended(void) arbitrary(hostid, sizeof(hostid)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_set_features_host_id(TEST_FD, true, false, hostid); + err = nvme_set_features_host_id(test_link, false, true, hostid); end_mock_cmds(); - check(err == 0, "set features returned error %d, errno %m", err); + check(err == 0, "set features returned error %d", err); } static void test_get_host_id(void) @@ -1272,9 +1253,9 @@ static void test_get_host_id(void) arbitrary(hostid, sizeof(hostid)); set_mock_admin_cmds(&mock_admin_cmd, 1); err = nvme_get_features_host_id( - TEST_FD, TEST_SEL, false, sizeof(hostid), get_hostid); + test_link, TEST_SEL, false, sizeof(hostid), get_hostid); end_mock_cmds(); - check(err == 0, "get features returned error %d, errno %m", err); + check(err == 0, "get features returned error %d", err); cmp(get_hostid, hostid, sizeof(hostid), "incorrect host identifier"); } @@ -1294,9 +1275,9 @@ static void test_get_host_id_extended(void) arbitrary(hostid, sizeof(hostid)); set_mock_admin_cmds(&mock_admin_cmd, 1); err = nvme_get_features_host_id( - TEST_FD, TEST_SEL, true, sizeof(hostid), get_hostid); + test_link, TEST_SEL, true, sizeof(hostid), get_hostid); end_mock_cmds(); - check(err == 0, "get features returned error %d, errno %m", err); + check(err == 0, "get features returned error %d", err); cmp(get_hostid, hostid, sizeof(hostid), "incorrect host identifier"); } @@ -1316,9 +1297,9 @@ static void test_set_resv_mask(void) set_mock_admin_cmds(&mock_admin_cmd, 1); err = nvme_set_features_resv_mask( - TEST_FD, TEST_NSID, MASK, true, &result); + test_link, TEST_NSID, true, MASK, &result); end_mock_cmds(); - check(err == 0, "set features returned error %d, errno %m", err); + check(err == 0, "set features returned error %d", err); check(result == TEST_RESULT, "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT); } @@ -1336,9 +1317,9 @@ static void test_get_resv_mask(void) set_mock_admin_cmds(&mock_admin_cmd, 1); err = nvme_get_features_resv_mask( - TEST_FD, TEST_SEL, TEST_NSID, &result); + test_link, TEST_NSID, TEST_SEL, &result); end_mock_cmds(); - check(err == 0, "get features returned error %d, errno %m", err); + check(err == 0, "get features returned error %d", err); check(result == TEST_RESULT, "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT); } @@ -1357,9 +1338,9 @@ static void test_set_resv_persist(void) set_mock_admin_cmds(&mock_admin_cmd, 1); err = nvme_set_features_resv_persist( - TEST_FD, TEST_NSID, true, false, &result); + test_link, TEST_NSID, false, true, &result); end_mock_cmds(); - check(err == 0, "set features returned error %d, errno %m", err); + check(err == 0, "set features returned error %d", err); check(result == TEST_RESULT, "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT); } @@ -1377,9 +1358,9 @@ static void test_get_resv_persist(void) set_mock_admin_cmds(&mock_admin_cmd, 1); err = nvme_get_features_resv_persist( - TEST_FD, TEST_SEL, TEST_NSID, &result); + test_link, TEST_NSID, TEST_SEL, &result); end_mock_cmds(); - check(err == 0, "get features returned error %d, errno %m", err); + check(err == 0, "get features returned error %d", err); check(result == TEST_RESULT, "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT); } @@ -1389,10 +1370,11 @@ static void test_set_write_protect(void) /* nvme_set_features_write_protect() ignores SAVE */ enum nvme_feat_nswpcfg_state STATE = NVME_FEAT_NS_WRITE_PROTECT_PERMANENT; + bool save = true; struct mock_cmd mock_admin_cmd = { .opcode = nvme_admin_set_features, .nsid = TEST_NSID, - .cdw10 = NVME_FEAT_FID_WRITE_PROTECT, + .cdw10 = NVME_FEAT_FID_WRITE_PROTECT | (!!save << 31), .cdw11 = STATE, .result = TEST_RESULT, }; @@ -1401,9 +1383,9 @@ static void test_set_write_protect(void) set_mock_admin_cmds(&mock_admin_cmd, 1); err = nvme_set_features_write_protect( - TEST_FD, TEST_NSID, STATE, true, &result); + test_link, TEST_NSID, save, STATE, &result); end_mock_cmds(); - check(err == 0, "set features returned error %d, errno %m", err); + check(err == 0, "set features returned error %d", err); check(result == TEST_RESULT, "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT); } @@ -1421,9 +1403,9 @@ static void test_get_write_protect(void) set_mock_admin_cmds(&mock_admin_cmd, 1); err = nvme_get_features_write_protect( - TEST_FD, TEST_NSID, TEST_SEL, &result); + test_link, TEST_NSID, TEST_SEL, &result); end_mock_cmds(); - check(err == 0, "get features returned error %d, errno %m", err); + check(err == 0, "get features returned error %d", err); check(result == TEST_RESULT, "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT); } @@ -1447,7 +1429,7 @@ static void test_set_status_code_error(void) int err; set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_set_features_async_event(TEST_FD, EVENTS, false, &result); + err = nvme_set_features_async_event(test_link, false, EVENTS, &result); end_mock_cmds(); check(err == TEST_SC, "got error %d, expected %d", err, TEST_SC); check(result == TEST_RESULT, @@ -1470,10 +1452,9 @@ static void test_set_kernel_error(void) set_mock_admin_cmds(&mock_admin_cmd, 1); err = nvme_set_features_resv_mask( - TEST_FD, TEST_NSID, MASK, false, &result); + test_link, TEST_NSID, false, MASK, &result); end_mock_cmds(); - check(err == -1, "got error %d, expected -1", err); - check(errno == EIO, "unexpected error %m"); + check(err == -EIO, "got error %d, expected -EIO", err); check(!result, "result unexpectedly set to %" PRIu32, result); } @@ -1494,7 +1475,7 @@ static void test_get_status_code_error(void) int err; set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_get_features_kato(TEST_FD, TEST_SEL, &result); + err = nvme_get_features_kato(test_link, TEST_SEL, &result); end_mock_cmds(); check(err == TEST_SC, "got error %d, expected %d", err, TEST_SC); check(result == TEST_RESULT, @@ -1513,10 +1494,9 @@ static void test_get_kernel_error(void) int err; set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_get_features_num_queues(TEST_FD, TEST_SEL, &result); + err = nvme_get_features_num_queues(test_link, TEST_SEL, &result); end_mock_cmds(); - check(err == -1, "got error %d, expected -1", err); - check(errno == EBUSY, "unexpected error %m"); + check(err == -EBUSY, "got error %d, expected -EBUSY", err); check(!result, "result unexpectedly set to %" PRIu32, result); } @@ -1537,7 +1517,7 @@ static void test_lm_set_features_ctrl_data_queue(void) int err; set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_lm_set_features_ctrl_data_queue(TEST_FD, TEST_CDQID, hp, tpt, + err = nvme_lm_set_features_ctrl_data_queue(test_link, TEST_CDQID, hp, tpt, etpt, &result); end_mock_cmds(); check(err == 0, "set features returned error %d, errno %m", err); @@ -1551,7 +1531,7 @@ static void test_lm_get_features_ctrl_data_queue(void) struct mock_cmd mock_admin_cmd = { .opcode = nvme_admin_get_features, .nsid = NVME_NSID_NONE, - .cdw10 = NVME_FEAT_FID_CTRL_DATA_QUEUE, + .cdw10 = TEST_SEL << 8 | NVME_FEAT_FID_CTRL_DATA_QUEUE, .cdw11 = TEST_CDQID, .data_len = sizeof(expected_data), .out_data = &expected_data, @@ -1562,8 +1542,8 @@ static void test_lm_get_features_ctrl_data_queue(void) arbitrary(&expected_data, sizeof(expected_data)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_lm_get_features_ctrl_data_queue(TEST_FD, TEST_CDQID, &data, - &result); + err = nvme_lm_get_features_ctrl_data_queue(test_link, TEST_SEL, TEST_CDQID, + &data, &result); end_mock_cmds(); check(err == 0, "get features returned error %d, errno %m", err); check(result == TEST_RESULT, @@ -1583,7 +1563,11 @@ static void run_test(const char *test_name, void (*test_fn)(void)) int main(void) { + nvme_root_t r = nvme_create_root(stdout, DEFAULT_LOGLEVEL); + set_mock_fd(TEST_FD); + check(!nvme_open(r, "NVME_TEST_FD", &test_link), "opening test link failed"); + RUN_TEST(set_features); RUN_TEST(get_features); RUN_TEST(set_features_data); @@ -1655,4 +1639,6 @@ int main(void) RUN_TEST(get_kernel_error); RUN_TEST(lm_set_features_ctrl_data_queue); RUN_TEST(lm_get_features_ctrl_data_queue); + + nvme_free_root(r); } diff --git a/test/ioctl/identify.c b/test/ioctl/identify.c index bec2a11fe..5dafca074 100644 --- a/test/ioctl/identify.c +++ b/test/ioctl/identify.c @@ -19,6 +19,8 @@ #define TEST_FIDX 0xF #define TEST_SC NVME_SC_INVALID_FIELD +static nvme_link_t test_link; + static void test_ns(void) { struct nvme_id_ns expected_id, id = {}; @@ -33,7 +35,7 @@ static void test_ns(void) arbitrary(&expected_id, sizeof(expected_id)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_identify_ns(TEST_FD, TEST_NSID, &id); + err = nvme_identify_ns(test_link, TEST_NSID, &id); end_mock_cmds(); check(err == 0, "identify returned error %d, errno %m", err); cmp(&id, &expected_id, sizeof(id), "incorrect identify data"); @@ -52,9 +54,9 @@ static void test_ctrl(void) arbitrary(&expected_id, sizeof(expected_id)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_identify_ctrl(TEST_FD, &id); + err = nvme_identify_ctrl(test_link, &id); end_mock_cmds(); - check(err == 0, "identify returned error %d, errno %m", err); + check(err == 0, "identify returned error %d", err); cmp(&id, &expected_id, sizeof(id), "incorrect identify data"); } @@ -72,9 +74,9 @@ static void test_active_ns_list(void) arbitrary(&expected_id, sizeof(expected_id)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_identify_active_ns_list(TEST_FD, TEST_NSID, &id); + err = nvme_identify_active_ns_list(test_link, TEST_NSID, &id); end_mock_cmds(); - check(err == 0, "identify returned error %d, errno %m", err); + check(err == 0, "identify returned error %d", err); cmp(&id, &expected_id, sizeof(id), "incorrect identify data"); } @@ -95,9 +97,9 @@ static void test_ns_descs(void) id = calloc(1, NVME_IDENTIFY_DATA_SIZE); check(id, "memory allocation failed"); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_identify_ns_descs(TEST_FD, TEST_NSID, id); + err = nvme_identify_ns_descs(test_link, TEST_NSID, id); end_mock_cmds(); - check(err == 0, "identify returned error %d, errno %m", err); + check(err == 0, "identify returned error %d", err); cmp(id, expected_id, sizeof(expected_id), "incorrect identify data"); free(id); } @@ -116,9 +118,9 @@ static void test_nvmset_list(void) arbitrary(&expected_id, sizeof(expected_id)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_identify_nvmset_list(TEST_FD, TEST_NVMSETID, &id); + err = nvme_identify_nvmset_list(test_link, TEST_NVMSETID, &id); end_mock_cmds(); - check(err == 0, "identify returned error %d, errno %m", err); + check(err == 0, "identify returned error %d", err); cmp(&id, &expected_id, sizeof(id), "incorrect identify data"); } @@ -139,9 +141,9 @@ static void test_ns_csi(void) arbitrary(expected_id, sizeof(expected_id)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_identify_ns_csi(TEST_FD, TEST_NSID, TEST_UUID, TEST_CSI, id); + err = nvme_identify_ns_csi(test_link, TEST_NSID, TEST_CSI, TEST_UUID, id); end_mock_cmds(); - check(err == 0, "identify returned error %d, errno %m", err); + check(err == 0, "identify returned error %d", err); cmp(id, expected_id, sizeof(id), "incorrect identify data"); } @@ -160,9 +162,9 @@ static void test_zns_identify_ns(void) arbitrary(&expected_id, sizeof(expected_id)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_zns_identify_ns(TEST_FD, TEST_NSID, &id); + err = nvme_zns_identify_ns(test_link, TEST_NSID, &id); end_mock_cmds(); - check(err == 0, "identify returned error %d, errno %m", err); + check(err == 0, "identify returned error %d", err); cmp(&id, &expected_id, sizeof(id), "incorrect identify data"); } @@ -180,9 +182,9 @@ static void test_nvm_identify_ctrl(void) arbitrary(&expected_id, sizeof(expected_id)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_nvm_identify_ctrl(TEST_FD, &id); + err = nvme_nvm_identify_ctrl(test_link, &id); end_mock_cmds(); - check(err == 0, "identify returned error %d, errno %m", err); + check(err == 0, "identify returned error %d", err); cmp(&id, &expected_id, sizeof(id), "incorrect identify data"); } @@ -200,9 +202,9 @@ static void test_zns_identify_ctrl(void) arbitrary(&expected_id, sizeof(expected_id)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_zns_identify_ctrl(TEST_FD, &id); + err = nvme_zns_identify_ctrl(test_link, &id); end_mock_cmds(); - check(err == 0, "identify returned error %d, errno %m", err); + check(err == 0, "identify returned error %d", err); cmp(&id, &expected_id, sizeof(id), "incorrect identify data"); } @@ -222,9 +224,9 @@ static void test_active_ns_list_csi(void) arbitrary(&expected_id, sizeof(expected_id)); set_mock_admin_cmds(&mock_admin_cmd, 1); err = nvme_identify_active_ns_list_csi( - TEST_FD, TEST_NSID, TEST_CSI, &id); + test_link, TEST_NSID, TEST_CSI, &id); end_mock_cmds(); - check(err == 0, "identify returned error %d, errno %m", err); + check(err == 0, "identify returned error %d", err); cmp(&id, &expected_id, sizeof(id), "incorrect identify data"); } @@ -243,9 +245,9 @@ static void test_independent_identify_ns(void) arbitrary(&expected_id, sizeof(expected_id)); set_mock_admin_cmds(&mock_admin_cmd, 1); /* That's a mouthful! */ - err = nvme_identify_independent_identify_ns(TEST_FD, TEST_NSID, &id); + err = nvme_identify_independent_identify_ns(test_link, TEST_NSID, &id); end_mock_cmds(); - check(err == 0, "identify returned error %d, errno %m", err); + check(err == 0, "identify returned error %d", err); cmp(&id, &expected_id, sizeof(id), "incorrect identify data"); } @@ -263,9 +265,9 @@ static void test_allocated_ns_list(void) arbitrary(&expected_id, sizeof(expected_id)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_identify_allocated_ns_list(TEST_FD, TEST_NSID, &id); + err = nvme_identify_allocated_ns_list(test_link, TEST_NSID, &id); end_mock_cmds(); - check(err == 0, "identify returned error %d, errno %m", err); + check(err == 0, "identify returned error %d", err); cmp(&id, &expected_id, sizeof(id), "incorrect identify data"); } @@ -283,9 +285,9 @@ static void test_allocated_ns(void) arbitrary(&expected_id, sizeof(expected_id)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_identify_allocated_ns(TEST_FD, TEST_NSID, &id); + err = nvme_identify_allocated_ns(test_link, TEST_NSID, &id); end_mock_cmds(); - check(err == 0, "identify returned error %d, errno %m", err); + check(err == 0, "identify returned error %d", err); cmp(&id, &expected_id, sizeof(id), "incorrect identify data"); } @@ -304,9 +306,9 @@ static void test_nsid_ctrl_list(void) arbitrary(&expected_id, sizeof(expected_id)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_identify_nsid_ctrl_list(TEST_FD, TEST_NSID, TEST_CNTID, &id); + err = nvme_identify_nsid_ctrl_list(test_link, TEST_NSID, TEST_CNTID, &id); end_mock_cmds(); - check(err == 0, "identify returned error %d, errno %m", err); + check(err == 0, "identify returned error %d", err); cmp(&id, &expected_id, sizeof(id), "incorrect identify data"); } @@ -324,9 +326,9 @@ static void test_ctrl_list(void) arbitrary(&expected_id, sizeof(expected_id)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_identify_ctrl_list(TEST_FD, TEST_CNTID, &id); + err = nvme_identify_ctrl_list(test_link, TEST_CNTID, &id); end_mock_cmds(); - check(err == 0, "identify returned error %d, errno %m", err); + check(err == 0, "identify returned error %d", err); cmp(&id, &expected_id, sizeof(id), "incorrect identify data"); } @@ -344,9 +346,9 @@ static void test_primary_ctrl(void) arbitrary(&expected_id, sizeof(expected_id)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_identify_primary_ctrl(TEST_FD, TEST_CNTID, &id); + err = nvme_identify_primary_ctrl(test_link, TEST_CNTID, &id); end_mock_cmds(); - check(err == 0, "identify returned error %d, errno %m", err); + check(err == 0, "identify returned error %d", err); cmp(&id, &expected_id, sizeof(id), "incorrect identify data"); } @@ -364,9 +366,9 @@ static void test_secondary_ctrl_list(void) arbitrary(&expected_id, sizeof(expected_id)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_identify_secondary_ctrl_list(TEST_FD, TEST_CNTID, &id); + err = nvme_identify_secondary_ctrl_list(test_link, TEST_CNTID, &id); end_mock_cmds(); - check(err == 0, "identify returned error %d, errno %m", err); + check(err == 0, "identify returned error %d", err); cmp(&id, &expected_id, sizeof(id), "incorrect identify data"); } @@ -383,9 +385,9 @@ static void test_ns_granularity(void) arbitrary(&expected_id, sizeof(expected_id)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_identify_ns_granularity(TEST_FD, &id); + err = nvme_identify_ns_granularity(test_link, &id); end_mock_cmds(); - check(err == 0, "identify returned error %d, errno %m", err); + check(err == 0, "identify returned error %d", err); cmp(&id, &expected_id, sizeof(id), "incorrect identify data"); } @@ -402,9 +404,9 @@ static void test_uuid(void) arbitrary(&expected_id, sizeof(expected_id)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_identify_uuid(TEST_FD, &id); + err = nvme_identify_uuid(test_link, &id); end_mock_cmds(); - check(err == 0, "identify returned error %d, errno %m", err); + check(err == 0, "identify returned error %d", err); cmp(&id, &expected_id, sizeof(id), "incorrect identify data"); } @@ -422,9 +424,9 @@ static void test_domain_list(void) arbitrary(&expected_id, sizeof(expected_id)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_identify_domain_list(TEST_FD, TEST_DOMID, &id); + err = nvme_identify_domain_list(test_link, TEST_DOMID, &id); end_mock_cmds(); - check(err == 0, "identify returned error %d, errno %m", err); + check(err == 0, "identify returned error %d", err); cmp(&id, &expected_id, sizeof(id), "incorrect identify data"); } @@ -442,9 +444,9 @@ static void test_endurance_group_list(void) arbitrary(&expected_id, sizeof(expected_id)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_identify_endurance_group_list(TEST_FD, TEST_ENDGID, &id); + err = nvme_identify_endurance_group_list(test_link, TEST_ENDGID, &id); end_mock_cmds(); - check(err == 0, "identify returned error %d, errno %m", err); + check(err == 0, "identify returned error %d", err); cmp(&id, &expected_id, sizeof(id), "incorrect identify data"); } @@ -464,9 +466,9 @@ static void test_allocated_ns_list_csi(void) arbitrary(&expected_id, sizeof(expected_id)); set_mock_admin_cmds(&mock_admin_cmd, 1); err = nvme_identify_allocated_ns_list_csi( - TEST_FD, TEST_NSID, TEST_CSI, &id); + test_link, TEST_NSID, TEST_CSI, &id); end_mock_cmds(); - check(err == 0, "identify returned error %d, errno %m", err); + check(err == 0, "identify returned error %d", err); cmp(&id, &expected_id, sizeof(id), "incorrect identify data"); } @@ -484,9 +486,9 @@ static void test_iocs(void) arbitrary(&expected_id, sizeof(expected_id)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_identify_iocs(TEST_FD, TEST_CNTID, &id); + err = nvme_identify_iocs(test_link, TEST_CNTID, &id); end_mock_cmds(); - check(err == 0, "identify returned error %d, errno %m", err); + check(err == 0, "identify returned error %d", err); cmp(&id, &expected_id, sizeof(id), "incorrect identify data"); } @@ -508,9 +510,9 @@ static void test_status_code_error(void) int err; set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_identify_nvmset_list(TEST_FD, TEST_NVMSETID, &id); + err = nvme_identify_nvmset_list(test_link, TEST_NVMSETID, &id); end_mock_cmds(); - check(err == TEST_SC, "got error %d, expected %d", err, TEST_SC); + check(err == TEST_SC, "got error %d, expected TEST_SC", err); } static void test_kernel_error(void) @@ -526,10 +528,9 @@ static void test_kernel_error(void) int err; set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_identify_ns(TEST_FD, TEST_NSID, &id); + err = nvme_identify_ns(test_link, TEST_NSID, &id); end_mock_cmds(); - check(err == -1, "got error %d, expected -1", err); - check(errno == EIO, "unexpected error %m"); + check(err == -EIO, "got error %d, expected -EIO", err); } static void test_identify_ns_csi_user_data_format(void) @@ -550,7 +551,7 @@ static void test_identify_ns_csi_user_data_format(void) arbitrary(&expected_id, sizeof(expected_id)); set_mock_admin_cmds(&mock_admin_cmd, 1); err = nvme_identify_ns_csi_user_data_format( - TEST_FD, TEST_FIDX, TEST_UUID, NVME_CSI_NVM, &id); + test_link, TEST_FIDX, TEST_UUID, NVME_CSI_NVM, &id); end_mock_cmds(); check(err == 0, "identify returned error %d, errno %m", err); cmp(&id, &expected_id, sizeof(id), "incorrect identify data"); @@ -573,7 +574,7 @@ static void test_identify_iocs_ns_csi_user_data_format(void) arbitrary(&expected_id, sizeof(expected_id)); set_mock_admin_cmds(&mock_admin_cmd, 1); err = nvme_identify_iocs_ns_csi_user_data_format( - TEST_FD, TEST_FIDX, TEST_UUID, TEST_CSI, &id); + test_link, TEST_CSI, TEST_FIDX, TEST_UUID, &id); end_mock_cmds(); check(err == 0, "identify returned error %d, errno %m", err); cmp(&id, &expected_id, sizeof(id), "incorrect identify data"); @@ -591,7 +592,11 @@ static void run_test(const char *test_name, void (*test_fn)(void)) int main(void) { + nvme_root_t r = nvme_create_root(stdout, DEFAULT_LOGLEVEL); + set_mock_fd(TEST_FD); + check(!nvme_open(r, "NVME_TEST_FD", &test_link), "opening test link failed"); + RUN_TEST(ns); RUN_TEST(ctrl); RUN_TEST(active_ns_list); @@ -619,4 +624,6 @@ int main(void) RUN_TEST(kernel_error); RUN_TEST(identify_ns_csi_user_data_format); RUN_TEST(identify_iocs_ns_csi_user_data_format); + + nvme_free_root(r); } diff --git a/test/ioctl/logs.c b/test/ioctl/logs.c index c3822991a..27d5864ed 100644 --- a/test/ioctl/logs.c +++ b/test/ioctl/logs.c @@ -14,7 +14,7 @@ #define TEST_CNTID 0x4321 #define TEST_DOMID 0xFEDC #define TEST_ENDGID 0x0123 -#define TEST_RAE true +#define TEST_RAE 0x1 #define TEST_MCDA NVME_TELEMETRY_DA_3 #define TEST_OFFSET 0xFFFFFFFF1 #define TEST_OFFSET_32 0xFFFFFFFF @@ -23,6 +23,8 @@ #define TEST_LSP NVME_LOG_CDW10_LSP_MASK #define TEST_PEVENT NVME_PEVENT_LOG_RELEASE_CTX +static nvme_link_t test_link; + static void test_get_log_sanitize(void) { struct nvme_sanitize_log_page expected_log, log = {}; @@ -30,7 +32,7 @@ static void test_get_log_sanitize(void) .opcode = nvme_admin_get_log_page, .nsid = NVME_NSID_ALL, .data_len = sizeof(expected_log), - .cdw10 = (NVME_LOG_LID_SANITIZE << 0) | (!!TEST_RAE << 15) | + .cdw10 = (NVME_LOG_LID_SANITIZE << 0) | (TEST_RAE << 15) | (((sizeof(expected_log) >> 2) - 1) << 16), .out_data = &expected_log, }; @@ -38,7 +40,7 @@ static void test_get_log_sanitize(void) arbitrary(&expected_log, sizeof(expected_log)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_get_log_sanitize(TEST_FD, true, &log); + err = nvme_get_log_sanitize(test_link, true, &log); end_mock_cmds(); check(err == 0, "get log returned error %d, errno %m", err); cmp(&log, &expected_log, sizeof(log), "incorrect log data"); @@ -59,9 +61,9 @@ static void test_get_log_mgmt_addr_list(void) arbitrary(&expected_log, sizeof(expected_log)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_get_log_mgmt_addr_list(TEST_FD, sizeof(log), &log); + err = nvme_get_log_mgmt_addr_list(test_link, &log, sizeof(log)); end_mock_cmds(); - check(err == 0, "get log returned error %d, errno %m", err); + check(err == 0, "get log returned error %d", err); cmp(&log, &expected_log, sizeof(log), "incorrect log data"); } @@ -81,9 +83,9 @@ static void test_get_log_supported_log_pages(void) arbitrary(&expected_log, sizeof(expected_log)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_get_log_supported_log_pages(TEST_FD, !TEST_RAE, &log); + err = nvme_get_log_supported_log_pages(test_link, !TEST_RAE, &log); end_mock_cmds(); - check(err == 0, "get log returned error %d, errno %m", err); + check(err == 0, "get log returned error %d", err); cmp(&log, &expected_log, sizeof(log), "incorrect log data"); } @@ -94,7 +96,7 @@ static void test_get_log_error(void) .opcode = nvme_admin_get_log_page, .nsid = NVME_NSID_ALL, .data_len = sizeof(expected_log), - .cdw10 = (NVME_LOG_LID_ERROR << 0) | (!!TEST_RAE << 15) | + .cdw10 = (NVME_LOG_LID_ERROR << 0) | (TEST_RAE << 15) | (((sizeof(expected_log) >> 2) - 1) << 16), .out_data = &expected_log, }; @@ -102,9 +104,9 @@ static void test_get_log_error(void) arbitrary(&expected_log, sizeof(expected_log)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_get_log_error(TEST_FD, 1, TEST_RAE, &log); + err = nvme_get_log_error(test_link, 1, TEST_RAE, &log); end_mock_cmds(); - check(err == 0, "get log returned error %d, errno %m", err); + check(err == 0, "get log returned error %d", err); cmp(&log, &expected_log, sizeof(log), "incorrect log data"); } @@ -115,7 +117,7 @@ static void test_get_log_smart(void) .opcode = nvme_admin_get_log_page, .nsid = TEST_NSID, .data_len = sizeof(expected_log), - .cdw10 = (NVME_LOG_LID_SMART << 0) | (!!TEST_RAE << 15) | + .cdw10 = (NVME_LOG_LID_SMART << 0) | (TEST_RAE << 15) | (((sizeof(expected_log) >> 2) - 1) << 16), .out_data = &expected_log, }; @@ -123,9 +125,9 @@ static void test_get_log_smart(void) arbitrary(&expected_log, sizeof(expected_log)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_get_log_smart(TEST_FD, TEST_NSID, TEST_RAE, &log); + err = nvme_get_log_smart(test_link, TEST_NSID, TEST_RAE, &log); end_mock_cmds(); - check(err == 0, "get log returned error %d, errno %m", err); + check(err == 0, "get log returned error %d", err); cmp(&log, &expected_log, sizeof(log), "incorrect log data"); } @@ -136,7 +138,7 @@ static void test_get_log_fw_slot(void) .opcode = nvme_admin_get_log_page, .nsid = NVME_NSID_ALL, .data_len = sizeof(expected_log), - .cdw10 = (NVME_LOG_LID_FW_SLOT << 0) | (!!TEST_RAE << 15) | + .cdw10 = (NVME_LOG_LID_FW_SLOT << 0) | (TEST_RAE << 15) | (((sizeof(expected_log) >> 2) - 1) << 16), .out_data = &expected_log, }; @@ -144,9 +146,9 @@ static void test_get_log_fw_slot(void) arbitrary(&expected_log, sizeof(expected_log)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_get_log_fw_slot(TEST_FD, TEST_RAE, &log); + err = nvme_get_log_fw_slot(test_link, TEST_RAE, &log); end_mock_cmds(); - check(err == 0, "get log returned error %d, errno %m", err); + check(err == 0, "get log returned error %d", err); cmp(&log, &expected_log, sizeof(log), "incorrect log data"); } @@ -165,9 +167,9 @@ static void test_get_log_changed_ns_list(void) arbitrary(&expected_log, sizeof(expected_log)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_get_log_changed_ns_list(TEST_FD, TEST_RAE, &log); + err = nvme_get_log_changed_ns_list(test_link, TEST_RAE, &log); end_mock_cmds(); - check(err == 0, "get log returned error %d, errno %m", err); + check(err == 0, "get log returned error %d", err); cmp(&log, &expected_log, sizeof(log), "incorrect log data"); } @@ -187,9 +189,9 @@ static void test_get_log_cmd_effects(void) arbitrary(&expected_log, sizeof(expected_log)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_get_log_cmd_effects(TEST_FD, TEST_CSI, &log); + err = nvme_get_log_cmd_effects(test_link, TEST_CSI, &log); end_mock_cmds(); - check(err == 0, "get log returned error %d, errno %m", err); + check(err == 0, "get log returned error %d", err); cmp(&log, &expected_log, sizeof(log), "incorrect log data"); } @@ -208,9 +210,9 @@ static void test_get_log_device_self_test(void) arbitrary(&expected_log, sizeof(expected_log)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_get_log_device_self_test(TEST_FD, &log); + err = nvme_get_log_device_self_test(test_link, &log); end_mock_cmds(); - check(err == 0, "get log returned error %d, errno %m", err); + check(err == 0, "get log returned error %d", err); cmp(&log, &expected_log, sizeof(log), "incorrect log data"); } @@ -231,9 +233,9 @@ static void test_get_log_create_telemetry_host_mcda(void) arbitrary(&expected_log, sizeof(expected_log)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_get_log_create_telemetry_host_mcda(TEST_FD, TEST_MCDA, &log); + err = nvme_get_log_create_telemetry_host_mcda(test_link, TEST_MCDA, &log); end_mock_cmds(); - check(err == 0, "get log returned error %d, errno %m", err); + check(err == 0, "get log returned error %d", err); cmp(&log, &expected_log, sizeof(log), "incorrect log data"); } @@ -255,9 +257,9 @@ static void test_get_log_create_telemetry_host(void) arbitrary(&expected_log, sizeof(expected_log)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_get_log_create_telemetry_host(TEST_FD, &log); + err = nvme_get_log_create_telemetry_host(test_link, &log); end_mock_cmds(); - check(err == 0, "get log returned error %d, errno %m", err); + check(err == 0, "get log returned error %d", err); cmp(&log, &expected_log, sizeof(log), "incorrect log data"); } @@ -281,10 +283,10 @@ static void test_get_log_telemetry_host(void) arbitrary(&expected_log, sizeof(expected_log)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_get_log_telemetry_host(TEST_FD, TEST_OFFSET, sizeof(log), - &log); + err = nvme_get_log_telemetry_host(test_link, TEST_OFFSET, + &log, sizeof(log)); end_mock_cmds(); - check(err == 0, "get log returned error %d, errno %m", err); + check(err == 0, "get log returned error %d", err); cmp(&log, &expected_log, sizeof(log), "incorrect log data"); } @@ -299,7 +301,7 @@ static void test_get_log_telemetry_ctrl(void) (((NVME_TELEMETRY_DA_CTRL_DETERMINE << 1) | NVME_LOG_TELEM_HOST_LSP_RETAIN) << 8) | - (!!TEST_RAE << 15) | + (TEST_RAE << 15) | (((sizeof(expected_log) >> 2) - 1) << 16), .cdw12 = TEST_OFFSET & 0xffffffff, .cdw13 = TEST_OFFSET >> 32, @@ -309,10 +311,10 @@ static void test_get_log_telemetry_ctrl(void) arbitrary(&expected_log, sizeof(expected_log)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_get_log_telemetry_ctrl(TEST_FD, TEST_RAE, TEST_OFFSET, - sizeof(log), &log); + err = nvme_get_log_telemetry_ctrl(test_link, TEST_RAE, TEST_OFFSET, + &log, sizeof(log)); end_mock_cmds(); - check(err == 0, "get log returned error %d, errno %m", err); + check(err == 0, "get log returned error %d", err); cmp(&log, &expected_log, sizeof(log), "incorrect log data"); } @@ -332,9 +334,9 @@ static void test_get_log_endurance_group(void) arbitrary(&expected_log, sizeof(expected_log)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_get_log_endurance_group(TEST_FD, TEST_ENDGID, &log); + err = nvme_get_log_endurance_group(test_link, TEST_ENDGID, &log); end_mock_cmds(); - check(err == 0, "get log returned error %d, errno %m", err); + check(err == 0, "get log returned error %d", err); cmp(&log, &expected_log, sizeof(log), "incorrect log data"); } @@ -354,9 +356,9 @@ static void test_get_log_predictable_lat_nvmset(void) arbitrary(&expected_log, sizeof(expected_log)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_get_log_predictable_lat_nvmset(TEST_FD, TEST_NVMSETID, &log); + err = nvme_get_log_predictable_lat_nvmset(test_link, TEST_NVMSETID, &log); end_mock_cmds(); - check(err == 0, "get log returned error %d, errno %m", err); + check(err == 0, "get log returned error %d", err); cmp(&log, &expected_log, sizeof(log), "incorrect log data"); } @@ -368,7 +370,7 @@ static void test_get_log_predictable_lat_event(void) .nsid = NVME_NSID_NONE, .data_len = sizeof(expected_log), .cdw10 = (NVME_LOG_LID_PREDICTABLE_LAT_AGG << 0) | - (!!TEST_RAE << 15) | + (TEST_RAE << 15) | (((sizeof(expected_log) >> 2) - 1) << 16), .cdw12 = TEST_OFFSET_32, .out_data = &expected_log, @@ -378,9 +380,9 @@ static void test_get_log_predictable_lat_event(void) arbitrary(&expected_log, sizeof(expected_log)); set_mock_admin_cmds(&mock_admin_cmd, 1); err = nvme_get_log_predictable_lat_event( - TEST_FD, TEST_RAE, TEST_OFFSET_32, sizeof(log), &log); + test_link, TEST_RAE, TEST_OFFSET_32, &log, sizeof(log)); end_mock_cmds(); - check(err == 0, "get log returned error %d, errno %m", err); + check(err == 0, "get log returned error %d", err); cmp(&log, &expected_log, sizeof(log), "incorrect log data"); } @@ -402,9 +404,9 @@ static void test_get_log_fdp_configurations(void) arbitrary(&expected_log, sizeof(expected_log)); set_mock_admin_cmds(&mock_admin_cmd, 1); err = nvme_get_log_fdp_configurations( - TEST_FD, TEST_ENDGID, TEST_OFFSET_32, sizeof(log), &log); + test_link, TEST_ENDGID, TEST_OFFSET_32, sizeof(log), &log); end_mock_cmds(); - check(err == 0, "get log returned error %d, errno %m", err); + check(err == 0, "get log returned error %d", err); cmp(&log, &expected_log, sizeof(log), "incorrect log data"); } @@ -426,9 +428,9 @@ static void test_get_log_reclaim_unit_handle_usage(void) arbitrary(&expected_log, sizeof(expected_log)); set_mock_admin_cmds(&mock_admin_cmd, 1); err = nvme_get_log_reclaim_unit_handle_usage( - TEST_FD, TEST_ENDGID, TEST_OFFSET_32, sizeof(log), &log); + test_link, TEST_ENDGID, TEST_OFFSET_32, &log, sizeof(log)); end_mock_cmds(); - check(err == 0, "get log returned error %d, errno %m", err); + check(err == 0, "get log returned error %d", err); cmp(&log, &expected_log, sizeof(log), "incorrect log data"); } @@ -449,10 +451,10 @@ static void test_get_log_fdp_stats(void) arbitrary(&expected_log, sizeof(expected_log)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_get_log_fdp_stats(TEST_FD, TEST_ENDGID, TEST_OFFSET_32, - sizeof(log), &log); + err = nvme_get_log_fdp_stats(test_link, TEST_ENDGID, TEST_OFFSET_32, + &log, sizeof(log)); end_mock_cmds(); - check(err == 0, "get log returned error %d, errno %m", err); + check(err == 0, "get log returned error %d", err); cmp(&log, &expected_log, sizeof(log), "incorrect log data"); } @@ -474,10 +476,10 @@ static void test_get_log_fdp_events(void) arbitrary(&expected_log, sizeof(expected_log)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_get_log_fdp_events(TEST_FD, TEST_ENDGID, TEST_EVENTS, - TEST_OFFSET_32, sizeof(log), &log); + err = nvme_get_log_fdp_events(test_link, TEST_ENDGID, TEST_EVENTS, + TEST_OFFSET_32, &log, sizeof(log)); end_mock_cmds(); - check(err == 0, "get log returned error %d, errno %m", err); + check(err == 0, "get log returned error %d", err); cmp(&log, &expected_log, sizeof(log), "incorrect log data"); } @@ -499,10 +501,10 @@ static void test_get_log_ana(void) arbitrary(&expected_log, sizeof(expected_log)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_get_log_ana(TEST_FD, TEST_ANA_LSP, TEST_RAE, TEST_OFFSET, - sizeof(log), &log); + err = nvme_get_log_ana(test_link, TEST_RAE, TEST_ANA_LSP, TEST_OFFSET, + &log, sizeof(log)); end_mock_cmds(); - check(err == 0, "get log returned error %d, errno %m", err); + check(err == 0, "get log returned error %d", err); cmp(&log, &expected_log, sizeof(log), "incorrect log data"); } @@ -515,7 +517,7 @@ static void test_get_log_ana_groups(void) .data_len = sizeof(expected_log), .cdw10 = (NVME_LOG_LID_ANA << 0) | (NVME_LOG_ANA_LSP_RGO_GROUPS_ONLY << 8) | - (!!TEST_RAE << 15) | + (TEST_RAE << 15) | (((sizeof(expected_log) >> 2) - 1) << 16), .out_data = &expected_log, }; @@ -523,9 +525,9 @@ static void test_get_log_ana_groups(void) arbitrary(&expected_log, sizeof(expected_log)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_get_log_ana_groups(TEST_FD, TEST_RAE, sizeof(log), &log); + err = nvme_get_log_ana_groups(test_link, TEST_RAE, &log, sizeof(log)); end_mock_cmds(); - check(err == 0, "get log returned error %d, errno %m", err); + check(err == 0, "get log returned error %d", err); cmp(&log, &expected_log, sizeof(log), "incorrect log data"); } @@ -536,7 +538,7 @@ static void test_get_log_lba_status(void) .opcode = nvme_admin_get_log_page, .nsid = NVME_NSID_NONE, .data_len = sizeof(expected_log), - .cdw10 = (NVME_LOG_LID_LBA_STATUS << 0) | (!!TEST_RAE << 15) | + .cdw10 = (NVME_LOG_LID_LBA_STATUS << 0) | (TEST_RAE << 15) | (((sizeof(expected_log) >> 2) - 1) << 16), .cdw12 = TEST_OFFSET & 0xffffffff, .cdw13 = TEST_OFFSET >> 32, @@ -546,10 +548,10 @@ static void test_get_log_lba_status(void) arbitrary(&expected_log, sizeof(expected_log)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_get_log_lba_status(TEST_FD, TEST_RAE, TEST_OFFSET, - sizeof(log), &log); + err = nvme_get_log_lba_status(test_link, TEST_RAE, TEST_OFFSET, + &log, sizeof(log)); end_mock_cmds(); - check(err == 0, "get log returned error %d, errno %m", err); + check(err == 0, "get log returned error %d", err); cmp(&log, &expected_log, sizeof(log), "incorrect log data"); } @@ -561,7 +563,7 @@ static void test_get_log_endurance_grp_evt(void) .nsid = NVME_NSID_NONE, .data_len = sizeof(expected_log), .cdw10 = (NVME_LOG_LID_ENDURANCE_GRP_EVT << 0) | - (!!TEST_RAE << 15) | + (TEST_RAE << 15) | (((sizeof(expected_log) >> 2) - 1) << 16), .cdw12 = TEST_OFFSET_32, .out_data = &expected_log, @@ -570,10 +572,10 @@ static void test_get_log_endurance_grp_evt(void) arbitrary(&expected_log, sizeof(expected_log)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_get_log_endurance_grp_evt(TEST_FD, TEST_RAE, TEST_OFFSET_32, - sizeof(log), &log); + err = nvme_get_log_endurance_grp_evt(test_link, TEST_RAE, TEST_OFFSET_32, + &log, sizeof(log)); end_mock_cmds(); - check(err == 0, "get log returned error %d, errno %m", err); + check(err == 0, "get log returned error %d", err); cmp(&log, &expected_log, sizeof(log), "incorrect log data"); } @@ -585,7 +587,7 @@ static void test_get_log_fid_supported_effects(void) .nsid = NVME_NSID_NONE, .data_len = sizeof(expected_log), .cdw10 = (NVME_LOG_LID_FID_SUPPORTED_EFFECTS << 0) | - (!!TEST_RAE << 15) | + (TEST_RAE << 15) | (((sizeof(expected_log) >> 2) - 1) << 16), .out_data = &expected_log, }; @@ -593,9 +595,9 @@ static void test_get_log_fid_supported_effects(void) arbitrary(&expected_log, sizeof(expected_log)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_get_log_fid_supported_effects(TEST_FD, TEST_RAE, &log); + err = nvme_get_log_fid_supported_effects(test_link, TEST_RAE, &log); end_mock_cmds(); - check(err == 0, "get log returned error %d, errno %m", err); + check(err == 0, "get log returned error %d", err); cmp(&log, &expected_log, sizeof(log), "incorrect log data"); } @@ -607,7 +609,7 @@ static void test_get_log_mi_cmd_supported_effects(void) .nsid = NVME_NSID_NONE, .data_len = sizeof(expected_log), .cdw10 = (NVME_LOG_LID_MI_CMD_SUPPORTED_EFFECTS << 0) | - (!!TEST_RAE << 15) | + (TEST_RAE << 15) | (((sizeof(expected_log) >> 2) - 1) << 16), .out_data = &expected_log, }; @@ -615,9 +617,9 @@ static void test_get_log_mi_cmd_supported_effects(void) arbitrary(&expected_log, sizeof(expected_log)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_get_log_mi_cmd_supported_effects(TEST_FD, TEST_RAE, &log); + err = nvme_get_log_mi_cmd_supported_effects(test_link, TEST_RAE, &log); end_mock_cmds(); - check(err == 0, "get log returned error %d, errno %m", err); + check(err == 0, "get log returned error %d", err); cmp(&log, &expected_log, sizeof(log), "incorrect log data"); } @@ -629,7 +631,7 @@ static void test_get_log_boot_partition(void) .nsid = NVME_NSID_NONE, .data_len = sizeof(expected_log), .cdw10 = (NVME_LOG_LID_BOOT_PARTITION << 0) | (TEST_LSP << 8) | - (!!TEST_RAE << 15) | + (TEST_RAE << 15) | (((sizeof(expected_log) >> 2) - 1) << 16), .out_data = &expected_log, }; @@ -637,10 +639,10 @@ static void test_get_log_boot_partition(void) arbitrary(&expected_log, sizeof(expected_log)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_get_log_boot_partition(TEST_FD, TEST_RAE, TEST_LSP, - sizeof(log), &log); + err = nvme_get_log_boot_partition(test_link, TEST_RAE, TEST_LSP, + &log, sizeof(log)); end_mock_cmds(); - check(err == 0, "get log returned error %d, errno %m", err); + check(err == 0, "get log returned error %d", err); cmp(&log, &expected_log, sizeof(log), "incorrect log data"); } @@ -660,10 +662,10 @@ static void test_get_log_rotational_media_info(void) arbitrary(&expected_log, sizeof(expected_log)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_get_log_rotational_media_info(TEST_FD, TEST_ENDGID, - sizeof(log), &log); + err = nvme_get_log_rotational_media_info(test_link, TEST_ENDGID, + &log, sizeof(log)); end_mock_cmds(); - check(err == 0, "get log returned error %d, errno %m", err); + check(err == 0, "get log returned error %d", err); cmp(&log, &expected_log, sizeof(log), "incorrect log data"); } @@ -682,10 +684,10 @@ static void test_get_log_dispersed_ns_participating_nss(void) arbitrary(&expected_log, sizeof(expected_log)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_get_log_dispersed_ns_participating_nss(TEST_FD, TEST_NSID, - sizeof(log), &log); + err = nvme_get_log_dispersed_ns_participating_nss(test_link, TEST_NSID, + &log, sizeof(log)); end_mock_cmds(); - check(err == 0, "get log returned error %d, errno %m", err); + check(err == 0, "get log returned error %d", err); cmp(&log, &expected_log, sizeof(log), "incorrect log data"); } @@ -705,10 +707,10 @@ static void test_get_log_phy_rx_eom(void) arbitrary(&expected_log, sizeof(expected_log)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_get_log_phy_rx_eom(TEST_FD, TEST_LSP, TEST_CNTID, - sizeof(log), &log); + err = nvme_get_log_phy_rx_eom(test_link, TEST_LSP, TEST_CNTID, + &log, sizeof(log)); end_mock_cmds(); - check(err == 0, "get log returned error %d, errno %m", err); + check(err == 0, "get log returned error %d", err); cmp(&log, &expected_log, sizeof(log), "incorrect log data"); } @@ -720,7 +722,7 @@ static void test_get_log_reachability_groups(void) .nsid = NVME_NSID_ALL, .data_len = sizeof(expected_log), .cdw10 = (NVME_LOG_LID_REACHABILITY_GROUPS << 0) | - (!!TEST_LSP << 8) | (!!TEST_RAE << 15) | + (0x1 << 8) | (TEST_RAE << 15) | (((sizeof(expected_log) >> 2) - 1) << 16), .out_data = &expected_log, }; @@ -728,10 +730,10 @@ static void test_get_log_reachability_groups(void) arbitrary(&expected_log, sizeof(expected_log)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_get_log_reachability_groups(TEST_FD, !!TEST_LSP, TEST_RAE, - sizeof(log), &log); + err = nvme_get_log_reachability_groups(test_link, !!TEST_RAE, true, + &log, sizeof(log)); end_mock_cmds(); - check(err == 0, "get log returned error %d, errno %m", err); + check(err == 0, "get log returned error %d", err); cmp(&log, &expected_log, sizeof(log), "incorrect log data"); } @@ -743,7 +745,7 @@ static void test_get_log_reachability_associations(void) .nsid = NVME_NSID_ALL, .data_len = sizeof(expected_log), .cdw10 = (NVME_LOG_LID_REACHABILITY_ASSOCIATIONS << 0) | - (!!TEST_LSP << 8) | (!!TEST_RAE << 15) | + (0x1 << 8) | (TEST_RAE << 15) | (((sizeof(expected_log) >> 2) - 1) << 16), .out_data = &expected_log, }; @@ -752,9 +754,9 @@ static void test_get_log_reachability_associations(void) arbitrary(&expected_log, sizeof(expected_log)); set_mock_admin_cmds(&mock_admin_cmd, 1); err = nvme_get_log_reachability_associations( - TEST_FD, !!TEST_LSP, TEST_RAE, sizeof(log), &log); + test_link, !!TEST_RAE, true, &log, sizeof(log)); end_mock_cmds(); - check(err == 0, "get log returned error %d, errno %m", err); + check(err == 0, "get log returned error %d", err); cmp(&log, &expected_log, sizeof(log), "incorrect log data"); } @@ -766,7 +768,7 @@ static void test_get_log_changed_alloc_ns_list(void) .nsid = NVME_NSID_ALL, .data_len = sizeof(expected_log), .cdw10 = (NVME_LOG_LID_CHANGED_ALLOC_NS_LIST << 0) | - (!!TEST_RAE << 15) | + (TEST_RAE << 15) | (((sizeof(expected_log) >> 2) - 1) << 16), .out_data = &expected_log, }; @@ -774,10 +776,10 @@ static void test_get_log_changed_alloc_ns_list(void) arbitrary(&expected_log, sizeof(expected_log)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_get_log_changed_alloc_ns_list(TEST_FD, TEST_RAE, sizeof(log), - &log); + err = nvme_get_log_changed_alloc_ns_list(test_link, TEST_RAE, + &log, sizeof(log)); end_mock_cmds(); - check(err == 0, "get log returned error %d, errno %m", err); + check(err == 0, "get log returned error %d", err); cmp(&log, &expected_log, sizeof(log), "incorrect log data"); } @@ -788,7 +790,7 @@ static void test_get_log_discovery(void) .opcode = nvme_admin_get_log_page, .nsid = NVME_NSID_NONE, .data_len = sizeof(expected_log), - .cdw10 = (NVME_LOG_LID_DISCOVER << 0) | (!!TEST_RAE << 15) | + .cdw10 = (NVME_LOG_LID_DISCOVER << 0) | (TEST_RAE << 15) | (((sizeof(expected_log) >> 2) - 1) << 16), .cdw12 = TEST_OFFSET_32, .out_data = &expected_log, @@ -797,10 +799,10 @@ static void test_get_log_discovery(void) arbitrary(&expected_log, sizeof(expected_log)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_get_log_discovery(TEST_FD, TEST_RAE, TEST_OFFSET_32, + err = nvme_get_log_discovery(test_link, TEST_RAE, TEST_OFFSET_32, sizeof(log), &log); end_mock_cmds(); - check(err == 0, "get log returned error %d, errno %m", err); + check(err == 0, "get log returned error %d", err); cmp(&log, &expected_log, sizeof(log), "incorrect log data"); } @@ -811,8 +813,8 @@ static void test_get_log_host_discover(void) .opcode = nvme_admin_get_log_page, .nsid = NVME_NSID_ALL, .data_len = sizeof(expected_log), - .cdw10 = (NVME_LOG_LID_HOST_DISCOVER << 0) | (!!TEST_LSP << 8) | - (!!TEST_RAE << 15) | + .cdw10 = (NVME_LOG_LID_HOST_DISCOVER << 0) | (0x1 << 8) | + (TEST_RAE << 15) | (((sizeof(expected_log) >> 2) - 1) << 16), .out_data = &expected_log, }; @@ -820,10 +822,10 @@ static void test_get_log_host_discover(void) arbitrary(&expected_log, sizeof(expected_log)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_get_log_host_discover(TEST_FD, !!TEST_LSP, TEST_RAE, - sizeof(log), &log); + err = nvme_get_log_host_discover(test_link, !!TEST_RAE, true, + &log, sizeof(log)); end_mock_cmds(); - check(err == 0, "get log returned error %d, errno %m", err); + check(err == 0, "get log returned error %d", err); cmp(&log, &expected_log, sizeof(log), "incorrect log data"); } @@ -834,7 +836,7 @@ static void test_get_log_ave_discover(void) .opcode = nvme_admin_get_log_page, .nsid = NVME_NSID_ALL, .data_len = sizeof(expected_log), - .cdw10 = (NVME_LOG_LID_AVE_DISCOVER << 0) | (!!TEST_RAE << 15) | + .cdw10 = (NVME_LOG_LID_AVE_DISCOVER << 0) | (TEST_RAE << 15) | (((sizeof(expected_log) >> 2) - 1) << 16), .out_data = &expected_log, }; @@ -842,9 +844,9 @@ static void test_get_log_ave_discover(void) arbitrary(&expected_log, sizeof(expected_log)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_get_log_ave_discover(TEST_FD, TEST_RAE, sizeof(log), &log); + err = nvme_get_log_ave_discover(test_link, TEST_RAE, &log, sizeof(log)); end_mock_cmds(); - check(err == 0, "get log returned error %d, errno %m", err); + check(err == 0, "get log returned error %d", err); cmp(&log, &expected_log, sizeof(log), "incorrect log data"); } @@ -856,7 +858,7 @@ static void test_get_log_pull_model_ddc_req(void) .nsid = NVME_NSID_ALL, .data_len = sizeof(expected_log), .cdw10 = (NVME_LOG_LID_PULL_MODEL_DDC_REQ << 0) | - (!!TEST_RAE << 15) | + (TEST_RAE << 15) | (((sizeof(expected_log) >> 2) - 1) << 16), .out_data = &expected_log, }; @@ -864,10 +866,10 @@ static void test_get_log_pull_model_ddc_req(void) arbitrary(&expected_log, sizeof(expected_log)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_get_log_pull_model_ddc_req(TEST_FD, TEST_RAE, sizeof(log), - &log); + err = nvme_get_log_pull_model_ddc_req(test_link, TEST_RAE, + &log, sizeof(log)); end_mock_cmds(); - check(err == 0, "get log returned error %d, errno %m", err); + check(err == 0, "get log returned error %d", err); cmp(&log, &expected_log, sizeof(log), "incorrect log data"); } @@ -887,9 +889,9 @@ static void test_get_log_media_unit_stat(void) arbitrary(&expected_log, sizeof(expected_log)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_get_log_media_unit_stat(TEST_FD, TEST_DOMID, &log); + err = nvme_get_log_media_unit_stat(test_link, TEST_DOMID, &log); end_mock_cmds(); - check(err == 0, "get log returned error %d, errno %m", err); + check(err == 0, "get log returned error %d", err); cmp(&log, &expected_log, sizeof(log), "incorrect log data"); } @@ -909,9 +911,9 @@ static void test_get_log_support_cap_config_list(void) arbitrary(&expected_log, sizeof(expected_log)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_get_log_support_cap_config_list(TEST_FD, TEST_DOMID, &log); + err = nvme_get_log_support_cap_config_list(test_link, TEST_DOMID, &log); end_mock_cmds(); - check(err == 0, "get log returned error %d, errno %m", err); + check(err == 0, "get log returned error %d", err); cmp(&log, &expected_log, sizeof(log), "incorrect log data"); } @@ -922,7 +924,7 @@ static void test_get_log_reservation(void) .opcode = nvme_admin_get_log_page, .nsid = NVME_NSID_ALL, .data_len = sizeof(expected_log), - .cdw10 = (NVME_LOG_LID_RESERVATION << 0) | (!!TEST_RAE << 15) | + .cdw10 = (NVME_LOG_LID_RESERVATION << 0) | (TEST_RAE << 15) | (((sizeof(expected_log) >> 2) - 1) << 16), .out_data = &expected_log, }; @@ -930,9 +932,9 @@ static void test_get_log_reservation(void) arbitrary(&expected_log, sizeof(expected_log)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_get_log_reservation(TEST_FD, TEST_RAE, &log); + err = nvme_get_log_reservation(test_link, TEST_RAE, &log); end_mock_cmds(); - check(err == 0, "get log returned error %d, errno %m", err); + check(err == 0, "get log returned error %d", err); cmp(&log, &expected_log, sizeof(log), "incorrect log data"); } @@ -944,7 +946,7 @@ static void test_get_log_zns_changed_zones(void) .nsid = TEST_NSID, .data_len = sizeof(expected_log), .cdw10 = (NVME_LOG_LID_ZNS_CHANGED_ZONES << 0) | - (!!TEST_RAE << 15) | + (TEST_RAE << 15) | (((sizeof(expected_log) >> 2) - 1) << 16), .cdw14 = NVME_CSI_ZNS << 24, .out_data = &expected_log, @@ -953,10 +955,10 @@ static void test_get_log_zns_changed_zones(void) arbitrary(&expected_log, sizeof(expected_log)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_get_log_zns_changed_zones(TEST_FD, TEST_NSID, TEST_RAE, + err = nvme_get_log_zns_changed_zones(test_link, TEST_NSID, TEST_RAE, &log); end_mock_cmds(); - check(err == 0, "get log returned error %d, errno %m", err); + check(err == 0, "get log returned error %d", err); cmp(&log, &expected_log, sizeof(log), "incorrect log data"); } @@ -976,10 +978,10 @@ static void test_get_log_persistent_event(void) arbitrary(&expected_log, sizeof(expected_log)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_get_log_persistent_event(TEST_FD, TEST_PEVENT, sizeof(log), - &log); + err = nvme_get_log_persistent_event(test_link, TEST_PEVENT, + &log, sizeof(log)); end_mock_cmds(); - check(err == 0, "get log returned error %d, errno %m", err); + check(err == 0, "get log returned error %d", err); cmp(&log, &expected_log, sizeof(log), "incorrect log data"); } @@ -999,9 +1001,9 @@ static void test_get_log_lockdown(void) arbitrary(&expected_log, sizeof(expected_log)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_get_log_lockdown(TEST_FD, TEST_LSP, &log); + err = nvme_get_log_lockdown(test_link, TEST_LSP, &log); end_mock_cmds(); - check(err == 0, "get log returned error %d, errno %m", err); + check(err == 0, "get log returned error %d", err); cmp(&log, &expected_log, sizeof(log), "incorrect log data"); } @@ -1017,7 +1019,11 @@ static void run_test(const char *test_name, void (*test_fn)(void)) int main(void) { + nvme_root_t r = nvme_create_root(stdout, DEFAULT_LOGLEVEL); + set_mock_fd(TEST_FD); + check(!nvme_open(r, "NVME_TEST_FD", &test_link), "opening test link failed"); + RUN_TEST(get_log_sanitize); RUN_TEST(get_log_mgmt_addr_list); RUN_TEST(get_log_supported_log_pages); @@ -1061,4 +1067,6 @@ int main(void) RUN_TEST(get_log_zns_changed_zones); RUN_TEST(get_log_persistent_event); RUN_TEST(get_log_lockdown); + + nvme_free_root(r); } diff --git a/test/ioctl/meson.build b/test/ioctl/meson.build index f97925fe5..e086cbf4a 100644 --- a/test/ioctl/meson.build +++ b/test/ioctl/meson.build @@ -15,7 +15,7 @@ mock_ioctl = library( 'mock-ioctl', ['mock.c', 'util.c'], include_directories: [incdir, internal_incdir], - dependencies: [dl_dep], + dependencies: [libnvme_dep, dl_dep], c_args: ['-DHAVE_GLIBC_IOCTL=' + (mock_conf.get('HAVE_GLIBC_IOCTL') ? '1' : '0')]) # Add mock-ioctl to the LD_PRELOAD path so it overrides libc. diff --git a/test/ioctl/misc.c b/test/ioctl/misc.c index 755cea603..9b5d2c4e8 100644 --- a/test/ioctl/misc.c +++ b/test/ioctl/misc.c @@ -13,59 +13,49 @@ #define TEST_NSID 0x12345678 #define TEST_CSI NVME_CSI_KV +static nvme_link_t test_link; + static void test_format_nvm(void) { + enum nvme_cmd_format_mset mset = NVME_FORMAT_MSET_EXTENDED; + enum nvme_cmd_format_pi pi = NVME_FORMAT_PI_TYPE2; + enum nvme_cmd_format_pil pil = NVME_FORMAT_PIL_FIRST; + enum nvme_cmd_format_ses ses = NVME_FORMAT_SES_USER_DATA_ERASE; + __u32 nsid = TEST_NSID; + __u8 lbaf = 0x1F; __u32 result = 0; - struct nvme_format_nvm_args args = { - .result = &result, - .args_size = sizeof(args), - .fd = TEST_FD, - .nsid = TEST_NSID, - .mset = NVME_FORMAT_MSET_EXTENDED, - .pi = NVME_FORMAT_PI_TYPE2, - .pil = NVME_FORMAT_PIL_FIRST, - .ses = NVME_FORMAT_SES_USER_DATA_ERASE, - .lbaf = 0xF, - .lbafu = 0x1, - }; struct mock_cmd mock_admin_cmd = { .opcode = nvme_admin_format_nvm, - .nsid = TEST_NSID, - .cdw10 = args.lbaf | (args.mset << 4) | (args.pi << 5) | - (args.pil << 8) | (args.ses << 9) | (args.lbafu << 12), + .nsid = nsid, + .cdw10 = lbaf | (mset << 4) | (pi << 5) | + (pil << 8) | (ses << 9) | ((lbaf >> 4) << 12), .result = 0, }; int err; set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_format_nvm(&args); + err = nvme_format_nvm(test_link, nsid, lbaf, mset, pi, pil, + ses, &result); end_mock_cmds(); - check(err == 0, "returned error %d, errno %m", err); + check(err == 0, "returned error %d", err); check(result == 0, "returned result %u", result); } static void test_ns_mgmt(void) { struct nvme_ns_mgmt_host_sw_specified expected_data, data = {}; + enum nvme_ns_mgmt_sel sel = NVME_NS_MGMT_SEL_CREATE; + __u32 nsid = TEST_NSID; + __u8 csi = TEST_CSI; __u32 result = 0; - struct nvme_ns_mgmt_args args = { - .result = &result, - .ns = NULL, - .args_size = sizeof(args), - .fd = TEST_FD, - .nsid = TEST_NSID, - .sel = NVME_NS_MGMT_SEL_CREATE, - .csi = TEST_CSI, - .data = &data, - }; struct mock_cmd mock_admin_cmd = { .opcode = nvme_admin_ns_mgmt, - .nsid = TEST_NSID, - .cdw10 = args.sel, - .cdw11 = args.csi << 24, + .nsid = nsid, + .cdw10 = sel, + .cdw11 = csi << 24, .result = 0, .data_len = sizeof(expected_data), .out_data = &expected_data, @@ -75,9 +65,10 @@ static void test_ns_mgmt(void) arbitrary(&expected_data, sizeof(expected_data)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_ns_mgmt(&args); + err = nvme_ns_mgmt(test_link, TEST_NSID, NVME_NS_MGMT_SEL_CREATE, + TEST_CSI, &data, &result); end_mock_cmds(); - check(err == 0, "returned error %d, errno %m", err); + check(err == 0, "returned error %d", err); check(result == 0, "returned result %u", result); cmp(&data, &expected_data, sizeof(data), "incorrect data"); } @@ -85,12 +76,15 @@ static void test_ns_mgmt(void) static void test_ns_mgmt_create(void) { struct nvme_ns_mgmt_host_sw_specified expected_data, data = {}; + enum nvme_ns_mgmt_sel sel = NVME_NS_MGMT_SEL_CREATE; + __u32 nsid = NVME_NSID_NONE; + __u8 csi = NVME_CSI_ZNS; __u32 result = 0; struct mock_cmd mock_admin_cmd = { .opcode = nvme_admin_ns_mgmt, - .nsid = NVME_NSID_NONE, - .cdw10 = NVME_NS_MGMT_SEL_CREATE, - .cdw11 = NVME_CSI_ZNS << 24, + .nsid = nsid, + .cdw10 = sel, + .cdw11 = csi << 24, .result = TEST_NSID, .data_len = sizeof(expected_data), .out_data = &expected_data, @@ -100,10 +94,9 @@ static void test_ns_mgmt_create(void) arbitrary(&expected_data, sizeof(expected_data)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_ns_mgmt_create(TEST_FD, NULL, &result, 0, NVME_CSI_ZNS, - &data); + err = nvme_ns_mgmt_create(test_link, csi, &data, &result); end_mock_cmds(); - check(err == 0, "returned error %d, errno %m", err); + check(err == 0, "returned error %d", err); check(result == TEST_NSID, "returned result %u", result); cmp(&data, &expected_data, sizeof(data), "incorrect data"); } @@ -119,20 +112,15 @@ static void test_ns_mgmt_delete(void) int err; set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_ns_mgmt_delete(TEST_FD, TEST_NSID); + err = nvme_ns_mgmt_delete(test_link, TEST_NSID); end_mock_cmds(); - check(err == 0, "returned error %d, errno %m", err); + check(err == 0, "returned error %d", err); } static void test_get_property(void) { __u64 expected_result, result; - struct nvme_get_property_args args = { - .value = &result, - .args_size = sizeof(args), - .fd = TEST_FD, - .offset = NVME_REG_ACQ, - }; + int err; arbitrary(&expected_result, sizeof(expected_result)); @@ -144,12 +132,10 @@ static void test_get_property(void) .result = expected_result, }; - int err; - set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_get_property(&args); + err = nvme_get_property(test_link, NVME_REG_ACQ, &result); end_mock_cmds(); - check(err == 0, "returned error %d, errno %m", err); + check(err == 0, "returned error %d", err); check(result == expected_result, "returned wrong result"); } @@ -157,13 +143,7 @@ static void test_set_property(void) { __u64 value = 0xffffffff; __u32 result; - struct nvme_set_property_args args = { - .value = value, - .result = &result, - .args_size = sizeof(args), - .fd = TEST_FD, - .offset = NVME_REG_BPMBL, - }; + int err; struct mock_cmd mock_admin_cmd = { .opcode = nvme_admin_fabrics, @@ -174,32 +154,24 @@ static void test_set_property(void) .cdw13 = value >> 32, }; - int err; - set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_set_property(&args); + err = nvme_set_property(test_link, NVME_REG_BPMBL, value, &result); end_mock_cmds(); - check(err == 0, "returned error %d, errno %m", err); + check(err == 0, "returned error %d", err); check(result == 0, "returned result %u", result); } static void test_ns_attach(void) { - __u32 result; struct nvme_ctrl_list expected_ctrlist, ctrlist; - struct nvme_ns_attach_args args = { - .result = &result, - .ctrlist = &ctrlist, - .args_size = sizeof(args), - .fd = TEST_FD, - .nsid = TEST_NSID, - .sel = NVME_NS_ATTACH_SEL_CTRL_DEATTACH, - }; + enum nvme_ns_attach_sel sel = NVME_NS_ATTACH_SEL_CTRL_DEATTACH; + __u32 nsid = TEST_NSID; + __u32 result; struct mock_cmd mock_admin_cmd = { .opcode = nvme_admin_ns_attach, - .nsid = TEST_NSID, - .cdw10 = NVME_NS_ATTACH_SEL_CTRL_DEATTACH, + .nsid = nsid, + .cdw10 = sel, .data_len = sizeof(expected_ctrlist), .out_data = &expected_ctrlist, }; @@ -208,9 +180,9 @@ static void test_ns_attach(void) arbitrary(&expected_ctrlist, sizeof(expected_ctrlist)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_ns_attach(&args); + err = nvme_ns_attach(test_link, nsid, sel, &ctrlist, &result); end_mock_cmds(); - check(err == 0, "returned error %d, errno %m", err); + check(err == 0, "returned error %d", err); check(result == 0, "returned result %u", result); cmp(&expected_ctrlist, &ctrlist, sizeof(expected_ctrlist), "incorrect data"); @@ -232,9 +204,9 @@ static void test_ns_attach_ctrls(void) arbitrary(&ctrlist, sizeof(ctrlist)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_ns_attach_ctrls(TEST_FD, TEST_NSID, &ctrlist); + err = nvme_ns_attach_ctrls(test_link, TEST_NSID, &ctrlist); end_mock_cmds(); - check(err == 0, "returned error %d, errno %m", err); + check(err == 0, "returned error %d", err); } static void test_ns_detach_ctrls(void) @@ -253,30 +225,23 @@ static void test_ns_detach_ctrls(void) arbitrary(&ctrlist, sizeof(ctrlist)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_ns_detach_ctrls(TEST_FD, TEST_NSID, &ctrlist); + err = nvme_ns_detach_ctrls(test_link, TEST_NSID, &ctrlist); end_mock_cmds(); - check(err == 0, "returned error %d, errno %m", err); + check(err == 0, "returned error %d", err); } static void test_fw_download(void) { __u32 result = 0; __u8 expected_data[8], data[8]; - - struct nvme_fw_download_args args = { - .result = &result, - .data = &expected_data, - .args_size = sizeof(args), - .fd = TEST_FD, - .offset = 123, - .data_len = sizeof(expected_data), - }; + __u32 data_len = sizeof(expected_data); + __u32 offset = 120; struct mock_cmd mock_admin_cmd = { .opcode = nvme_admin_fw_download, - .cdw10 = (args.data_len >> 2) - 1, - .cdw11 = args.offset >> 2, - .data_len = args.data_len, + .cdw10 = (data_len >> 2) - 1, + .cdw11 = offset >> 2, + .data_len = data_len, .in_data = &data, }; @@ -285,66 +250,51 @@ static void test_fw_download(void) arbitrary(&expected_data, sizeof(expected_data)); memcpy(&data, &expected_data, sizeof(expected_data)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_fw_download(&args); + err = nvme_fw_download(test_link, expected_data, data_len, offset, &result); end_mock_cmds(); - check(err == 0, "returned error %d, errno %m", err); + check(err == 0, "returned error %d", err); check(result == 0, "returned result %u", result); } static void test_fw_commit(void) { + enum nvme_fw_commit_ca action = NVME_FW_COMMIT_CA_REPLACE_AND_ACTIVATE_IMMEDIATE; __u32 result = 0; - - struct nvme_fw_commit_args args = { - .result = &result, - .args_size = sizeof(args), - .fd = TEST_FD, - .action = NVME_FW_COMMIT_CA_REPLACE_AND_ACTIVATE_IMMEDIATE, - .slot = 0xf, - .bpid = true, - }; + __u8 slot = 0xf; + bool bpid = true; struct mock_cmd mock_admin_cmd = { .opcode = nvme_admin_fw_commit, - .cdw10 = (!!args.bpid << 31) | (args.action << 3) | args.slot, + .cdw10 = (!!bpid << 31) | (action << 3) | slot, }; int err; set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_fw_commit(&args); + err = nvme_fw_commit(test_link, slot, action, bpid, &result); end_mock_cmds(); - check(err == 0, "returned error %d, errno %m", err); + check(err == 0, "returned error %d", err); check(result == 0, "returned result %u", result); } static void test_security_send(void) { __u8 expected_data[8], data[8]; + __u32 data_len = sizeof(expected_data); + __u32 nsid = TEST_NSID; + __u32 tl = 0xffff; __u32 result = 0; - - struct nvme_security_send_args args = { - .result = &result, - .data = &expected_data, - .args_size = sizeof(args), - .fd = TEST_FD, - .nsid = TEST_NSID, - .tl = 0xffff, - .data_len = sizeof(expected_data), - .nssf = 0x1, - .spsp0 = 0x1, - .spsp1 = 0x1, - .secp = 0xE9, - }; + __u8 nssf = 0x1; + __u16 spsp = 0x0101; + __u8 secp = 0xE9; struct mock_cmd mock_admin_cmd = { .opcode = nvme_admin_security_send, .nsid = TEST_NSID, - .cdw10 = args.nssf | (args.spsp0 << 8) | (args.spsp1 << 16) | - (args.secp << 24), - .cdw11 = args.tl, - .data_len = args.data_len, - .in_data = &data, + .cdw10 = nssf | (spsp << 8) | (secp << 24), + .cdw11 = tl, + .data_len = data_len, + .in_data = &expected_data, }; int err; @@ -352,9 +302,10 @@ static void test_security_send(void) arbitrary(&expected_data, sizeof(expected_data)); memcpy(&data, &expected_data, sizeof(expected_data)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_security_send(&args); + err = nvme_security_send(test_link, nsid, nssf, spsp, secp, tl, + &expected_data, data_len, &result); end_mock_cmds(); - check(err == 0, "returned error %d, errno %m", err); + check(err == 0, "returned error %d", err); check(result == 0, "returned result %u", result); cmp(&data, &expected_data, sizeof(data), "incorrect data"); } @@ -363,48 +314,43 @@ static void test_security_receive(void) { __u8 expected_data[8], data[8]; __u32 result = 0; - - struct nvme_security_receive_args args = { - .result = &result, - .data = &data, - .args_size = sizeof(args), - .fd = TEST_FD, - .nsid = TEST_NSID, - .al = 0xffff, - .data_len = sizeof(data), - .nssf = 0x1, - .spsp0 = 0x1, - .spsp1 = 0x1, - .secp = 0xE9, - }; + __u32 al = 0xffff; + __u8 spsp0 = 0x1; + __u8 spsp1 = 0x1; + __u8 secp = 0xE9; + __u8 nssf = 0x1; + int err; struct mock_cmd mock_admin_cmd = { .opcode = nvme_admin_security_recv, .nsid = TEST_NSID, - .cdw10 = args.nssf | (args.spsp0 << 8) | (args.spsp1 << 16) | - (args.secp << 24), - .cdw11 = args.al, - .data_len = args.data_len, + .cdw10 = nssf | (spsp0 << 8) | (spsp1 << 16) | (secp << 24), + .cdw11 = al, + .data_len = sizeof(expected_data), .out_data = &expected_data, }; - int err; - arbitrary(&expected_data, sizeof(expected_data)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_security_receive(&args); + err = nvme_security_receive(test_link, TEST_NSID, nssf, spsp0, spsp1, + secp, al, &data, sizeof(data), &result); end_mock_cmds(); - check(err == 0, "returned error %d, errno %m", err); + check(err == 0, "returned error %d", err); check(result == 0, "returned result %u", result); cmp(&data, &expected_data, sizeof(data), "incorrect data"); } static void test_get_lba_status(void) { - __u32 result = 0; __u8 nlsd = 3; int lba_status_size = sizeof(struct nvme_lba_status) + nlsd * sizeof(struct nvme_lba_status_desc); + enum nvme_lba_status_atype atype = 0x11; + __u32 mndw = (lba_status_size - 1) >> 2; + __u64 slba = 0x123456789; + __u32 result = 0; + __u16 rl = 0x42; + int err; _cleanup_free_ struct nvme_lba_status *lbas = NULL; _cleanup_free_ struct nvme_lba_status *expected_lbas = NULL; @@ -414,76 +360,56 @@ static void test_get_lba_status(void) expected_lbas = malloc(lba_status_size); check(expected_lbas, "expected_lbas: ENOMEM"); - struct nvme_get_lba_status_args args = { - .slba = 0x123456789, - .result = &result, - .lbas = lbas, - .args_size = sizeof(args), - .fd = TEST_FD, - .nsid = TEST_NSID, - .mndw = ((lba_status_size - 1) >> 2), - .atype = 0x11, - .rl = 0x42, - }; - struct mock_cmd mock_admin_cmd = { .opcode = nvme_admin_get_lba_status, .nsid = TEST_NSID, - .cdw10 = args.slba & 0xffffffff, - .cdw11 = args.slba >> 32, - .cdw12 = args.mndw, - .cdw13 = args.rl | (args.atype << 24), - .data_len = (args.mndw + 1) << 2, + .cdw10 = slba & 0xffffffff, + .cdw11 = slba >> 32, + .cdw12 = mndw, + .cdw13 = rl | (atype << 24), + .data_len = (mndw + 1) << 2, .out_data = expected_lbas, }; - int err; - arbitrary(expected_lbas, lba_status_size); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_get_lba_status(&args); + err = nvme_get_lba_status(test_link, TEST_NSID, slba, mndw, atype, + rl, lbas, &result); end_mock_cmds(); - check(err == 0, "returned error %d, errno %m", err); + check(err == 0, "returned error %d", err); check(result == 0, "returned wrong result"); cmp(lbas, expected_lbas, lba_status_size, "incorrect lbas"); } static void test_directive_send(void) { + enum nvme_directive_send_doper doper = NVME_DIRECTIVE_SEND_STREAMS_DOPER_RELEASE_RESOURCE; + enum nvme_directive_dtype dtype = NVME_DIRECTIVE_DTYPE_STREAMS; __u8 expected_data[8], data[8]; + __u32 cdw12 = 0xffff; + __u16 dspec = 0x0; __u32 result = 0; - - struct nvme_directive_send_args args = { - .result = &result, - .data = &expected_data, - .args_size = sizeof(args), - .fd = TEST_FD, - .nsid = TEST_NSID, - .doper = NVME_DIRECTIVE_SEND_STREAMS_DOPER_RELEASE_RESOURCE, - .dtype = NVME_DIRECTIVE_DTYPE_STREAMS, - .cdw12 = 0xffff, - .data_len = sizeof(expected_data), - .dspec = 0x0, - }; + __u32 data_len = sizeof(expected_data); + int err; struct mock_cmd mock_admin_cmd = { .opcode = nvme_admin_directive_send, .nsid = TEST_NSID, - .cdw10 = args.data_len ? (args.data_len >> 2) - 1 : 0, - .cdw11 = args.doper | (args.dtype << 8) | (args.dspec << 16), - .cdw12 = args.cdw12, - .data_len = args.data_len, + .cdw10 = data_len ? (data_len >> 2) - 1 : 0, + .cdw11 = doper | (dtype << 8) | (dspec << 16), + .cdw12 = cdw12, + .data_len = data_len, .in_data = &data, }; - int err; - arbitrary(&expected_data, sizeof(expected_data)); memcpy(&data, &expected_data, sizeof(expected_data)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_directive_send(&args); + err = nvme_directive_send(test_link, TEST_NSID, doper, dtype, dspec, + cdw12, &expected_data, + data_len, &result); end_mock_cmds(); - check(err == 0, "returned error %d, errno %m", err); + check(err == 0, "returned error %d", err); check(result == 0, "returned wrong result"); cmp(&data, &expected_data, sizeof(data), "incorrect data"); } @@ -508,10 +434,10 @@ static void test_directive_send_id_endir(void) arbitrary(&expected_id, sizeof(expected_id)); memcpy(&id, &expected_id, sizeof(expected_id)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_directive_send_id_endir(TEST_FD, TEST_NSID, true, + err = nvme_directive_send_id_endir(test_link, TEST_NSID, true, NVME_DIRECTIVE_DTYPE_STREAMS, &id); end_mock_cmds(); - check(err == 0, "returned error %d, errno %m", err); + check(err == 0, "returned error %d", err); cmp(&id, &expected_id, sizeof(id), "incorrect id"); } @@ -529,10 +455,10 @@ static void test_directive_send_stream_release_identifier(void) int err; set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_directive_send_stream_release_identifier(TEST_FD, TEST_NSID, + err = nvme_directive_send_stream_release_identifier(test_link, TEST_NSID, stream_id); end_mock_cmds(); - check(err == 0, "returned error %d, errno %m", err); + check(err == 0, "returned error %d", err); } static void test_directive_send_stream_release_resource(void) @@ -547,46 +473,39 @@ static void test_directive_send_stream_release_resource(void) int err; set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_directive_send_stream_release_resource(TEST_FD, TEST_NSID); + err = nvme_directive_send_stream_release_resource(test_link, TEST_NSID); end_mock_cmds(); - check(err == 0, "returned error %d, errno %m", err); + check(err == 0, "returned error %d", err); } static void test_directive_recv(void) { + enum nvme_directive_receive_doper doper = NVME_DIRECTIVE_RECEIVE_STREAMS_DOPER_PARAM; + enum nvme_directive_dtype dtype = NVME_DIRECTIVE_DTYPE_STREAMS; __u8 expected_data[8], data[8]; + __u32 data_len = sizeof(data); + __u32 cdw12 = 0xffff; + __u16 dspec = 0x0; __u32 result = 0; - - struct nvme_directive_recv_args args = { - .result = &result, - .data = &data, - .args_size = sizeof(args), - .fd = TEST_FD, - .nsid = TEST_NSID, - .doper = NVME_DIRECTIVE_RECEIVE_STREAMS_DOPER_PARAM, - .dtype = NVME_DIRECTIVE_DTYPE_STREAMS, - .cdw12 = 0xffff, - .data_len = sizeof(data), - .dspec = 0x0, - }; + int err; struct mock_cmd mock_admin_cmd = { .opcode = nvme_admin_directive_recv, .nsid = TEST_NSID, - .cdw10 = args.data_len ? (args.data_len >> 2) - 1 : 0, - .cdw11 = args.doper | (args.dtype << 8) | (args.dspec << 16), - .cdw12 = args.cdw12, + .cdw10 = data_len ? (data_len >> 2) - 1 : 0, + .cdw11 = doper | (dtype << 8) | (dspec << 16), + .cdw12 = cdw12, .data_len = sizeof(expected_data), .out_data = &expected_data, }; - int err; - arbitrary(&expected_data, sizeof(expected_data)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_directive_recv(&args); + err = nvme_directive_recv(test_link, TEST_NSID, doper, dtype, + dspec, cdw12, &data, data_len, + &result); end_mock_cmds(); - check(err == 0, "returned error %d, errno %m", err); + check(err == 0, "returned error %d", err); check(result == 0, "returned wrong result"); cmp(&data, &expected_data, sizeof(data), "incorrect data"); } @@ -609,9 +528,9 @@ static void test_directive_recv_identify_parameters(void) arbitrary(&expected_id, sizeof(expected_id)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_directive_recv_identify_parameters(TEST_FD, TEST_NSID, &id); + err = nvme_directive_recv_identify_parameters(test_link, TEST_NSID, &id); end_mock_cmds(); - check(err == 0, "returned error %d, errno %m", err); + check(err == 0, "returned error %d", err); cmp(&id, &expected_id, sizeof(id), "incorrect id"); } @@ -633,10 +552,10 @@ static void test_directive_recv_stream_parameters(void) arbitrary(&expected_params, sizeof(expected_params)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_directive_recv_stream_parameters(TEST_FD, TEST_NSID, + err = nvme_directive_recv_stream_parameters(test_link, TEST_NSID, ¶ms); end_mock_cmds(); - check(err == 0, "returned error %d, errno %m", err); + check(err == 0, "returned error %d", err); cmp(¶ms, &expected_params, sizeof(params), "incorrect params"); } @@ -670,10 +589,10 @@ static void test_directive_recv_stream_status(void) arbitrary(expected_status, stream_status_size); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_directive_recv_stream_status(TEST_FD, TEST_NSID, nr_entries, + err = nvme_directive_recv_stream_status(test_link, TEST_NSID, nr_entries, status); end_mock_cmds(); - check(err == 0, "returned error %d, errno %m", err); + check(err == 0, "returned error %d", err); cmp(status, expected_status, stream_status_size, "incorrect status"); } @@ -694,166 +613,131 @@ static void test_directive_recv_stream_allocate(void) int err; set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_directive_recv_stream_allocate(TEST_FD, TEST_NSID, nsr, + err = nvme_directive_recv_stream_allocate(test_link, TEST_NSID, nsr, &result); end_mock_cmds(); - check(err == 0, "returned error %d, errno %m", err); + check(err == 0, "returned error %d", err); check(result == expected_result, "wrong result"); } static void test_capacity_mgmt(void) { __u32 expected_result = 0x45, result = 0; - - struct nvme_capacity_mgmt_args args = { - .result = &result, - .args_size = sizeof(args), - .fd = TEST_FD, - .cdw11 = 0x1234, - .cdw12 = 0x5678, - .element_id = 0x12, - .op = 0x3, - }; + __u16 elid = 0x12; + __u32 cdw11 = 0x1234; + __u32 cdw12 = 0x5678; + __u8 op = 0x3; + int err; struct mock_cmd mock_admin_cmd = { .opcode = nvme_admin_capacity_mgmt, .nsid = NVME_NSID_NONE, - .cdw10 = args.op | args.element_id << 16, - .cdw11 = args.cdw11, - .cdw12 = args.cdw12, + .cdw10 = op | elid << 16, + .cdw11 = cdw11, + .cdw12 = cdw12, .result = expected_result, }; - int err; - set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_capacity_mgmt(&args); + err = nvme_capacity_mgmt(test_link, op, elid, cdw11, cdw12, &result); end_mock_cmds(); - check(err == 0, "returned error %d, errno %m", err); + check(err == 0, "returned error %d", err); check(result == expected_result, "wrong result"); } static void test_lockdown(void) { __u32 expected_result = 0x45, result = 0; - - struct nvme_lockdown_args args = { - .result = &result, - .args_size = sizeof(args), - .fd = TEST_FD, - .scp = 0x2, - .prhbt = !!true, - .ifc = 0x1, - .ofi = 0x12, - .uuidx = 0x34, - }; + __u8 prhbt = !!true; + __u8 uuidx = 0x34; + __u8 ofi = 0x12; + __u8 scp = 0x2; + __u8 ifc = 0x1; + int err; struct mock_cmd mock_admin_cmd = { .opcode = nvme_admin_lockdown, - .cdw10 = args.ofi << 8 | (args.ifc & 0x3) << 5 | - (args.prhbt & 0x1) << 4 | (args.scp & 0xF), - .cdw14 = args.uuidx & 0x3F, + .cdw10 = ofi << 8 | (ifc & 0x3) << 5 | (prhbt & 0x1) << 4 | (scp & 0xF), + .cdw14 = (__u32)(uuidx & 0x3F), .result = expected_result, }; - int err; - set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_lockdown(&args); + err = nvme_lockdown(test_link, scp, prhbt, ifc, ofi, uuidx, &result); end_mock_cmds(); - check(err == 0, "returned error %d, errno %m", err); + check(err == 0, "returned error %d", err); check(result == expected_result, "wrong result"); } static void test_sanitize_nvm(void) { + enum nvme_sanitize_sanact sanact = NVME_SANITIZE_SANACT_START_CRYPTO_ERASE; __u32 expected_result = 0x45, result = 0; - - struct nvme_sanitize_nvm_args args = { - .result = &result, - .args_size = sizeof(args), - .fd = TEST_FD, - .sanact = NVME_SANITIZE_SANACT_START_CRYPTO_ERASE, - .ovrpat = 0x101010, - .ause = true, - .owpass = 0x2, - .oipbp = false, - .nodas = true, - .emvs = false, - }; + __u32 ovrpat = 0x101010; + bool oipbp = false; + __u8 owpass = 0x2; + bool nodas = true; + bool emvs = false; + bool ause = true; + int err; struct mock_cmd mock_admin_cmd = { .opcode = nvme_admin_sanitize_nvm, - .cdw10 = args.sanact | (!!args.ause << 3) | (args.owpass << 4) | - (!!args.oipbp << 8) | (!!args.nodas << 9), - .cdw11 = args.ovrpat, + .cdw10 = sanact | (ause << 3) | (owpass << 4) | (oipbp << 8) | (nodas << 9), + .cdw11 = ovrpat, .result = expected_result, }; - int err; - set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_sanitize_nvm(&args); + err = nvme_sanitize_nvm(test_link, sanact, ause, + owpass, oipbp, nodas, emvs, + ovrpat, &result); end_mock_cmds(); - check(err == 0, "returned error %d, errno %m", err); + check(err == 0, "returned error %d", err); check(result == expected_result, "wrong result"); } static void test_dev_self_test(void) { + enum nvme_dst_stc stc = NVME_DST_STC_ABORT; __u32 expected_result = 0x45, result = 0; - - struct nvme_dev_self_test_args args = { - .result = &result, - .args_size = sizeof(args), - .fd = TEST_FD, - .nsid = TEST_NSID, - .stc = NVME_DST_STC_ABORT, - }; + __u32 nsid = TEST_NSID; + int err; struct mock_cmd mock_admin_cmd = { .opcode = nvme_admin_dev_self_test, - .nsid = args.nsid, - .cdw10 = args.stc, + .nsid = nsid, + .cdw10 = stc, .result = expected_result, }; - int err; - set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_dev_self_test(&args); + err = nvme_dev_self_test(test_link, nsid, stc, &result); end_mock_cmds(); - check(err == 0, "returned error %d, errno %m", err); + check(err == 0, "returned error %d", err); check(result == expected_result, "wrong result"); } static void test_virtual_mgmt(void) { + enum nvme_virt_mgmt_act act = NVME_VIRT_MGMT_ACT_ASSIGN_SEC_CTRL; + enum nvme_virt_mgmt_rt rt = NVME_VIRT_MGMT_RT_VI_RESOURCE; __u32 expected_result = 0x45, result = 0; - - struct nvme_virtual_mgmt_args args = { - .result = &result, - .args_size = sizeof(args), - .fd = TEST_FD, - .act = NVME_VIRT_MGMT_ACT_ASSIGN_SEC_CTRL, - .rt = NVME_VIRT_MGMT_RT_VI_RESOURCE, - .cntlid = 0x0, - .nr = 0xff, - }; + __u16 cntlid = 0x0; + __u16 nr = 0xff; + int err; struct mock_cmd mock_admin_cmd = { .opcode = nvme_admin_virtual_mgmt, - .cdw10 = args.act | (args.rt << 8) | (args.cntlid << 16), - .cdw11 = args.nr, + .cdw10 = act | (rt << 8) | (cntlid << 16), + .cdw11 = nr, .result = expected_result, }; - int err; - set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_virtual_mgmt(&args); + err = nvme_virtual_mgmt(test_link, act, rt, cntlid, nr, &result); end_mock_cmds(); - check(err == 0, "returned error %d, errno %m", err); + check(err == 0, "returned error %d", err); check(result == expected_result, "wrong result"); } @@ -867,42 +751,31 @@ static void test_flush(void) int err; set_mock_io_cmds(&mock_io_cmd, 1); - err = nvme_flush(TEST_FD, TEST_NSID); + err = nvme_flush(test_link, TEST_NSID); end_mock_cmds(); - check(err == 0, "returned error %d, errno %m", err); + check(err == 0, "returned error %d", err); } static void test_read(void) { __u8 expected_data[512], data[512] = {}; __u32 result = 0; - - struct nvme_io_args args = { - .slba = 0xffffffffff, - .storage_tag = 0xef, - .result = &result, - .data = &data, - .args_size = sizeof(args), - .fd = TEST_FD, - .nsid = TEST_NSID, - .reftag = 0xab, - .data_len = sizeof(data), - .nlb = 0x3, - .control = NVME_IO_FUA, - .apptag = 0x12, - .appmask = 0x34, - .dspec = 0x0, - .dsm = NVME_IO_DSM_LATENCY_LOW, - }; + __u64 slba = 0xffffffffff; + __u16 nlb = 0x3; + __u16 control = NVME_IO_FUA; + __u8 dsm = NVME_IO_DSM_LATENCY_LOW; + __u16 dspec = 0x0; + __u16 apptag = 0x12; + __u16 appmask = 0x34; struct mock_cmd mock_io_cmd = { .opcode = nvme_cmd_read, .nsid = TEST_NSID, - .cdw10 = args.slba & 0xffffffff, - .cdw11 = args.slba >> 32, - .cdw12 = args.nlb | (args.control << 16), - .cdw13 = args.dsm | (args.dspec << 16), - .cdw15 = args.apptag | (args.appmask << 16), + .cdw10 = slba & 0xffffffff, + .cdw11 = slba >> 32, + .cdw12 = nlb | (control << 16), + .cdw13 = dsm | (dspec << 16), + .cdw15 = apptag | (appmask << 16), .data_len = sizeof(expected_data), .out_data = &expected_data, }; @@ -911,9 +784,10 @@ static void test_read(void) arbitrary(&expected_data, sizeof(expected_data)); set_mock_io_cmds(&mock_io_cmd, 1); - err = nvme_read(&args); + err = nvme_read(test_link, TEST_NSID, slba, 0xef, 0xab, nlb, control, apptag, appmask, + dspec, dsm, 0, 0, 0, &data, sizeof(data), NULL, 0, &result); end_mock_cmds(); - check(err == 0, "returned error %d, errno %m", err); + check(err == 0, "returned error %d", err); check(result == 0, "returned result %u", result); } @@ -921,33 +795,22 @@ static void test_write(void) { __u8 expected_data[512], data[512] = {}; __u32 result = 0; - - struct nvme_io_args args = { - .slba = 0xfffffffabcde, - .storage_tag = 0xab, - .result = &result, - .data = &expected_data, - .args_size = sizeof(args), - .fd = TEST_FD, - .nsid = TEST_NSID, - .reftag = 0xef, - .data_len = sizeof(expected_data), - .nlb = 0x5, - .control = NVME_IO_FUA, - .apptag = 0x59, - .appmask = 0x94, - .dspec = 0xa, - .dsm = NVME_IO_DSM_COMPRESSED, - }; + __u64 slba = 0xfffffffabcde; + __u16 nlb = 0x5; + __u16 control = NVME_IO_FUA; + __u8 dsm = NVME_IO_DSM_COMPRESSED; + __u16 dspec = 0xa; + __u16 apptag = 0x59; + __u16 appmask = 0x94; struct mock_cmd mock_io_cmd = { .opcode = nvme_cmd_write, .nsid = TEST_NSID, - .cdw10 = args.slba & 0xffffffff, - .cdw11 = args.slba >> 32, - .cdw12 = args.nlb | (args.control << 16), - .cdw13 = args.dsm | (args.dspec << 16), - .cdw15 = args.apptag | (args.appmask << 16), + .cdw10 = slba & 0xffffffff, + .cdw11 = slba >> 32, + .cdw12 = nlb | (control << 16), + .cdw13 = dsm | (dspec << 16), + .cdw15 = apptag | (appmask << 16), .data_len = sizeof(data), .in_data = &data, }; @@ -957,9 +820,11 @@ static void test_write(void) arbitrary(&expected_data, sizeof(expected_data)); memcpy(&data, &expected_data, sizeof(expected_data)); set_mock_io_cmds(&mock_io_cmd, 1); - err = nvme_write(&args); + err = nvme_write(test_link, TEST_NSID, slba, 0xab, 0xef, nlb, control, apptag, appmask, + dspec, dsm, 0, 0, 0, &expected_data, sizeof(expected_data), NULL, 0, + &result); end_mock_cmds(); - check(err == 0, "returned error %d, errno %m", err); + check(err == 0, "returned error %d", err); check(result == 0, "returned result %u", result); } @@ -967,33 +832,22 @@ static void test_compare(void) { __u8 expected_data[512], data[512] = {}; __u32 result = 0; - - struct nvme_io_args args = { - .slba = 0xabcde, - .storage_tag = 0xab, - .result = &result, - .data = &expected_data, - .args_size = sizeof(args), - .fd = TEST_FD, - .nsid = TEST_NSID, - .reftag = 0xff, - .data_len = sizeof(expected_data), - .nlb = 0x0, - .control = NVME_IO_LR, - .apptag = 0x59, - .appmask = 0x94, - .dspec = 0xa, - .dsm = NVME_IO_DSM_COMPRESSED, - }; + __u64 slba = 0xabcde; + __u16 nlb = 0x0; + __u16 control = NVME_IO_LR; + __u8 dsm = NVME_IO_DSM_COMPRESSED; + __u16 dspec = 0xa; + __u16 apptag = 0x59; + __u16 appmask = 0x94; struct mock_cmd mock_io_cmd = { .opcode = nvme_cmd_compare, .nsid = TEST_NSID, - .cdw10 = args.slba & 0xffffffff, - .cdw11 = args.slba >> 32, - .cdw12 = args.nlb | (args.control << 16), - .cdw13 = args.dsm | (args.dspec << 16), - .cdw15 = args.apptag | (args.appmask << 16), + .cdw10 = slba & 0xffffffff, + .cdw11 = slba >> 32, + .cdw12 = nlb | (control << 16), + .cdw13 = dsm | (dspec << 16), + .cdw15 = apptag | (appmask << 16), .data_len = sizeof(data), .in_data = &data, }; @@ -1003,9 +857,11 @@ static void test_compare(void) arbitrary(&expected_data, sizeof(expected_data)); memcpy(&data, &expected_data, sizeof(expected_data)); set_mock_io_cmds(&mock_io_cmd, 1); - err = nvme_compare(&args); + err = nvme_compare(test_link, TEST_NSID, slba, 0xab, 0xff, nlb, control, apptag, appmask, + dspec, dsm, 0, 0, 0, &expected_data, sizeof(expected_data), NULL, 0, + &result); end_mock_cmds(); - check(err == 0, "returned error %d, errno %m", err); + check(err == 0, "returned error %d", err); check(result == 0, "returned result %u", result); } @@ -1013,33 +869,22 @@ static void test_write_zeros(void) { __u8 expected_data[512], data[512] = {}; __u32 result = 0; - - struct nvme_io_args args = { - .slba = 0x0, - .storage_tag = 0xab, - .result = &result, - .data = &expected_data, - .args_size = sizeof(args), - .fd = TEST_FD, - .nsid = TEST_NSID, - .reftag = 0xff, - .data_len = sizeof(expected_data), - .nlb = 0xffff, - .control = NVME_IO_LR, - .apptag = 0xfa, - .appmask = 0x72, - .dspec = 0xbb, - .dsm = NVME_IO_DSM_FREQ_ONCE, - }; + __u64 slba = 0x0; + __u16 nlb = 0xffff; + __u16 control = NVME_IO_LR; + __u8 dsm = NVME_IO_DSM_FREQ_ONCE; + __u16 dspec = 0xbb; + __u16 apptag = 0xfa; + __u16 appmask = 0x72; struct mock_cmd mock_io_cmd = { .opcode = nvme_cmd_write_zeroes, .nsid = TEST_NSID, - .cdw10 = args.slba & 0xffffffff, - .cdw11 = args.slba >> 32, - .cdw12 = args.nlb | (args.control << 16), - .cdw13 = args.dsm | (args.dspec << 16), - .cdw15 = args.apptag | (args.appmask << 16), + .cdw10 = slba & 0xffffffff, + .cdw11 = slba >> 32, + .cdw12 = nlb | (control << 16), + .cdw13 = dsm | (dspec << 16), + .cdw15 = apptag | (appmask << 16), .data_len = sizeof(data), .in_data = &data, }; @@ -1049,9 +894,11 @@ static void test_write_zeros(void) arbitrary(&expected_data, sizeof(expected_data)); memcpy(&data, &expected_data, sizeof(expected_data)); set_mock_io_cmds(&mock_io_cmd, 1); - err = nvme_write_zeros(&args); + err = nvme_write_zeros(test_link, TEST_NSID, slba, 0xab, 0xff, nlb, control, apptag, + appmask, dspec, dsm, 0, 0, 0, &expected_data, sizeof(expected_data), + NULL, 0, &result); end_mock_cmds(); - check(err == 0, "returned error %d, errno %m", err); + check(err == 0, "returned error %d", err); check(result == 0, "returned result %u", result); } @@ -1059,33 +906,22 @@ static void test_write_uncorrectable(void) { __u8 expected_data[512], data[512] = {}; __u32 result = 0; - - struct nvme_io_args args = { - .slba = 0x0, - .storage_tag = 0x0, - .result = &result, - .data = &expected_data, - .args_size = sizeof(args), - .fd = TEST_FD, - .nsid = TEST_NSID, - .reftag = 0x0, - .data_len = sizeof(expected_data), - .nlb = 0x0, - .control = 0x0, - .apptag = 0x0, - .appmask = 0x0, - .dspec = 0x0, - .dsm = 0x0, - }; + __u64 slba = 0x0; + __u16 nlb = 0x0; + __u16 control = 0x0; + __u8 dsm = 0x0; + __u16 dspec = 0x0; + __u16 apptag = 0x0; + __u16 appmask = 0x0; struct mock_cmd mock_io_cmd = { .opcode = nvme_cmd_write_uncor, .nsid = TEST_NSID, - .cdw10 = args.slba & 0xffffffff, - .cdw11 = args.slba >> 32, - .cdw12 = args.nlb | (args.control << 16), - .cdw13 = args.dsm | (args.dspec << 16), - .cdw15 = args.apptag | (args.appmask << 16), + .cdw10 = slba & 0xffffffff, + .cdw11 = slba >> 32, + .cdw12 = nlb | (control << 16), + .cdw13 = dsm | (dspec << 16), + .cdw15 = apptag | (appmask << 16), .data_len = sizeof(data), .in_data = &data, }; @@ -1095,9 +931,11 @@ static void test_write_uncorrectable(void) arbitrary(&expected_data, sizeof(expected_data)); memcpy(&data, &expected_data, sizeof(expected_data)); set_mock_io_cmds(&mock_io_cmd, 1); - err = nvme_write_uncorrectable(&args); + err = nvme_write_uncorrectable(test_link, TEST_NSID, slba, 0x0, 0x0, nlb, control, apptag, + appmask, dspec, dsm, 0, 0, 0, &expected_data, + sizeof(expected_data), NULL, 0, &result); end_mock_cmds(); - check(err == 0, "returned error %d, errno %m", err); + check(err == 0, "returned error %d", err); check(result == 0, "returned result %u", result); } @@ -1105,33 +943,22 @@ static void test_verify(void) { __u8 expected_data[512], data[512] = {}; __u32 result = 0; - - struct nvme_io_args args = { - .slba = 0xffffffffffffffff, - .storage_tag = 0xffffffffffffffff, - .result = &result, - .data = &expected_data, - .args_size = sizeof(args), - .fd = TEST_FD, - .nsid = TEST_NSID, - .reftag = 0xffffffff, - .data_len = sizeof(expected_data), - .nlb = 0xffff, - .control = 0xffff, - .apptag = 0xffff, - .appmask = 0xffff, - .dspec = 0xffff, - .dsm = 0xff, - }; + __u64 slba = 0xffffffffffffffff; + __u16 nlb = 0xffff; + __u16 control = 0xfd0f; + __u8 dsm = 0xff; + __u16 dspec = 0xffff; + __u16 apptag = 0xffff; + __u16 appmask = 0xffff; struct mock_cmd mock_io_cmd = { .opcode = nvme_cmd_verify, .nsid = TEST_NSID, - .cdw10 = args.slba & 0xffffffff, - .cdw11 = args.slba >> 32, - .cdw12 = args.nlb | (args.control << 16), - .cdw13 = args.dsm | (args.dspec << 16), - .cdw15 = args.apptag | (args.appmask << 16), + .cdw10 = slba & 0xffffffff, + .cdw11 = slba >> 32, + .cdw12 = nlb | (control << 16), + .cdw13 = dsm | (dspec << 16), + .cdw15 = apptag | (appmask << 16), .data_len = sizeof(data), .in_data = &data, }; @@ -1141,9 +968,11 @@ static void test_verify(void) arbitrary(&expected_data, sizeof(expected_data)); memcpy(&data, &expected_data, sizeof(expected_data)); set_mock_io_cmds(&mock_io_cmd, 1); - err = nvme_verify(&args); + err = nvme_verify(test_link, TEST_NSID, slba, 0xffffffffffffffff, 0xffffffff, nlb, control, + apptag, appmask, dspec, dsm, 0, 0, 0, &expected_data, + sizeof(expected_data), NULL, 0, &result); end_mock_cmds(); - check(err == 0, "returned error %d, errno %m", err); + check(err == 0, "returned error %d", err); check(result == 0, "returned result %u", result); } @@ -1158,219 +987,163 @@ static void test_dsm(void) dsm = malloc(dsm_size); check(dsm, "dsm: ENOMEM"); - struct nvme_dsm_args args = { - .result = &result, - .dsm = dsm, - .args_size = sizeof(args), - .fd = TEST_FD, - .nsid = TEST_NSID, - .attrs = NVME_DSMGMT_AD, - .nr_ranges = nr_ranges, - }; - struct mock_cmd mock_io_cmd = { .opcode = nvme_cmd_dsm, .nsid = TEST_NSID, - .cdw10 = args.nr_ranges - 1, - .cdw11 = args.attrs, + .cdw10 = nr_ranges - 1, + .cdw11 = NVME_DSMGMT_AD, .data_len = dsm_size, - .in_data = args.dsm, + .in_data = dsm, }; int err; arbitrary(dsm, dsm_size); set_mock_io_cmds(&mock_io_cmd, 1); - err = nvme_dsm(&args); + err = nvme_dsm(test_link, TEST_NSID, nr_ranges, NVME_DSMGMT_AD, dsm, &result); end_mock_cmds(); - check(err == 0, "returned error %d, errno %m", err); + check(err == 0, "returned error %d", err); check(result == 0, "returned result %u", result); } static void test_copy(void) { - __u32 result = 0; - __u16 nr = 0x12; - int copy_size = sizeof(struct nvme_copy_range) * nr; + __u16 nr = 0x12, cev = 0, dspec = 0, lbat = 0, lbatm = 0; + int copy_size = sizeof(struct nvme_copy_range) * nr, err; + bool prinfor = false, prinfow = false, stcw = false, + stcr = false, fua = false, lr = false; + __u8 cetype = 0, dtype = 0, desfmt = 0xf, sts = 0, pif = 0; + __u64 sdlba = 0xfffff, storage_tag = 0; + __u32 reftag = 0, result = 0; _cleanup_free_ struct nvme_copy_range *copy = NULL; copy = malloc(copy_size); check(copy, "copy: ENOMEM"); - struct nvme_copy_args args = { - .sdlba = 0xfffff, - .result = &result, - .copy = copy, - .args_size = sizeof(args), - .fd = TEST_FD, - .nsid = TEST_NSID, - .nr = nr, - .format = 0xf, - }; - struct mock_cmd mock_io_cmd = { .opcode = nvme_cmd_copy, .nsid = TEST_NSID, - .cdw10 = args.sdlba & 0xffffffff, - .cdw11 = args.sdlba >> 32, - .cdw12 = ((args.nr - 1) & 0xff) | ((args.format & 0xf) << 8) | - ((args.prinfor & 0xf) << 12) | - ((args.dtype & 0xf) << 20) | - ((args.prinfow & 0xf) << 26) | - ((args.fua & 0x1) << 30) | ((args.lr & 0x1) << 31), - .data_len = args.nr * sizeof(struct nvme_copy_range), - .in_data = args.copy, + .cdw10 = sdlba & 0xffffffff, + .cdw11 = sdlba >> 32, + .cdw12 = ((nr - 1) & 0xff) | ((desfmt & 0xf) << 8) | + ((prinfor & 0xf) << 12) | + ((dtype & 0xf) << 20) | + ((prinfow & 0xf) << 26) | + ((fua & 0x1) << 30) | ((lr & 0x1) << 31), + .data_len = nr * sizeof(struct nvme_copy_range), + .in_data = copy, }; - int err; - set_mock_io_cmds(&mock_io_cmd, 1); - err = nvme_copy(&args); + err = nvme_copy(test_link, TEST_NSID, sdlba, nr, desfmt, + prinfor, prinfow, cetype, dtype, stcw, stcr, + fua, lr, cev, dspec, + sts, pif, storage_tag, reftag, lbat, lbatm, + (void *)copy, &result); end_mock_cmds(); - check(err == 0, "returned error %d, errno %m", err); + check(err == 0, "returned error %d", err); check(result == 0, "returned result %u", result); } static void test_resv_acquire(void) { - __u32 result = 0; - - struct nvme_resv_acquire_args args = { - .crkey = 0, - .nrkey = 0, - .result = &result, - .args_size = sizeof(args), - .fd = TEST_FD, - .nsid = TEST_NSID, - .rtype = NVME_RESERVATION_RTYPE_EAAR, - .racqa = NVME_RESERVATION_RACQA_PREEMPT, - .iekey = true, - }; - + enum nvme_resv_rtype rtype = NVME_RESERVATION_RTYPE_EAAR; + enum nvme_resv_racqa racqa = NVME_RESERVATION_RACQA_PREEMPT; __le64 payload[2] = { 0 }; + bool iekey = true; + __u32 result = 0; + int err; struct mock_cmd mock_io_cmd = { .opcode = nvme_cmd_resv_acquire, .nsid = TEST_NSID, - .cdw10 = (args.racqa & 0x7) | (args.iekey ? 1 << 3 : 0) | - (args.rtype << 8), + .cdw10 = (racqa & 0x7) | (iekey ? 1 << 3 : 0) | (rtype << 8), .data_len = sizeof(payload), .in_data = payload, }; - int err; - set_mock_io_cmds(&mock_io_cmd, 1); - err = nvme_resv_acquire(&args); + err = nvme_resv_acquire(test_link, TEST_NSID, racqa, iekey, + false, rtype, 0, 0, 0, &result); end_mock_cmds(); - check(err == 0, "returned error %d, errno %m", err); + check(err == 0, "returned error %d", err); check(result == 0, "returned result %u", result); } static void test_resv_register(void) { - __u32 result = 0; - - struct nvme_resv_register_args args = { - .crkey = 0xffffffffffffffff, - .nrkey = 0, - .result = &result, - .args_size = sizeof(args), - .fd = TEST_FD, - .nsid = TEST_NSID, - .rrega = NVME_RESERVATION_RREGA_UNREGISTER_KEY, - .cptpl = NVME_RESERVATION_CPTPL_PERSIST, - .iekey = true, - }; - + enum nvme_resv_rrega rrega = NVME_RESERVATION_RREGA_UNREGISTER_KEY; + enum nvme_resv_cptpl cptpl = NVME_RESERVATION_CPTPL_PERSIST; __le64 payload[2] = { 0xffffffffffffffff, 0 }; + bool iekey = true; + __u32 result = 0; + int err; struct mock_cmd mock_io_cmd = { .opcode = nvme_cmd_resv_register, .nsid = TEST_NSID, - .cdw10 = (args.rrega & 0x7) | (args.iekey ? 1 << 3 : 0) | - (args.cptpl << 30), + .cdw10 = (rrega & 0x7) | (iekey ? 1 << 3 : 0) | (cptpl << 30), .data_len = sizeof(payload), .in_data = payload, }; - int err; - set_mock_io_cmds(&mock_io_cmd, 1); - err = nvme_resv_register(&args); + err = nvme_resv_register(test_link, TEST_NSID, rrega, iekey, false, cptpl, + 0xffffffffffffffff, 0, &result); end_mock_cmds(); - check(err == 0, "returned error %d, errno %m", err); + check(err == 0, "returned error %d", err); check(result == 0, "returned result %u", result); } static void test_resv_release(void) { - __u32 result = 0; - - struct nvme_resv_release_args args = { - .crkey = 0xffffffffffffffff, - .result = &result, - .args_size = sizeof(args), - .fd = TEST_FD, - .nsid = TEST_NSID, - .rtype = NVME_RESERVATION_RTYPE_WE, - .rrela = NVME_RESERVATION_RRELA_RELEASE, - .iekey = true, - }; - + enum nvme_resv_rtype rtype = NVME_RESERVATION_RTYPE_WE; + enum nvme_resv_rrela rrela = NVME_RESERVATION_RRELA_RELEASE; __le64 payload[1] = { 0xffffffffffffffff }; + bool iekey = true; + __u32 result = 0; + int err; struct mock_cmd mock_io_cmd = { .opcode = nvme_cmd_resv_release, .nsid = TEST_NSID, - .cdw10 = (args.rrela & 0x7) | (args.iekey ? 1 << 3 : 0) | - (args.rtype << 8), + .cdw10 = (rrela & 0x7) | (iekey ? 1 << 3 : 0) | (rtype << 8), .data_len = sizeof(payload), .in_data = payload, }; - int err; set_mock_io_cmds(&mock_io_cmd, 1); - err = nvme_resv_release(&args); + err = nvme_resv_release(test_link, TEST_NSID, rrela, 0xffffffffffffffff, + iekey, false, rtype, &result); end_mock_cmds(); - check(err == 0, "returned error %d, errno %m", err); + check(err == 0, "returned error %d", err); check(result == 0, "returned result %u", result); } static void test_resv_report(void) { - __u32 result = 0; - struct nvme_resv_status expected_status, status = {}; - - struct nvme_resv_report_args args = { - .result = &result, - .report = &status, - .args_size = sizeof(args), - .fd = TEST_FD, - .nsid = TEST_NSID, - .len = sizeof(status), - .eds = false, - }; + __u32 len = sizeof(status); + __u32 result = 0; + bool eds = false; + int err; struct mock_cmd mock_io_cmd = { .opcode = nvme_cmd_resv_report, .nsid = TEST_NSID, - .cdw10 = (args.len >> 2) - 1, - .cdw11 = args.eds ? 1 : 0, - .data_len = args.len, + .cdw10 = (len >> 2) - 1, + .cdw11 = eds ? 1 : 0, + .data_len = len, .out_data = &expected_status, }; - int err; - arbitrary(&expected_status, sizeof(expected_status)); set_mock_io_cmds(&mock_io_cmd, 1); - err = nvme_resv_report(&args); + err = nvme_resv_report(test_link, TEST_NSID, eds, &status, len, &result); end_mock_cmds(); - check(err == 0, "returned error %d, errno %m", err); + check(err == 0, "returned error %d", err); check(result == 0, "returned result %u", result); cmp(&status, &expected_status, sizeof(status), "incorrect status"); } @@ -1378,64 +1151,51 @@ static void test_resv_report(void) static void test_io_mgmt_recv(void) { __u8 expected_data[8], data[8] = {}; - struct nvme_io_mgmt_recv_args args = { - .data = &data, - .args_size = sizeof(args), - .fd = TEST_FD, - .nsid = TEST_NSID, - .data_len = sizeof(data), - .mos = 0x1, - .mo = 0x2, - }; + __u32 data_len = sizeof(data); + __u16 mos = 0x1; + __u8 mo = 0x2; + int err; struct mock_cmd mock_io_cmd = { .opcode = nvme_cmd_io_mgmt_recv, .nsid = TEST_NSID, - .cdw10 = args.mo | (args.mos << 16), - .cdw11 = (args.data_len >> 2) - 1, - .data_len = args.data_len, + .cdw10 = mo | (mos << 16), + .cdw11 = (data_len >> 2) - 1, + .data_len = data_len, .out_data = &expected_data, }; - int err; - arbitrary(&expected_data, sizeof(expected_data)); set_mock_io_cmds(&mock_io_cmd, 1); - err = nvme_io_mgmt_recv(&args); + err = nvme_io_mgmt_recv(test_link, TEST_NSID, mo, mos, &data, data_len); end_mock_cmds(); - check(err == 0, "returned error %d, errno %m", err); + check(err == 0, "returned error %d", err); cmp(&data, &expected_data, sizeof(data), "incorrect data"); } static void test_io_mgmt_send(void) { __u8 expected_data[8], data[8] = {}; - struct nvme_io_mgmt_send_args args = { - .data = &expected_data, - .args_size = sizeof(args), - .fd = TEST_FD, - .nsid = TEST_NSID, - .data_len = sizeof(expected_data), - .mos = 0x1, - .mo = 0x2, - }; + __u32 data_len = sizeof(expected_data); + __u16 mos = 0x1; + __u8 mo = 0x2; + int err; struct mock_cmd mock_io_cmd = { .opcode = nvme_cmd_io_mgmt_send, .nsid = TEST_NSID, - .cdw10 = args.mo | (args.mos << 16), - .data_len = args.data_len, + .cdw10 = mo | (mos << 16), + .data_len = data_len, .in_data = &data, }; - int err; - arbitrary(&expected_data, sizeof(expected_data)); memcpy(&data, &expected_data, sizeof(expected_data)); set_mock_io_cmds(&mock_io_cmd, 1); - err = nvme_io_mgmt_send(&args); + err = nvme_io_mgmt_send(test_link, TEST_NSID, mo, mos, + &expected_data, data_len); end_mock_cmds(); - check(err == 0, "returned error %d, errno %m", err); + check(err == 0, "returned error %d", err); cmp(&data, &expected_data, sizeof(data), "incorrect data"); } @@ -1456,10 +1216,10 @@ static void test_fdp_reclaim_unit_handle_status(void) arbitrary(&expected_data, sizeof(expected_data)); set_mock_io_cmds(&mock_io_cmd, 1); - err = nvme_fdp_reclaim_unit_handle_status(TEST_FD, TEST_NSID, data_len, + err = nvme_fdp_reclaim_unit_handle_status(test_link, TEST_NSID, data_len, &data); end_mock_cmds(); - check(err == 0, "returned error %d, errno %m", err); + check(err == 0, "returned error %d", err); cmp(&data, &expected_data, sizeof(data), "incorrect data"); } @@ -1479,40 +1239,33 @@ static void test_fdp_reclaim_unit_handle_update(void) arbitrary(&pids, sizeof(pids)); set_mock_io_cmds(&mock_io_cmd, 1); - err = nvme_fdp_reclaim_unit_handle_update(TEST_FD, TEST_NSID, npids, + err = nvme_fdp_reclaim_unit_handle_update(test_link, TEST_NSID, npids, &pids); end_mock_cmds(); - check(err == 0, "returned error %d, errno %m", err); + check(err == 0, "returned error %d", err); } static void test_dim_send(void) { - __u32 result = 0; __u8 expected_data[8], data[8] = {}; - struct nvme_dim_args args = { - .result = 0, - .data = &data, - .args_size = sizeof(args), - .fd = TEST_FD, - .data_len = sizeof(data), - .tas = 0xf, - }; + __u32 data_len = sizeof(data); + __u32 result = 0; + __u8 tas = 0xf; + int err; struct mock_cmd mock_admin_cmd = { .opcode = nvme_admin_discovery_info_mgmt, - .cdw10 = args.tas, - .data_len = args.data_len, + .cdw10 = tas, + .data_len = data_len, .in_data = &expected_data, }; - int err; - arbitrary(&expected_data, sizeof(expected_data)); memcpy(&data, &expected_data, sizeof(expected_data)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_dim_send(&args); + err = nvme_dim_send(test_link, tas, &data, data_len, NULL); end_mock_cmds(); - check(err == 0, "returned error %d, errno %m", err); + check(err == 0, "returned error %d", err); check(result == 0, "returned result %u", result); cmp(&data, &expected_data, sizeof(data), "incorrect data"); } @@ -1521,23 +1274,16 @@ static void test_lm_cdq(void) { __u32 result = 0; __u8 expected_data[8], data[8] = {}; - struct nvme_lm_cdq_args args = { - .result = 0, - .data = &data, - .args_size = sizeof(args), - .fd = TEST_FD, - .mos = 0x1, - .cntlid = 0x2, - .cdqid = 0x3, - .sel = NVME_LM_SEL_DELETE_CDQ, - .sz = 0x4, - }; + __u16 mos = 0x1; + __u16 cdqid = 0x3; + __u8 sel = NVME_LM_SEL_DELETE_CDQ; + __u32 sz = 0x4; struct mock_cmd mock_admin_cmd = { .opcode = nvme_admin_ctrl_data_queue, - .cdw10 = args.sel | (args.mos << 16), - .cdw11 = args.cdqid, - .cdw12 = args.sz, + .cdw10 = sel | (mos << 16), + .cdw11 = cdqid, + .cdw12 = sz, .data_len = 0, .in_data = &expected_data, }; @@ -1547,125 +1293,108 @@ static void test_lm_cdq(void) arbitrary(&expected_data, sizeof(expected_data)); memcpy(&data, &expected_data, sizeof(expected_data)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_lm_cdq(&args); + err = nvme_lm_cdq(test_link, sel, mos, 0x2, sz, &data, &cdqid, NULL); end_mock_cmds(); - check(err == 0, "returned error %d, errno %m", err); + check(err == 0, "returned error %d", err); check(result == 0, "returned result %u", result); cmp(&data, &expected_data, sizeof(data), "incorrect data"); } static void test_lm_track_send(void) { + __u8 sel = NVME_LM_SEL_DELETE_CDQ; + __u16 cdqid = 0x3; __u32 result = 0; - struct nvme_lm_track_send_args args = { - .result = 0, - .args_size = sizeof(args), - .fd = TEST_FD, - .mos = 0x1, - .cdqid = 0x3, - .sel = NVME_LM_SEL_DELETE_CDQ, - }; + __u16 mos = 0x1; + int err; struct mock_cmd mock_admin_cmd = { .opcode = nvme_admin_track_send, - .cdw10 = args.sel | (args.mos << 16), - .cdw11 = args.cdqid, + .cdw10 = sel | (mos << 16), + .cdw11 = cdqid, }; - int err; - set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_lm_track_send(&args); + err = nvme_lm_track_send(test_link, sel, mos, cdqid, NULL); end_mock_cmds(); - check(err == 0, "returned error %d, errno %m", err); + check(err == 0, "returned error %d", err); check(result == 0, "returned result %u", result); } static void test_lm_migration_send(void) { - __u32 result = 0; __u32 expected_data[8], data[8] = {}; - struct nvme_lm_migration_send_args args = { - .offset = 0xffffffffff, - .result = 0, - .data = &expected_data, - .args_size = sizeof(args), - .fd = TEST_FD, - .numd = 8 - 1, - .mos = 0x1, - .cntlid = 0x2, - .csuuidi = 0x3, - .sel = NVME_LM_SEL_RESUME, - .uidx = 0x4, - .stype = 0x5, - .seqind = 0x6, - .csvi = 0x7, - .dudmq = true, - }; + __u8 sel = NVME_LM_SEL_RESUME; + __u64 offset = 0xffffffffff; + __u32 numd = 8; + __u16 cntlid = 0x2; + __u32 result = 0; + __u16 mos = 0x1; + __u8 uidx = 0x4; + __u8 stype = 0x1; + __u8 csvi = 0x2; + __u16 csuuidi = 0x13; + bool dudmq = false; + int err; struct mock_cmd mock_admin_cmd = { .opcode = nvme_admin_migration_send, - .cdw10 = args.sel | (args.mos << 16), - .cdw11 = args.cntlid, - .cdw12 = (__u32)args.offset, - .cdw13 = (__u32)(args.offset >> 32), - .cdw14 = args.uidx, - .cdw15 = args.numd, - .data_len = args.numd << 2, + .cdw10 = sel | (mos << 16), + .cdw11 = cntlid, + .cdw12 = (__u32)offset, + .cdw13 = (__u32)(offset >> 32), + .cdw14 = uidx, + .cdw15 = numd, + .data_len = numd << 2, .in_data = &data, }; - int err; - arbitrary(&expected_data, sizeof(expected_data)); memcpy(&data, &expected_data, sizeof(expected_data)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_lm_migration_send(&args); + err = nvme_lm_migration_send(test_link, sel, mos, + cntlid, stype, dudmq, csvi, csuuidi, + offset, uidx, &expected_data, + sizeof(expected_data), NULL); end_mock_cmds(); - check(err == 0, "returned error %d, errno %m", err); + check(err == 0, "returned error %d", err); check(result == 0, "returned result %u", result); cmp(&data, &expected_data, sizeof(data), "incorrect data"); } static void test_lm_migration_recv(void) { - __u32 result = 0; + __u8 sel = NVME_LM_SEL_GET_CONTROLLER_STATE; __u32 expected_data[8], data[8] = {}; - struct nvme_lm_migration_recv_args args = { - .offset = 0xffffffffff, - .result = 0, - .data = &data, - .args_size = sizeof(args), - .fd = TEST_FD, - .numd = 8 - 1, - .mos = 0x1, - .cntlid = 0x2, - .csuuidi = 0x3, - .sel = NVME_LM_SEL_GET_CONTROLLER_STATE, - .uidx = 0x4, - .csuidxp = 0x5, - }; + __u64 offset = 0xffffffffff; + __u16 csuuidi = 0x3; + __u32 numd = 8 - 1; + __u16 cntlid = 0x2; + __u8 csuidxp = 0x5; + __u32 result = 0; + __u16 mos = 0x1; + __u8 uidx = 0x4; + int err; struct mock_cmd mock_admin_cmd = { .opcode = nvme_admin_migration_receive, - .cdw10 = args.sel | (args.mos << 16), - .cdw11 = args.cntlid | (args.csuuidi << 16) | - (args.csuidxp << 24), - .cdw12 = (__u32)args.offset, - .cdw13 = (__u32)(args.offset >> 32), - .cdw14 = args.uidx, - .cdw15 = args.numd, - .data_len = (args.numd + 1) << 2, + .cdw10 = sel | (mos << 16), + .cdw11 = cntlid | (csuuidi << 16) | + (csuidxp << 24), + .cdw12 = (__u32)offset, + .cdw13 = (__u32)(offset >> 32), + .cdw14 = uidx, + .cdw15 = numd, + .data_len = (numd + 1) << 2, .out_data = &expected_data, }; - int err; - arbitrary(&expected_data, sizeof(expected_data)); set_mock_admin_cmds(&mock_admin_cmd, 1); - err = nvme_lm_migration_recv(&args); + err = nvme_lm_migration_recv(test_link, offset, mos, cntlid, csuuidi, sel, uidx, csuidxp, + &data, sizeof(data), NULL); end_mock_cmds(); - check(err == 0, "returned error %d, errno %m", err); + check(err == 0, "returned error %d", err); check(result == 0, "returned result %u", result); cmp(&data, &expected_data, sizeof(data), "incorrect data"); } @@ -1682,7 +1411,11 @@ static void run_test(const char *test_name, void (*test_fn)(void)) int main(void) { + nvme_root_t r = nvme_create_root(stdout, DEFAULT_LOGLEVEL); + set_mock_fd(TEST_FD); + check(!nvme_open(r, "NVME_TEST_FD", &test_link), "opening test link failed"); + RUN_TEST(format_nvm); RUN_TEST(ns_mgmt); RUN_TEST(ns_mgmt_create); @@ -1733,4 +1466,6 @@ int main(void) RUN_TEST(lm_track_send); RUN_TEST(lm_migration_send); RUN_TEST(lm_migration_recv); + + nvme_free_root(r); } diff --git a/test/ioctl/zns.c b/test/ioctl/zns.c index 204093535..3e2d16766 100644 --- a/test/ioctl/zns.c +++ b/test/ioctl/zns.c @@ -12,57 +12,54 @@ #define TEST_NSID 0x12345678 #define TEST_SLBA 0xffffffff12345678 +static nvme_link_t test_link; + static void test_zns_append(void) { __u8 expected_data[8], data[8] = {}; + __u64 zslba = TEST_SLBA; + __u64 ilbrt_u64 = 0x76; + __u16 control = 0xcd; + __u16 cev = 0; + __u16 dspec = 0; + __u16 lbatm = 0x98; + __u16 lbat = 0xef; + __u16 nlb = 0xab; __u64 result = 0; - struct nvme_zns_append_args args = { - .zslba = TEST_SLBA, - .result = &result, - .data = &data, - .args_size = sizeof(args), - .fd = TEST_FD, - .nsid = TEST_NSID, - .data_len = sizeof(data), - .nlb = 0xab, - .control = 0xcd, - .lbat = 0xef, - .lbatm = 0x98, - .ilbrt_u64 = 0x76, - }; + int err; struct mock_cmd mock_io_cmd = { .opcode = nvme_zns_cmd_append, .nsid = TEST_NSID, - .cdw3 = (args.ilbrt_u64 >> 32) & 0xffffffff, - .cdw10 = args.zslba & 0xffffffff, - .cdw11 = args.zslba >> 32, - .cdw12 = args.nlb | (args.control << 16), - .cdw14 = args.ilbrt_u64 & 0xffffffff, - .cdw15 = args.lbat | (args.lbatm << 16), + .cdw3 = (ilbrt_u64 >> 32) & 0xffffffff, + .cdw10 = zslba & 0xffffffff, + .cdw11 = zslba >> 32, + .cdw12 = nlb | (control << 16), + .cdw14 = ilbrt_u64 & 0xffffffff, + .cdw15 = lbat | (lbatm << 16), .data_len = sizeof(expected_data), .out_data = &expected_data, }; - int err; - arbitrary(&expected_data, sizeof(expected_data)); set_mock_io_cmds(&mock_io_cmd, 1); - err = nvme_zns_append(&args); + err = nvme_zns_append(test_link, TEST_NSID, zslba, nlb, control, + cev, dspec, lbat, lbatm, ilbrt_u64, + NULL, 0, &data, sizeof(data), &result); end_mock_cmds(); - check(err == 0, "returned error %d, errno %m", err); + check(err == 0, "returned error %d", err); check(result == 0, "wrong result"); cmp(&data, &expected_data, sizeof(data), "incorrect data"); } static void test_zns_report_zones(void) { + enum nvme_zns_report_options opts = NVME_ZNS_ZRAS_REPORT_CLOSED; __u8 expected_data[8], data[8] = {}; - __u32 result = 0; - uint32_t timeout = 1234; bool extended = true; bool partial = true; - enum nvme_zns_report_options opts = NVME_ZNS_ZRAS_REPORT_CLOSED; + __u32 result = 0; + int err; struct mock_cmd mock_io_cmd = { .opcode = nvme_zns_cmd_mgmt_recv, @@ -74,104 +71,73 @@ static void test_zns_report_zones(void) (!!partial << 16), .data_len = sizeof(expected_data), .out_data = &expected_data, - .timeout_ms = timeout, }; - int err; - arbitrary(&expected_data, sizeof(expected_data)); set_mock_io_cmds(&mock_io_cmd, 1); - err = nvme_zns_report_zones(TEST_FD, TEST_NSID, TEST_SLBA, opts, - extended, partial, sizeof(data), &data, - timeout, &result); + err = nvme_zns_report_zones(test_link, TEST_NSID, TEST_SLBA, opts, extended, partial, + sizeof(data), &data, &result); end_mock_cmds(); - check(err == 0, "returned error %d, errno %m", err); + check(err == 0, "returned error %d", err); check(result == 0, "returned result %u", result); cmp(&data, &expected_data, sizeof(data), "incorrect data"); } static void test_zns_mgmt_send(void) { + enum nvme_zns_send_action zsa = NVME_ZNS_ZSA_OPEN; __u8 expected_data[8], data[8] = {}; + __u64 slba = TEST_SLBA; + bool select_all = true; + __u8 zsaso = !!true; __u32 result = 0; - uint32_t timeout = 1234; - - struct nvme_zns_mgmt_send_args args = { - .slba = TEST_SLBA, - .result = &result, - .data = data, - .args_size = sizeof(args), - .fd = TEST_FD, - .timeout = timeout, - .nsid = TEST_NSID, - .zsa = NVME_ZNS_ZSA_OPEN, - .data_len = sizeof(data), - .select_all = true, - .zsaso = !!true, - }; + int err; struct mock_cmd mock_io_cmd = { .opcode = nvme_zns_cmd_mgmt_send, .nsid = TEST_NSID, - .cdw10 = args.slba & 0xffffffff, - .cdw11 = args.slba >> 32, - .cdw13 = (args.zsaso << 9) | (!!args.select_all << 8) | - (args.zsa << 0), + .cdw10 = slba & 0xffffffff, + .cdw11 = slba >> 32, + .cdw13 = (zsaso << 9) | (!!select_all << 8) | (zsa << 0), .data_len = sizeof(expected_data), .out_data = &expected_data, - .timeout_ms = timeout, }; - int err; - arbitrary(&expected_data, sizeof(expected_data)); set_mock_io_cmds(&mock_io_cmd, 1); - err = nvme_zns_mgmt_send(&args); + err = nvme_zns_mgmt_send(test_link, TEST_NSID, slba, zsa, select_all, + zsaso, 0, data, + sizeof(data), &result); end_mock_cmds(); - check(err == 0, "returned error %d, errno %m", err); + check(err == 0, "returned error %d", err); check(result == 0, "returned result %u", result); cmp(&data, &expected_data, sizeof(data), "incorrect data"); } static void test_zns_mgmt_recv(void) { + enum nvme_zns_recv_action zra = NVME_ZNS_ZRA_REPORT_ZONES; __u8 expected_data[8], data[8] = {}; + __u16 zrasf = (__u16)NVME_ZNS_ZRAS_REPORT_ALL; + bool zras_feat = false; __u32 result = 0; - uint32_t timeout = 1234; - bool partial = false; - - struct nvme_zns_mgmt_recv_args args = { - .slba = 0, - .result = &result, - .data = data, - .args_size = sizeof(args), - .fd = TEST_FD, - .timeout = timeout, - .nsid = TEST_NSID, - .zra = NVME_ZNS_ZRA_REPORT_ZONES, - .data_len = sizeof(data), - .zrasf = (__u16)NVME_ZNS_ZRAS_REPORT_ALL, - .zras_feat = partial, - }; + int err; struct mock_cmd mock_io_cmd = { .opcode = nvme_zns_cmd_mgmt_recv, .nsid = TEST_NSID, .cdw12 = (sizeof(expected_data) >> 2) - 1, - .cdw13 = (!!args.zra << 0) | ((__u16)args.zrasf << 8) | - (!!args.zras_feat << 16), + .cdw13 = (!!zra << 0) | ((__u16)zrasf << 8) | (!!zras_feat << 16), .data_len = sizeof(expected_data), .out_data = &expected_data, - .timeout_ms = timeout, }; - int err; - arbitrary(&expected_data, sizeof(expected_data)); set_mock_io_cmds(&mock_io_cmd, 1); - err = nvme_zns_mgmt_recv(&args); + err = nvme_zns_mgmt_recv(test_link, TEST_NSID, 0, zra, zrasf, zras_feat, data, sizeof(data), + &result); end_mock_cmds(); - check(err == 0, "returned error %d, errno %m", err); + check(err == 0, "returned error %d", err); check(result == 0, "returned result %u", result); cmp(&data, &expected_data, sizeof(data), "incorrect data"); } @@ -188,9 +154,15 @@ static void run_test(const char *test_name, void (*test_fn)(void)) int main(void) { + nvme_root_t r = nvme_create_root(stdout, DEFAULT_LOGLEVEL); + set_mock_fd(TEST_FD); + check(!nvme_open(r, "NVME_TEST_FD", &test_link), "opening test link failed"); + RUN_TEST(zns_append); RUN_TEST(zns_report_zones); RUN_TEST(zns_mgmt_send); RUN_TEST(zns_mgmt_recv); + + nvme_free_root(r); } diff --git a/test/meson.build b/test/meson.build index b73e12d60..64db67e43 100644 --- a/test/meson.build +++ b/test/meson.build @@ -110,6 +110,7 @@ if conf.get('HAVE_NETDB') test_util = executable( 'test-util', ['test-util.c'], + dependencies: libnvme_dep, include_directories: [incdir, internal_incdir] ) test('util', test_util) diff --git a/test/mi-mctp.c b/test/mi-mctp.c index 7d1acd2c6..590243483 100644 --- a/test/mi-mctp.c +++ b/test/mi-mctp.c @@ -19,6 +19,7 @@ #include #include "libnvme-mi.h" +#include "nvme/linux.h" #include "nvme/private.h" #include "utils.h" @@ -405,18 +406,18 @@ static void test_mi_resp_unaligned_expected(nvme_mi_ep_t ep, static void test_admin_resp_err(nvme_mi_ep_t ep, struct test_peer *peer) { struct nvme_id_ctrl id; - nvme_mi_ctrl_t ctrl; + nvme_link_t link; int rc; - ctrl = nvme_mi_init_ctrl(ep, 1); - assert(ctrl); + link = nvme_mi_init_link(ep, 1); + assert(link); /* Simple error response, will be shorter than the expected Admin * command response header. */ peer->tx_buf[4] = 0x02; /* internal error */ peer->tx_buf_len = 8; - rc = nvme_mi_admin_identify_ctrl(ctrl, &id); + rc = nvme_identify_ctrl(link, &id); assert(nvme_status_get_type(rc) == NVME_STATUS_TYPE_MI); assert(nvme_status_get_value(rc) == NVME_MI_RESP_INTERNAL_ERR); } @@ -430,23 +431,23 @@ static void test_admin_resp_err(nvme_mi_ep_t ep, struct test_peer *peer) static void test_admin_resp_sizes(nvme_mi_ep_t ep, struct test_peer *peer) { struct nvme_id_ctrl id; - nvme_mi_ctrl_t ctrl; + nvme_link_t link; unsigned int i; int rc; - ctrl = nvme_mi_init_ctrl(ep, 1); - assert(ctrl); + link = nvme_mi_init_link(ep, 1); + assert(link); peer->tx_buf[4] = 0x02; /* internal error */ for (i = 8; i <= 4096 + 8; i+=4) { peer->tx_buf_len = i; - rc = nvme_mi_admin_identify_ctrl(ctrl, &id); + rc = nvme_identify_ctrl(link, &id); assert(nvme_status_get_type(rc) == NVME_STATUS_TYPE_MI); assert(nvme_status_get_value(rc) == NVME_MI_RESP_INTERNAL_ERR); } - nvme_mi_close_ctrl(ctrl); + nvme_close(link); } /* test: timeout value passed to poll */ @@ -552,7 +553,7 @@ static void test_mpr_admin(nvme_mi_ep_t ep, struct test_peer *peer) { struct mpr_tx_info tx_info; struct nvme_id_ctrl id; - nvme_mi_ctrl_t ctrl; + nvme_link_t link; int rc; tx_info.msg_no = 1; @@ -562,12 +563,12 @@ static void test_mpr_admin(nvme_mi_ep_t ep, struct test_peer *peer) peer->tx_fn = tx_mpr; peer->tx_data = &tx_info; - ctrl = nvme_mi_init_ctrl(ep, 1); + link = nvme_mi_init_link(ep, 1); - rc = nvme_mi_admin_identify_ctrl(ctrl, &id); + rc = nvme_identify_ctrl(link, &id); assert(rc == 0); - nvme_mi_close_ctrl(ctrl); + nvme_close(link); } /* We have seen drives that send a MPR response as a full Admin message, @@ -577,7 +578,7 @@ static void test_mpr_admin_quirked(nvme_mi_ep_t ep, struct test_peer *peer) { struct mpr_tx_info tx_info; struct nvme_id_ctrl id; - nvme_mi_ctrl_t ctrl; + nvme_link_t link; int rc; tx_info.msg_no = 1; @@ -587,12 +588,12 @@ static void test_mpr_admin_quirked(nvme_mi_ep_t ep, struct test_peer *peer) peer->tx_fn = tx_mpr; peer->tx_data = &tx_info; - ctrl = nvme_mi_init_ctrl(ep, 1); + link = nvme_mi_init_link(ep, 1); - rc = nvme_mi_admin_identify_ctrl(ctrl, &id); + rc = nvme_identify_ctrl(link, &id); assert(rc == 0); - nvme_mi_close_ctrl(ctrl); + nvme_close(link); } /* helpers for the MPR + poll tests */ @@ -1167,16 +1168,14 @@ static void test_mi_aem_ep_based_failure_helper(nvme_mi_ep_t ep, case AEM_FC_BAD_OCC_RSP_TOTAL_LEN_SYNC: case AEM_FC_BAD_OCC_RSP_BUFFER_LEN_SYNC: //These all should fail before processing - assert(nvme_mi_aem_enable(ep, &config, &fn_data) == -1); - assert(errno == EPROTO); + assert(nvme_mi_aem_enable(ep, &config, &fn_data) == -EPROTO); break; case AEM_FC_BAD_OCC_RSP_HDR_LEN_AEM: case AEM_FC_BAD_OCC_RSP_TOTAL_LEN_AEM: case AEM_FC_BAD_OCC_RSP_BUFFER_LEN_AEM: //These should fail on the processing assert(nvme_mi_aem_enable(ep, &config, &fn_data) == 0); - assert(nvme_mi_aem_process(ep, &fn_data) == -1); - assert(errno == EPROTO); + assert(nvme_mi_aem_process(ep, &fn_data) == -EPROTO); break; default: assert(false);//Unexpected diff --git a/test/mi.c b/test/mi.c index f92b3b131..18f430532 100644 --- a/test/mi.c +++ b/test/mi.c @@ -1,9 +1,10 @@ // SPDX-License-Identifier: LGPL-2.1-or-later -/** +/* * This file is part of libnvme. * Copyright (c) 2022 Code Construct */ +#include "nvme/types.h" #undef NDEBUG #include #include @@ -14,6 +15,7 @@ #include /* we define a custom transport, so need the internal headers */ +#include "nvme/linux.h" #include "nvme/private.h" #include "libnvme-mi.h" @@ -168,9 +170,9 @@ static void test_endpoint_lifetime(nvme_mi_ep_t ep) unsigned int count_ep_controllers(nvme_mi_ep_t ep) { unsigned int i = 0; - nvme_mi_ctrl_t ctrl; + nvme_link_t link; - nvme_mi_for_each_ctrl(ep, ctrl) + nvme_mi_for_each_link(ep, link) i++; return i; @@ -180,7 +182,7 @@ unsigned int count_ep_controllers(nvme_mi_ep_t ep) * creation/destruction */ static void test_ctrl_lifetime(nvme_mi_ep_t ep) { - nvme_mi_ctrl_t c1, c2; + nvme_link_t l1, l2; int count; ep->controllers_scanned = true; @@ -188,19 +190,19 @@ static void test_ctrl_lifetime(nvme_mi_ep_t ep) count = count_ep_controllers(ep); assert(count == 0); - c1 = nvme_mi_init_ctrl(ep, 1); + l1 = nvme_mi_init_link(ep, 1); count = count_ep_controllers(ep); assert(count == 1); - c2 = nvme_mi_init_ctrl(ep, 2); + l2 = nvme_mi_init_link(ep, 2); count = count_ep_controllers(ep); assert(count == 2); - nvme_mi_close_ctrl(c1); + nvme_close(l1); count = count_ep_controllers(ep); assert(count == 1); - nvme_mi_close_ctrl(c2); + nvme_close(l2); count = count_ep_controllers(ep); assert(count == 0); } @@ -361,7 +363,7 @@ static int test_scan_ctrl_list_cb(struct nvme_mi_ep *ep, static void test_scan_ctrl_list(nvme_mi_ep_t ep) { - struct nvme_mi_ctrl *ctrl; + struct nvme_link *link; ep->controllers_scanned = false; @@ -369,20 +371,20 @@ static void test_scan_ctrl_list(nvme_mi_ep_t ep) nvme_mi_scan_ep(ep, false); - ctrl = nvme_mi_first_ctrl(ep); - assert(ctrl); - assert(ctrl->id == 1); + link = nvme_mi_first_link(ep); + assert(link); + assert(link->id == 1); - ctrl = nvme_mi_next_ctrl(ep, ctrl); - assert(ctrl); - assert(ctrl->id == 4); + link = nvme_mi_next_link(ep, link); + assert(link); + assert(link->id == 4); - ctrl = nvme_mi_next_ctrl(ep, ctrl); - assert(ctrl); - assert(ctrl->id == 5); + link = nvme_mi_next_link(ep, link); + assert(link); + assert(link->id == 5); - ctrl = nvme_mi_next_ctrl(ep, ctrl); - assert(ctrl == NULL); + link = nvme_mi_next_link(ep, link); + assert(link == NULL); } /* test: simple NVMe admin request/response */ @@ -438,15 +440,15 @@ static int test_admin_id_cb(struct nvme_mi_ep *ep, static void test_admin_id(nvme_mi_ep_t ep) { struct nvme_id_ctrl id; - nvme_mi_ctrl_t ctrl; + nvme_link_t link; int rc; test_set_transport_callback(ep, test_admin_id_cb, NULL); - ctrl = nvme_mi_init_ctrl(ep, 5); - assert(ctrl); + link = nvme_mi_init_link(ep, 5); + assert(link); - rc = nvme_mi_admin_identify_ctrl(ctrl, &id); + rc = nvme_identify_ctrl(link, &id); assert(rc == 0); } @@ -492,15 +494,15 @@ static int test_admin_err_mi_resp_cb(struct nvme_mi_ep *ep, static void test_admin_err_mi_resp(nvme_mi_ep_t ep) { struct nvme_id_ctrl id; - nvme_mi_ctrl_t ctrl; + nvme_link_t link ; int rc; test_set_transport_callback(ep, test_admin_err_mi_resp_cb, NULL); - ctrl = nvme_mi_init_ctrl(ep, 1); - assert(ctrl); + link = nvme_mi_init_link(ep, 1); + assert(link); - rc = nvme_mi_admin_identify_ctrl(ctrl, &id); + rc = nvme_identify_ctrl(link, &id); assert(rc != 0); assert(nvme_status_get_type(rc) == NVME_STATUS_TYPE_MI); assert(nvme_status_get_value(rc) == NVME_MI_RESP_INTERNAL_ERR); @@ -554,15 +556,15 @@ static int test_admin_err_nvme_resp_cb(struct nvme_mi_ep *ep, static void test_admin_err_nvme_resp(nvme_mi_ep_t ep) { struct nvme_id_ctrl id; - nvme_mi_ctrl_t ctrl; + nvme_link_t link; int rc; test_set_transport_callback(ep, test_admin_err_nvme_resp_cb, NULL); - ctrl = nvme_mi_init_ctrl(ep, 1); - assert(ctrl); + link = nvme_mi_init_link(ep, 1); + assert(link); - rc = nvme_mi_admin_identify_ctrl(ctrl, &id); + rc = nvme_identify_ctrl(link, &id); assert(rc != 0); assert(nvme_status_get_type(rc) == NVME_STATUS_TYPE_NVME); assert(nvme_status_get_value(rc) == @@ -588,48 +590,48 @@ static void test_admin_invalid_formats(nvme_mi_ep_t ep) uint8_t data[4]; } req = { 0 }; struct nvme_mi_admin_resp_hdr resp = { 0 }; - nvme_mi_ctrl_t ctrl; + nvme_link_t link; size_t len; int rc; test_set_transport_callback(ep, test_rejected_command_cb, NULL); - ctrl = nvme_mi_init_ctrl(ep, 1); - assert(ctrl); + link = nvme_mi_init_link(ep, 1); + assert(link); /* unaligned req size */ len = 0; - rc = nvme_mi_admin_xfer(ctrl, &req.hdr, 1, &resp, 0, &len); + rc = nvme_mi_admin_xfer(link, &req.hdr, 1, &resp, 0, &len); assert(rc != 0); /* unaligned resp size */ len = 1; - rc = nvme_mi_admin_xfer(ctrl, &req.hdr, 0, &resp, 0, &len); + rc = nvme_mi_admin_xfer(link, &req.hdr, 0, &resp, 0, &len); assert(rc != 0); /* unaligned resp offset */ len = 4; - rc = nvme_mi_admin_xfer(ctrl, &req.hdr, 0, &resp, 1, &len); + rc = nvme_mi_admin_xfer(link, &req.hdr, 0, &resp, 1, &len); assert(rc != 0); /* resp too large */ len = 4096 + 4; - rc = nvme_mi_admin_xfer(ctrl, &req.hdr, 0, &resp, 0, &len); + rc = nvme_mi_admin_xfer(link, &req.hdr, 0, &resp, 0, &len); assert(rc != 0); /* resp offset too large */ len = 4; - rc = nvme_mi_admin_xfer(ctrl, &req.hdr, 0, &resp, (off_t)1 << 32, &len); + rc = nvme_mi_admin_xfer(link, &req.hdr, 0, &resp, (off_t)1 << 32, &len); assert(rc != 0); /* resp offset with no len */ len = 0; - rc = nvme_mi_admin_xfer(ctrl, &req.hdr, 0, &resp, 4, &len); + rc = nvme_mi_admin_xfer(link, &req.hdr, 0, &resp, 4, &len); assert(rc != 0); /* req and resp payloads */ len = 4; - rc = nvme_mi_admin_xfer(ctrl, &req.hdr, 4, &resp, 0, &len); + rc = nvme_mi_admin_xfer(link, &req.hdr, 4, &resp, 0, &len); assert(rc != 0); } @@ -640,14 +642,14 @@ static void test_mi_invalid_formats(nvme_mi_ep_t ep) uint8_t data[4]; } req = { 0 }; struct nvme_mi_mi_resp_hdr resp = { 0 }; - nvme_mi_ctrl_t ctrl; + nvme_link_t link; size_t len; int rc; test_set_transport_callback(ep, test_rejected_command_cb, NULL); - ctrl = nvme_mi_init_ctrl(ep, 1); - assert(ctrl); + link = nvme_mi_init_link(ep, 1); + assert(link); /* resp too large */ len = 4096 + 4; @@ -960,55 +962,41 @@ static int test_admin_get_features_cb(struct nvme_mi_ep *ep, static void test_get_features_nodata(nvme_mi_ep_t ep) { - struct nvme_get_features_args args = { 0 }; - nvme_mi_ctrl_t ctrl; + nvme_link_t link; uint32_t res; int rc; test_set_transport_callback(ep, test_admin_get_features_cb, NULL); - ctrl = nvme_mi_init_ctrl(ep, 5); - assert(ctrl); + link = nvme_mi_init_link(ep, 5); + assert(link); - args.args_size = sizeof(args); - args.fid = NVME_FEAT_FID_ARBITRATION; - args.sel = 0; - args.result = &res; - - rc = nvme_mi_admin_get_features(ctrl, &args); + rc = nvme_get_features(link, NVME_NSID_NONE, NVME_FEAT_FID_ARBITRATION, + 0, 0, NVME_UUID_NONE, NULL, 0, &res); assert(rc == 0); - assert(args.data_len == 0); assert(res == 0x04030201); } static void test_get_features_data(nvme_mi_ep_t ep) { - struct nvme_get_features_args args = { 0 }; struct nvme_timestamp tstamp; - nvme_mi_ctrl_t ctrl; + nvme_link_t link; uint8_t exp[6]; uint32_t res; int rc, i; test_set_transport_callback(ep, test_admin_get_features_cb, NULL); - ctrl = nvme_mi_init_ctrl(ep, 5); - assert(ctrl); - - args.args_size = sizeof(args); - args.fid = NVME_FEAT_FID_TIMESTAMP; - args.sel = 0; - args.result = &res; - args.data = &tstamp; - args.data_len = sizeof(tstamp); + link = nvme_mi_init_link(ep, 5); + assert(link); /* expected timestamp value */ for (i = 0; i < sizeof(tstamp.timestamp); i++) exp[i] = i; - rc = nvme_mi_admin_get_features(ctrl, &args); + rc = nvme_get_features(link, NVME_NSID_NONE, NVME_FEAT_FID_TIMESTAMP, + 0, 0, NVME_UUID_NONE, &tstamp, sizeof(tstamp), &res); assert(rc == 0); - assert(args.data_len == sizeof(tstamp)); assert(tstamp.attr == 1); assert(!memcmp(tstamp.timestamp, exp, sizeof(tstamp.timestamp))); } @@ -1067,30 +1055,23 @@ static int test_admin_set_features_cb(struct nvme_mi_ep *ep, static void test_set_features(nvme_mi_ep_t ep) { - struct nvme_set_features_args args = { 0 }; struct nvme_timestamp tstamp = { 0 }; - nvme_mi_ctrl_t ctrl; + nvme_link_t link; uint32_t res; int rc, i; test_set_transport_callback(ep, test_admin_set_features_cb, NULL); - ctrl = nvme_mi_init_ctrl(ep, 5); - assert(ctrl); + link = nvme_mi_init_link(ep, 5); + assert(link); for (i = 0; i < sizeof(tstamp.timestamp); i++) tstamp.timestamp[i] = i; - args.args_size = sizeof(args); - args.fid = NVME_FEAT_FID_TIMESTAMP; - args.save = 1; - args.result = &res; - args.data = &tstamp; - args.data_len = sizeof(tstamp); - - rc = nvme_mi_admin_set_features(ctrl, &args); + rc = nvme_set_features(link, NVME_NSID_NONE, NVME_FEAT_FID_TIMESTAMP, true, + 0, 0, 0, 0, 0, &tstamp, sizeof(tstamp), &res); assert(rc == 0); - assert(args.data_len == 0); + assert(sizeof(tstamp) == 8); } enum ns_type { @@ -1147,17 +1128,17 @@ static int test_admin_id_ns_list_cb(struct nvme_mi_ep *ep, static void test_admin_id_alloc_ns_list(struct nvme_mi_ep *ep) { struct nvme_ns_list list; - nvme_mi_ctrl_t ctrl; + nvme_link_t link; enum ns_type type; int rc; type = NS_ALLOC; test_set_transport_callback(ep, test_admin_id_ns_list_cb, &type); - ctrl = nvme_mi_init_ctrl(ep, 5); - assert(ctrl); + link = nvme_mi_init_link(ep, 5); + assert(link); - rc = nvme_mi_admin_identify_allocated_ns_list(ctrl, 1, &list); + rc = nvme_identify_allocated_ns_list(link, 1, &list); assert(!rc); assert(le32_to_cpu(list.ns[0]) == 2); @@ -1168,17 +1149,17 @@ static void test_admin_id_alloc_ns_list(struct nvme_mi_ep *ep) static void test_admin_id_active_ns_list(struct nvme_mi_ep *ep) { struct nvme_ns_list list; - nvme_mi_ctrl_t ctrl; + nvme_link_t link; enum ns_type type; int rc; type = NS_ACTIVE; test_set_transport_callback(ep, test_admin_id_ns_list_cb, &type); - ctrl = nvme_mi_init_ctrl(ep, 5); - assert(ctrl); + link = nvme_mi_init_link(ep, 5); + assert(link); - rc = nvme_mi_admin_identify_active_ns_list(ctrl, 1, &list); + rc = nvme_identify_active_ns_list(link, 1, &list); assert(!rc); assert(le32_to_cpu(list.ns[0]) == 4); @@ -1231,17 +1212,17 @@ static int test_admin_id_ns_cb(struct nvme_mi_ep *ep, static void test_admin_id_alloc_ns(struct nvme_mi_ep *ep) { struct nvme_id_ns id; - nvme_mi_ctrl_t ctrl; + nvme_link_t link; enum ns_type type; int rc; type = NS_ALLOC; test_set_transport_callback(ep, test_admin_id_ns_cb, &type); - ctrl = nvme_mi_init_ctrl(ep, 5); - assert(ctrl); + link = nvme_mi_init_link(ep, 5); + assert(link); - rc = nvme_mi_admin_identify_allocated_ns(ctrl, 1, &id); + rc = nvme_identify_allocated_ns(link, 1, &id); assert(!rc); assert(le64_to_cpu(id.nsze) == 1); } @@ -1249,17 +1230,17 @@ static void test_admin_id_alloc_ns(struct nvme_mi_ep *ep) static void test_admin_id_active_ns(struct nvme_mi_ep *ep) { struct nvme_id_ns id; - nvme_mi_ctrl_t ctrl; + nvme_link_t link; enum ns_type type; int rc; type = NS_ACTIVE; test_set_transport_callback(ep, test_admin_id_ns_cb, &type); - ctrl = nvme_mi_init_ctrl(ep, 5); - assert(ctrl); + link = nvme_mi_init_link(ep, 5); + assert(link); - rc = nvme_mi_admin_identify_ns(ctrl, 1, &id); + rc = nvme_identify_ns(link, 1, &id); assert(!rc); assert(le64_to_cpu(id.nsze) == 1); } @@ -1296,15 +1277,15 @@ static int test_admin_id_nsid_ctrl_list_cb(struct nvme_mi_ep *ep, static void test_admin_id_nsid_ctrl_list(struct nvme_mi_ep *ep) { struct nvme_ctrl_list list; - nvme_mi_ctrl_t ctrl; + nvme_link_t link; int rc; test_set_transport_callback(ep, test_admin_id_nsid_ctrl_list_cb, NULL); - ctrl = nvme_mi_init_ctrl(ep, 5); - assert(ctrl); + link = nvme_mi_init_link(ep, 5); + assert(link); - rc = nvme_mi_admin_identify_nsid_ctrl_list(ctrl, 0x01020304, 5, &list); + rc = nvme_identify_nsid_ctrl_list(link, 0x01020304, 5, &list); assert(!rc); } @@ -1336,16 +1317,16 @@ static int test_admin_id_secondary_ctrl_list_cb(struct nvme_mi_ep *ep, static void test_admin_id_secondary_ctrl_list(struct nvme_mi_ep *ep) { struct nvme_secondary_ctrl_list list; - nvme_mi_ctrl_t ctrl; + nvme_link_t link; int rc; test_set_transport_callback(ep, test_admin_id_secondary_ctrl_list_cb, NULL); - ctrl = nvme_mi_init_ctrl(ep, 5); - assert(ctrl); + link = nvme_mi_init_link(ep, 5); + assert(link); - rc = nvme_mi_admin_identify_secondary_ctrl_list(ctrl, 5, &list); + rc = nvme_identify_secondary_ctrl_list(link, 5, &list); assert(!rc); } @@ -1407,35 +1388,35 @@ static int test_admin_ns_mgmt_cb(struct nvme_mi_ep *ep, static void test_admin_ns_mgmt_create(struct nvme_mi_ep *ep) { struct nvme_ns_mgmt_host_sw_specified data = { 0 }; - nvme_mi_ctrl_t ctrl; + nvme_link_t link; __u32 ns; int rc; test_set_transport_callback(ep, test_admin_ns_mgmt_cb, NULL); - ctrl = nvme_mi_init_ctrl(ep, 5); - assert(ctrl); + link = nvme_mi_init_link(ep, 5); + assert(link); - rc = nvme_mi_admin_ns_mgmt_create(ctrl, NULL, 0, &ns, &data); + rc = nvme_ns_mgmt_create(link, NVME_CSI_NVM, &data, &ns); assert(!rc); assert(ns == 0x01020304); data.nsze = cpu_to_le64(42); - rc = nvme_mi_admin_ns_mgmt_create(ctrl, NULL, 0, &ns, &data); + rc = nvme_ns_mgmt_create(link, NVME_CSI_NVM, &data, &ns); assert(rc); } static void test_admin_ns_mgmt_delete(struct nvme_mi_ep *ep) { - nvme_mi_ctrl_t ctrl; + nvme_link_t link; int rc; test_set_transport_callback(ep, test_admin_ns_mgmt_cb, NULL); - ctrl = nvme_mi_init_ctrl(ep, 5); - assert(ctrl); + link = nvme_mi_init_link(ep, 5); + assert(link); - rc = nvme_mi_admin_ns_mgmt_delete(ctrl, 0x05060708); + rc = nvme_ns_mgmt_delete(link, 0x05060708); assert(!rc); } @@ -1487,7 +1468,7 @@ static void test_admin_ns_attach(struct nvme_mi_ep *ep) { struct nvme_ctrl_list list = { 0 }; struct attach_op aop; - nvme_mi_ctrl_t ctrl; + nvme_link_t link; int rc; list.num = cpu_to_le16(2); @@ -1499,10 +1480,10 @@ static void test_admin_ns_attach(struct nvme_mi_ep *ep) test_set_transport_callback(ep, test_admin_ns_attach_cb, &aop); - ctrl = nvme_mi_init_ctrl(ep, 5); - assert(ctrl); + link = nvme_mi_init_link(ep, 5); + assert(link); - rc = nvme_mi_admin_ns_attach_ctrls(ctrl, 0x02030405, &list); + rc = nvme_ns_attach_ctrls(link, 0x02030405, &list); assert(!rc); } @@ -1510,7 +1491,7 @@ static void test_admin_ns_detach(struct nvme_mi_ep *ep) { struct nvme_ctrl_list list = { 0 }; struct attach_op aop; - nvme_mi_ctrl_t ctrl; + nvme_link_t link; int rc; list.num = cpu_to_le16(2); @@ -1522,10 +1503,10 @@ static void test_admin_ns_detach(struct nvme_mi_ep *ep) test_set_transport_callback(ep, test_admin_ns_attach_cb, &aop); - ctrl = nvme_mi_init_ctrl(ep, 5); - assert(ctrl); + link = nvme_mi_init_link(ep, 5); + assert(link); - rc = nvme_mi_admin_ns_detach_ctrls(ctrl, 0x02030405, &list); + rc = nvme_ns_detach_ctrls(link, 0x02030405, &list); assert(!rc); } @@ -1565,10 +1546,9 @@ static int test_admin_fw_download_cb(struct nvme_mi_ep *ep, static void test_admin_fw_download(struct nvme_mi_ep *ep) { - struct nvme_fw_download_args args; struct fw_download_info info; unsigned char fw[4096]; - nvme_mi_ctrl_t ctrl; + nvme_link_t link; int rc, i; for (i = 0; i < sizeof(fw); i++) @@ -1577,48 +1557,46 @@ static void test_admin_fw_download(struct nvme_mi_ep *ep) info.offset = 0; info.len = 0; info.data = fw; - args.data = fw; - args.args_size = sizeof(args); test_set_transport_callback(ep, test_admin_fw_download_cb, &info); - ctrl = nvme_mi_init_ctrl(ep, 5); - assert(ctrl); + link = nvme_mi_init_link(ep, 5); + assert(link); /* invalid (zero) len */ - args.data_len = info.len = 1; - args.offset = info.offset = 0; - rc = nvme_mi_admin_fw_download(ctrl, &args); + info.len = 1; + info.offset = 0; + rc = nvme_fw_download(link, fw, info.len, info.offset, NULL); assert(rc); /* invalid (unaligned) len */ - args.data_len = info.len = 1; - args.offset = info.offset = 0; - rc = nvme_mi_admin_fw_download(ctrl, &args); + info.len = 1; + info.offset = 0; + rc = nvme_fw_download(link, fw, info.len, info.offset, NULL); assert(rc); /* invalid offset */ - args.data_len = info.len = 4; - args.offset = info.offset = 1; - rc = nvme_mi_admin_fw_download(ctrl, &args); + info.len = 4; + info.offset = 1; + rc = nvme_fw_download(link, fw, info.len, info.offset, NULL); assert(rc); /* smallest len */ - args.data_len = info.len = 4; - args.offset = info.offset = 0; - rc = nvme_mi_admin_fw_download(ctrl, &args); + info.len = 4; + info.offset = 0; + rc = nvme_fw_download(link, fw, info.len, info.offset, NULL); assert(!rc); /* largest len */ - args.data_len = info.len = 4096; - args.offset = info.offset = 0; - rc = nvme_mi_admin_fw_download(ctrl, &args); + info.len = 4096; + info.offset = 0; + rc = nvme_fw_download(link, fw, info.len, info.offset, NULL); assert(!rc); /* offset value */ - args.data_len = info.len = 4096; - args.offset = info.offset = 4096; - rc = nvme_mi_admin_fw_download(ctrl, &args); + info.len = 4096; + info.offset = 4096; + rc = nvme_fw_download(link, fw, info.len, info.offset, NULL); assert(!rc); } @@ -1655,49 +1633,44 @@ static int test_admin_fw_commit_cb(struct nvme_mi_ep *ep, static void test_admin_fw_commit(struct nvme_mi_ep *ep) { - struct nvme_fw_commit_args args; struct fw_commit_info info; - nvme_mi_ctrl_t ctrl; + nvme_link_t link; int rc; - args.args_size = sizeof(args); - info.bpid = args.bpid = 0; - test_set_transport_callback(ep, test_admin_fw_commit_cb, &info); - ctrl = nvme_mi_init_ctrl(ep, 5); - assert(ctrl); + link = nvme_mi_init_link(ep, 5); + assert(link); /* all zeros */ - info.bpid = args.bpid = 0; - info.slot = args.slot = 0; - info.action = args.action = 0; - rc = nvme_mi_admin_fw_commit(ctrl, &args); + info.bpid = 0; + info.slot = 0; + info.action = 0; + rc = nvme_fw_commit(link, info.slot, info.action, info.bpid, NULL); assert(!rc); /* all ones */ - info.bpid = args.bpid = 1; - info.slot = args.slot = 0x7; - info.action = args.action = 0x7; - rc = nvme_mi_admin_fw_commit(ctrl, &args); + info.bpid = 1; + info.slot = 0x7; + info.action = 0x7; + rc = nvme_fw_commit(link, info.slot, info.action, info.bpid, NULL); assert(!rc); /* correct fields */ - info.bpid = args.bpid = 1; - info.slot = args.slot = 2; - info.action = args.action = 3; - rc = nvme_mi_admin_fw_commit(ctrl, &args); + info.bpid = 1; + info.slot = 2; + info.action = 3; + rc = nvme_fw_commit(link, info.slot, info.action, info.bpid, NULL); assert(!rc); } struct format_data { __u32 nsid; - __u8 lbafu; __u8 ses; __u8 pil; __u8 pi; __u8 mset; - __u8 lbafl; + __u8 lbaf; }; static int test_admin_format_nvm_cb(struct nvme_mi_ep *ep, @@ -1705,7 +1678,7 @@ static int test_admin_format_nvm_cb(struct nvme_mi_ep *ep, struct nvme_mi_resp *resp, void *data) { - struct nvme_format_nvm_args *args = data; + struct format_data *args = data; __u8 *rq_hdr; __u32 nsid; @@ -1721,13 +1694,13 @@ static int test_admin_format_nvm_cb(struct nvme_mi_ep *ep, | rq_hdr[8]; assert(nsid == args->nsid); - assert(((rq_hdr[44] >> 0) & 0xf) == args->lbaf); + assert(((rq_hdr[44] >> 0) & 0xf) == (args->lbaf & 0xf)); assert(((rq_hdr[44] >> 4) & 0x1) == args->mset); assert(((rq_hdr[44] >> 5) & 0x7) == args->pi); assert(((rq_hdr[45] >> 0) & 0x1) == args->pil); assert(((rq_hdr[45] >> 1) & 0x7) == args->ses); - assert(((rq_hdr[45] >> 4) & 0x3) == args->lbafu); + assert(((rq_hdr[45] >> 4) & 0x3) == (args->lbaf >> 4)); test_transport_resp_calc_mic(resp); @@ -1736,66 +1709,70 @@ static int test_admin_format_nvm_cb(struct nvme_mi_ep *ep, static void test_admin_format_nvm(struct nvme_mi_ep *ep) { - struct nvme_format_nvm_args args = { 0 }; - nvme_mi_ctrl_t ctrl; + struct format_data args = { 0 }; + nvme_link_t link; int rc; - ctrl = nvme_mi_init_ctrl(ep, 5); - assert(ctrl); + link = nvme_mi_init_link(ep, 5); + assert(link); test_set_transport_callback(ep, test_admin_format_nvm_cb, &args); /* ensure we have the cdw0 bit field encoding correct, by testing twice * with inverted bit values */ - args.args_size = sizeof(args); args.nsid = 0x04030201; - args.lbafu = 0x3; args.ses = 0x0; args.pil = 0x1; args.pi = 0x0; args.mset = 0x1; - args.lbaf = 0x0; + args.lbaf = 0x30; - rc = nvme_mi_admin_format_nvm(ctrl, &args); + rc = nvme_format_nvm(link, args.nsid, args.lbaf, args.mset, + args.pi, args.pil, args.ses, NULL); assert(!rc); args.nsid = ~args.nsid; - args.lbafu = 0; args.ses = 0x7; args.pil = 0x0; args.pi = 0x7; args.mset = 0x0; - args.lbaf = 0xf; + args.lbaf = 0x0f; - rc = nvme_mi_admin_format_nvm(ctrl, &args); + rc = nvme_format_nvm(link, args.nsid, args.lbaf, args.mset, + args.pi, args.pil, args.ses, NULL); assert(!rc); } -static int test_admin_sanitize_nvm_cb(struct nvme_mi_ep *ep, - struct nvme_mi_req *req, - struct nvme_mi_resp *resp, - void *data) -{ - struct nvme_sanitize_nvm_args *args = data; - __u8 *rq_hdr; +struct sanitize_nvm_info { + enum nvme_sanitize_sanact sanact; + bool ause; + __u8 owpass; + bool oipbp; + bool ndas; + bool emvs; __u32 ovrpat; +}; - assert(req->data_len == 0); +static int test_admin_sanitize_nvm_cb(struct nvme_mi_ep *ep, struct nvme_mi_req *req, + struct nvme_mi_resp *resp, void *data) +{ + struct sanitize_nvm_info *info = data; + __u8 *rq_hdr = (__u8 *)req->hdr; + __u32 ovrpat; - rq_hdr = (__u8 *)req->hdr; + assert(!req->data_len); assert(rq_hdr[4] == nvme_admin_sanitize_nvm); - assert(((rq_hdr[44] >> 0) & 0x7) == args->sanact); - assert(((rq_hdr[44] >> 3) & 0x1) == args->ause); - assert(((rq_hdr[44] >> 4) & 0xf) == args->owpass); + assert(((rq_hdr[44] >> 0) & 0x7) == info->sanact); + assert(((rq_hdr[44] >> 3) & 0x1) == info->ause); + assert(((rq_hdr[44] >> 4) & 0xf) == info->owpass); - assert(((rq_hdr[45] >> 0) & 0x1) == args->oipbp); - assert(((rq_hdr[45] >> 1) & 0x1) == args->nodas); + assert(((rq_hdr[45] >> 0) & 0x1) == info->oipbp); + assert(((rq_hdr[45] >> 1) & 0x1) == info->ndas); - ovrpat = (__u32)rq_hdr[51] << 24 | rq_hdr[50] << 16 | - rq_hdr[49] << 8 | rq_hdr[48]; - assert(ovrpat == args->ovrpat); + ovrpat = (__u32)rq_hdr[51] << 24 | rq_hdr[50] << 16 | rq_hdr[49] << 8 | rq_hdr[48]; + assert(ovrpat == info->ovrpat); test_transport_resp_calc_mic(resp); @@ -1804,34 +1781,37 @@ static int test_admin_sanitize_nvm_cb(struct nvme_mi_ep *ep, static void test_admin_sanitize_nvm(struct nvme_mi_ep *ep) { - struct nvme_sanitize_nvm_args args = { 0 }; - nvme_mi_ctrl_t ctrl; + struct sanitize_nvm_info info; + nvme_link_t link; int rc; - ctrl = nvme_mi_init_ctrl(ep, 5); - assert(ctrl); + link = nvme_mi_init_link(ep, 5); + assert(link); - test_set_transport_callback(ep, test_admin_sanitize_nvm_cb, &args); + test_set_transport_callback(ep, test_admin_sanitize_nvm_cb, &info); - args.args_size = sizeof(args); - args.sanact = 0x7; - args.ause = 0x0; - args.owpass = 0xf; - args.oipbp = 0x0; - args.nodas = 0x1; - args.ovrpat = ~0x04030201; + info.sanact = 0x7; + info.ause = 0x0; + info.owpass = 0xf; + info.oipbp = 0x0; + info.ndas = 0x1; + info.ovrpat = ~0x04030201; - rc = nvme_mi_admin_sanitize_nvm(ctrl, &args); + rc = nvme_sanitize_nvm(link, info.sanact, info.ause, info.owpass, + info.oipbp, info.ndas, info.emvs, + info.ovrpat, NULL); assert(!rc); - args.sanact = 0x0; - args.ause = 0x1; - args.owpass = 0x0; - args.oipbp = 0x1; - args.nodas = 0x0; - args.ovrpat = 0x04030201; + info.sanact = 0x0; + info.ause = 0x1; + info.owpass = 0x0; + info.oipbp = 0x1; + info.ndas = 0x0; + info.ovrpat = 0x04030201; - rc = nvme_mi_admin_sanitize_nvm(ctrl, &args); + rc = nvme_sanitize_nvm(link, info.sanact, info.ause, info.owpass, + info.oipbp, info.ndas, info.emvs, + info.ovrpat, NULL); assert(!rc); } @@ -1898,25 +1878,21 @@ static int test_admin_get_log_split_cb(struct nvme_mi_ep *ep, static void test_admin_get_log_split(struct nvme_mi_ep *ep) { - struct nvme_get_log_args args = { 0 }; unsigned char buf[4096 * 2 + 4]; struct log_data ldata; - nvme_mi_ctrl_t ctrl; + nvme_link_t link; int rc; ldata.n = 0; test_set_transport_callback(ep, test_admin_get_log_split_cb, &ldata); - ctrl = nvme_mi_init_ctrl(ep, 5); - - args.args_size = sizeof(args); - args.lid = 1; - args.log = buf; - args.len = sizeof(buf); - args.lpo = 0; - args.ot = false; + link = nvme_mi_init_link(ep, 5); - rc = nvme_mi_admin_get_log(ctrl, &args); + rc = nvme_get_log(link, NVME_NSID_NONE, false, NVME_LOG_LSP_NONE, + NVME_LOG_LID_ERROR, NVME_LOG_LSI_NONE, NVME_CSI_NVM, + false, NVME_UUID_NONE, + 0, buf, sizeof(buf), + NVME_LOG_PAGE_PDU_SIZE, NULL); assert(!rc); @@ -2024,7 +2000,7 @@ static void test_admin_dlen_doff_req(struct nvme_mi_ep *ep) struct nvme_mi_admin_resp_hdr admin_resp = { 0 }; struct req_dlen_doff_data data = { 0 }; size_t resp_sz = 0; - nvme_mi_ctrl_t ctrl; + nvme_link_t link; int rc; data.direction = DATA_DIR_OUT; @@ -2032,10 +2008,10 @@ static void test_admin_dlen_doff_req(struct nvme_mi_ep *ep) test_set_transport_callback(ep, test_admin_dlen_doff_cb, &data); - ctrl = nvme_mi_init_ctrl(ep, 0); - assert(ctrl); + link = nvme_mi_init_link(ep, 0); + assert(link); - rc = nvme_mi_admin_xfer(ctrl, &admin_req.hdr, sizeof(admin_req.data), + rc = nvme_mi_admin_xfer(link, &admin_req.hdr, sizeof(admin_req.data), &admin_resp, 0, &resp_sz); assert(!rc); @@ -2051,7 +2027,7 @@ static void test_admin_dlen_doff_resp(struct nvme_mi_ep *ep) } admin_resp = { 0 }; struct nvme_mi_admin_req_hdr admin_req = { 0 }; struct req_dlen_doff_data data = { 0 }; - nvme_mi_ctrl_t ctrl; + nvme_link_t link; size_t resp_sz; int rc; @@ -2061,10 +2037,10 @@ static void test_admin_dlen_doff_resp(struct nvme_mi_ep *ep) test_set_transport_callback(ep, test_admin_dlen_doff_cb, &data); - ctrl = nvme_mi_init_ctrl(ep, 0); - assert(ctrl); + link = nvme_mi_init_link(ep, 0); + assert(link); - rc = nvme_mi_admin_xfer(ctrl, &admin_req, 0, &admin_resp.hdr, 0, + rc = nvme_mi_admin_xfer(link, &admin_req, 0, &admin_resp.hdr, 0, &resp_sz); assert(!rc); diff --git a/test/psk.c b/test/psk.c index 02cb6d813..6f65ce142 100644 --- a/test/psk.c +++ b/test/psk.c @@ -73,6 +73,7 @@ static void check_str(const char *exp, const char *res) static void export_test(struct test_data *test) { char *psk; + int ret; if (test->version != 1 || !(test->hmac == NVME_HMAC_ALG_SHA2_256 || @@ -82,10 +83,10 @@ static void export_test(struct test_data *test) printf("test nvme_export_tls_key hmac %d %s\n", test->hmac, test->exported_psk); - psk = nvme_export_tls_key(test->configured_psk, test->psk_length); - if (!psk) { + ret = nvme_export_tls_key(test->configured_psk, test->psk_length, &psk); + if (ret) { test_rc = 1; - printf("ERROR: nvme_export_tls_key() failed with %d\n", errno); + printf("ERROR: nvme_export_tls_key() failed with %d\n", ret); return; } check_str(test->exported_psk, psk); @@ -97,6 +98,7 @@ static void import_test(struct test_data *test) unsigned char *psk; int psk_length; unsigned int hmac; + int ret; if (test->version != 1 || !(test->hmac == NVME_HMAC_ALG_SHA2_256 || @@ -106,10 +108,10 @@ static void import_test(struct test_data *test) printf("test nvme_import_tls_key hmac %d %s\n", test->hmac, test->exported_psk); - psk = nvme_import_tls_key(test->exported_psk, &psk_length, &hmac); - if (!psk) { + ret = nvme_import_tls_key(test->exported_psk, &psk_length, &hmac, &psk); + if (ret) { test_rc = 1; - printf("ERROR: nvme_import_tls_key() failed with %d\n", errno); + printf("ERROR: nvme_import_tls_key() failed with %d\n", ret); return; } @@ -136,6 +138,7 @@ static void import_test(struct test_data *test) static void export_versioned_test(struct test_data *test) { char *psk; + int ret; if (test->version != 1) return; @@ -143,13 +146,13 @@ static void export_versioned_test(struct test_data *test) printf("test nvme_export_tls_key_versioned hmac %d %s\n", test->hmac, test->exported_psk); - psk = nvme_export_tls_key_versioned(test->version, test->hmac, + ret = nvme_export_tls_key_versioned(test->version, test->hmac, test->configured_psk, - test->psk_length); - if (!psk) { + test->psk_length, &psk); + if (ret) { test_rc = 1; printf("ERROR: nvme_export_tls_key_versioned() failed with %d\n", - errno); + ret); return; } @@ -164,6 +167,7 @@ static void import_versioned_test(struct test_data *test) unsigned char version; unsigned char hmac; size_t psk_length; + int ret; if (test->version != 1) return; @@ -171,12 +175,12 @@ static void import_versioned_test(struct test_data *test) printf("test nvme_import_tls_key_versioned hmac %d %s\n", test->hmac, test->exported_psk); - psk = nvme_import_tls_key_versioned(test->exported_psk, &version, - &hmac, &psk_length); - if (!psk) { + ret = nvme_import_tls_key_versioned(test->exported_psk, &version, + &hmac, &psk_length, &psk); + if (ret) { test_rc = 1; printf("ERROR: nvme_import_tls_key_versioned() failed with %d\n", - errno); + ret); return; } diff --git a/test/sysfs/tree-dump.c b/test/sysfs/tree-dump.c index bcf871b36..b3555299f 100644 --- a/test/sysfs/tree-dump.c +++ b/test/sysfs/tree-dump.c @@ -22,10 +22,8 @@ static bool tree_dump(void) return false; err = nvme_scan_topology(r, NULL, NULL); - if (err) { - if (errno != ENOENT) - goto out; - } + if (err && err != ENOENT) + goto out; if (nvme_dump_tree(r)) goto out; @@ -34,7 +32,7 @@ static bool tree_dump(void) pass = true; out: - nvme_free_tree(r); + nvme_free_root(r); return pass; } diff --git a/test/test.c b/test/test.c index 6655083ea..9729f0705 100644 --- a/test/test.c +++ b/test/test.c @@ -39,8 +39,9 @@ static int test_ctrl(nvme_ctrl_t c) static __u8 buf[0x1000]; enum nvme_get_features_sel sel = NVME_GET_FEATURES_SEL_CURRENT; - int ret, temp, fd = nvme_ctrl_get_fd(c); - struct nvme_error_log_page error[64]; + nvme_link_t l = nvme_ctrl_get_link(c); + int ret, temp; + struct nvme_error_log_page error[64]; struct nvme_smart_log smart = { 0 }; struct nvme_firmware_slot fw = { 0 }; struct nvme_ns_list ns_list = { 0 }; @@ -69,7 +70,7 @@ static int test_ctrl(nvme_ctrl_t c) printf("PASSED: Identify controller\n"); } - ret = nvme_get_log_smart(fd, NVME_NSID_ALL, true, &smart); + ret = nvme_get_log_smart(l, NVME_NSID_ALL, true, &smart); if (ret) { printf("ERROR: no smart log for:%s %#x\n", nvme_ctrl_get_name(c), ret); return ret; @@ -88,42 +89,42 @@ static int test_ctrl(nvme_ctrl_t c) printf(" sn:%-.20s\n", id.sn); printf(" model:%-.40s\n", id.mn); - ret = nvme_identify_allocated_ns_list(fd, 0, &ns_list); + ret = nvme_identify_allocated_ns_list(l, 0, &ns_list); if (!ret) printf(" PASSED: Allocated NS List\n"); else printf(" ERROR: Allocated NS List:%x\n", ret); - ret = nvme_identify_active_ns_list(fd, 0, &ns_list); + ret = nvme_identify_active_ns_list(l, 0, &ns_list); if (!ret) printf(" PASSED: Active NS List\n"); else printf(" ERROR: Active NS List:%x\n", ret); - ret = nvme_identify_ctrl_list(fd, 0, &ctrlist); + ret = nvme_identify_ctrl_list(l, 0, &ctrlist); if (!ret) printf(" PASSED: Ctrl List\n"); else printf(" ERROR: CtrlList:%x\n", ret); - ret = nvme_identify_nsid_ctrl_list(fd, 1, 0, &ctrlist); + ret = nvme_identify_nsid_ctrl_list(l, 1, 0, &ctrlist); if (!ret) printf(" PASSED: NSID Ctrl List\n"); else printf(" ERROR: NSID CtrlList:%x\n", ret); - ret = nvme_identify_primary_ctrl(fd, 0, &prim); + ret = nvme_identify_primary_ctrl(l, 0, &prim); if (!ret) printf(" PASSED: Identify Primary\n"); else printf(" ERROR: Identify Primary:%x\n", ret); - ret = nvme_identify_secondary_ctrl_list(fd, 0, &sec); + ret = nvme_identify_secondary_ctrl_list(l, 0, &sec); if (!ret) printf(" PASSED: Identify Secondary\n"); else printf(" ERROR: Identify Secondary:%x\n", ret); - ret = nvme_identify_ns_granularity(fd, &gran); + ret = nvme_identify_ns_granularity(l, &gran); if (!ret) printf(" PASSED: Identify NS granularity\n"); else printf(" ERROR: Identify NS granularity:%x\n", ret); - ret = nvme_identify_uuid(fd, &uuid); + ret = nvme_identify_uuid(l, &uuid); if (!ret) printf(" PASSED: Identify UUID List\n"); else @@ -132,133 +133,133 @@ static int test_ctrl(nvme_ctrl_t c) printf("\nLogs\n"); printf(" SMART: Current temperature:%d percent used:%d%%\n", temp, smart.percent_used); - ret = nvme_get_log_sanitize(fd, true, &sanlog); + ret = nvme_get_log_sanitize(l, true, &sanlog); if (!ret) printf(" Sanitize Log:\n"); else printf(" ERROR: Sanitize Log:%x\n", ret); - ret = nvme_get_log_reservation(fd, true, &resvnotify); + ret = nvme_get_log_reservation(l, true, &resvnotify); if (!ret) printf(" Reservation Log\n"); else printf(" ERROR: Reservation Log:%x\n", ret); - ret = nvme_get_log_ana_groups(fd, true, sizeof(buf), analog); + ret = nvme_get_log_ana_groups(l, true, analog, sizeof(buf)); if (!ret) printf(" ANA Groups\n"); else printf(" ERROR: ANA Groups:%x\n", ret); - ret = nvme_get_log_endurance_group(fd, 0, &eglog); + ret = nvme_get_log_endurance_group(l, 0, &eglog); if (!ret) printf(" Endurance Group\n"); else printf(" ERROR: Endurance Group:%x\n", ret); - ret = nvme_get_log_telemetry_ctrl(fd, true, 0, sizeof(buf), telem); + ret = nvme_get_log_telemetry_ctrl(l, true, 0, telem, sizeof(buf)); if (!ret) printf(" Telemetry Controller\n"); else printf(" ERROR: Telemetry Controller:%x\n", ret); - ret = nvme_get_log_device_self_test(fd, &st); + ret = nvme_get_log_device_self_test(l, &st); if (!ret) printf(" Device Self Test\n"); else printf(" ERROR: Device Self Test:%x\n", ret); - ret = nvme_get_log_cmd_effects(fd, NVME_CSI_NVM, &cfx); + ret = nvme_get_log_cmd_effects(l, NVME_CSI_NVM, &cfx); if (!ret) printf(" Command Effects\n"); else printf(" ERROR: Command Effects:%x\n", ret); - ret = nvme_get_log_changed_ns_list(fd, true, &ns_list); + ret = nvme_get_log_changed_ns_list(l, true, &ns_list); if (!ret) printf(" Change NS List\n"); else printf(" ERROR: Change NS List:%x\n", ret); - ret = nvme_get_log_fw_slot(fd, true, &fw); + ret = nvme_get_log_fw_slot(l, true, &fw); if (!ret) printf(" FW Slot\n"); else printf(" ERROR: FW Slot%x\n", ret); - ret = nvme_get_log_error(fd, 64, true, error); + ret = nvme_get_log_error(l, 64, true, error); if (!ret) printf(" Error Log\n"); else printf(" ERROR: Error Log:%x\n", ret); printf("\nFeatures\n"); - ret = nvme_get_features_arbitration(fd, sel, &result); + ret = nvme_get_features_arbitration(l, sel, &result); if (!ret) printf(" Arbitration:%x\n", result); else if (ret > 0) printf(" ERROR: Arbitration:%x\n", ret); - ret = nvme_get_features_power_mgmt(fd, sel, &result); + ret = nvme_get_features_power_mgmt(l, sel, &result); if (!ret) printf(" Power Management:%x\n", result); else if (ret > 0) printf(" ERROR: Power Management:%x\n", ret); - ret = nvme_get_features_temp_thresh(fd, sel, 0, 0, &result); + ret = nvme_get_features_temp_thresh(l, sel, 0, 0, &result); if (!ret) printf(" Temperature Threshold:%x\n", result); else if (ret > 0) printf(" ERROR: Temperature Threshold:%x\n", ret); - ret = nvme_get_features_volatile_wc(fd, sel, &result); + ret = nvme_get_features_volatile_wc(l, sel, &result); if (!ret) printf(" Volatile Write Cache:%x\n", result); else if (ret > 0) printf(" ERROR: Volatile Write Cache:%x\n", ret); - ret = nvme_get_features_num_queues(fd, sel, &result); + ret = nvme_get_features_num_queues(l, sel, &result); if (!ret) printf(" Number of Queues:%x\n", result); else if (ret > 0) printf(" ERROR: Number of Queues:%x\n", ret); - ret = nvme_get_features_irq_coalesce(fd, sel, &result); + ret = nvme_get_features_irq_coalesce(l, sel, &result); if (!ret) printf(" IRQ Coalescing:%x\n", result); else if (ret > 0) printf(" ERROR: IRQ Coalescing:%x\n", ret); - ret = nvme_get_features_write_atomic(fd, sel, &result); + ret = nvme_get_features_write_atomic(l, sel, &result); if (!ret) printf(" Write Atomic:%x\n", result); else if (ret > 0) printf(" ERROR: Write Atomic:%x\n", ret); - ret = nvme_get_features_async_event(fd, sel, &result); + ret = nvme_get_features_async_event(l, sel, &result); if (!ret) printf(" Asycn Event Config:%x\n", result); else if (ret > 0) printf(" ERROR: Asycn Event Config:%x\n", ret); - ret = nvme_get_features_hctm(fd, sel, &result); + ret = nvme_get_features_hctm(l, sel, &result); if (!ret) printf(" HCTM:%x\n", result); else if (ret > 0) printf(" ERROR: HCTM:%x\n", ret); - ret = nvme_get_features_nopsc(fd, sel, &result); + ret = nvme_get_features_nopsc(l, sel, &result); if (!ret) printf(" NOP Power State Config:%x\n", result); else if (ret > 0) printf(" ERROR: NOP Power State Configrbitration:%x\n", ret); - ret = nvme_get_features_rrl(fd, sel, &result); + ret = nvme_get_features_rrl(l, sel, &result); if (!ret) printf(" Read Recover Levels:%x\n", result); else if (ret > 0) printf(" ERROR: Read Recover Levels:%x\n", ret); - ret = nvme_get_features_lba_sts_interval(fd, sel, &result); + ret = nvme_get_features_lba_sts_interval(l, sel, &result); if (!ret) printf(" LBA Status Interval:%x\n", result); else if (ret > 0) printf(" ERROR: LBA Status Interval:%x\n", ret); - ret = nvme_get_features_sanitize(fd, sel, &result); + ret = nvme_get_features_sanitize(l, sel, &result); if (!ret) printf(" Sanitize:%x\n", result); else if (ret > 0) printf(" ERROR: SW Progress Marker:%x\n", ret); - ret = nvme_get_features_sw_progress(fd, sel, &result); + ret = nvme_get_features_sw_progress(l, sel, &result); if (!ret) printf(" SW Progress Marker:%x\n", result); else if (ret > 0) printf(" ERROR: Sanitize:%x\n", ret); - ret = nvme_get_features_resv_mask(fd, sel, 0, &result); + ret = nvme_get_features_resv_mask(l, sel, 0, &result); if (!ret) printf(" Reservation Mask:%x\n", result); else if (ret > 0) printf(" ERROR: Reservation Mask:%x\n", ret); - ret = nvme_get_features_resv_persist(fd, sel, 0, &result); + ret = nvme_get_features_resv_persist(l, sel, 0, &result); if (!ret) printf(" Reservation Persistence:%x\n", result); else if (ret > 0) @@ -268,7 +269,8 @@ static int test_ctrl(nvme_ctrl_t c) static int test_namespace(nvme_ns_t n) { - int ret, nsid = nvme_ns_get_nsid(n), fd = nvme_ns_get_fd(n); + int ret, nsid = nvme_ns_get_nsid(n); + nvme_link_t l = nvme_ns_get_link(n); struct nvme_id_ns ns = { 0 }, allocated = { 0 }; struct nvme_ns_id_desc *descs; __u32 result = 0; @@ -283,7 +285,7 @@ static int test_namespace(nvme_ns_t n) nvme_ns_get_name(n), le64_to_cpu(ns.nsze), 1 << ns.lbaf[flbas].ds); - ret = nvme_identify_allocated_ns(fd, nsid, &allocated); + ret = nvme_identify_allocated_ns(l, nsid, &allocated); if (!ret) printf(" Identify allocated ns\n"); else @@ -292,13 +294,13 @@ static int test_namespace(nvme_ns_t n) if (!descs) return -1; - ret = nvme_identify_ns_descs(fd, nsid, descs); + ret = nvme_identify_ns_descs(l, nsid, descs); if (!ret) printf(" Identify NS Descriptors\n"); else printf(" ERROR: Identify NS Descriptors:%x\n", ret); free(descs); - ret = nvme_get_features_write_protect(fd, nsid, + ret = nvme_get_features_write_protect(l, nsid, NVME_GET_FEATURES_SEL_CURRENT, &result); if (!ret) printf(" Write Protect:%x\n", result); @@ -349,8 +351,7 @@ int main(int argc, char **argv) ctrl = argv[1]; printf("Test scan specific controller\n"); - c = nvme_scan_ctrl(r, ctrl); - if (c) { + if (!nvme_scan_ctrl(r, ctrl, &c)) { printf("%s %s %s %s\n", nvme_ctrl_get_name(c), nvme_ctrl_get_transport(c), nvme_ctrl_get_address(c), @@ -358,10 +359,9 @@ int main(int argc, char **argv) nvme_free_ctrl(c); } printf("\n"); - nvme_free_tree(r); + nvme_free_root(r); - r = nvme_scan(NULL); - if (!r) + if (nvme_scan(NULL, &r)) return -1; printf("Test walking the topology\n"); @@ -426,7 +426,7 @@ int main(int argc, char **argv) } } } - nvme_free_tree(r); + nvme_free_root(r); return 0; } diff --git a/test/tree.c b/test/tree.c index c9370f971..0eb155626 100644 --- a/test/tree.c +++ b/test/tree.c @@ -125,7 +125,7 @@ static nvme_root_t create_tree() r = nvme_create_root(stdout, LOG_DEBUG); assert(r); - h = nvme_default_host(r); + nvme_default_host(r, &h); assert(h); printf(" ctrls created:\n"); @@ -261,7 +261,7 @@ static bool test_lookup(void) pass = count_entries(r) == ARRAY_SIZE(test_data); pass &= ctrl_lookups(r); - nvme_free_tree(r); + nvme_free_root(r); return pass; } @@ -281,7 +281,7 @@ static bool test_src_addr() r = nvme_create_root(stdout, LOG_DEBUG); assert(r); - h = nvme_default_host(r); + nvme_default_host(r, &h); assert(h); s = nvme_lookup_subsystem(h, DEFAULT_SUBSYSNAME, DEFAULT_SUBSYSNQN); @@ -407,7 +407,7 @@ static bool test_src_addr() c->address = NULL; /* Needed to avoid freeing non-malloced memory (see above) */ - nvme_free_tree(r); + nvme_free_root(r); return pass; } @@ -457,7 +457,7 @@ static bool ctrl_match(const char *tag, r = nvme_create_root(stdout, LOG_INFO); assert(r); - h = nvme_default_host(r); + nvme_default_host(r, &h); assert(h); s = nvme_lookup_subsystem(h, DEFAULT_SUBSYSNAME, reference->subsysnqn ? reference->subsysnqn : DEFAULT_SUBSYSNQN); @@ -524,7 +524,7 @@ static bool ctrl_match(const char *tag, reference_ctrl->name = NULL; reference_ctrl->address = NULL; - nvme_free_tree(r); + nvme_free_root(r); return true; } @@ -1070,7 +1070,7 @@ static bool ctrl_config_match(const char *tag, r = nvme_create_root(stdout, LOG_INFO); assert(r); - h = nvme_default_host(r); + nvme_default_host(r, &h); assert(h); s = nvme_lookup_subsystem(h, DEFAULT_SUBSYSNAME, reference->subsysnqn ? reference->subsysnqn : DEFAULT_SUBSYSNQN); @@ -1111,7 +1111,7 @@ static bool ctrl_config_match(const char *tag, reference_ctrl->name = NULL; reference_ctrl->address = NULL; - nvme_free_tree(r); + nvme_free_root(r); return true; } diff --git a/test/uriparser.c b/test/uriparser.c index 09b2a732b..428c5495d 100644 --- a/test/uriparser.c +++ b/test/uriparser.c @@ -159,8 +159,7 @@ static void test_uriparser(void) int i; printf(" '%s'...", d->uri); - parsed_data = nvme_parse_uri(d->uri); - assert(parsed_data); + assert(!nvme_parse_uri(d->uri, &parsed_data)); assert(strcmp(d->scheme, parsed_data->scheme) == 0); if (d->proto) { @@ -201,10 +200,10 @@ static void test_uriparser_bad(void) { printf("Testing malformed URI strings:\n"); for (int i = 0; i < ARRAY_SIZE(test_data_bad); i++) { - struct nvme_fabrics_uri *parsed_data; + struct nvme_fabrics_uri *parsed_data = NULL; printf(" '%s'...", test_data_bad[i]); - parsed_data = nvme_parse_uri(test_data_bad[i]); + assert(nvme_parse_uri(test_data_bad[i], &parsed_data)); assert(parsed_data == NULL); printf(" OK\n"); } diff --git a/test/zns.c b/test/zns.c index 6d06d7257..742a7297d 100644 --- a/test/zns.c +++ b/test/zns.c @@ -1,12 +1,12 @@ // SPDX-License-Identifier: LGPL-2.1-or-later -/** +/* * This file is part of libnvme. * Copyright (c) 2020 Western Digital Corporation or its affiliates. * * Authors: Keith Busch */ -/** +/* * Search out for ZNS type namespaces, and if found, report their properties. */ #include @@ -29,7 +29,7 @@ static void show_zns_properties(nvme_ns_t n) if (!zr) return; - if (nvme_zns_identify_ns(nvme_ns_get_fd(n), nvme_ns_get_nsid(n), + if (nvme_zns_identify_ns(nvme_ns_get_link(n), nvme_ns_get_nsid(n), &zns_ns)) { fprintf(stderr, "failed to identify zns ns\n");; } @@ -38,7 +38,7 @@ static void show_zns_properties(nvme_ns_t n) le16_to_cpu(zns_ns.ozcs), le32_to_cpu(zns_ns.mar), le32_to_cpu(zns_ns.mor)); - if (nvme_zns_identify_ctrl(nvme_ns_get_fd(n), &zns_ctrl)) { + if (nvme_zns_identify_ctrl(nvme_ns_get_link(n), &zns_ctrl)) { fprintf(stderr, "failed to identify zns ctrl\n");; free(zr); return; @@ -46,10 +46,9 @@ static void show_zns_properties(nvme_ns_t n) printf("zasl:%u\n", zns_ctrl.zasl); - if (nvme_zns_report_zones(nvme_ns_get_fd(n), nvme_ns_get_nsid(n), 0, - NVME_ZNS_ZRAS_REPORT_ALL, false, - true, 0x1000, (void *)zr, - NVME_DEFAULT_IOCTL_TIMEOUT, &result)) { + if (nvme_zns_report_zones(nvme_ns_get_link(n), nvme_ns_get_nsid(n), 0, + NVME_ZNS_ZRAS_REPORT_ALL, false, true, 0x1000, (void *)zr, + &result)) { fprintf(stderr, "failed to report zones, result %x\n", le32_to_cpu(result)); free(zr); @@ -68,8 +67,7 @@ int main() nvme_ctrl_t c; nvme_ns_t n; - r = nvme_scan(NULL); - if (!r) + if (nvme_scan(NULL, &r)) return -1; nvme_for_each_host(r, h) { @@ -86,5 +84,5 @@ int main() } } } - nvme_free_tree(r); + nvme_free_root(r); }