summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2023-12-24 07:51:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2023-12-24 07:51:44 +0000
commit4da5b4b2fba02bd3e78f16828359cef79a757911 (patch)
tree326db4edaddfc20f78fb048509fd646f497e2a65
parentAdding upstream version 1.5. (diff)
downloadlibnvme-4da5b4b2fba02bd3e78f16828359cef79a757911.tar.xz
libnvme-4da5b4b2fba02bd3e78f16828359cef79a757911.zip
Adding upstream version 1.7.1.upstream/1.7.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--.checkpatch.conf24
-rw-r--r--.github/workflows/build.yml70
-rw-r--r--.github/workflows/checkpatch.yml15
-rw-r--r--.github/workflows/coverage.yml30
-rw-r--r--.github/workflows/release-python.yml16
-rw-r--r--.github/workflows/release.yml4
-rw-r--r--.readthedocs.yaml3
-rw-r--r--README.md26
-rw-r--r--codecov.yml6
-rw-r--r--doc/conf.py2
-rw-r--r--doc/man/nbft_control.22
-rw-r--r--doc/man/nbft_control_flags.22
-rw-r--r--doc/man/nbft_desc_type.22
-rw-r--r--doc/man/nbft_discovery.22
-rw-r--r--doc/man/nbft_discovery_flags.22
-rw-r--r--doc/man/nbft_header.22
-rw-r--r--doc/man/nbft_heap_obj.22
-rw-r--r--doc/man/nbft_hfi.22
-rw-r--r--doc/man/nbft_hfi_flags.22
-rw-r--r--doc/man/nbft_hfi_info_tcp.22
-rw-r--r--doc/man/nbft_hfi_info_tcp_flags.22
-rw-r--r--doc/man/nbft_host.22
-rw-r--r--doc/man/nbft_host_flags.22
-rw-r--r--doc/man/nbft_info.22
-rw-r--r--doc/man/nbft_info_discovery.22
-rw-r--r--doc/man/nbft_info_hfi.22
-rw-r--r--doc/man/nbft_info_hfi_info_tcp.22
-rw-r--r--doc/man/nbft_info_host.22
-rw-r--r--doc/man/nbft_info_nid_type.22
-rw-r--r--doc/man/nbft_info_primary_admin_host_flag.22
-rw-r--r--doc/man/nbft_info_security.22
-rw-r--r--doc/man/nbft_info_subsystem_ns.22
-rw-r--r--doc/man/nbft_security.22
-rw-r--r--doc/man/nbft_security_flags.22
-rw-r--r--doc/man/nbft_security_secret_type.22
-rw-r--r--doc/man/nbft_ssns.22
-rw-r--r--doc/man/nbft_ssns_ext_info.22
-rw-r--r--doc/man/nbft_ssns_ext_info_flags.22
-rw-r--r--doc/man/nbft_ssns_flags.22
-rw-r--r--doc/man/nbft_ssns_trflags.22
-rw-r--r--doc/man/nbft_trtype.22
-rw-r--r--doc/man/nvme_admin_opcode.22
-rw-r--r--doc/man/nvme_admin_passthru.22
-rw-r--r--doc/man/nvme_admin_passthru64.22
-rw-r--r--doc/man/nvme_ae_info_css_nvm.22
-rw-r--r--doc/man/nvme_ae_info_error.22
-rw-r--r--doc/man/nvme_ae_info_notice.22
-rw-r--r--doc/man/nvme_ae_info_smart.22
-rw-r--r--doc/man/nvme_ae_type.22
-rw-r--r--doc/man/nvme_aggregate_endurance_group_event.22
-rw-r--r--doc/man/nvme_aggregate_predictable_lat_event.22
-rw-r--r--doc/man/nvme_ana_group_desc.22
-rw-r--r--doc/man/nvme_ana_log.22
-rw-r--r--doc/man/nvme_ana_state.22
-rw-r--r--doc/man/nvme_apst_entry.22
-rw-r--r--doc/man/nvme_boot_partition.22
-rw-r--r--doc/man/nvme_capacity_config_desc.22
-rw-r--r--doc/man/nvme_capacity_mgmt.22
-rw-r--r--doc/man/nvme_change_ns_event.22
-rw-r--r--doc/man/nvme_channel_config_desc.22
-rw-r--r--doc/man/nvme_cmb_size.22
-rw-r--r--doc/man/nvme_cmd_effects.22
-rw-r--r--doc/man/nvme_cmd_effects_log.22
-rw-r--r--doc/man/nvme_cmd_format_mset.22
-rw-r--r--doc/man/nvme_cmd_format_pi.22
-rw-r--r--doc/man/nvme_cmd_format_pil.22
-rw-r--r--doc/man/nvme_cmd_format_ses.22
-rw-r--r--doc/man/nvme_cmd_get_log_lid.28
-rw-r--r--doc/man/nvme_cmd_get_log_telemetry_host_lsp.22
-rw-r--r--doc/man/nvme_compare.22
-rw-r--r--doc/man/nvme_connect_err.22
-rw-r--r--doc/man/nvme_constants.22
-rw-r--r--doc/man/nvme_copy.22
-rw-r--r--doc/man/nvme_copy_range.22
-rw-r--r--doc/man/nvme_copy_range_f1.22
-rw-r--r--doc/man/nvme_copy_range_f2.248
-rw-r--r--doc/man/nvme_copy_range_f3.252
-rw-r--r--doc/man/nvme_copy_range_sopt.212
-rw-r--r--doc/man/nvme_create_ctrl.22
-rw-r--r--doc/man/nvme_create_root.22
-rw-r--r--doc/man/nvme_csi.22
-rw-r--r--doc/man/nvme_ctrl_config_match.233
-rw-r--r--doc/man/nvme_ctrl_find.237
-rw-r--r--doc/man/nvme_ctrl_first_ns.22
-rw-r--r--doc/man/nvme_ctrl_first_path.22
-rw-r--r--doc/man/nvme_ctrl_for_each_ns.22
-rw-r--r--doc/man/nvme_ctrl_for_each_ns_safe.22
-rw-r--r--doc/man/nvme_ctrl_for_each_path.22
-rw-r--r--doc/man/nvme_ctrl_for_each_path_safe.22
-rw-r--r--doc/man/nvme_ctrl_get_address.22
-rw-r--r--doc/man/nvme_ctrl_get_config.22
-rw-r--r--doc/man/nvme_ctrl_get_dhchap_host_key.22
-rw-r--r--doc/man/nvme_ctrl_get_dhchap_key.22
-rw-r--r--doc/man/nvme_ctrl_get_fd.29
-rw-r--r--doc/man/nvme_ctrl_get_firmware.22
-rw-r--r--doc/man/nvme_ctrl_get_host_iface.22
-rw-r--r--doc/man/nvme_ctrl_get_host_traddr.22
-rw-r--r--doc/man/nvme_ctrl_get_model.22
-rw-r--r--doc/man/nvme_ctrl_get_name.22
-rw-r--r--doc/man/nvme_ctrl_get_numa_node.22
-rw-r--r--doc/man/nvme_ctrl_get_phy_slot.22
-rw-r--r--doc/man/nvme_ctrl_get_queue_count.22
-rw-r--r--doc/man/nvme_ctrl_get_serial.22
-rw-r--r--doc/man/nvme_ctrl_get_sqsize.22
-rw-r--r--doc/man/nvme_ctrl_get_src_addr.217
-rw-r--r--doc/man/nvme_ctrl_get_state.24
-rw-r--r--doc/man/nvme_ctrl_get_subsysnqn.22
-rw-r--r--doc/man/nvme_ctrl_get_subsystem.22
-rw-r--r--doc/man/nvme_ctrl_get_sysfs_dir.22
-rw-r--r--doc/man/nvme_ctrl_get_traddr.22
-rw-r--r--doc/man/nvme_ctrl_get_transport.22
-rw-r--r--doc/man/nvme_ctrl_get_trsvcid.22
-rw-r--r--doc/man/nvme_ctrl_identify.22
-rw-r--r--doc/man/nvme_ctrl_is_discovered.22
-rw-r--r--doc/man/nvme_ctrl_is_discovery_ctrl.22
-rw-r--r--doc/man/nvme_ctrl_is_persistent.22
-rw-r--r--doc/man/nvme_ctrl_is_unique_discovery_ctrl.22
-rw-r--r--doc/man/nvme_ctrl_list.22
-rw-r--r--doc/man/nvme_ctrl_metadata_type.22
-rw-r--r--doc/man/nvme_ctrl_next_ns.22
-rw-r--r--doc/man/nvme_ctrl_next_path.22
-rw-r--r--doc/man/nvme_ctrl_release_fd.29
-rw-r--r--doc/man/nvme_ctrl_reset.22
-rw-r--r--doc/man/nvme_ctrl_set_dhchap_host_key.22
-rw-r--r--doc/man/nvme_ctrl_set_dhchap_key.22
-rw-r--r--doc/man/nvme_ctrl_set_discovered.22
-rw-r--r--doc/man/nvme_ctrl_set_discovery_ctrl.22
-rw-r--r--doc/man/nvme_ctrl_set_persistent.22
-rw-r--r--doc/man/nvme_ctrl_set_unique_discovery_ctrl.22
-rw-r--r--doc/man/nvme_ctrls_filter.22
-rw-r--r--doc/man/nvme_data_tfr.22
-rw-r--r--doc/man/nvme_default_host.22
-rw-r--r--doc/man/nvme_describe_key_serial.22
-rw-r--r--doc/man/nvme_dev_self_test.22
-rw-r--r--doc/man/nvme_directive_dtype.22
-rw-r--r--doc/man/nvme_directive_receive_doper.22
-rw-r--r--doc/man/nvme_directive_recv.22
-rw-r--r--doc/man/nvme_directive_recv_identify_parameters.22
-rw-r--r--doc/man/nvme_directive_recv_stream_allocate.22
-rw-r--r--doc/man/nvme_directive_recv_stream_parameters.22
-rw-r--r--doc/man/nvme_directive_recv_stream_status.22
-rw-r--r--doc/man/nvme_directive_send.22
-rw-r--r--doc/man/nvme_directive_send_doper.22
-rw-r--r--doc/man/nvme_directive_send_id_endir.22
-rw-r--r--doc/man/nvme_directive_send_identify_endir.22
-rw-r--r--doc/man/nvme_directive_send_stream_release_identifier.22
-rw-r--r--doc/man/nvme_directive_send_stream_release_resource.22
-rw-r--r--doc/man/nvme_directive_types.22
-rw-r--r--doc/man/nvme_disconnect_ctrl.22
-rw-r--r--doc/man/nvme_dsm.22
-rw-r--r--doc/man/nvme_dsm_attributes.22
-rw-r--r--doc/man/nvme_dsm_range.22
-rw-r--r--doc/man/nvme_dst_stc.22
-rw-r--r--doc/man/nvme_dump_config.22
-rw-r--r--doc/man/nvme_dump_tree.22
-rw-r--r--doc/man/nvme_eg_critical_warning_flags.22
-rw-r--r--doc/man/nvme_eg_event_aggregate_log.22
-rw-r--r--doc/man/nvme_end_grp_chan_desc.22
-rw-r--r--doc/man/nvme_end_grp_config_desc.22
-rw-r--r--doc/man/nvme_endurance_group_log.230
-rw-r--r--doc/man/nvme_eom_lane_desc.263
-rw-r--r--doc/man/nvme_eom_optional_data.218
-rw-r--r--doc/man/nvme_errno_to_string.22
-rw-r--r--doc/man/nvme_error_log_page.22
-rw-r--r--doc/man/nvme_fabrics_config.22
-rw-r--r--doc/man/nvme_fctype.22
-rw-r--r--doc/man/nvme_fdp_config_desc.22
-rw-r--r--doc/man/nvme_fdp_config_fdpa.22
-rw-r--r--doc/man/nvme_fdp_config_log.22
-rw-r--r--doc/man/nvme_fdp_event.22
-rw-r--r--doc/man/nvme_fdp_event_flags.22
-rw-r--r--doc/man/nvme_fdp_event_realloc.22
-rw-r--r--doc/man/nvme_fdp_event_realloc_flags.22
-rw-r--r--doc/man/nvme_fdp_event_type.22
-rw-r--r--doc/man/nvme_fdp_events_log.22
-rw-r--r--doc/man/nvme_fdp_reclaim_unit_handle_status.22
-rw-r--r--doc/man/nvme_fdp_reclaim_unit_handle_update.22
-rw-r--r--doc/man/nvme_fdp_ruh_desc.22
-rw-r--r--doc/man/nvme_fdp_ruh_status.22
-rw-r--r--doc/man/nvme_fdp_ruh_status_desc.22
-rw-r--r--doc/man/nvme_fdp_ruh_type.22
-rw-r--r--doc/man/nvme_fdp_ruha.22
-rw-r--r--doc/man/nvme_fdp_ruhu_desc.22
-rw-r--r--doc/man/nvme_fdp_ruhu_log.22
-rw-r--r--doc/man/nvme_fdp_stats_log.22
-rw-r--r--doc/man/nvme_fdp_supported_event_attributes.22
-rw-r--r--doc/man/nvme_fdp_supported_event_desc.22
-rw-r--r--doc/man/nvme_feat.22
-rw-r--r--doc/man/nvme_feat_auto_pst.22
-rw-r--r--doc/man/nvme_feat_fdp_events_cdw11.22
-rw-r--r--doc/man/nvme_feat_host_behavior.222
-rw-r--r--doc/man/nvme_feat_nswpcfg_state.22
-rw-r--r--doc/man/nvme_feat_plm_window_select.22
-rw-r--r--doc/man/nvme_feat_resv_notify_flags.22
-rw-r--r--doc/man/nvme_feat_tmpthresh_thsel.22
-rw-r--r--doc/man/nvme_features_async_event_config_flags.22
-rw-r--r--doc/man/nvme_features_id.22
-rw-r--r--doc/man/nvme_fid_supported_effects.22
-rw-r--r--doc/man/nvme_fid_supported_effects_log.22
-rw-r--r--doc/man/nvme_firmware_slot.22
-rw-r--r--doc/man/nvme_first_host.22
-rw-r--r--doc/man/nvme_first_subsystem.22
-rw-r--r--doc/man/nvme_flush.22
-rw-r--r--doc/man/nvme_for_each_host.22
-rw-r--r--doc/man/nvme_for_each_host_safe.22
-rw-r--r--doc/man/nvme_for_each_subsystem.22
-rw-r--r--doc/man/nvme_for_each_subsystem_safe.22
-rw-r--r--doc/man/nvme_format_nvm.22
-rw-r--r--doc/man/nvme_format_nvm_compln_event.22
-rw-r--r--doc/man/nvme_format_nvm_start_event.22
-rw-r--r--doc/man/nvme_free_ctrl.22
-rw-r--r--doc/man/nvme_free_host.22
-rw-r--r--doc/man/nvme_free_ns.22
-rw-r--r--doc/man/nvme_free_subsystem.22
-rw-r--r--doc/man/nvme_free_tree.22
-rw-r--r--doc/man/nvme_fw_commit.22
-rw-r--r--doc/man/nvme_fw_commit_ca.22
-rw-r--r--doc/man/nvme_fw_commit_event.22
-rw-r--r--doc/man/nvme_fw_download.22
-rw-r--r--doc/man/nvme_fw_download_seq.22
-rw-r--r--doc/man/nvme_gen_dhchap_key.22
-rw-r--r--doc/man/nvme_generate_tls_key_identity.230
-rw-r--r--doc/man/nvme_get_ana_log_len.22
-rw-r--r--doc/man/nvme_get_attr.22
-rw-r--r--doc/man/nvme_get_ctrl_attr.22
-rw-r--r--doc/man/nvme_get_ctrl_telemetry.22
-rw-r--r--doc/man/nvme_get_directive_receive_length.22
-rw-r--r--doc/man/nvme_get_discovery_args.22
-rw-r--r--doc/man/nvme_get_feature_length.22
-rw-r--r--doc/man/nvme_get_feature_length2.22
-rw-r--r--doc/man/nvme_get_features.22
-rw-r--r--doc/man/nvme_get_features_arbitration.22
-rw-r--r--doc/man/nvme_get_features_async_event.22
-rw-r--r--doc/man/nvme_get_features_auto_pst.22
-rw-r--r--doc/man/nvme_get_features_data.22
-rw-r--r--doc/man/nvme_get_features_endurance_event_cfg.22
-rw-r--r--doc/man/nvme_get_features_err_recovery.26
-rw-r--r--doc/man/nvme_get_features_err_recovery2.221
-rw-r--r--doc/man/nvme_get_features_hctm.22
-rw-r--r--doc/man/nvme_get_features_host_behavior.22
-rw-r--r--doc/man/nvme_get_features_host_id.22
-rw-r--r--doc/man/nvme_get_features_host_mem_buf.26
-rw-r--r--doc/man/nvme_get_features_host_mem_buf2.221
-rw-r--r--doc/man/nvme_get_features_iocs_profile.22
-rw-r--r--doc/man/nvme_get_features_irq_coalesce.22
-rw-r--r--doc/man/nvme_get_features_irq_config.22
-rw-r--r--doc/man/nvme_get_features_kato.22
-rw-r--r--doc/man/nvme_get_features_lba_range.26
-rw-r--r--doc/man/nvme_get_features_lba_range2.224
-rw-r--r--doc/man/nvme_get_features_lba_sts_interval.22
-rw-r--r--doc/man/nvme_get_features_nopsc.22
-rw-r--r--doc/man/nvme_get_features_num_queues.22
-rw-r--r--doc/man/nvme_get_features_plm_config.22
-rw-r--r--doc/man/nvme_get_features_plm_window.22
-rw-r--r--doc/man/nvme_get_features_power_mgmt.22
-rw-r--r--doc/man/nvme_get_features_resv_mask.26
-rw-r--r--doc/man/nvme_get_features_resv_mask2.221
-rw-r--r--doc/man/nvme_get_features_resv_persist.26
-rw-r--r--doc/man/nvme_get_features_resv_persist2.221
-rw-r--r--doc/man/nvme_get_features_rrl.22
-rw-r--r--doc/man/nvme_get_features_sanitize.22
-rw-r--r--doc/man/nvme_get_features_sel.22
-rw-r--r--doc/man/nvme_get_features_simple.22
-rw-r--r--doc/man/nvme_get_features_sw_progress.22
-rw-r--r--doc/man/nvme_get_features_temp_thresh.22
-rw-r--r--doc/man/nvme_get_features_timestamp.22
-rw-r--r--doc/man/nvme_get_features_volatile_wc.22
-rw-r--r--doc/man/nvme_get_features_write_atomic.22
-rw-r--r--doc/man/nvme_get_features_write_protect.22
-rw-r--r--doc/man/nvme_get_host_telemetry.22
-rw-r--r--doc/man/nvme_get_lba_status.22
-rw-r--r--doc/man/nvme_get_lba_status_log.22
-rw-r--r--doc/man/nvme_get_log.22
-rw-r--r--doc/man/nvme_get_log_ana.22
-rw-r--r--doc/man/nvme_get_log_ana_groups.22
-rw-r--r--doc/man/nvme_get_log_boot_partition.22
-rw-r--r--doc/man/nvme_get_log_changed_ns_list.22
-rw-r--r--doc/man/nvme_get_log_cmd_effects.22
-rw-r--r--doc/man/nvme_get_log_create_telemetry_host.22
-rw-r--r--doc/man/nvme_get_log_device_self_test.22
-rw-r--r--doc/man/nvme_get_log_discovery.22
-rw-r--r--doc/man/nvme_get_log_endurance_group.22
-rw-r--r--doc/man/nvme_get_log_endurance_grp_evt.22
-rw-r--r--doc/man/nvme_get_log_error.22
-rw-r--r--doc/man/nvme_get_log_fdp_configurations.22
-rw-r--r--doc/man/nvme_get_log_fdp_events.22
-rw-r--r--doc/man/nvme_get_log_fdp_stats.22
-rw-r--r--doc/man/nvme_get_log_fid_supported_effects.22
-rw-r--r--doc/man/nvme_get_log_fw_slot.22
-rw-r--r--doc/man/nvme_get_log_lba_status.22
-rw-r--r--doc/man/nvme_get_log_media_unit_stat.22
-rw-r--r--doc/man/nvme_get_log_mi_cmd_supported_effects.22
-rw-r--r--doc/man/nvme_get_log_page.22
-rw-r--r--doc/man/nvme_get_log_persistent_event.22
-rw-r--r--doc/man/nvme_get_log_phy_rx_eom.225
-rw-r--r--doc/man/nvme_get_log_predictable_lat_event.22
-rw-r--r--doc/man/nvme_get_log_predictable_lat_nvmset.22
-rw-r--r--doc/man/nvme_get_log_reclaim_unit_handle_usage.22
-rw-r--r--doc/man/nvme_get_log_reservation.22
-rw-r--r--doc/man/nvme_get_log_sanitize.22
-rw-r--r--doc/man/nvme_get_log_smart.22
-rw-r--r--doc/man/nvme_get_log_support_cap_config_list.22
-rw-r--r--doc/man/nvme_get_log_supported_log_pages.22
-rw-r--r--doc/man/nvme_get_log_telemetry_ctrl.22
-rw-r--r--doc/man/nvme_get_log_telemetry_host.22
-rw-r--r--doc/man/nvme_get_log_zns_changed_zones.22
-rw-r--r--doc/man/nvme_get_logical_block_size.22
-rw-r--r--doc/man/nvme_get_new_host_telemetry.22
-rw-r--r--doc/man/nvme_get_ns_attr.22
-rw-r--r--doc/man/nvme_get_nsid.22
-rw-r--r--doc/man/nvme_get_path_attr.22
-rw-r--r--doc/man/nvme_get_property.22
-rw-r--r--doc/man/nvme_get_subsys_attr.22
-rw-r--r--doc/man/nvme_get_telemetry_log.236
-rw-r--r--doc/man/nvme_get_telemetry_max.218
-rw-r--r--doc/man/nvme_hmac_alg.22
-rw-r--r--doc/man/nvme_host_behavior_support.22
-rw-r--r--doc/man/nvme_host_get_dhchap_key.22
-rw-r--r--doc/man/nvme_host_get_hostid.22
-rw-r--r--doc/man/nvme_host_get_hostnqn.22
-rw-r--r--doc/man/nvme_host_get_hostsymname.22
-rw-r--r--doc/man/nvme_host_get_root.22
-rw-r--r--doc/man/nvme_host_is_pdc_enabled.22
-rw-r--r--doc/man/nvme_host_mem_buf_attrs.22
-rw-r--r--doc/man/nvme_host_metadata.22
-rw-r--r--doc/man/nvme_host_release_fds.213
-rw-r--r--doc/man/nvme_host_set_dhchap_key.22
-rw-r--r--doc/man/nvme_host_set_hostsymname.22
-rw-r--r--doc/man/nvme_host_set_pdc_enabled.22
-rw-r--r--doc/man/nvme_id_ctrl.212
-rw-r--r--doc/man/nvme_id_ctrl_anacap.22
-rw-r--r--doc/man/nvme_id_ctrl_apsta.22
-rw-r--r--doc/man/nvme_id_ctrl_avscc.22
-rw-r--r--doc/man/nvme_id_ctrl_cmic.22
-rw-r--r--doc/man/nvme_id_ctrl_cntrltype.22
-rw-r--r--doc/man/nvme_id_ctrl_cqes.22
-rw-r--r--doc/man/nvme_id_ctrl_ctratt.22
-rw-r--r--doc/man/nvme_id_ctrl_dctype.22
-rw-r--r--doc/man/nvme_id_ctrl_dsto.22
-rw-r--r--doc/man/nvme_id_ctrl_fcatt.22
-rw-r--r--doc/man/nvme_id_ctrl_fna.22
-rw-r--r--doc/man/nvme_id_ctrl_frmw.22
-rw-r--r--doc/man/nvme_id_ctrl_fuses.22
-rw-r--r--doc/man/nvme_id_ctrl_hctm.22
-rw-r--r--doc/man/nvme_id_ctrl_lpa.22
-rw-r--r--doc/man/nvme_id_ctrl_mec.22
-rw-r--r--doc/man/nvme_id_ctrl_nvm.22
-rw-r--r--doc/man/nvme_id_ctrl_nvmsr.22
-rw-r--r--doc/man/nvme_id_ctrl_nvscc.22
-rw-r--r--doc/man/nvme_id_ctrl_nwpc.22
-rw-r--r--doc/man/nvme_id_ctrl_oacs.22
-rw-r--r--doc/man/nvme_id_ctrl_oaes.22
-rw-r--r--doc/man/nvme_id_ctrl_ofcs.22
-rw-r--r--doc/man/nvme_id_ctrl_oncs.220
-rw-r--r--doc/man/nvme_id_ctrl_rpmbs.22
-rw-r--r--doc/man/nvme_id_ctrl_sanicap.22
-rw-r--r--doc/man/nvme_id_ctrl_sgls.22
-rw-r--r--doc/man/nvme_id_ctrl_sqes.22
-rw-r--r--doc/man/nvme_id_ctrl_vwc.22
-rw-r--r--doc/man/nvme_id_ctrl_vwci.22
-rw-r--r--doc/man/nvme_id_directives.22
-rw-r--r--doc/man/nvme_id_domain_attr.22
-rw-r--r--doc/man/nvme_id_domain_list.22
-rw-r--r--doc/man/nvme_id_endurance_group_list.22
-rw-r--r--doc/man/nvme_id_independent_id_ns.22
-rw-r--r--doc/man/nvme_id_iocs.22
-rw-r--r--doc/man/nvme_id_ns.28
-rw-r--r--doc/man/nvme_id_ns_attr.22
-rw-r--r--doc/man/nvme_id_ns_dlfeat.22
-rw-r--r--doc/man/nvme_id_ns_dpc.22
-rw-r--r--doc/man/nvme_id_ns_dps.22
-rw-r--r--doc/man/nvme_id_ns_flbas.22
-rw-r--r--doc/man/nvme_id_ns_granularity_desc.22
-rw-r--r--doc/man/nvme_id_ns_granularity_list.22
-rw-r--r--doc/man/nvme_id_ns_mc.22
-rw-r--r--doc/man/nvme_id_ns_nmic.22
-rw-r--r--doc/man/nvme_id_ns_rescap.22
-rw-r--r--doc/man/nvme_id_nsfeat.22
-rw-r--r--doc/man/nvme_id_nvmset_list.22
-rw-r--r--doc/man/nvme_id_psd.22
-rw-r--r--doc/man/nvme_id_uuid.22
-rw-r--r--doc/man/nvme_id_uuid_list.22
-rw-r--r--doc/man/nvme_id_uuid_list_entry.22
-rw-r--r--doc/man/nvme_identify.22
-rw-r--r--doc/man/nvme_identify_active_ns_list.22
-rw-r--r--doc/man/nvme_identify_active_ns_list_csi.22
-rw-r--r--doc/man/nvme_identify_allocated_ns.22
-rw-r--r--doc/man/nvme_identify_allocated_ns_list.22
-rw-r--r--doc/man/nvme_identify_allocated_ns_list_csi.22
-rw-r--r--doc/man/nvme_identify_cns.22
-rw-r--r--doc/man/nvme_identify_ctrl.22
-rw-r--r--doc/man/nvme_identify_ctrl_csi.22
-rw-r--r--doc/man/nvme_identify_ctrl_list.22
-rw-r--r--doc/man/nvme_identify_domain_list.22
-rw-r--r--doc/man/nvme_identify_endurance_group_list.22
-rw-r--r--doc/man/nvme_identify_independent_identify_ns.22
-rw-r--r--doc/man/nvme_identify_iocs.22
-rw-r--r--doc/man/nvme_identify_iocs_ns_csi_user_data_format.22
-rw-r--r--doc/man/nvme_identify_ns.22
-rw-r--r--doc/man/nvme_identify_ns_csi.22
-rw-r--r--doc/man/nvme_identify_ns_csi_user_data_format.22
-rw-r--r--doc/man/nvme_identify_ns_descs.22
-rw-r--r--doc/man/nvme_identify_ns_granularity.22
-rw-r--r--doc/man/nvme_identify_nsid_ctrl_list.22
-rw-r--r--doc/man/nvme_identify_nvmset_list.22
-rw-r--r--doc/man/nvme_identify_primary_ctrl.22
-rw-r--r--doc/man/nvme_identify_secondary_ctrl_list.25
-rw-r--r--doc/man/nvme_identify_uuid.22
-rw-r--r--doc/man/nvme_init_copy_range.22
-rw-r--r--doc/man/nvme_init_copy_range_f1.22
-rw-r--r--doc/man/nvme_init_copy_range_f2.233
-rw-r--r--doc/man/nvme_init_copy_range_f3.233
-rw-r--r--doc/man/nvme_init_ctrl.22
-rw-r--r--doc/man/nvme_init_ctrl_list.22
-rw-r--r--doc/man/nvme_init_dsm_range.22
-rw-r--r--doc/man/nvme_init_logging.22
-rw-r--r--doc/man/nvme_insert_tls_key.22
-rw-r--r--doc/man/nvme_insert_tls_key_versioned.237
-rw-r--r--doc/man/nvme_io.22
-rw-r--r--doc/man/nvme_io_control_flags.22
-rw-r--r--doc/man/nvme_io_dsm_flags.22
-rw-r--r--doc/man/nvme_io_mgmt_recv.22
-rw-r--r--doc/man/nvme_io_mgmt_recv_mo.22
-rw-r--r--doc/man/nvme_io_mgmt_send.22
-rw-r--r--doc/man/nvme_io_mgmt_send_mo.22
-rw-r--r--doc/man/nvme_io_opcode.22
-rw-r--r--doc/man/nvme_io_passthru.22
-rw-r--r--doc/man/nvme_io_passthru64.22
-rw-r--r--doc/man/nvme_is_64bit_reg.22
-rw-r--r--doc/man/nvme_lba_range_type.22
-rw-r--r--doc/man/nvme_lba_range_type_entry.22
-rw-r--r--doc/man/nvme_lba_rd.22
-rw-r--r--doc/man/nvme_lba_status.22
-rw-r--r--doc/man/nvme_lba_status_atype.22
-rw-r--r--doc/man/nvme_lba_status_desc.22
-rw-r--r--doc/man/nvme_lba_status_log.22
-rw-r--r--doc/man/nvme_lbaf.22
-rw-r--r--doc/man/nvme_lbaf_rp.22
-rw-r--r--doc/man/nvme_lbart.22
-rw-r--r--doc/man/nvme_lbas_ns_element.22
-rw-r--r--doc/man/nvme_lockdown.22
-rw-r--r--doc/man/nvme_log_ana_lsp.22
-rw-r--r--doc/man/nvme_log_phy_rx_eom_action.224
-rw-r--r--doc/man/nvme_log_phy_rx_eom_quality.224
-rw-r--r--doc/man/nvme_lookup_ctrl.22
-rw-r--r--doc/man/nvme_lookup_host.22
-rw-r--r--doc/man/nvme_lookup_key.22
-rw-r--r--doc/man/nvme_lookup_keyring.22
-rw-r--r--doc/man/nvme_lookup_subsystem.22
-rw-r--r--doc/man/nvme_media_unit_config_desc.22
-rw-r--r--doc/man/nvme_media_unit_stat_desc.22
-rw-r--r--doc/man/nvme_media_unit_stat_log.22
-rw-r--r--doc/man/nvme_metadata_element_desc.22
-rw-r--r--doc/man/nvme_mi_admin_admin_passthru.22
-rw-r--r--doc/man/nvme_mi_admin_format_nvm.22
-rw-r--r--doc/man/nvme_mi_admin_fw_commit.22
-rw-r--r--doc/man/nvme_mi_admin_fw_download.22
-rw-r--r--doc/man/nvme_mi_admin_get_features_data.22
-rw-r--r--doc/man/nvme_mi_admin_get_log.22
-rw-r--r--doc/man/nvme_mi_admin_get_log_ana.22
-rw-r--r--doc/man/nvme_mi_admin_get_log_ana_groups.22
-rw-r--r--doc/man/nvme_mi_admin_get_log_boot_partition.22
-rw-r--r--doc/man/nvme_mi_admin_get_log_changed_ns_list.22
-rw-r--r--doc/man/nvme_mi_admin_get_log_cmd_effects.22
-rw-r--r--doc/man/nvme_mi_admin_get_log_create_telemetry_host.22
-rw-r--r--doc/man/nvme_mi_admin_get_log_device_self_test.22
-rw-r--r--doc/man/nvme_mi_admin_get_log_discovery.22
-rw-r--r--doc/man/nvme_mi_admin_get_log_endurance_group.22
-rw-r--r--doc/man/nvme_mi_admin_get_log_endurance_grp_evt.22
-rw-r--r--doc/man/nvme_mi_admin_get_log_error.22
-rw-r--r--doc/man/nvme_mi_admin_get_log_fid_supported_effects.22
-rw-r--r--doc/man/nvme_mi_admin_get_log_fw_slot.22
-rw-r--r--doc/man/nvme_mi_admin_get_log_lba_status.22
-rw-r--r--doc/man/nvme_mi_admin_get_log_media_unit_stat.22
-rw-r--r--doc/man/nvme_mi_admin_get_log_mi_cmd_supported_effects.22
-rw-r--r--doc/man/nvme_mi_admin_get_log_page.22
-rw-r--r--doc/man/nvme_mi_admin_get_log_persistent_event.22
-rw-r--r--doc/man/nvme_mi_admin_get_log_phy_rx_eom.225
-rw-r--r--doc/man/nvme_mi_admin_get_log_predictable_lat_event.22
-rw-r--r--doc/man/nvme_mi_admin_get_log_predictable_lat_nvmset.22
-rw-r--r--doc/man/nvme_mi_admin_get_log_reservation.22
-rw-r--r--doc/man/nvme_mi_admin_get_log_sanitize.22
-rw-r--r--doc/man/nvme_mi_admin_get_log_simple.22
-rw-r--r--doc/man/nvme_mi_admin_get_log_smart.22
-rw-r--r--doc/man/nvme_mi_admin_get_log_support_cap_config_list.22
-rw-r--r--doc/man/nvme_mi_admin_get_log_supported_log_pages.22
-rw-r--r--doc/man/nvme_mi_admin_get_log_telemetry_ctrl.22
-rw-r--r--doc/man/nvme_mi_admin_get_log_telemetry_host.22
-rw-r--r--doc/man/nvme_mi_admin_get_log_zns_changed_zones.22
-rw-r--r--doc/man/nvme_mi_admin_get_nsid_log.22
-rw-r--r--doc/man/nvme_mi_admin_identify.22
-rw-r--r--doc/man/nvme_mi_admin_identify_active_ns_list.22
-rw-r--r--doc/man/nvme_mi_admin_identify_allocated_ns.22
-rw-r--r--doc/man/nvme_mi_admin_identify_allocated_ns_list.22
-rw-r--r--doc/man/nvme_mi_admin_identify_cns_nsid.22
-rw-r--r--doc/man/nvme_mi_admin_identify_ctrl.22
-rw-r--r--doc/man/nvme_mi_admin_identify_ctrl_list.22
-rw-r--r--doc/man/nvme_mi_admin_identify_ns.22
-rw-r--r--doc/man/nvme_mi_admin_identify_ns_descs.22
-rw-r--r--doc/man/nvme_mi_admin_identify_nsid_ctrl_list.22
-rw-r--r--doc/man/nvme_mi_admin_identify_partial.22
-rw-r--r--doc/man/nvme_mi_admin_identify_primary_ctrl.22
-rw-r--r--doc/man/nvme_mi_admin_identify_secondary_ctrl_list.25
-rw-r--r--doc/man/nvme_mi_admin_ns_attach.22
-rw-r--r--doc/man/nvme_mi_admin_ns_attach_ctrls.22
-rw-r--r--doc/man/nvme_mi_admin_ns_detach_ctrls.22
-rw-r--r--doc/man/nvme_mi_admin_req_hdr.22
-rw-r--r--doc/man/nvme_mi_admin_resp_hdr.22
-rw-r--r--doc/man/nvme_mi_admin_sanitize_nvm.22
-rw-r--r--doc/man/nvme_mi_admin_security_recv.22
-rw-r--r--doc/man/nvme_mi_admin_security_send.22
-rw-r--r--doc/man/nvme_mi_admin_xfer.22
-rw-r--r--doc/man/nvme_mi_ccs.22
-rw-r--r--doc/man/nvme_mi_close.22
-rw-r--r--doc/man/nvme_mi_close_ctrl.22
-rw-r--r--doc/man/nvme_mi_cmd_supported_effects.22
-rw-r--r--doc/man/nvme_mi_cmd_supported_effects_log.22
-rw-r--r--doc/man/nvme_mi_config_id.22
-rw-r--r--doc/man/nvme_mi_config_smbus_freq.22
-rw-r--r--doc/man/nvme_mi_create_root.22
-rw-r--r--doc/man/nvme_mi_csts.22
-rw-r--r--doc/man/nvme_mi_ctrl_health_status.22
-rw-r--r--doc/man/nvme_mi_ctrl_id.22
-rw-r--r--doc/man/nvme_mi_cwarn.22
-rw-r--r--doc/man/nvme_mi_dtyp.22
-rw-r--r--doc/man/nvme_mi_elem.22
-rw-r--r--doc/man/nvme_mi_free_root.22
-rw-r--r--doc/man/nvme_mi_init_ctrl.22
-rw-r--r--doc/man/nvme_mi_message_type.22
-rw-r--r--doc/man/nvme_mi_mi_opcode.22
-rw-r--r--doc/man/nvme_mi_mi_read_mi_data_ctrl.22
-rw-r--r--doc/man/nvme_mi_mi_read_mi_data_ctrl_list.22
-rw-r--r--doc/man/nvme_mi_mi_read_mi_data_port.22
-rw-r--r--doc/man/nvme_mi_mi_read_mi_data_subsys.22
-rw-r--r--doc/man/nvme_mi_mi_req_hdr.22
-rw-r--r--doc/man/nvme_mi_mi_resp_hdr.22
-rw-r--r--doc/man/nvme_mi_mi_subsystem_health_status_poll.22
-rw-r--r--doc/man/nvme_mi_msg_hdr.22
-rw-r--r--doc/man/nvme_mi_msg_resp.22
-rw-r--r--doc/man/nvme_mi_nvm_ss_health_status.22
-rw-r--r--doc/man/nvme_mi_open_mctp.22
-rw-r--r--doc/man/nvme_mi_osc.22
-rw-r--r--doc/man/nvme_mi_port_pcie.22
-rw-r--r--doc/man/nvme_mi_port_smb.22
-rw-r--r--doc/man/nvme_mi_read_ctrl_info.22
-rw-r--r--doc/man/nvme_mi_read_nvm_ss_info.22
-rw-r--r--doc/man/nvme_mi_read_port_info.22
-rw-r--r--doc/man/nvme_mi_read_sc_list.22
-rw-r--r--doc/man/nvme_mi_resp_status.22
-rw-r--r--doc/man/nvme_mi_set_probe_enabled.22
-rw-r--r--doc/man/nvme_mi_status_to_string.22
-rw-r--r--doc/man/nvme_mi_vpd_hdr.22
-rw-r--r--doc/man/nvme_mi_vpd_mr_common.22
-rw-r--r--doc/man/nvme_mi_vpd_mra.22
-rw-r--r--doc/man/nvme_mi_vpd_ppmra.22
-rw-r--r--doc/man/nvme_mi_vpd_telem.22
-rw-r--r--doc/man/nvme_mi_vpd_tra.22
-rw-r--r--doc/man/nvme_namespace_attach_ctrls.22
-rw-r--r--doc/man/nvme_namespace_detach_ctrls.22
-rw-r--r--doc/man/nvme_namespace_filter.22
-rw-r--r--doc/man/nvme_namespace_first_path.22
-rw-r--r--doc/man/nvme_namespace_for_each_path.22
-rw-r--r--doc/man/nvme_namespace_for_each_path_safe.22
-rw-r--r--doc/man/nvme_namespace_next_path.22
-rw-r--r--doc/man/nvme_nbft_free.22
-rw-r--r--doc/man/nvme_nbft_read.22
-rw-r--r--doc/man/nvme_nd_ns_fpi.22
-rw-r--r--doc/man/nvme_next_host.22
-rw-r--r--doc/man/nvme_next_subsystem.22
-rw-r--r--doc/man/nvme_ns_attach.22
-rw-r--r--doc/man/nvme_ns_attach_ctrls.22
-rw-r--r--doc/man/nvme_ns_attach_sel.22
-rw-r--r--doc/man/nvme_ns_compare.22
-rw-r--r--doc/man/nvme_ns_detach_ctrls.22
-rw-r--r--doc/man/nvme_ns_flush.22
-rw-r--r--doc/man/nvme_ns_get_csi.22
-rw-r--r--doc/man/nvme_ns_get_ctrl.22
-rw-r--r--doc/man/nvme_ns_get_eui64.22
-rw-r--r--doc/man/nvme_ns_get_fd.29
-rw-r--r--doc/man/nvme_ns_get_firmware.22
-rw-r--r--doc/man/nvme_ns_get_generic_name.22
-rw-r--r--doc/man/nvme_ns_get_lba_count.22
-rw-r--r--doc/man/nvme_ns_get_lba_size.22
-rw-r--r--doc/man/nvme_ns_get_lba_util.22
-rw-r--r--doc/man/nvme_ns_get_meta_size.22
-rw-r--r--doc/man/nvme_ns_get_model.22
-rw-r--r--doc/man/nvme_ns_get_name.22
-rw-r--r--doc/man/nvme_ns_get_nguid.22
-rw-r--r--doc/man/nvme_ns_get_nsid.22
-rw-r--r--doc/man/nvme_ns_get_serial.22
-rw-r--r--doc/man/nvme_ns_get_subsystem.22
-rw-r--r--doc/man/nvme_ns_get_sysfs_dir.22
-rw-r--r--doc/man/nvme_ns_get_uuid.22
-rw-r--r--doc/man/nvme_ns_id_desc.22
-rw-r--r--doc/man/nvme_ns_id_desc_nidt.22
-rw-r--r--doc/man/nvme_ns_identify.22
-rw-r--r--doc/man/nvme_ns_identify_descs.22
-rw-r--r--doc/man/nvme_ns_list.22
-rw-r--r--doc/man/nvme_ns_metadata_type.22
-rw-r--r--doc/man/nvme_ns_mgmt.22
-rw-r--r--doc/man/nvme_ns_mgmt_create.22
-rw-r--r--doc/man/nvme_ns_mgmt_delete.22
-rw-r--r--doc/man/nvme_ns_mgmt_host_sw_specified.22
-rw-r--r--doc/man/nvme_ns_mgmt_sel.22
-rw-r--r--doc/man/nvme_ns_read.22
-rw-r--r--doc/man/nvme_ns_release_fd.29
-rw-r--r--doc/man/nvme_ns_rescan.22
-rw-r--r--doc/man/nvme_ns_verify.22
-rw-r--r--doc/man/nvme_ns_write.22
-rw-r--r--doc/man/nvme_ns_write_protect_cfg.22
-rw-r--r--doc/man/nvme_ns_write_uncorrectable.22
-rw-r--r--doc/man/nvme_ns_write_zeros.22
-rw-r--r--doc/man/nvme_nss_hw_err_event.22
-rw-r--r--doc/man/nvme_nvm_id_ns.22
-rw-r--r--doc/man/nvme_nvm_id_ns_elbaf.22
-rw-r--r--doc/man/nvme_nvm_identify_ctrl.22
-rw-r--r--doc/man/nvme_nvmeset_pl_status.22
-rw-r--r--doc/man/nvme_nvmset_attr.22
-rw-r--r--doc/man/nvme_nvmset_pl_events.22
-rw-r--r--doc/man/nvme_nvmset_predictable_lat_log.22
-rw-r--r--doc/man/nvme_open.22
-rw-r--r--doc/man/nvme_passthru_cmd.22
-rw-r--r--doc/man/nvme_passthru_cmd64.22
-rw-r--r--doc/man/nvme_path_get_ana_state.22
-rw-r--r--doc/man/nvme_path_get_ctrl.22
-rw-r--r--doc/man/nvme_path_get_name.22
-rw-r--r--doc/man/nvme_path_get_ns.22
-rw-r--r--doc/man/nvme_path_get_sysfs_dir.22
-rw-r--r--doc/man/nvme_paths_filter.22
-rw-r--r--doc/man/nvme_persistent_event_entry.22
-rw-r--r--doc/man/nvme_persistent_event_log.22
-rw-r--r--doc/man/nvme_persistent_event_types.22
-rw-r--r--doc/man/nvme_pevent_log_action.22
-rw-r--r--doc/man/nvme_phy_rx_eom_log.299
-rw-r--r--doc/man/nvme_phy_rx_eom_progress.224
-rw-r--r--doc/man/nvme_plm_config.22
-rw-r--r--doc/man/nvme_pmr_size.22
-rw-r--r--doc/man/nvme_pmr_throughput.22
-rw-r--r--doc/man/nvme_power_on_reset_info_list.22
-rw-r--r--doc/man/nvme_primary_ctrl_cap.22
-rw-r--r--doc/man/nvme_psd_flags.22
-rw-r--r--doc/man/nvme_psd_power_scale.22
-rw-r--r--doc/man/nvme_psd_ps.22
-rw-r--r--doc/man/nvme_psd_workload.22
-rw-r--r--doc/man/nvme_read.22
-rw-r--r--doc/man/nvme_read_config.22
-rw-r--r--doc/man/nvme_refresh_topology.22
-rw-r--r--doc/man/nvme_register_offsets.22
-rw-r--r--doc/man/nvme_registered_ctrl.22
-rw-r--r--doc/man/nvme_registered_ctrl_ext.22
-rw-r--r--doc/man/nvme_rescan_ctrl.22
-rw-r--r--doc/man/nvme_resv_acquire.22
-rw-r--r--doc/man/nvme_resv_cptpl.22
-rw-r--r--doc/man/nvme_resv_notification_log.22
-rw-r--r--doc/man/nvme_resv_notify_rnlpt.22
-rw-r--r--doc/man/nvme_resv_racqa.22
-rw-r--r--doc/man/nvme_resv_register.22
-rw-r--r--doc/man/nvme_resv_release.22
-rw-r--r--doc/man/nvme_resv_report.22
-rw-r--r--doc/man/nvme_resv_rrega.22
-rw-r--r--doc/man/nvme_resv_rrela.22
-rw-r--r--doc/man/nvme_resv_rtype.22
-rw-r--r--doc/man/nvme_resv_status.22
-rw-r--r--doc/man/nvme_sanitize_compln_event.22
-rw-r--r--doc/man/nvme_sanitize_log_page.22
-rw-r--r--doc/man/nvme_sanitize_nvm.22
-rw-r--r--doc/man/nvme_sanitize_sanact.22
-rw-r--r--doc/man/nvme_sanitize_sstat.22
-rw-r--r--doc/man/nvme_sanitize_start_event.22
-rw-r--r--doc/man/nvme_scan.22
-rw-r--r--doc/man/nvme_scan_ctrl.22
-rw-r--r--doc/man/nvme_scan_ctrl_namespace_paths.22
-rw-r--r--doc/man/nvme_scan_ctrl_namespaces.22
-rw-r--r--doc/man/nvme_scan_ctrls.22
-rw-r--r--doc/man/nvme_scan_namespace.22
-rw-r--r--doc/man/nvme_scan_subsystem_namespaces.22
-rw-r--r--doc/man/nvme_scan_subsystems.22
-rw-r--r--doc/man/nvme_scan_topology.22
-rw-r--r--doc/man/nvme_secondary_ctrl.22
-rw-r--r--doc/man/nvme_secondary_ctrl_list.22
-rw-r--r--doc/man/nvme_security_receive.22
-rw-r--r--doc/man/nvme_security_send.22
-rw-r--r--doc/man/nvme_self_test_log.22
-rw-r--r--doc/man/nvme_set_feature_event.22
-rw-r--r--doc/man/nvme_set_features.22
-rw-r--r--doc/man/nvme_set_features_arbitration.22
-rw-r--r--doc/man/nvme_set_features_async_event.22
-rw-r--r--doc/man/nvme_set_features_auto_pst.22
-rw-r--r--doc/man/nvme_set_features_data.22
-rw-r--r--doc/man/nvme_set_features_endurance_evt_cfg.22
-rw-r--r--doc/man/nvme_set_features_err_recovery.22
-rw-r--r--doc/man/nvme_set_features_hctm.22
-rw-r--r--doc/man/nvme_set_features_host_behavior.22
-rw-r--r--doc/man/nvme_set_features_host_id.22
-rw-r--r--doc/man/nvme_set_features_iocs_profile.218
-rw-r--r--doc/man/nvme_set_features_irq_coalesce.22
-rw-r--r--doc/man/nvme_set_features_irq_config.22
-rw-r--r--doc/man/nvme_set_features_lba_range.24
-rw-r--r--doc/man/nvme_set_features_lba_sts_interval.22
-rw-r--r--doc/man/nvme_set_features_nopsc.22
-rw-r--r--doc/man/nvme_set_features_plm_config.22
-rw-r--r--doc/man/nvme_set_features_plm_window.22
-rw-r--r--doc/man/nvme_set_features_power_mgmt.22
-rw-r--r--doc/man/nvme_set_features_resv_mask.26
-rw-r--r--doc/man/nvme_set_features_resv_mask2.224
-rw-r--r--doc/man/nvme_set_features_resv_persist.26
-rw-r--r--doc/man/nvme_set_features_resv_persist2.224
-rw-r--r--doc/man/nvme_set_features_rrl.22
-rw-r--r--doc/man/nvme_set_features_sanitize.22
-rw-r--r--doc/man/nvme_set_features_simple.22
-rw-r--r--doc/man/nvme_set_features_sw_progress.22
-rw-r--r--doc/man/nvme_set_features_temp_thresh.22
-rw-r--r--doc/man/nvme_set_features_timestamp.22
-rw-r--r--doc/man/nvme_set_features_volatile_wc.22
-rw-r--r--doc/man/nvme_set_features_write_atomic.22
-rw-r--r--doc/man/nvme_set_features_write_protect.26
-rw-r--r--doc/man/nvme_set_features_write_protect2.224
-rw-r--r--doc/man/nvme_set_keyring.22
-rw-r--r--doc/man/nvme_set_property.22
-rw-r--r--doc/man/nvme_set_root.216
-rw-r--r--doc/man/nvme_smart_crit.22
-rw-r--r--doc/man/nvme_smart_egcw.22
-rw-r--r--doc/man/nvme_smart_log.22
-rw-r--r--doc/man/nvme_st_code.22
-rw-r--r--doc/man/nvme_st_curr_op.22
-rw-r--r--doc/man/nvme_st_result.22
-rw-r--r--doc/man/nvme_st_valid_diag_info.22
-rw-r--r--doc/man/nvme_status_code.22
-rw-r--r--doc/man/nvme_status_code_type.22
-rw-r--r--doc/man/nvme_status_equals.22
-rw-r--r--doc/man/nvme_status_field.237
-rw-r--r--doc/man/nvme_status_get_type.22
-rw-r--r--doc/man/nvme_status_get_value.22
-rw-r--r--doc/man/nvme_status_result.22
-rw-r--r--doc/man/nvme_status_to_errno.22
-rw-r--r--doc/man/nvme_status_to_string.22
-rw-r--r--doc/man/nvme_status_type.22
-rw-r--r--doc/man/nvme_streams_directive_params.22
-rw-r--r--doc/man/nvme_streams_directive_status.22
-rw-r--r--doc/man/nvme_submit_admin_passthru.22
-rw-r--r--doc/man/nvme_submit_admin_passthru64.22
-rw-r--r--doc/man/nvme_submit_io_passthru.22
-rw-r--r--doc/man/nvme_submit_io_passthru64.22
-rw-r--r--doc/man/nvme_subsys_filter.22
-rw-r--r--doc/man/nvme_subsys_type.22
-rw-r--r--doc/man/nvme_subsystem_first_ctrl.22
-rw-r--r--doc/man/nvme_subsystem_first_ns.22
-rw-r--r--doc/man/nvme_subsystem_for_each_ctrl.22
-rw-r--r--doc/man/nvme_subsystem_for_each_ctrl_safe.22
-rw-r--r--doc/man/nvme_subsystem_for_each_ns.22
-rw-r--r--doc/man/nvme_subsystem_for_each_ns_safe.22
-rw-r--r--doc/man/nvme_subsystem_get_application.22
-rw-r--r--doc/man/nvme_subsystem_get_host.22
-rw-r--r--doc/man/nvme_subsystem_get_iopolicy.211
-rw-r--r--doc/man/nvme_subsystem_get_name.22
-rw-r--r--doc/man/nvme_subsystem_get_nqn.22
-rw-r--r--doc/man/nvme_subsystem_get_sysfs_dir.22
-rw-r--r--doc/man/nvme_subsystem_get_type.22
-rw-r--r--doc/man/nvme_subsystem_lookup_namespace.22
-rw-r--r--doc/man/nvme_subsystem_next_ctrl.22
-rw-r--r--doc/man/nvme_subsystem_next_ns.22
-rw-r--r--doc/man/nvme_subsystem_release_fds.213
-rw-r--r--doc/man/nvme_subsystem_reset.22
-rw-r--r--doc/man/nvme_subsystem_set_application.22
-rw-r--r--doc/man/nvme_supported_cap_config_list_log.22
-rw-r--r--doc/man/nvme_supported_log_pages.22
-rw-r--r--doc/man/nvme_telemetry_da.22
-rw-r--r--doc/man/nvme_telemetry_log.22
-rw-r--r--doc/man/nvme_thermal_exc_event.22
-rw-r--r--doc/man/nvme_time_stamp_change_event.22
-rw-r--r--doc/man/nvme_timestamp.22
-rw-r--r--doc/man/nvme_unlink_ctrl.22
-rw-r--r--doc/man/nvme_update_config.22
-rw-r--r--doc/man/nvme_uring_cmd.22
-rw-r--r--doc/man/nvme_verify.22
-rw-r--r--doc/man/nvme_version.22
-rw-r--r--doc/man/nvme_virt_mgmt_act.22
-rw-r--r--doc/man/nvme_virt_mgmt_rt.22
-rw-r--r--doc/man/nvme_virtual_mgmt.22
-rw-r--r--doc/man/nvme_write.22
-rw-r--r--doc/man/nvme_write_uncorrectable.22
-rw-r--r--doc/man/nvme_write_zeros.22
-rw-r--r--doc/man/nvme_zns_append.22
-rw-r--r--doc/man/nvme_zns_changed_zone_log.22
-rw-r--r--doc/man/nvme_zns_desc.22
-rw-r--r--doc/man/nvme_zns_id_ctrl.22
-rw-r--r--doc/man/nvme_zns_id_ns.22
-rw-r--r--doc/man/nvme_zns_identify_ctrl.22
-rw-r--r--doc/man/nvme_zns_identify_ns.22
-rw-r--r--doc/man/nvme_zns_lbafe.22
-rw-r--r--doc/man/nvme_zns_mgmt_recv.22
-rw-r--r--doc/man/nvme_zns_mgmt_send.22
-rw-r--r--doc/man/nvme_zns_recv_action.22
-rw-r--r--doc/man/nvme_zns_report_options.22
-rw-r--r--doc/man/nvme_zns_report_zones.22
-rw-r--r--doc/man/nvme_zns_send_action.22
-rw-r--r--doc/man/nvme_zns_za.22
-rw-r--r--doc/man/nvme_zns_zs.22
-rw-r--r--doc/man/nvme_zns_zt.22
-rw-r--r--doc/man/nvme_zone_report.22
-rw-r--r--doc/man/nvmf_add_ctrl.22
-rw-r--r--doc/man/nvmf_addr_family.22
-rw-r--r--doc/man/nvmf_adrfam_str.22
-rw-r--r--doc/man/nvmf_cms_str.22
-rw-r--r--doc/man/nvmf_connect_data.22
-rw-r--r--doc/man/nvmf_connect_disc_entry.22
-rw-r--r--doc/man/nvmf_default_config.22
-rw-r--r--doc/man/nvmf_dim_data.22
-rw-r--r--doc/man/nvmf_dim_entfmt.22
-rw-r--r--doc/man/nvmf_dim_etype.22
-rw-r--r--doc/man/nvmf_dim_tas.22
-rw-r--r--doc/man/nvmf_disc_eflags.22
-rw-r--r--doc/man/nvmf_disc_log_entry.22
-rw-r--r--doc/man/nvmf_discovery_log.22
-rw-r--r--doc/man/nvmf_eflags_str.22
-rw-r--r--doc/man/nvmf_exat_len.22
-rw-r--r--doc/man/nvmf_exattype.22
-rw-r--r--doc/man/nvmf_ext_attr.22
-rw-r--r--doc/man/nvmf_ext_die.22
-rw-r--r--doc/man/nvmf_get_discovery_log.22
-rw-r--r--doc/man/nvmf_get_discovery_wargs.22
-rw-r--r--doc/man/nvmf_hostid_from_file.22
-rw-r--r--doc/man/nvmf_hostnqn_from_file.22
-rw-r--r--doc/man/nvmf_hostnqn_generate.22
-rw-r--r--doc/man/nvmf_log_discovery_lid_support.22
-rw-r--r--doc/man/nvmf_log_discovery_lsp.22
-rw-r--r--doc/man/nvmf_prtype_str.22
-rw-r--r--doc/man/nvmf_qptype_str.22
-rw-r--r--doc/man/nvmf_rdma_cms.22
-rw-r--r--doc/man/nvmf_rdma_prtype.22
-rw-r--r--doc/man/nvmf_rdma_qptype.22
-rw-r--r--doc/man/nvmf_register_ctrl.22
-rw-r--r--doc/man/nvmf_sectype_str.22
-rw-r--r--doc/man/nvmf_subtype_str.22
-rw-r--r--doc/man/nvmf_tcp_sectype.22
-rw-r--r--doc/man/nvmf_treq.22
-rw-r--r--doc/man/nvmf_treq_str.22
-rw-r--r--doc/man/nvmf_trtype.22
-rw-r--r--doc/man/nvmf_trtype_str.22
-rw-r--r--doc/man/nvmf_update_config.22
-rw-r--r--doc/rst/ioctl.rst334
-rw-r--r--doc/rst/linux.rst139
-rw-r--r--doc/rst/log.rst19
-rw-r--r--doc/rst/mi.rst33
-rw-r--r--doc/rst/tree.rst202
-rw-r--r--doc/rst/types.rst469
-rw-r--r--doc/rst/util.rst117
-rw-r--r--internal/meson.build9
-rw-r--r--libnvme/meson.build10
-rw-r--r--meson.build27
-rw-r--r--meson_options.txt1
-rwxr-xr-xscripts/build.sh94
-rw-r--r--src/libnvme-mi.map1
-rw-r--r--src/libnvme.map114
-rw-r--r--src/meson.build3
-rw-r--r--src/nvme/base64.c94
-rw-r--r--src/nvme/base64.h8
-rw-r--r--src/nvme/cleanup.c5
-rw-r--r--src/nvme/cleanup.h24
-rw-r--r--src/nvme/fabrics.c395
-rw-r--r--src/nvme/ioctl.c272
-rw-r--r--src/nvme/ioctl.h262
-rw-r--r--src/nvme/json.c28
-rw-r--r--src/nvme/linux.c829
-rw-r--r--src/nvme/linux.h73
-rw-r--r--src/nvme/log.c19
-rw-r--r--src/nvme/log.h13
-rw-r--r--src/nvme/mi-mctp.c180
-rw-r--r--src/nvme/mi.c15
-rw-r--r--src/nvme/mi.h39
-rw-r--r--src/nvme/nbft.c42
-rw-r--r--src/nvme/private.h10
-rw-r--r--src/nvme/tree.c1006
-rw-r--r--src/nvme/tree.h127
-rw-r--r--src/nvme/types.h282
-rw-r--r--src/nvme/util.c230
-rw-r--r--src/nvme/util.h67
-rw-r--r--subprojects/json-c.wrap17
-rw-r--r--subprojects/openssl.wrap18
-rw-r--r--test/ioctl/discovery.c428
-rw-r--r--test/ioctl/features.c1604
-rw-r--r--test/ioctl/identify.c572
-rw-r--r--test/ioctl/meson.build42
-rw-r--r--test/ioctl/mock.c174
-rw-r--r--test/ioctl/mock.h104
-rw-r--r--test/ioctl/util.c65
-rw-r--r--test/ioctl/util.h19
-rw-r--r--test/meson.build18
-rw-r--r--test/mi-mctp.c118
-rw-r--r--test/mi.c17
-rw-r--r--test/mock-ifaddrs.c123
-rw-r--r--test/test-util.c1
-rw-r--r--test/test.c18
-rw-r--r--test/tree.c1115
894 files changed, 10762 insertions, 2205 deletions
diff --git a/.checkpatch.conf b/.checkpatch.conf
new file mode 100644
index 0000000..5541a56
--- /dev/null
+++ b/.checkpatch.conf
@@ -0,0 +1,24 @@
+# Checkpatch options.
+# REF: https://docs.kernel.org/dev-tools/checkpatch.html
+
+# This isn't actually a Linux kernel tree
+--no-tree
+
+--max-line-length=120
+
+--ignore EMAIL_SUBJECT
+
+# FILE_PATH_CHANGES reports this kind of message:
+# "added, moved or deleted file(s), does MAINTAINERS need updating?"
+--ignore FILE_PATH_CHANGES
+
+
+# Commit messages might contain a Gerrit Change-Id.
+--ignore GERRIT_CHANGE_ID
+
+# Do not check the format of commit messages, as Gerrit's merge commits do not
+# preserve it.
+--ignore GIT_COMMIT_ID
+
+# Avoid "Does not appear to be a unified-diff format patch" message
+--ignore NOT_UNIFIED_DIFF
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 0a9a369..df79f65 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -17,16 +17,13 @@ jobs:
compiler: [gcc, clang]
buildtype: [debug, release]
container:
- image: ghcr.io/igaw/linux-nvme/debian:0.30
+ image: ghcr.io/igaw/linux-nvme/debian.python:latest
steps:
- - uses: actions/checkout@v3
- - uses: actions/setup-python@v4
- with:
- python-version: '3.x'
+ - uses: actions/checkout@v4
- name: build
run: |
scripts/build.sh -b ${{ matrix.buildtype }} -c ${{ matrix.compiler }}
- - uses: actions/upload-artifact@v3
+ - uses: actions/upload-artifact@v4
name: upload logs
if: failure()
with:
@@ -40,34 +37,23 @@ jobs:
matrix:
include:
- arch: armhf
- port: armhf
- compiler: gcc-arm-linux-gnueabihf
- packages:
- arch: s390x
- port: s390x
- compiler: gcc-s390x-linux-gnu
- packages: libgcc-s1:s390x
- arch: ppc64le
- port: ppc64el
- compiler: gcc-powerpc64le-linux-gnu
- packges:
steps:
- - uses: actions/checkout@v3
- - name: set up arm architecture
- run: |
- export release=$(lsb_release -c -s)
- sudo dpkg --add-architecture ${{ matrix.port }}
- sudo sed -i -e 's/deb http/deb [arch=amd64] http/g' /etc/apt/sources.list
- sudo dd of=/etc/apt/sources.list.d/${{ matrix.arch }}.list <<EOF
- deb [arch=${{ matrix.port }}] http://ports.ubuntu.com/ $release main universe restricted"
- deb [arch=${{ matrix.port }}] http://ports.ubuntu.com/ $release-updates main universe restricted"
- EOF
- sudo apt update
- sudo apt install -y meson pkg-config qemu-user-static ${{ matrix.compiler}} libjson-c-dev:${{ matrix.port }} ${{ matrix.packages }}
- - name: build
- run: |
- scripts/build.sh -b release -c gcc -t ${{ matrix.arch }} cross
- - uses: actions/upload-artifact@v3
+ - uses: actions/checkout@v4
+ - name: enable foreign arch
+ uses: dbhi/qus/action@main
+ - name: compile and run unit tests
+ uses: mosteo-actions/docker-run@v1
+ with:
+ image: ghcr.io/igaw/linux-nvme/ubuntu-cross-${{ matrix.arch }}:latest
+ guest-dir: /build
+ host-dir: ${{ github.workspace }}
+ command: |
+ scripts/build.sh -b release -c gcc -t ${{ matrix.arch }} cross
+ params: "--platform linux/amd64"
+ pull-params: "--platform linux/amd64"
+ - uses: actions/upload-artifact@v4
name: upload logs
if: failure()
with:
@@ -79,16 +65,13 @@ jobs:
name: libdbus
runs-on: ubuntu-latest
container:
- image: ghcr.io/igaw/linux-nvme/debian:0.30
+ image: ghcr.io/igaw/linux-nvme/debian:latest
steps:
- - uses: actions/checkout@v3
- - uses: actions/setup-python@v4
- with:
- python-version: '3.x'
+ - uses: actions/checkout@v4
- name: build
run: |
scripts/build.sh -b release -c gcc libdbus
- - uses: actions/upload-artifact@v3
+ - uses: actions/upload-artifact@v4
name: upload logs
if: failure()
with:
@@ -100,17 +83,14 @@ jobs:
name: fallback shared libraries
runs-on: ubuntu-latest
container:
- image: ghcr.io/igaw/linux-nvme/debian:0.30
+ image: ghcr.io/igaw/linux-nvme/debian:latest
if: github.ref == 'refs/heads/master'
steps:
- - uses: actions/checkout@v3
- - uses: actions/setup-python@v4
- with:
- python-version: '3.x'
+ - uses: actions/checkout@v4
- name: build
run: |
scripts/build.sh -b release -c gcc fallback
- - uses: actions/upload-artifact@v3
+ - uses: actions/upload-artifact@v4
if: failure()
with:
name: log files
@@ -121,9 +101,9 @@ jobs:
name: muon minimal static
runs-on: ubuntu-latest
container:
- image: ghcr.io/igaw/linux-nvme/debian:0.30
+ image: ghcr.io/igaw/linux-nvme/debian:latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: build
run: |
scripts/build.sh -m muon
diff --git a/.github/workflows/checkpatch.yml b/.github/workflows/checkpatch.yml
new file mode 100644
index 0000000..8cf5e49
--- /dev/null
+++ b/.github/workflows/checkpatch.yml
@@ -0,0 +1,15 @@
+name: checkpatch review
+on: [pull_request]
+jobs:
+ checkpatch:
+ name: checkpatch review
+ runs-on: ubuntu-latest
+ steps:
+ - name: 'Calculate PR commits + 1'
+ run: echo "PR_FETCH_DEPTH=$(( ${{ github.event.pull_request.commits }} + 1 ))" >> $GITHUB_ENV
+ - uses: actions/checkout@v4
+ with:
+ ref: ${{ github.event.pull_request.head.sha }}
+ fetch-depth: ${{ env.PR_FETCH_DEPTH }}
+ - name: Run checkpatch review
+ uses: webispy/checkpatch-action@v9
diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml
index e26ffab..3ed1f99 100644
--- a/.github/workflows/coverage.yml
+++ b/.github/workflows/coverage.yml
@@ -7,32 +7,16 @@ on:
jobs:
code-coverage:
+ if: github.repository == 'linux-nvme/libnvme'
name: code coverage
runs-on: ubuntu-latest
+ container:
+ image: ghcr.io/igaw/linux-nvme/debian.python:latest
steps:
- - name: install libraries
- run: sudo apt-get install libjson-c-dev libdbus-1-dev lcov
- - uses: actions/checkout@v3
- - uses: actions/setup-python@v4
- with:
- python-version: '3.x'
- - uses: BSFishy/meson-build@v1.0.3
- with:
- # Can't use 'coverage' here, see
- # https://github.com/BSFishy/meson-build/issues/4
- action: test
- options: --verbose
- setup-options: >
- --werror
- --buildtype=release
- --wrap-mode=nofallback
- -Dlibdbus=enabled
- -Db_coverage=true
- meson-version: 0.61.2
- - name: Generate Coverage Report
- # Can't use meson here, see
- # https://github.com/mesonbuild/meson/issues/7895
- run: ninja -C build coverage --verbose
+ - uses: actions/checkout@v4
+ - name: build
+ run: |
+ scripts/build.sh coverage
- uses: codecov/codecov-action@v3
with:
fail_ci_if_error: false
diff --git a/.github/workflows/release-python.yml b/.github/workflows/release-python.yml
index 86dc0de..57f36e7 100644
--- a/.github/workflows/release-python.yml
+++ b/.github/workflows/release-python.yml
@@ -15,16 +15,18 @@ jobs:
build_sdist:
name: Build source distribution
runs-on: ubuntu-latest
+ container:
+ image: ghcr.io/igaw/linux-nvme/debian.python:latest
steps:
- - name: install libraries
- run: sudo apt-get install gcc pkg-config libjson-c-dev libssl-dev python3-dev
+ - uses: actions/checkout@v4
- - uses: actions/checkout@v3
+ - name: Allow workspace
+ run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
- name: Build sdist
run: pipx run build --sdist
- - uses: actions/upload-artifact@v3
+ - uses: actions/upload-artifact@v4
with:
path: dist/*.tar.gz
retention-days: 5
@@ -34,7 +36,7 @@ jobs:
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/v')
steps:
- - uses: actions/download-artifact@v3
+ - uses: actions/download-artifact@v4
with:
name: artifact
path: dist
@@ -49,7 +51,7 @@ jobs:
upload_pypi:
needs: [build_sdist]
runs-on: ubuntu-latest
- if: startsWith(github.ref, 'refs/tags/v')
+ if: startsWith(github.ref, 'refs/tags/v') && github.repository == 'linux-nvme/libnvme'
steps:
- name: Check if it is a release tag
id: check-tag
@@ -58,7 +60,7 @@ jobs:
echo ::set-output name=match::true
fi
- name: Download artifiact
- uses: actions/download-artifact@v3
+ uses: actions/download-artifact@v4
if: steps.check-tag.outputs.match == 'true'
with:
name: artifact
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 6ca2741..d4ef038 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -10,11 +10,11 @@ on:
jobs:
build:
runs-on: ubuntu-latest
- if: startsWith(github.ref, 'refs/tags/v')
+ if: startsWith(github.ref, 'refs/tags/v') && github.repository == 'linux-nvme/libnvme'
permissions:
contents: write
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- uses: ncipollo/release-action@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.readthedocs.yaml b/.readthedocs.yaml
index 283a2dc..3505101 100644
--- a/.readthedocs.yaml
+++ b/.readthedocs.yaml
@@ -2,9 +2,6 @@
version: 2
-python:
- system_packages: true
-
build:
os: ubuntu-22.04
tools:
diff --git a/README.md b/README.md
index 0b0fae8..758d5d5 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
# libnvme
-![MesonBuild](https://github.com/linux-nvme/libnvme/actions/workflows/meson.yml/badge.svg)
-![PyBuild](https://github.com/linux-nvme/libnvme/actions/workflows/python-publish.yml/badge.svg)
+![MesonBuild](https://github.com/linux-nvme/libnvme/actions/workflows/build.yml/badge.svg)
+![PyBuild](https://github.com/linux-nvme/libnvme/actions/workflows/release-python.yml/badge.svg)
[![PyPI](https://img.shields.io/pypi/v/libnvme)](https://pypi.org/project/libnvme/)
[![PyPI - Wheel](https://img.shields.io/pypi/wheel/libnvme)](https://pypi.org/project/libnvme/)
![GitHub](https://img.shields.io/github/license/linux-nvme/libnvme)
@@ -79,7 +79,13 @@ there are two project which implement the Ninja and the Meson API in pure C99
- samurai: https://github.com/michaelforney/samurai.git
- muon: https://git.sr.ht/~lattis/muon
-See the CI [build](.github/workflows/build.yml) for an example how to use it.
+The CI build helper script `scripts/build.sh` is able to setup and build this
+project in a minimal setup using samurai and muon and thus only depending on:
+- gcc
+- make
+- git
+
+`scripts/build.sh -m muon`
## To compile libnvme
@@ -106,7 +112,7 @@ completely "clean" all the build artifacts, one need only delete the
To compile:
```
-meson -C .build
+meson compile -C .build
```
## To install libnvme
@@ -145,10 +151,10 @@ A few build options can be specified on the command line when invoking meson.
| docs | [false], html, man, rst, all | Install documentation |
| docs-build | [false], true | Enable build documentation |
| python | [auto], enabled, disabled | Whether to build the Python bindings. When set to `auto`, the default, meson will check for the presence of the tools and libraries (e.g. `swig`) required to build the Python bindings. If found, meson will configure the project to build the Python bindings. If a tool or library is missing, then the Python bindings won't be built. Setting this to `enabled`, forces the Python bindings to be built. When set to `disabled`, meson will configure the project to not build the Python bindings.<br />Example: `meson setup .build -Dpython=disabled` |
-| openssl | [auto], enabled, disabled | Enables OpenSSL dependend features (e.g. authentication), adds build dependency on OpenSSL |
-| libdbus | auto, enabled, [disabled] | Enables D-Bus dependend features (libnvme-mi: End point discovery), adds build dependency on libdbus |
+| openssl | [auto], enabled, disabled | Enables OpenSSL dependent features (e.g. TLS over TCP), adds build dependency on OpenSSL |
+| libdbus | auto, enabled, [disabled] | Enables D-Bus dependent features (libnvme-mi: End point discovery), adds build dependency on libdbus |
| json-c | [auto], enabled, disabled | (recommended) Enables JSON-C dependend features (e.g. config.json parsing), adds build depdency on json-c |
-| keyutils | [auto], enabled, disabled | Enables keyutils dependend features (e.g. TLS over TCP), adds build dependency on keyutils |
+| keyutils | [auto], enabled, disabled | Enables keyutils dependent features (e.g. authentication), adds build dependency on keyutils |
See the full configuration options with
@@ -171,8 +177,12 @@ To enable address sanitizer (advanced debugging of memory issues):
meson setup .build -Db_sanitize=address
```
-This option adds `-fsanitize=address` to the gcc options. Note that when using the sanitize feature, the library `libasan.so` must be available and must be the very first library loaded when running an executable. Ensuring that `libasan.so` gets loaded first can be achieved with the `LD_PRELOAD` environment variable as follows:
+This option adds `-fsanitize=address` to the gcc options. The tests can then be run normally (`meson test -C .build`).
+
+Note that when using the sanitize feature, the library `libasan.so` must be available and must be the very first library loaded when running an executable. If experiencing linking issues, you can ensure that `libasan.so` gets loaded first with the `LD_PRELOAD` environment variable as follows:
```
meson setup .build -Db_sanitize=address && LD_PRELOAD=/lib64/libasan.so.6 ninja -C .build test
```
+
+It's also possible to enable the undefined behavior sanitizer with `-Db_sanitize=undefined`. To enable both, use `-Db_sanitize=address,undefined`.
diff --git a/codecov.yml b/codecov.yml
new file mode 100644
index 0000000..d40a8ea
--- /dev/null
+++ b/codecov.yml
@@ -0,0 +1,6 @@
+---
+ignore:
+ - 'subprojects'
+ - 'ccan'
+ - 'test'
+ - 'examples'
diff --git a/doc/conf.py b/doc/conf.py
index fe594e8..bec47b2 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -12,7 +12,7 @@ copyright = '2020, Keith Busch'
author = 'Keith Busch <kbusch@kernel.org>'
master_doc = 'index'
-release = '1.5'
+release = '1.7.1'
# -- General configuration ---------------------------------------------------
diff --git a/doc/man/nbft_control.2 b/doc/man/nbft_control.2
index 7da4f26..d498210 100644
--- a/doc/man/nbft_control.2
+++ b/doc/man/nbft_control.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nbft_control" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nbft_control" "December 2023" "API Manual" LINUX
.SH NAME
struct nbft_control \- NBFT Table - Control Descriptor (Figure 8)
.SH SYNOPSIS
diff --git a/doc/man/nbft_control_flags.2 b/doc/man/nbft_control_flags.2
index e2f6e0f..47d3f30 100644
--- a/doc/man/nbft_control_flags.2
+++ b/doc/man/nbft_control_flags.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nbft_control_flags" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nbft_control_flags" "December 2023" "API Manual" LINUX
.SH NAME
enum nbft_control_flags \- Control Descriptor Flags
.SH SYNOPSIS
diff --git a/doc/man/nbft_desc_type.2 b/doc/man/nbft_desc_type.2
index 40d00f6..886e314 100644
--- a/doc/man/nbft_desc_type.2
+++ b/doc/man/nbft_desc_type.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nbft_desc_type" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nbft_desc_type" "December 2023" "API Manual" LINUX
.SH NAME
enum nbft_desc_type \- NBFT Elements - Descriptor Types (Figure 5)
.SH SYNOPSIS
diff --git a/doc/man/nbft_discovery.2 b/doc/man/nbft_discovery.2
index 61614ff..c08fae6 100644
--- a/doc/man/nbft_discovery.2
+++ b/doc/man/nbft_discovery.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nbft_discovery" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nbft_discovery" "December 2023" "API Manual" LINUX
.SH NAME
struct nbft_discovery \- Discovery Descriptor (Figure 24)
.SH SYNOPSIS
diff --git a/doc/man/nbft_discovery_flags.2 b/doc/man/nbft_discovery_flags.2
index 9d0685c..fb6f42b 100644
--- a/doc/man/nbft_discovery_flags.2
+++ b/doc/man/nbft_discovery_flags.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nbft_discovery_flags" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nbft_discovery_flags" "December 2023" "API Manual" LINUX
.SH NAME
enum nbft_discovery_flags \- Discovery Descriptor Flags
.SH SYNOPSIS
diff --git a/doc/man/nbft_header.2 b/doc/man/nbft_header.2
index 2990736..fea70df 100644
--- a/doc/man/nbft_header.2
+++ b/doc/man/nbft_header.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nbft_header" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nbft_header" "December 2023" "API Manual" LINUX
.SH NAME
struct nbft_header \- NBFT Table - Header (Figure 8)
.SH SYNOPSIS
diff --git a/doc/man/nbft_heap_obj.2 b/doc/man/nbft_heap_obj.2
index 81d6425..426dcaf 100644
--- a/doc/man/nbft_heap_obj.2
+++ b/doc/man/nbft_heap_obj.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nbft_heap_obj" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nbft_heap_obj" "December 2023" "API Manual" LINUX
.SH NAME
struct nbft_heap_obj \- NBFT Header Driver Signature
.SH SYNOPSIS
diff --git a/doc/man/nbft_hfi.2 b/doc/man/nbft_hfi.2
index 7679e0f..ae47656 100644
--- a/doc/man/nbft_hfi.2
+++ b/doc/man/nbft_hfi.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nbft_hfi" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nbft_hfi" "December 2023" "API Manual" LINUX
.SH NAME
struct nbft_hfi \- Host Fabric Interface (HFI) Descriptor (Figure 11)
.SH SYNOPSIS
diff --git a/doc/man/nbft_hfi_flags.2 b/doc/man/nbft_hfi_flags.2
index 74ba678..63df9db 100644
--- a/doc/man/nbft_hfi_flags.2
+++ b/doc/man/nbft_hfi_flags.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nbft_hfi_flags" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nbft_hfi_flags" "December 2023" "API Manual" LINUX
.SH NAME
enum nbft_hfi_flags \- HFI Descriptor Flags
.SH SYNOPSIS
diff --git a/doc/man/nbft_hfi_info_tcp.2 b/doc/man/nbft_hfi_info_tcp.2
index 5419330..2dba60d 100644
--- a/doc/man/nbft_hfi_info_tcp.2
+++ b/doc/man/nbft_hfi_info_tcp.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nbft_hfi_info_tcp" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nbft_hfi_info_tcp" "December 2023" "API Manual" LINUX
.SH NAME
struct nbft_hfi_info_tcp \- HFI Transport Info Descriptor - NVMe/TCP (Figure 13)
.SH SYNOPSIS
diff --git a/doc/man/nbft_hfi_info_tcp_flags.2 b/doc/man/nbft_hfi_info_tcp_flags.2
index f3d8173..830b035 100644
--- a/doc/man/nbft_hfi_info_tcp_flags.2
+++ b/doc/man/nbft_hfi_info_tcp_flags.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nbft_hfi_info_tcp_flags" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nbft_hfi_info_tcp_flags" "December 2023" "API Manual" LINUX
.SH NAME
enum nbft_hfi_info_tcp_flags \- HFI Transport Flags
.SH SYNOPSIS
diff --git a/doc/man/nbft_host.2 b/doc/man/nbft_host.2
index a747255..f057936 100644
--- a/doc/man/nbft_host.2
+++ b/doc/man/nbft_host.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nbft_host" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nbft_host" "December 2023" "API Manual" LINUX
.SH NAME
struct nbft_host \- Host Descriptor (Figure 9)
.SH SYNOPSIS
diff --git a/doc/man/nbft_host_flags.2 b/doc/man/nbft_host_flags.2
index f5ef688..f16d62b 100644
--- a/doc/man/nbft_host_flags.2
+++ b/doc/man/nbft_host_flags.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nbft_host_flags" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nbft_host_flags" "December 2023" "API Manual" LINUX
.SH NAME
enum nbft_host_flags \- Host Flags
.SH SYNOPSIS
diff --git a/doc/man/nbft_info.2 b/doc/man/nbft_info.2
index 38b2ffd..27a985a 100644
--- a/doc/man/nbft_info.2
+++ b/doc/man/nbft_info.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nbft_info" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nbft_info" "December 2023" "API Manual" LINUX
.SH NAME
struct nbft_info \- The parsed NBFT table data.
.SH SYNOPSIS
diff --git a/doc/man/nbft_info_discovery.2 b/doc/man/nbft_info_discovery.2
index 03e5245..81a997e 100644
--- a/doc/man/nbft_info_discovery.2
+++ b/doc/man/nbft_info_discovery.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nbft_info_discovery" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nbft_info_discovery" "December 2023" "API Manual" LINUX
.SH NAME
struct nbft_info_discovery \- Discovery Descriptor
.SH SYNOPSIS
diff --git a/doc/man/nbft_info_hfi.2 b/doc/man/nbft_info_hfi.2
index 438e76a..321c37a 100644
--- a/doc/man/nbft_info_hfi.2
+++ b/doc/man/nbft_info_hfi.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nbft_info_hfi" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nbft_info_hfi" "December 2023" "API Manual" LINUX
.SH NAME
struct nbft_info_hfi \- Host Fabric Interface (HFI) Descriptor
.SH SYNOPSIS
diff --git a/doc/man/nbft_info_hfi_info_tcp.2 b/doc/man/nbft_info_hfi_info_tcp.2
index 23a35a2..295841b 100644
--- a/doc/man/nbft_info_hfi_info_tcp.2
+++ b/doc/man/nbft_info_hfi_info_tcp.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nbft_info_hfi_info_tcp" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nbft_info_hfi_info_tcp" "December 2023" "API Manual" LINUX
.SH NAME
struct nbft_info_hfi_info_tcp \- HFI Transport Info Descriptor - NVMe/TCP
.SH SYNOPSIS
diff --git a/doc/man/nbft_info_host.2 b/doc/man/nbft_info_host.2
index f664b6d..60c67c6 100644
--- a/doc/man/nbft_info_host.2
+++ b/doc/man/nbft_info_host.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nbft_info_host" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nbft_info_host" "December 2023" "API Manual" LINUX
.SH NAME
struct nbft_info_host \- Host Descriptor
.SH SYNOPSIS
diff --git a/doc/man/nbft_info_nid_type.2 b/doc/man/nbft_info_nid_type.2
index e4bae03..5b5b479 100644
--- a/doc/man/nbft_info_nid_type.2
+++ b/doc/man/nbft_info_nid_type.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nbft_info_nid_type" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nbft_info_nid_type" "December 2023" "API Manual" LINUX
.SH NAME
enum nbft_info_nid_type \- Namespace Identifier Type (NIDT)
.SH SYNOPSIS
diff --git a/doc/man/nbft_info_primary_admin_host_flag.2 b/doc/man/nbft_info_primary_admin_host_flag.2
index ccfcf22..823449d 100644
--- a/doc/man/nbft_info_primary_admin_host_flag.2
+++ b/doc/man/nbft_info_primary_admin_host_flag.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nbft_info_primary_admin_host_flag" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nbft_info_primary_admin_host_flag" "December 2023" "API Manual" LINUX
.SH NAME
enum nbft_info_primary_admin_host_flag \- Primary Administrative Host Descriptor Flags
.SH SYNOPSIS
diff --git a/doc/man/nbft_info_security.2 b/doc/man/nbft_info_security.2
index ab46e20..872464a 100644
--- a/doc/man/nbft_info_security.2
+++ b/doc/man/nbft_info_security.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nbft_info_security" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nbft_info_security" "December 2023" "API Manual" LINUX
.SH NAME
struct nbft_info_security \- Security Profile Descriptor
.SH SYNOPSIS
diff --git a/doc/man/nbft_info_subsystem_ns.2 b/doc/man/nbft_info_subsystem_ns.2
index fc5a441..3dfaa14 100644
--- a/doc/man/nbft_info_subsystem_ns.2
+++ b/doc/man/nbft_info_subsystem_ns.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nbft_info_subsystem_ns" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nbft_info_subsystem_ns" "December 2023" "API Manual" LINUX
.SH NAME
struct nbft_info_subsystem_ns \- Subsystem Namespace (SSNS) info
.SH SYNOPSIS
diff --git a/doc/man/nbft_security.2 b/doc/man/nbft_security.2
index df97f10..bb90560 100644
--- a/doc/man/nbft_security.2
+++ b/doc/man/nbft_security.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nbft_security" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nbft_security" "December 2023" "API Manual" LINUX
.SH NAME
struct nbft_security \- Security Profile Descriptor (Figure 21)
.SH SYNOPSIS
diff --git a/doc/man/nbft_security_flags.2 b/doc/man/nbft_security_flags.2
index 10185ce..5c3392d 100644
--- a/doc/man/nbft_security_flags.2
+++ b/doc/man/nbft_security_flags.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nbft_security_flags" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nbft_security_flags" "December 2023" "API Manual" LINUX
.SH NAME
enum nbft_security_flags \- Security Profile Descriptor Flags (Figure 22)
.SH SYNOPSIS
diff --git a/doc/man/nbft_security_secret_type.2 b/doc/man/nbft_security_secret_type.2
index 76cc048..aa47e90 100644
--- a/doc/man/nbft_security_secret_type.2
+++ b/doc/man/nbft_security_secret_type.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nbft_security_secret_type" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nbft_security_secret_type" "December 2023" "API Manual" LINUX
.SH NAME
enum nbft_security_secret_type \- Security Profile Descriptor Secret Type
.SH SYNOPSIS
diff --git a/doc/man/nbft_ssns.2 b/doc/man/nbft_ssns.2
index 91eb2c5..6588f43 100644
--- a/doc/man/nbft_ssns.2
+++ b/doc/man/nbft_ssns.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nbft_ssns" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nbft_ssns" "December 2023" "API Manual" LINUX
.SH NAME
struct nbft_ssns \- Subsystem Namespace (SSNS) Descriptor (Figure 15)
.SH SYNOPSIS
diff --git a/doc/man/nbft_ssns_ext_info.2 b/doc/man/nbft_ssns_ext_info.2
index 63cd106..1062ecf 100644
--- a/doc/man/nbft_ssns_ext_info.2
+++ b/doc/man/nbft_ssns_ext_info.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nbft_ssns_ext_info" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nbft_ssns_ext_info" "December 2023" "API Manual" LINUX
.SH NAME
struct nbft_ssns_ext_info \- Subsystem and Namespace Extended Information Descriptor (Figure 19)
.SH SYNOPSIS
diff --git a/doc/man/nbft_ssns_ext_info_flags.2 b/doc/man/nbft_ssns_ext_info_flags.2
index 2723c61..5753db5 100644
--- a/doc/man/nbft_ssns_ext_info_flags.2
+++ b/doc/man/nbft_ssns_ext_info_flags.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nbft_ssns_ext_info_flags" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nbft_ssns_ext_info_flags" "December 2023" "API Manual" LINUX
.SH NAME
enum nbft_ssns_ext_info_flags \- Subsystem and Namespace Extended Information Descriptor Flags
.SH SYNOPSIS
diff --git a/doc/man/nbft_ssns_flags.2 b/doc/man/nbft_ssns_flags.2
index 10237e6..90a4595 100644
--- a/doc/man/nbft_ssns_flags.2
+++ b/doc/man/nbft_ssns_flags.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nbft_ssns_flags" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nbft_ssns_flags" "December 2023" "API Manual" LINUX
.SH NAME
enum nbft_ssns_flags \- Subsystem and Namespace Specific Flags Field (Figure 16)
.SH SYNOPSIS
diff --git a/doc/man/nbft_ssns_trflags.2 b/doc/man/nbft_ssns_trflags.2
index 0a52871..a58f0e5 100644
--- a/doc/man/nbft_ssns_trflags.2
+++ b/doc/man/nbft_ssns_trflags.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nbft_ssns_trflags" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nbft_ssns_trflags" "December 2023" "API Manual" LINUX
.SH NAME
enum nbft_ssns_trflags \- SSNS Transport Specific Flags Field (Figure 17)
.SH SYNOPSIS
diff --git a/doc/man/nbft_trtype.2 b/doc/man/nbft_trtype.2
index 2af7850..ff40743 100644
--- a/doc/man/nbft_trtype.2
+++ b/doc/man/nbft_trtype.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nbft_trtype" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nbft_trtype" "December 2023" "API Manual" LINUX
.SH NAME
enum nbft_trtype \- NBFT Interface Transport Types (Figure 7)
.SH SYNOPSIS
diff --git a/doc/man/nvme_admin_opcode.2 b/doc/man/nvme_admin_opcode.2
index fc95c2f..6e02bd9 100644
--- a/doc/man/nvme_admin_opcode.2
+++ b/doc/man/nvme_admin_opcode.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_admin_opcode" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_admin_opcode" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_admin_opcode \- Known NVMe admin opcodes
.SH SYNOPSIS
diff --git a/doc/man/nvme_admin_passthru.2 b/doc/man/nvme_admin_passthru.2
index 3a382eb..7a05f98 100644
--- a/doc/man/nvme_admin_passthru.2
+++ b/doc/man/nvme_admin_passthru.2
@@ -1,4 +1,4 @@
-.TH "nvme_admin_passthru" 9 "nvme_admin_passthru" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_admin_passthru" 9 "nvme_admin_passthru" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_admin_passthru \- Submit an nvme passthrough command
.SH SYNOPSIS
diff --git a/doc/man/nvme_admin_passthru64.2 b/doc/man/nvme_admin_passthru64.2
index c770c60..62cda8f 100644
--- a/doc/man/nvme_admin_passthru64.2
+++ b/doc/man/nvme_admin_passthru64.2
@@ -1,4 +1,4 @@
-.TH "nvme_admin_passthru64" 9 "nvme_admin_passthru64" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_admin_passthru64" 9 "nvme_admin_passthru64" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_admin_passthru64 \- Submit a 64-bit nvme passthrough command
.SH SYNOPSIS
diff --git a/doc/man/nvme_ae_info_css_nvm.2 b/doc/man/nvme_ae_info_css_nvm.2
index ea0128d..b22cb29 100644
--- a/doc/man/nvme_ae_info_css_nvm.2
+++ b/doc/man/nvme_ae_info_css_nvm.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_ae_info_css_nvm" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_ae_info_css_nvm" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_ae_info_css_nvm \- Asynchronous Event Information - I/O Command Specific Status
.SH SYNOPSIS
diff --git a/doc/man/nvme_ae_info_error.2 b/doc/man/nvme_ae_info_error.2
index 85de328..7bb2831 100644
--- a/doc/man/nvme_ae_info_error.2
+++ b/doc/man/nvme_ae_info_error.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_ae_info_error" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_ae_info_error" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_ae_info_error \- Asynchronous Event Information - Error Status
.SH SYNOPSIS
diff --git a/doc/man/nvme_ae_info_notice.2 b/doc/man/nvme_ae_info_notice.2
index b5257d8..4860dc9 100644
--- a/doc/man/nvme_ae_info_notice.2
+++ b/doc/man/nvme_ae_info_notice.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_ae_info_notice" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_ae_info_notice" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_ae_info_notice \- Asynchronous Event Information - Notice
.SH SYNOPSIS
diff --git a/doc/man/nvme_ae_info_smart.2 b/doc/man/nvme_ae_info_smart.2
index 2b290b6..17e8f78 100644
--- a/doc/man/nvme_ae_info_smart.2
+++ b/doc/man/nvme_ae_info_smart.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_ae_info_smart" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_ae_info_smart" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_ae_info_smart \- Asynchronous Event Information - SMART / Health Status
.SH SYNOPSIS
diff --git a/doc/man/nvme_ae_type.2 b/doc/man/nvme_ae_type.2
index 2ab217d..69bdd57 100644
--- a/doc/man/nvme_ae_type.2
+++ b/doc/man/nvme_ae_type.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_ae_type" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_ae_type" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_ae_type \- Asynchronous Event Type
.SH SYNOPSIS
diff --git a/doc/man/nvme_aggregate_endurance_group_event.2 b/doc/man/nvme_aggregate_endurance_group_event.2
index 1f9dc9c..e696a57 100644
--- a/doc/man/nvme_aggregate_endurance_group_event.2
+++ b/doc/man/nvme_aggregate_endurance_group_event.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_aggregate_endurance_group_event" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_aggregate_endurance_group_event" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_aggregate_endurance_group_event \- Endurance Group Event Aggregate
.SH SYNOPSIS
diff --git a/doc/man/nvme_aggregate_predictable_lat_event.2 b/doc/man/nvme_aggregate_predictable_lat_event.2
index c860a99..5673701 100644
--- a/doc/man/nvme_aggregate_predictable_lat_event.2
+++ b/doc/man/nvme_aggregate_predictable_lat_event.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_aggregate_predictable_lat_event" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_aggregate_predictable_lat_event" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_aggregate_predictable_lat_event \- Predictable Latency Event Aggregate Log Page
.SH SYNOPSIS
diff --git a/doc/man/nvme_ana_group_desc.2 b/doc/man/nvme_ana_group_desc.2
index 941ff9b..c1b159f 100644
--- a/doc/man/nvme_ana_group_desc.2
+++ b/doc/man/nvme_ana_group_desc.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_ana_group_desc" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_ana_group_desc" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_ana_group_desc \- ANA Group Descriptor
.SH SYNOPSIS
diff --git a/doc/man/nvme_ana_log.2 b/doc/man/nvme_ana_log.2
index 66cada5..812d580 100644
--- a/doc/man/nvme_ana_log.2
+++ b/doc/man/nvme_ana_log.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_ana_log" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_ana_log" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_ana_log \- Asymmetric Namespace Access Log
.SH SYNOPSIS
diff --git a/doc/man/nvme_ana_state.2 b/doc/man/nvme_ana_state.2
index 18b0070..cd405a4 100644
--- a/doc/man/nvme_ana_state.2
+++ b/doc/man/nvme_ana_state.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_ana_state" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_ana_state" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_ana_state \- ANA Group Descriptor - Asymmetric Namespace Access State
.SH SYNOPSIS
diff --git a/doc/man/nvme_apst_entry.2 b/doc/man/nvme_apst_entry.2
index db6419f..4d18d5d 100644
--- a/doc/man/nvme_apst_entry.2
+++ b/doc/man/nvme_apst_entry.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_apst_entry" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_apst_entry" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_apst_entry \- Autonomous Power State Transition
.SH SYNOPSIS
diff --git a/doc/man/nvme_boot_partition.2 b/doc/man/nvme_boot_partition.2
index 2bb6065..d0a6f07 100644
--- a/doc/man/nvme_boot_partition.2
+++ b/doc/man/nvme_boot_partition.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_boot_partition" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_boot_partition" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_boot_partition \- Boot Partition Log
.SH SYNOPSIS
diff --git a/doc/man/nvme_capacity_config_desc.2 b/doc/man/nvme_capacity_config_desc.2
index 298ac63..f0db6f2 100644
--- a/doc/man/nvme_capacity_config_desc.2
+++ b/doc/man/nvme_capacity_config_desc.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_capacity_config_desc" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_capacity_config_desc" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_capacity_config_desc \- Capacity Configuration structure definitions
.SH SYNOPSIS
diff --git a/doc/man/nvme_capacity_mgmt.2 b/doc/man/nvme_capacity_mgmt.2
index d75a6fb..4de5cfc 100644
--- a/doc/man/nvme_capacity_mgmt.2
+++ b/doc/man/nvme_capacity_mgmt.2
@@ -1,4 +1,4 @@
-.TH "nvme_capacity_mgmt" 9 "nvme_capacity_mgmt" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_capacity_mgmt" 9 "nvme_capacity_mgmt" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_capacity_mgmt \- Capacity management command
.SH SYNOPSIS
diff --git a/doc/man/nvme_change_ns_event.2 b/doc/man/nvme_change_ns_event.2
index b1dd10f..674c941 100644
--- a/doc/man/nvme_change_ns_event.2
+++ b/doc/man/nvme_change_ns_event.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_change_ns_event" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_change_ns_event" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_change_ns_event \- Change Namespace Event Data
.SH SYNOPSIS
diff --git a/doc/man/nvme_channel_config_desc.2 b/doc/man/nvme_channel_config_desc.2
index 1860f91..7ddc180 100644
--- a/doc/man/nvme_channel_config_desc.2
+++ b/doc/man/nvme_channel_config_desc.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_channel_config_desc" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_channel_config_desc" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_channel_config_desc \- Channel Configuration Descriptor
.SH SYNOPSIS
diff --git a/doc/man/nvme_cmb_size.2 b/doc/man/nvme_cmb_size.2
index 8e369d8..3c3e9ab 100644
--- a/doc/man/nvme_cmb_size.2
+++ b/doc/man/nvme_cmb_size.2
@@ -1,4 +1,4 @@
-.TH "nvme_cmb_size" 9 "nvme_cmb_size" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_cmb_size" 9 "nvme_cmb_size" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_cmb_size \- Calculate size of the controller memory buffer
.SH SYNOPSIS
diff --git a/doc/man/nvme_cmd_effects.2 b/doc/man/nvme_cmd_effects.2
index 6559bd8..30528fa 100644
--- a/doc/man/nvme_cmd_effects.2
+++ b/doc/man/nvme_cmd_effects.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_cmd_effects" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_cmd_effects" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_cmd_effects \- Commands Supported and Effects
.SH SYNOPSIS
diff --git a/doc/man/nvme_cmd_effects_log.2 b/doc/man/nvme_cmd_effects_log.2
index 90cba63..616807e 100644
--- a/doc/man/nvme_cmd_effects_log.2
+++ b/doc/man/nvme_cmd_effects_log.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_cmd_effects_log" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_cmd_effects_log" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_cmd_effects_log \- Commands Supported and Effects Log
.SH SYNOPSIS
diff --git a/doc/man/nvme_cmd_format_mset.2 b/doc/man/nvme_cmd_format_mset.2
index c827719..353c038 100644
--- a/doc/man/nvme_cmd_format_mset.2
+++ b/doc/man/nvme_cmd_format_mset.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_cmd_format_mset" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_cmd_format_mset" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_cmd_format_mset \- Format NVM - Metadata Settings
.SH SYNOPSIS
diff --git a/doc/man/nvme_cmd_format_pi.2 b/doc/man/nvme_cmd_format_pi.2
index 29d6609..54ad461 100644
--- a/doc/man/nvme_cmd_format_pi.2
+++ b/doc/man/nvme_cmd_format_pi.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_cmd_format_pi" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_cmd_format_pi" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_cmd_format_pi \- Format NVM - Protection Information
.SH SYNOPSIS
diff --git a/doc/man/nvme_cmd_format_pil.2 b/doc/man/nvme_cmd_format_pil.2
index f8d5110..c203f6d 100644
--- a/doc/man/nvme_cmd_format_pil.2
+++ b/doc/man/nvme_cmd_format_pil.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_cmd_format_pil" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_cmd_format_pil" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_cmd_format_pil \- Format NVM - Protection Information Location
.SH SYNOPSIS
diff --git a/doc/man/nvme_cmd_format_ses.2 b/doc/man/nvme_cmd_format_ses.2
index 028c59f..58701e3 100644
--- a/doc/man/nvme_cmd_format_ses.2
+++ b/doc/man/nvme_cmd_format_ses.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_cmd_format_ses" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_cmd_format_ses" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_cmd_format_ses \- Format NVM - Secure Erase Settings
.SH SYNOPSIS
diff --git a/doc/man/nvme_cmd_get_log_lid.2 b/doc/man/nvme_cmd_get_log_lid.2
index 755e38b..a0b43f3 100644
--- a/doc/man/nvme_cmd_get_log_lid.2
+++ b/doc/man/nvme_cmd_get_log_lid.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_cmd_get_log_lid" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_cmd_get_log_lid" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_cmd_get_log_lid \- Get Log Page -Log Page Identifiers
.SH SYNOPSIS
@@ -88,6 +88,10 @@ enum nvme_cmd_get_log_lid {
,
.br
.br
+.BI " NVME_LOG_LID_PHY_RX_EOM"
+,
+.br
+.br
.BI " NVME_LOG_LID_FDP_CONFIGS"
,
.br
@@ -162,6 +166,8 @@ Feature Identifiers Supported and Effects
NVMe-MI Commands Supported and Effects
.IP "NVME_LOG_LID_BOOT_PARTITION" 12
Boot Partition
+.IP "NVME_LOG_LID_PHY_RX_EOM" 12
+Physical Interface Receiver Eye Opening Measurement
.IP "NVME_LOG_LID_FDP_CONFIGS" 12
FDP Configurations
.IP "NVME_LOG_LID_FDP_RUH_USAGE" 12
diff --git a/doc/man/nvme_cmd_get_log_telemetry_host_lsp.2 b/doc/man/nvme_cmd_get_log_telemetry_host_lsp.2
index 486c355..6eda5bc 100644
--- a/doc/man/nvme_cmd_get_log_telemetry_host_lsp.2
+++ b/doc/man/nvme_cmd_get_log_telemetry_host_lsp.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_cmd_get_log_telemetry_host_lsp" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_cmd_get_log_telemetry_host_lsp" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_cmd_get_log_telemetry_host_lsp \- Telemetry Host-Initiated log specific field
.SH SYNOPSIS
diff --git a/doc/man/nvme_compare.2 b/doc/man/nvme_compare.2
index ef2c020..48448b1 100644
--- a/doc/man/nvme_compare.2
+++ b/doc/man/nvme_compare.2
@@ -1,4 +1,4 @@
-.TH "nvme_compare" 9 "nvme_compare" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_compare" 9 "nvme_compare" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_compare \- Submit an nvme user compare command
.SH SYNOPSIS
diff --git a/doc/man/nvme_connect_err.2 b/doc/man/nvme_connect_err.2
index 0cd9568..e08a15d 100644
--- a/doc/man/nvme_connect_err.2
+++ b/doc/man/nvme_connect_err.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_connect_err" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_connect_err" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_connect_err \- nvme connect error codes
.SH SYNOPSIS
diff --git a/doc/man/nvme_constants.2 b/doc/man/nvme_constants.2
index b83d506..bf716cb 100644
--- a/doc/man/nvme_constants.2
+++ b/doc/man/nvme_constants.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_constants" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_constants" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_constants \- A place to stash various constant nvme values
.SH SYNOPSIS
diff --git a/doc/man/nvme_copy.2 b/doc/man/nvme_copy.2
index 4cc230d..72ac033 100644
--- a/doc/man/nvme_copy.2
+++ b/doc/man/nvme_copy.2
@@ -1,4 +1,4 @@
-.TH "nvme_copy" 9 "nvme_copy" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_copy" 9 "nvme_copy" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_copy \- Copy command
.SH SYNOPSIS
diff --git a/doc/man/nvme_copy_range.2 b/doc/man/nvme_copy_range.2
index f470dcf..0c3f31d 100644
--- a/doc/man/nvme_copy_range.2
+++ b/doc/man/nvme_copy_range.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_copy_range" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_copy_range" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_copy_range \- Copy - Source Range Entries Descriptor Format
.SH SYNOPSIS
diff --git a/doc/man/nvme_copy_range_f1.2 b/doc/man/nvme_copy_range_f1.2
index 069bff6..8757368 100644
--- a/doc/man/nvme_copy_range_f1.2
+++ b/doc/man/nvme_copy_range_f1.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_copy_range_f1" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_copy_range_f1" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_copy_range_f1 \- Copy - Source Range Entries Descriptor Format 1h
.SH SYNOPSIS
diff --git a/doc/man/nvme_copy_range_f2.2 b/doc/man/nvme_copy_range_f2.2
new file mode 100644
index 0000000..d02fa7e
--- /dev/null
+++ b/doc/man/nvme_copy_range_f2.2
@@ -0,0 +1,48 @@
+.TH "libnvme" 9 "struct nvme_copy_range_f2" "December 2023" "API Manual" LINUX
+.SH NAME
+struct nvme_copy_range_f2 \- Copy - Source Range Entries Descriptor Format 2h
+.SH SYNOPSIS
+struct nvme_copy_range_f2 {
+.br
+.BI " __le32 snsid;"
+.br
+.BI " __u8 rsvd4[4];"
+.br
+.BI " __le64 slba;"
+.br
+.BI " __le16 nlb;"
+.br
+.BI " __u8 rsvd18[4];"
+.br
+.BI " __le16 sopt;"
+.br
+.BI " __le32 eilbrt;"
+.br
+.BI " __le16 elbat;"
+.br
+.BI " __le16 elbatm;"
+.br
+.BI "
+};
+.br
+
+.SH Members
+.IP "snsid" 12
+Source Namespace Identifier
+.IP "rsvd4" 12
+Reserved
+.IP "slba" 12
+Starting LBA
+.IP "nlb" 12
+Number of Logical Blocks
+.IP "rsvd18" 12
+Reserved
+.IP "sopt" 12
+Source Options
+.IP "eilbrt" 12
+Expected Initial Logical Block Reference Tag /
+Expected Logical Block Storage Tag
+.IP "elbat" 12
+Expected Logical Block Application Tag
+.IP "elbatm" 12
+Expected Logical Block Application Tag Mask
diff --git a/doc/man/nvme_copy_range_f3.2 b/doc/man/nvme_copy_range_f3.2
new file mode 100644
index 0000000..b88d93d
--- /dev/null
+++ b/doc/man/nvme_copy_range_f3.2
@@ -0,0 +1,52 @@
+.TH "libnvme" 9 "struct nvme_copy_range_f3" "December 2023" "API Manual" LINUX
+.SH NAME
+struct nvme_copy_range_f3 \- Copy - Source Range Entries Descriptor Format 3h
+.SH SYNOPSIS
+struct nvme_copy_range_f3 {
+.br
+.BI " __le32 snsid;"
+.br
+.BI " __u8 rsvd4[4];"
+.br
+.BI " __le64 slba;"
+.br
+.BI " __le16 nlb;"
+.br
+.BI " __u8 rsvd18[4];"
+.br
+.BI " __le16 sopt;"
+.br
+.BI " __u8 rsvd24[2];"
+.br
+.BI " __u8 elbt[10];"
+.br
+.BI " __le16 elbat;"
+.br
+.BI " __le16 elbatm;"
+.br
+.BI "
+};
+.br
+
+.SH Members
+.IP "snsid" 12
+Source Namespace Identifier
+.IP "rsvd4" 12
+Reserved
+.IP "slba" 12
+Starting LBA
+.IP "nlb" 12
+Number of Logical Blocks
+.IP "rsvd18" 12
+Reserved
+.IP "sopt" 12
+Source Options
+.IP "rsvd24" 12
+Reserved
+.IP "elbt" 12
+Expected Initial Logical Block Reference Tag /
+Expected Logical Block Storage Tag
+.IP "elbat" 12
+Expected Logical Block Application Tag
+.IP "elbatm" 12
+Expected Logical Block Application Tag Mask
diff --git a/doc/man/nvme_copy_range_sopt.2 b/doc/man/nvme_copy_range_sopt.2
new file mode 100644
index 0000000..cf9620a
--- /dev/null
+++ b/doc/man/nvme_copy_range_sopt.2
@@ -0,0 +1,12 @@
+.TH "libnvme" 9 "enum nvme_copy_range_sopt" "December 2023" "API Manual" LINUX
+.SH NAME
+enum nvme_copy_range_sopt \- NVMe Copy Range Source Options
+.SH SYNOPSIS
+enum nvme_copy_range_sopt {
+.br
+.BI " NVME_COPY_SOPT_FCO"
+
+};
+.SH Constants
+.IP "NVME_COPY_SOPT_FCO" 12
+NVMe Copy Source Option Fast Copy Only
diff --git a/doc/man/nvme_create_ctrl.2 b/doc/man/nvme_create_ctrl.2
index 217235c..4b2b410 100644
--- a/doc/man/nvme_create_ctrl.2
+++ b/doc/man/nvme_create_ctrl.2
@@ -1,4 +1,4 @@
-.TH "nvme_create_ctrl" 9 "nvme_create_ctrl" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_create_ctrl" 9 "nvme_create_ctrl" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_create_ctrl \- Allocate an unconnected NVMe controller
.SH SYNOPSIS
diff --git a/doc/man/nvme_create_root.2 b/doc/man/nvme_create_root.2
index b41325d..0b16ba2 100644
--- a/doc/man/nvme_create_root.2
+++ b/doc/man/nvme_create_root.2
@@ -1,4 +1,4 @@
-.TH "nvme_create_root" 9 "nvme_create_root" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_create_root" 9 "nvme_create_root" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_create_root \- Initialize root object
.SH SYNOPSIS
diff --git a/doc/man/nvme_csi.2 b/doc/man/nvme_csi.2
index 7a0a7f1..64e6c24 100644
--- a/doc/man/nvme_csi.2
+++ b/doc/man/nvme_csi.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_csi" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_csi" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_csi \- Defined command set indicators
.SH SYNOPSIS
diff --git a/doc/man/nvme_ctrl_config_match.2 b/doc/man/nvme_ctrl_config_match.2
new file mode 100644
index 0000000..906654f
--- /dev/null
+++ b/doc/man/nvme_ctrl_config_match.2
@@ -0,0 +1,33 @@
+.TH "nvme_ctrl_config_match" 9 "nvme_ctrl_config_match" "December 2023" "libnvme API manual" LINUX
+.SH NAME
+nvme_ctrl_config_match \- Check if ctrl @c matches config params
+.SH SYNOPSIS
+.B "bool" nvme_ctrl_config_match
+.BI "(struct nvme_ctrl *c " ","
+.BI "const char *transport " ","
+.BI "const char *traddr " ","
+.BI "const char *trsvcid " ","
+.BI "const char *subsysnqn " ","
+.BI "const char *host_traddr " ","
+.BI "const char *host_iface " ");"
+.SH ARGUMENTS
+.IP "c" 12
+An existing controller instance
+.IP "transport" 12
+Transport name
+.IP "traddr" 12
+Transport address
+.IP "trsvcid" 12
+Transport service identifier
+.IP "subsysnqn" 12
+Subsystem NQN
+.IP "host_traddr" 12
+Host transport address
+.IP "host_iface" 12
+Host interface name
+.SH "DESCRIPTION"
+Check that controller \fIc\fP matches parameters: \fItransport\fP, \fItraddr\fP,
+\fItrsvcid\fP, \fIsubsysnqn\fP, \fIhost_traddr\fP, and \fIhost_iface\fP. Parameters set
+to NULL will be ignored.
+.SH "RETURN"
+true if there's a match, false otherwise.
diff --git a/doc/man/nvme_ctrl_find.2 b/doc/man/nvme_ctrl_find.2
new file mode 100644
index 0000000..f95640b
--- /dev/null
+++ b/doc/man/nvme_ctrl_find.2
@@ -0,0 +1,37 @@
+.TH "nvme_ctrl_find" 9 "nvme_ctrl_find" "December 2023" "libnvme API manual" LINUX
+.SH NAME
+nvme_ctrl_find \- Locate an existing controller
+.SH SYNOPSIS
+.B "nvme_ctrl_t" nvme_ctrl_find
+.BI "(nvme_subsystem_t s " ","
+.BI "const char *transport " ","
+.BI "const char *traddr " ","
+.BI "const char *trsvcid " ","
+.BI "const char *subsysnqn " ","
+.BI "const char *host_traddr " ","
+.BI "const char *host_iface " ");"
+.SH ARGUMENTS
+.IP "s" 12
+\fInvme_subsystem_t\fP object
+.IP "transport" 12
+Transport name
+.IP "traddr" 12
+Transport address
+.IP "trsvcid" 12
+Transport service identifier
+.IP "subsysnqn" 12
+Subsystem NQN
+.IP "host_traddr" 12
+Host transport address
+.IP "host_iface" 12
+Host interface name
+.SH "DESCRIPTION"
+Lookup a controller in \fIs\fP based on \fItransport\fP, \fItraddr\fP, \fItrsvcid\fP,
+\fIsubsysnqn\fP, \fIhost_traddr\fP, and \fIhost_iface\fP. \fItransport\fP must be specified,
+other fields may be required depending on the transport. Parameters set
+to NULL will be ignored.
+
+Unlike \fBnvme_lookup_ctrl\fP, this function does not create a new object if
+an existing controller cannot be found.
+.SH "RETURN"
+Controller instance on success, NULL otherwise.
diff --git a/doc/man/nvme_ctrl_first_ns.2 b/doc/man/nvme_ctrl_first_ns.2
index ed38019..c0f0c49 100644
--- a/doc/man/nvme_ctrl_first_ns.2
+++ b/doc/man/nvme_ctrl_first_ns.2
@@ -1,4 +1,4 @@
-.TH "nvme_ctrl_first_ns" 9 "nvme_ctrl_first_ns" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ctrl_first_ns" 9 "nvme_ctrl_first_ns" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ctrl_first_ns \- Start namespace iterator
.SH SYNOPSIS
diff --git a/doc/man/nvme_ctrl_first_path.2 b/doc/man/nvme_ctrl_first_path.2
index 29f7436..aee3c90 100644
--- a/doc/man/nvme_ctrl_first_path.2
+++ b/doc/man/nvme_ctrl_first_path.2
@@ -1,4 +1,4 @@
-.TH "nvme_ctrl_first_path" 9 "nvme_ctrl_first_path" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ctrl_first_path" 9 "nvme_ctrl_first_path" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ctrl_first_path \- Start path iterator
.SH SYNOPSIS
diff --git a/doc/man/nvme_ctrl_for_each_ns.2 b/doc/man/nvme_ctrl_for_each_ns.2
index 139126d..04db2b0 100644
--- a/doc/man/nvme_ctrl_for_each_ns.2
+++ b/doc/man/nvme_ctrl_for_each_ns.2
@@ -1,4 +1,4 @@
-.TH "nvme_ctrl_for_each_ns" 9 "nvme_ctrl_for_each_ns" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ctrl_for_each_ns" 9 "nvme_ctrl_for_each_ns" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ctrl_for_each_ns \- Traverse namespaces
.SH SYNOPSIS
diff --git a/doc/man/nvme_ctrl_for_each_ns_safe.2 b/doc/man/nvme_ctrl_for_each_ns_safe.2
index 3420e49..84b4d24 100644
--- a/doc/man/nvme_ctrl_for_each_ns_safe.2
+++ b/doc/man/nvme_ctrl_for_each_ns_safe.2
@@ -1,4 +1,4 @@
-.TH "nvme_ctrl_for_each_ns_safe" 9 "nvme_ctrl_for_each_ns_safe" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ctrl_for_each_ns_safe" 9 "nvme_ctrl_for_each_ns_safe" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ctrl_for_each_ns_safe \- Traverse namespaces
.SH SYNOPSIS
diff --git a/doc/man/nvme_ctrl_for_each_path.2 b/doc/man/nvme_ctrl_for_each_path.2
index c98f33b..93bf81f 100644
--- a/doc/man/nvme_ctrl_for_each_path.2
+++ b/doc/man/nvme_ctrl_for_each_path.2
@@ -1,4 +1,4 @@
-.TH "nvme_ctrl_for_each_path" 9 "nvme_ctrl_for_each_path" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ctrl_for_each_path" 9 "nvme_ctrl_for_each_path" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ctrl_for_each_path \- Traverse paths
.SH SYNOPSIS
diff --git a/doc/man/nvme_ctrl_for_each_path_safe.2 b/doc/man/nvme_ctrl_for_each_path_safe.2
index b7da27f..955836a 100644
--- a/doc/man/nvme_ctrl_for_each_path_safe.2
+++ b/doc/man/nvme_ctrl_for_each_path_safe.2
@@ -1,4 +1,4 @@
-.TH "nvme_ctrl_for_each_path_safe" 9 "nvme_ctrl_for_each_path_safe" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ctrl_for_each_path_safe" 9 "nvme_ctrl_for_each_path_safe" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ctrl_for_each_path_safe \- Traverse paths
.SH SYNOPSIS
diff --git a/doc/man/nvme_ctrl_get_address.2 b/doc/man/nvme_ctrl_get_address.2
index 44de2a2..98ccc8a 100644
--- a/doc/man/nvme_ctrl_get_address.2
+++ b/doc/man/nvme_ctrl_get_address.2
@@ -1,4 +1,4 @@
-.TH "nvme_ctrl_get_address" 9 "nvme_ctrl_get_address" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ctrl_get_address" 9 "nvme_ctrl_get_address" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ctrl_get_address \- Address string of a controller
.SH SYNOPSIS
diff --git a/doc/man/nvme_ctrl_get_config.2 b/doc/man/nvme_ctrl_get_config.2
index 8fbc976..8543a45 100644
--- a/doc/man/nvme_ctrl_get_config.2
+++ b/doc/man/nvme_ctrl_get_config.2
@@ -1,4 +1,4 @@
-.TH "nvme_ctrl_get_config" 9 "nvme_ctrl_get_config" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ctrl_get_config" 9 "nvme_ctrl_get_config" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ctrl_get_config \- Fabrics configuration of a controller
.SH SYNOPSIS
diff --git a/doc/man/nvme_ctrl_get_dhchap_host_key.2 b/doc/man/nvme_ctrl_get_dhchap_host_key.2
index 48526e5..a417495 100644
--- a/doc/man/nvme_ctrl_get_dhchap_host_key.2
+++ b/doc/man/nvme_ctrl_get_dhchap_host_key.2
@@ -1,4 +1,4 @@
-.TH "nvme_ctrl_get_dhchap_host_key" 9 "nvme_ctrl_get_dhchap_host_key" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ctrl_get_dhchap_host_key" 9 "nvme_ctrl_get_dhchap_host_key" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ctrl_get_dhchap_host_key \- Return host key
.SH SYNOPSIS
diff --git a/doc/man/nvme_ctrl_get_dhchap_key.2 b/doc/man/nvme_ctrl_get_dhchap_key.2
index f190577..0dc9b2b 100644
--- a/doc/man/nvme_ctrl_get_dhchap_key.2
+++ b/doc/man/nvme_ctrl_get_dhchap_key.2
@@ -1,4 +1,4 @@
-.TH "nvme_ctrl_get_dhchap_key" 9 "nvme_ctrl_get_dhchap_key" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ctrl_get_dhchap_key" 9 "nvme_ctrl_get_dhchap_key" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ctrl_get_dhchap_key \- Return controller key
.SH SYNOPSIS
diff --git a/doc/man/nvme_ctrl_get_fd.2 b/doc/man/nvme_ctrl_get_fd.2
index f8a92a4..491c194 100644
--- a/doc/man/nvme_ctrl_get_fd.2
+++ b/doc/man/nvme_ctrl_get_fd.2
@@ -1,4 +1,4 @@
-.TH "nvme_ctrl_get_fd" 9 "nvme_ctrl_get_fd" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ctrl_get_fd" 9 "nvme_ctrl_get_fd" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ctrl_get_fd \- Get associated file descriptor
.SH SYNOPSIS
@@ -7,5 +7,12 @@ nvme_ctrl_get_fd \- Get associated file descriptor
.SH ARGUMENTS
.IP "c" 12
Controller instance
+.SH "DESCRIPTION"
+libnvme will \fBopen\fP 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
+\fBnvme_ctrl_release_fd\fP is called.
.SH "RETURN"
File descriptor associated with \fIc\fP or -1
diff --git a/doc/man/nvme_ctrl_get_firmware.2 b/doc/man/nvme_ctrl_get_firmware.2
index 45d2c1a..b6a08ee 100644
--- a/doc/man/nvme_ctrl_get_firmware.2
+++ b/doc/man/nvme_ctrl_get_firmware.2
@@ -1,4 +1,4 @@
-.TH "nvme_ctrl_get_firmware" 9 "nvme_ctrl_get_firmware" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ctrl_get_firmware" 9 "nvme_ctrl_get_firmware" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ctrl_get_firmware \- Firmware string of a controller
.SH SYNOPSIS
diff --git a/doc/man/nvme_ctrl_get_host_iface.2 b/doc/man/nvme_ctrl_get_host_iface.2
index 1130ad0..50f64a7 100644
--- a/doc/man/nvme_ctrl_get_host_iface.2
+++ b/doc/man/nvme_ctrl_get_host_iface.2
@@ -1,4 +1,4 @@
-.TH "nvme_ctrl_get_host_iface" 9 "nvme_ctrl_get_host_iface" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ctrl_get_host_iface" 9 "nvme_ctrl_get_host_iface" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ctrl_get_host_iface \- Host interface name of a controller
.SH SYNOPSIS
diff --git a/doc/man/nvme_ctrl_get_host_traddr.2 b/doc/man/nvme_ctrl_get_host_traddr.2
index bc3d2e0..7463337 100644
--- a/doc/man/nvme_ctrl_get_host_traddr.2
+++ b/doc/man/nvme_ctrl_get_host_traddr.2
@@ -1,4 +1,4 @@
-.TH "nvme_ctrl_get_host_traddr" 9 "nvme_ctrl_get_host_traddr" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ctrl_get_host_traddr" 9 "nvme_ctrl_get_host_traddr" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ctrl_get_host_traddr \- Host transport address of a controller
.SH SYNOPSIS
diff --git a/doc/man/nvme_ctrl_get_model.2 b/doc/man/nvme_ctrl_get_model.2
index d2f2e26..470bc4e 100644
--- a/doc/man/nvme_ctrl_get_model.2
+++ b/doc/man/nvme_ctrl_get_model.2
@@ -1,4 +1,4 @@
-.TH "nvme_ctrl_get_model" 9 "nvme_ctrl_get_model" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ctrl_get_model" 9 "nvme_ctrl_get_model" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ctrl_get_model \- Model of a controller
.SH SYNOPSIS
diff --git a/doc/man/nvme_ctrl_get_name.2 b/doc/man/nvme_ctrl_get_name.2
index bdcbc7c..5fc7351 100644
--- a/doc/man/nvme_ctrl_get_name.2
+++ b/doc/man/nvme_ctrl_get_name.2
@@ -1,4 +1,4 @@
-.TH "nvme_ctrl_get_name" 9 "nvme_ctrl_get_name" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ctrl_get_name" 9 "nvme_ctrl_get_name" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ctrl_get_name \- sysfs name of a controller
.SH SYNOPSIS
diff --git a/doc/man/nvme_ctrl_get_numa_node.2 b/doc/man/nvme_ctrl_get_numa_node.2
index b0625cd..aea22c2 100644
--- a/doc/man/nvme_ctrl_get_numa_node.2
+++ b/doc/man/nvme_ctrl_get_numa_node.2
@@ -1,4 +1,4 @@
-.TH "nvme_ctrl_get_numa_node" 9 "nvme_ctrl_get_numa_node" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ctrl_get_numa_node" 9 "nvme_ctrl_get_numa_node" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ctrl_get_numa_node \- NUMA node of a controller
.SH SYNOPSIS
diff --git a/doc/man/nvme_ctrl_get_phy_slot.2 b/doc/man/nvme_ctrl_get_phy_slot.2
index 3427078..74fe3d8 100644
--- a/doc/man/nvme_ctrl_get_phy_slot.2
+++ b/doc/man/nvme_ctrl_get_phy_slot.2
@@ -1,4 +1,4 @@
-.TH "nvme_ctrl_get_phy_slot" 9 "nvme_ctrl_get_phy_slot" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ctrl_get_phy_slot" 9 "nvme_ctrl_get_phy_slot" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ctrl_get_phy_slot \- PCI physical slot number of a controller
.SH SYNOPSIS
diff --git a/doc/man/nvme_ctrl_get_queue_count.2 b/doc/man/nvme_ctrl_get_queue_count.2
index 6d5753f..50da6a8 100644
--- a/doc/man/nvme_ctrl_get_queue_count.2
+++ b/doc/man/nvme_ctrl_get_queue_count.2
@@ -1,4 +1,4 @@
-.TH "nvme_ctrl_get_queue_count" 9 "nvme_ctrl_get_queue_count" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ctrl_get_queue_count" 9 "nvme_ctrl_get_queue_count" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ctrl_get_queue_count \- Queue count of a controller
.SH SYNOPSIS
diff --git a/doc/man/nvme_ctrl_get_serial.2 b/doc/man/nvme_ctrl_get_serial.2
index 7ca8800..20de29c 100644
--- a/doc/man/nvme_ctrl_get_serial.2
+++ b/doc/man/nvme_ctrl_get_serial.2
@@ -1,4 +1,4 @@
-.TH "nvme_ctrl_get_serial" 9 "nvme_ctrl_get_serial" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ctrl_get_serial" 9 "nvme_ctrl_get_serial" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ctrl_get_serial \- Serial number of a controller
.SH SYNOPSIS
diff --git a/doc/man/nvme_ctrl_get_sqsize.2 b/doc/man/nvme_ctrl_get_sqsize.2
index 46d91ce..bdd03b0 100644
--- a/doc/man/nvme_ctrl_get_sqsize.2
+++ b/doc/man/nvme_ctrl_get_sqsize.2
@@ -1,4 +1,4 @@
-.TH "nvme_ctrl_get_sqsize" 9 "nvme_ctrl_get_sqsize" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ctrl_get_sqsize" 9 "nvme_ctrl_get_sqsize" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ctrl_get_sqsize \- SQ size of a controller
.SH SYNOPSIS
diff --git a/doc/man/nvme_ctrl_get_src_addr.2 b/doc/man/nvme_ctrl_get_src_addr.2
new file mode 100644
index 0000000..82573e7
--- /dev/null
+++ b/doc/man/nvme_ctrl_get_src_addr.2
@@ -0,0 +1,17 @@
+.TH "nvme_ctrl_get_src_addr" 9 "nvme_ctrl_get_src_addr" "December 2023" "libnvme API manual" LINUX
+.SH NAME
+nvme_ctrl_get_src_addr \- Extract src_addr from the c->address string
+.SH SYNOPSIS
+.B "char *" nvme_ctrl_get_src_addr
+.BI "(nvme_ctrl_t c " ","
+.BI "char *src_addr " ","
+.BI "size_t src_addr_len " ");"
+.SH ARGUMENTS
+.IP "c" 12
+Controller instance
+.IP "src_addr" 12
+Where to copy the src_addr. Size must be at least INET6_ADDRSTRLEN.
+.IP "src_addr_len" 12
+Length of the buffer \fIsrc_addr\fP.
+.SH "RETURN"
+Pointer to \fIsrc_addr\fP on success. NULL on failure to extract the src_addr.
diff --git a/doc/man/nvme_ctrl_get_state.2 b/doc/man/nvme_ctrl_get_state.2
index 5336673..7d4b6e8 100644
--- a/doc/man/nvme_ctrl_get_state.2
+++ b/doc/man/nvme_ctrl_get_state.2
@@ -1,6 +1,6 @@
-.TH "nvme_ctrl_get_state" 9 "nvme_ctrl_get_state" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ctrl_get_state" 9 "nvme_ctrl_get_state" "December 2023" "libnvme API manual" LINUX
.SH NAME
-nvme_ctrl_get_state \- Running state of an controller
+nvme_ctrl_get_state \- Running state of a controller
.SH SYNOPSIS
.B "const char *" nvme_ctrl_get_state
.BI "(nvme_ctrl_t c " ");"
diff --git a/doc/man/nvme_ctrl_get_subsysnqn.2 b/doc/man/nvme_ctrl_get_subsysnqn.2
index 7bb8c7e..858ff4d 100644
--- a/doc/man/nvme_ctrl_get_subsysnqn.2
+++ b/doc/man/nvme_ctrl_get_subsysnqn.2
@@ -1,4 +1,4 @@
-.TH "nvme_ctrl_get_subsysnqn" 9 "nvme_ctrl_get_subsysnqn" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ctrl_get_subsysnqn" 9 "nvme_ctrl_get_subsysnqn" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ctrl_get_subsysnqn \- Subsystem NQN of a controller
.SH SYNOPSIS
diff --git a/doc/man/nvme_ctrl_get_subsystem.2 b/doc/man/nvme_ctrl_get_subsystem.2
index 83380fe..2fd4bc2 100644
--- a/doc/man/nvme_ctrl_get_subsystem.2
+++ b/doc/man/nvme_ctrl_get_subsystem.2
@@ -1,4 +1,4 @@
-.TH "nvme_ctrl_get_subsystem" 9 "nvme_ctrl_get_subsystem" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ctrl_get_subsystem" 9 "nvme_ctrl_get_subsystem" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ctrl_get_subsystem \- Parent subsystem of a controller
.SH SYNOPSIS
diff --git a/doc/man/nvme_ctrl_get_sysfs_dir.2 b/doc/man/nvme_ctrl_get_sysfs_dir.2
index a2115b9..6eac969 100644
--- a/doc/man/nvme_ctrl_get_sysfs_dir.2
+++ b/doc/man/nvme_ctrl_get_sysfs_dir.2
@@ -1,4 +1,4 @@
-.TH "nvme_ctrl_get_sysfs_dir" 9 "nvme_ctrl_get_sysfs_dir" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ctrl_get_sysfs_dir" 9 "nvme_ctrl_get_sysfs_dir" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ctrl_get_sysfs_dir \- sysfs directory of a controller
.SH SYNOPSIS
diff --git a/doc/man/nvme_ctrl_get_traddr.2 b/doc/man/nvme_ctrl_get_traddr.2
index e1ec4a9..49e2fc7 100644
--- a/doc/man/nvme_ctrl_get_traddr.2
+++ b/doc/man/nvme_ctrl_get_traddr.2
@@ -1,4 +1,4 @@
-.TH "nvme_ctrl_get_traddr" 9 "nvme_ctrl_get_traddr" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ctrl_get_traddr" 9 "nvme_ctrl_get_traddr" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ctrl_get_traddr \- Transport address of a controller
.SH SYNOPSIS
diff --git a/doc/man/nvme_ctrl_get_transport.2 b/doc/man/nvme_ctrl_get_transport.2
index b69b72b..a74468f 100644
--- a/doc/man/nvme_ctrl_get_transport.2
+++ b/doc/man/nvme_ctrl_get_transport.2
@@ -1,4 +1,4 @@
-.TH "nvme_ctrl_get_transport" 9 "nvme_ctrl_get_transport" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ctrl_get_transport" 9 "nvme_ctrl_get_transport" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ctrl_get_transport \- Transport type of a controller
.SH SYNOPSIS
diff --git a/doc/man/nvme_ctrl_get_trsvcid.2 b/doc/man/nvme_ctrl_get_trsvcid.2
index 8d17c64..58b6aba 100644
--- a/doc/man/nvme_ctrl_get_trsvcid.2
+++ b/doc/man/nvme_ctrl_get_trsvcid.2
@@ -1,4 +1,4 @@
-.TH "nvme_ctrl_get_trsvcid" 9 "nvme_ctrl_get_trsvcid" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ctrl_get_trsvcid" 9 "nvme_ctrl_get_trsvcid" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ctrl_get_trsvcid \- Transport service identifier of a controller
.SH SYNOPSIS
diff --git a/doc/man/nvme_ctrl_identify.2 b/doc/man/nvme_ctrl_identify.2
index 32e2d34..b0bafbc 100644
--- a/doc/man/nvme_ctrl_identify.2
+++ b/doc/man/nvme_ctrl_identify.2
@@ -1,4 +1,4 @@
-.TH "nvme_ctrl_identify" 9 "nvme_ctrl_identify" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ctrl_identify" 9 "nvme_ctrl_identify" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ctrl_identify \- Issues an 'identify controller' command
.SH SYNOPSIS
diff --git a/doc/man/nvme_ctrl_is_discovered.2 b/doc/man/nvme_ctrl_is_discovered.2
index 27c3c4b..a5984bb 100644
--- a/doc/man/nvme_ctrl_is_discovered.2
+++ b/doc/man/nvme_ctrl_is_discovered.2
@@ -1,4 +1,4 @@
-.TH "nvme_ctrl_is_discovered" 9 "nvme_ctrl_is_discovered" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ctrl_is_discovered" 9 "nvme_ctrl_is_discovered" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ctrl_is_discovered \- Returns the value of the 'discovered' flag
.SH SYNOPSIS
diff --git a/doc/man/nvme_ctrl_is_discovery_ctrl.2 b/doc/man/nvme_ctrl_is_discovery_ctrl.2
index fc105d6..b9a59e7 100644
--- a/doc/man/nvme_ctrl_is_discovery_ctrl.2
+++ b/doc/man/nvme_ctrl_is_discovery_ctrl.2
@@ -1,4 +1,4 @@
-.TH "nvme_ctrl_is_discovery_ctrl" 9 "nvme_ctrl_is_discovery_ctrl" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ctrl_is_discovery_ctrl" 9 "nvme_ctrl_is_discovery_ctrl" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ctrl_is_discovery_ctrl \- Check the 'discovery_ctrl' flag
.SH SYNOPSIS
diff --git a/doc/man/nvme_ctrl_is_persistent.2 b/doc/man/nvme_ctrl_is_persistent.2
index e6abc2b..2f1a28f 100644
--- a/doc/man/nvme_ctrl_is_persistent.2
+++ b/doc/man/nvme_ctrl_is_persistent.2
@@ -1,4 +1,4 @@
-.TH "nvme_ctrl_is_persistent" 9 "nvme_ctrl_is_persistent" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ctrl_is_persistent" 9 "nvme_ctrl_is_persistent" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ctrl_is_persistent \- Returns the value of the 'persistent' flag
.SH SYNOPSIS
diff --git a/doc/man/nvme_ctrl_is_unique_discovery_ctrl.2 b/doc/man/nvme_ctrl_is_unique_discovery_ctrl.2
index c3e6fc4..57cd5cf 100644
--- a/doc/man/nvme_ctrl_is_unique_discovery_ctrl.2
+++ b/doc/man/nvme_ctrl_is_unique_discovery_ctrl.2
@@ -1,4 +1,4 @@
-.TH "nvme_ctrl_is_unique_discovery_ctrl" 9 "nvme_ctrl_is_unique_discovery_ctrl" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ctrl_is_unique_discovery_ctrl" 9 "nvme_ctrl_is_unique_discovery_ctrl" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ctrl_is_unique_discovery_ctrl \- Check the 'unique_discovery_ctrl' flag
.SH SYNOPSIS
diff --git a/doc/man/nvme_ctrl_list.2 b/doc/man/nvme_ctrl_list.2
index 6e2ae8d..01ce6be 100644
--- a/doc/man/nvme_ctrl_list.2
+++ b/doc/man/nvme_ctrl_list.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_ctrl_list" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_ctrl_list" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_ctrl_list \- Controller List
.SH SYNOPSIS
diff --git a/doc/man/nvme_ctrl_metadata_type.2 b/doc/man/nvme_ctrl_metadata_type.2
index 61e1785..3fc97dc 100644
--- a/doc/man/nvme_ctrl_metadata_type.2
+++ b/doc/man/nvme_ctrl_metadata_type.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_ctrl_metadata_type" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_ctrl_metadata_type" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_ctrl_metadata_type \- Controller Metadata Element Types
.SH SYNOPSIS
diff --git a/doc/man/nvme_ctrl_next_ns.2 b/doc/man/nvme_ctrl_next_ns.2
index 0dcedec..a0f8456 100644
--- a/doc/man/nvme_ctrl_next_ns.2
+++ b/doc/man/nvme_ctrl_next_ns.2
@@ -1,4 +1,4 @@
-.TH "nvme_ctrl_next_ns" 9 "nvme_ctrl_next_ns" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ctrl_next_ns" 9 "nvme_ctrl_next_ns" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ctrl_next_ns \- Next namespace iterator
.SH SYNOPSIS
diff --git a/doc/man/nvme_ctrl_next_path.2 b/doc/man/nvme_ctrl_next_path.2
index 1d16b54..1e1bc6a 100644
--- a/doc/man/nvme_ctrl_next_path.2
+++ b/doc/man/nvme_ctrl_next_path.2
@@ -1,4 +1,4 @@
-.TH "nvme_ctrl_next_path" 9 "nvme_ctrl_next_path" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ctrl_next_path" 9 "nvme_ctrl_next_path" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ctrl_next_path \- Next path iterator
.SH SYNOPSIS
diff --git a/doc/man/nvme_ctrl_release_fd.2 b/doc/man/nvme_ctrl_release_fd.2
new file mode 100644
index 0000000..d75683d
--- /dev/null
+++ b/doc/man/nvme_ctrl_release_fd.2
@@ -0,0 +1,9 @@
+.TH "nvme_ctrl_release_fd" 9 "nvme_ctrl_release_fd" "December 2023" "libnvme API manual" LINUX
+.SH NAME
+nvme_ctrl_release_fd \- Close fd and clear fd from controller object
+.SH SYNOPSIS
+.B "void" nvme_ctrl_release_fd
+.BI "(nvme_ctrl_t c " ");"
+.SH ARGUMENTS
+.IP "c" 12
+Controller instance
diff --git a/doc/man/nvme_ctrl_reset.2 b/doc/man/nvme_ctrl_reset.2
index 07e09c0..ffbcba8 100644
--- a/doc/man/nvme_ctrl_reset.2
+++ b/doc/man/nvme_ctrl_reset.2
@@ -1,4 +1,4 @@
-.TH "nvme_ctrl_reset" 9 "nvme_ctrl_reset" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ctrl_reset" 9 "nvme_ctrl_reset" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ctrl_reset \- Initiate a controller reset
.SH SYNOPSIS
diff --git a/doc/man/nvme_ctrl_set_dhchap_host_key.2 b/doc/man/nvme_ctrl_set_dhchap_host_key.2
index 29f3ada..2d00a73 100644
--- a/doc/man/nvme_ctrl_set_dhchap_host_key.2
+++ b/doc/man/nvme_ctrl_set_dhchap_host_key.2
@@ -1,4 +1,4 @@
-.TH "nvme_ctrl_set_dhchap_host_key" 9 "nvme_ctrl_set_dhchap_host_key" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ctrl_set_dhchap_host_key" 9 "nvme_ctrl_set_dhchap_host_key" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ctrl_set_dhchap_host_key \- Set host key
.SH SYNOPSIS
diff --git a/doc/man/nvme_ctrl_set_dhchap_key.2 b/doc/man/nvme_ctrl_set_dhchap_key.2
index a2fed0e..285c3a5 100644
--- a/doc/man/nvme_ctrl_set_dhchap_key.2
+++ b/doc/man/nvme_ctrl_set_dhchap_key.2
@@ -1,4 +1,4 @@
-.TH "nvme_ctrl_set_dhchap_key" 9 "nvme_ctrl_set_dhchap_key" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ctrl_set_dhchap_key" 9 "nvme_ctrl_set_dhchap_key" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ctrl_set_dhchap_key \- Set controller key
.SH SYNOPSIS
diff --git a/doc/man/nvme_ctrl_set_discovered.2 b/doc/man/nvme_ctrl_set_discovered.2
index bc7ae03..02250bf 100644
--- a/doc/man/nvme_ctrl_set_discovered.2
+++ b/doc/man/nvme_ctrl_set_discovered.2
@@ -1,4 +1,4 @@
-.TH "nvme_ctrl_set_discovered" 9 "nvme_ctrl_set_discovered" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ctrl_set_discovered" 9 "nvme_ctrl_set_discovered" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ctrl_set_discovered \- Set the 'discovered' flag
.SH SYNOPSIS
diff --git a/doc/man/nvme_ctrl_set_discovery_ctrl.2 b/doc/man/nvme_ctrl_set_discovery_ctrl.2
index c018fff..48bbadb 100644
--- a/doc/man/nvme_ctrl_set_discovery_ctrl.2
+++ b/doc/man/nvme_ctrl_set_discovery_ctrl.2
@@ -1,4 +1,4 @@
-.TH "nvme_ctrl_set_discovery_ctrl" 9 "nvme_ctrl_set_discovery_ctrl" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ctrl_set_discovery_ctrl" 9 "nvme_ctrl_set_discovery_ctrl" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ctrl_set_discovery_ctrl \- Set the 'discovery_ctrl' flag
.SH SYNOPSIS
diff --git a/doc/man/nvme_ctrl_set_persistent.2 b/doc/man/nvme_ctrl_set_persistent.2
index 11cfc17..ecbf070 100644
--- a/doc/man/nvme_ctrl_set_persistent.2
+++ b/doc/man/nvme_ctrl_set_persistent.2
@@ -1,4 +1,4 @@
-.TH "nvme_ctrl_set_persistent" 9 "nvme_ctrl_set_persistent" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ctrl_set_persistent" 9 "nvme_ctrl_set_persistent" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ctrl_set_persistent \- Set the 'persistent' flag
.SH SYNOPSIS
diff --git a/doc/man/nvme_ctrl_set_unique_discovery_ctrl.2 b/doc/man/nvme_ctrl_set_unique_discovery_ctrl.2
index ae9963f..ca85fa5 100644
--- a/doc/man/nvme_ctrl_set_unique_discovery_ctrl.2
+++ b/doc/man/nvme_ctrl_set_unique_discovery_ctrl.2
@@ -1,4 +1,4 @@
-.TH "nvme_ctrl_set_unique_discovery_ctrl" 9 "nvme_ctrl_set_unique_discovery_ctrl" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ctrl_set_unique_discovery_ctrl" 9 "nvme_ctrl_set_unique_discovery_ctrl" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ctrl_set_unique_discovery_ctrl \- Set the 'unique_discovery_ctrl' flag
.SH SYNOPSIS
diff --git a/doc/man/nvme_ctrls_filter.2 b/doc/man/nvme_ctrls_filter.2
index a3f99d2..0b2d808 100644
--- a/doc/man/nvme_ctrls_filter.2
+++ b/doc/man/nvme_ctrls_filter.2
@@ -1,4 +1,4 @@
-.TH "nvme_ctrls_filter" 9 "nvme_ctrls_filter" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ctrls_filter" 9 "nvme_ctrls_filter" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ctrls_filter \- Filter for controllers
.SH SYNOPSIS
diff --git a/doc/man/nvme_data_tfr.2 b/doc/man/nvme_data_tfr.2
index 53dced7..efe6929 100644
--- a/doc/man/nvme_data_tfr.2
+++ b/doc/man/nvme_data_tfr.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_data_tfr" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_data_tfr" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_data_tfr \- Data transfer direction of the command
.SH SYNOPSIS
diff --git a/doc/man/nvme_default_host.2 b/doc/man/nvme_default_host.2
index ae32203..2d4949d 100644
--- a/doc/man/nvme_default_host.2
+++ b/doc/man/nvme_default_host.2
@@ -1,4 +1,4 @@
-.TH "nvme_default_host" 9 "nvme_default_host" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_default_host" 9 "nvme_default_host" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_default_host \- Initializes the default host
.SH SYNOPSIS
diff --git a/doc/man/nvme_describe_key_serial.2 b/doc/man/nvme_describe_key_serial.2
index 96dc547..205fcd7 100644
--- a/doc/man/nvme_describe_key_serial.2
+++ b/doc/man/nvme_describe_key_serial.2
@@ -1,4 +1,4 @@
-.TH "nvme_describe_key_serial" 9 "nvme_describe_key_serial" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_describe_key_serial" 9 "nvme_describe_key_serial" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_describe_key_serial \- Return key description
.SH SYNOPSIS
diff --git a/doc/man/nvme_dev_self_test.2 b/doc/man/nvme_dev_self_test.2
index 7e26efc..9d963f7 100644
--- a/doc/man/nvme_dev_self_test.2
+++ b/doc/man/nvme_dev_self_test.2
@@ -1,4 +1,4 @@
-.TH "nvme_dev_self_test" 9 "nvme_dev_self_test" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_dev_self_test" 9 "nvme_dev_self_test" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_dev_self_test \- Start or abort a self test
.SH SYNOPSIS
diff --git a/doc/man/nvme_directive_dtype.2 b/doc/man/nvme_directive_dtype.2
index 8a19713..3e72770 100644
--- a/doc/man/nvme_directive_dtype.2
+++ b/doc/man/nvme_directive_dtype.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_directive_dtype" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_directive_dtype" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_directive_dtype \- Directive Types
.SH SYNOPSIS
diff --git a/doc/man/nvme_directive_receive_doper.2 b/doc/man/nvme_directive_receive_doper.2
index ed2acc7..8d5514b 100644
--- a/doc/man/nvme_directive_receive_doper.2
+++ b/doc/man/nvme_directive_receive_doper.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_directive_receive_doper" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_directive_receive_doper" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_directive_receive_doper \- Directive Receive Directive Operation
.SH SYNOPSIS
diff --git a/doc/man/nvme_directive_recv.2 b/doc/man/nvme_directive_recv.2
index 2ca72f3..7289060 100644
--- a/doc/man/nvme_directive_recv.2
+++ b/doc/man/nvme_directive_recv.2
@@ -1,4 +1,4 @@
-.TH "nvme_directive_recv" 9 "nvme_directive_recv" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_directive_recv" 9 "nvme_directive_recv" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_directive_recv \- Receive directive specific data
.SH SYNOPSIS
diff --git a/doc/man/nvme_directive_recv_identify_parameters.2 b/doc/man/nvme_directive_recv_identify_parameters.2
index 5272e40..8789028 100644
--- a/doc/man/nvme_directive_recv_identify_parameters.2
+++ b/doc/man/nvme_directive_recv_identify_parameters.2
@@ -1,4 +1,4 @@
-.TH "nvme_directive_recv_identify_parameters" 9 "nvme_directive_recv_identify_parameters" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_directive_recv_identify_parameters" 9 "nvme_directive_recv_identify_parameters" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_directive_recv_identify_parameters \- Directive receive identifier parameters
.SH SYNOPSIS
diff --git a/doc/man/nvme_directive_recv_stream_allocate.2 b/doc/man/nvme_directive_recv_stream_allocate.2
index a818f9d..e78dc97 100644
--- a/doc/man/nvme_directive_recv_stream_allocate.2
+++ b/doc/man/nvme_directive_recv_stream_allocate.2
@@ -1,4 +1,4 @@
-.TH "nvme_directive_recv_stream_allocate" 9 "nvme_directive_recv_stream_allocate" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_directive_recv_stream_allocate" 9 "nvme_directive_recv_stream_allocate" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_directive_recv_stream_allocate \- Directive receive stream allocate
.SH SYNOPSIS
diff --git a/doc/man/nvme_directive_recv_stream_parameters.2 b/doc/man/nvme_directive_recv_stream_parameters.2
index af7c367..c6dd32e 100644
--- a/doc/man/nvme_directive_recv_stream_parameters.2
+++ b/doc/man/nvme_directive_recv_stream_parameters.2
@@ -1,4 +1,4 @@
-.TH "nvme_directive_recv_stream_parameters" 9 "nvme_directive_recv_stream_parameters" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_directive_recv_stream_parameters" 9 "nvme_directive_recv_stream_parameters" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_directive_recv_stream_parameters \- Directive receive stream parameters
.SH SYNOPSIS
diff --git a/doc/man/nvme_directive_recv_stream_status.2 b/doc/man/nvme_directive_recv_stream_status.2
index 13a69ca..601b858 100644
--- a/doc/man/nvme_directive_recv_stream_status.2
+++ b/doc/man/nvme_directive_recv_stream_status.2
@@ -1,4 +1,4 @@
-.TH "nvme_directive_recv_stream_status" 9 "nvme_directive_recv_stream_status" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_directive_recv_stream_status" 9 "nvme_directive_recv_stream_status" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_directive_recv_stream_status \- Directive receive stream status
.SH SYNOPSIS
diff --git a/doc/man/nvme_directive_send.2 b/doc/man/nvme_directive_send.2
index 7c50c76..3623448 100644
--- a/doc/man/nvme_directive_send.2
+++ b/doc/man/nvme_directive_send.2
@@ -1,4 +1,4 @@
-.TH "nvme_directive_send" 9 "nvme_directive_send" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_directive_send" 9 "nvme_directive_send" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_directive_send \- Send directive command
.SH SYNOPSIS
diff --git a/doc/man/nvme_directive_send_doper.2 b/doc/man/nvme_directive_send_doper.2
index da6d395..2dd1175 100644
--- a/doc/man/nvme_directive_send_doper.2
+++ b/doc/man/nvme_directive_send_doper.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_directive_send_doper" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_directive_send_doper" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_directive_send_doper \- Directive Send Directive Operation
.SH SYNOPSIS
diff --git a/doc/man/nvme_directive_send_id_endir.2 b/doc/man/nvme_directive_send_id_endir.2
index 14affd7..ddf4078 100644
--- a/doc/man/nvme_directive_send_id_endir.2
+++ b/doc/man/nvme_directive_send_id_endir.2
@@ -1,4 +1,4 @@
-.TH "nvme_directive_send_id_endir" 9 "nvme_directive_send_id_endir" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_directive_send_id_endir" 9 "nvme_directive_send_id_endir" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_directive_send_id_endir \- Directive Send Enable Directive
.SH SYNOPSIS
diff --git a/doc/man/nvme_directive_send_identify_endir.2 b/doc/man/nvme_directive_send_identify_endir.2
index 9e31733..fd7aa25 100644
--- a/doc/man/nvme_directive_send_identify_endir.2
+++ b/doc/man/nvme_directive_send_identify_endir.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_directive_send_identify_endir" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_directive_send_identify_endir" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_directive_send_identify_endir \- Enable Directive
.SH SYNOPSIS
diff --git a/doc/man/nvme_directive_send_stream_release_identifier.2 b/doc/man/nvme_directive_send_stream_release_identifier.2
index 9529463..f572152 100644
--- a/doc/man/nvme_directive_send_stream_release_identifier.2
+++ b/doc/man/nvme_directive_send_stream_release_identifier.2
@@ -1,4 +1,4 @@
-.TH "nvme_directive_send_stream_release_identifier" 9 "nvme_directive_send_stream_release_identifier" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_directive_send_stream_release_identifier" 9 "nvme_directive_send_stream_release_identifier" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_directive_send_stream_release_identifier \- Directive Send Stream release
.SH SYNOPSIS
diff --git a/doc/man/nvme_directive_send_stream_release_resource.2 b/doc/man/nvme_directive_send_stream_release_resource.2
index 0a75237..e139db6 100644
--- a/doc/man/nvme_directive_send_stream_release_resource.2
+++ b/doc/man/nvme_directive_send_stream_release_resource.2
@@ -1,4 +1,4 @@
-.TH "nvme_directive_send_stream_release_resource" 9 "nvme_directive_send_stream_release_resource" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_directive_send_stream_release_resource" 9 "nvme_directive_send_stream_release_resource" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_directive_send_stream_release_resource \- Directive Send Stream release resources
.SH SYNOPSIS
diff --git a/doc/man/nvme_directive_types.2 b/doc/man/nvme_directive_types.2
index fa74691..c877df9 100644
--- a/doc/man/nvme_directive_types.2
+++ b/doc/man/nvme_directive_types.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_directive_types" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_directive_types" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_directive_types \- Directives Supported or Enabled
.SH SYNOPSIS
diff --git a/doc/man/nvme_disconnect_ctrl.2 b/doc/man/nvme_disconnect_ctrl.2
index dad0253..83406bd 100644
--- a/doc/man/nvme_disconnect_ctrl.2
+++ b/doc/man/nvme_disconnect_ctrl.2
@@ -1,4 +1,4 @@
-.TH "nvme_disconnect_ctrl" 9 "nvme_disconnect_ctrl" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_disconnect_ctrl" 9 "nvme_disconnect_ctrl" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_disconnect_ctrl \- Disconnect a controller
.SH SYNOPSIS
diff --git a/doc/man/nvme_dsm.2 b/doc/man/nvme_dsm.2
index 1b7cac0..02363a9 100644
--- a/doc/man/nvme_dsm.2
+++ b/doc/man/nvme_dsm.2
@@ -1,4 +1,4 @@
-.TH "nvme_dsm" 9 "nvme_dsm" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_dsm" 9 "nvme_dsm" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_dsm \- Send an nvme data set management command
.SH SYNOPSIS
diff --git a/doc/man/nvme_dsm_attributes.2 b/doc/man/nvme_dsm_attributes.2
index 7bf524c..596cc4d 100644
--- a/doc/man/nvme_dsm_attributes.2
+++ b/doc/man/nvme_dsm_attributes.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_dsm_attributes" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_dsm_attributes" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_dsm_attributes \- Dataset Management attributes
.SH SYNOPSIS
diff --git a/doc/man/nvme_dsm_range.2 b/doc/man/nvme_dsm_range.2
index d251d23..0fe1724 100644
--- a/doc/man/nvme_dsm_range.2
+++ b/doc/man/nvme_dsm_range.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_dsm_range" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_dsm_range" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_dsm_range \- Dataset Management - Range Definition
.SH SYNOPSIS
diff --git a/doc/man/nvme_dst_stc.2 b/doc/man/nvme_dst_stc.2
index e6eeb5e..67d38ee 100644
--- a/doc/man/nvme_dst_stc.2
+++ b/doc/man/nvme_dst_stc.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_dst_stc" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_dst_stc" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_dst_stc \- Action taken by the Device Self-test command
.SH SYNOPSIS
diff --git a/doc/man/nvme_dump_config.2 b/doc/man/nvme_dump_config.2
index 583c6c2..9d9db10 100644
--- a/doc/man/nvme_dump_config.2
+++ b/doc/man/nvme_dump_config.2
@@ -1,4 +1,4 @@
-.TH "nvme_dump_config" 9 "nvme_dump_config" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_dump_config" 9 "nvme_dump_config" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_dump_config \- Print the JSON configuration
.SH SYNOPSIS
diff --git a/doc/man/nvme_dump_tree.2 b/doc/man/nvme_dump_tree.2
index e096496..94c2359 100644
--- a/doc/man/nvme_dump_tree.2
+++ b/doc/man/nvme_dump_tree.2
@@ -1,4 +1,4 @@
-.TH "nvme_dump_tree" 9 "nvme_dump_tree" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_dump_tree" 9 "nvme_dump_tree" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_dump_tree \- Dump internal object tree
.SH SYNOPSIS
diff --git a/doc/man/nvme_eg_critical_warning_flags.2 b/doc/man/nvme_eg_critical_warning_flags.2
index 3c95a7d..e0fd244 100644
--- a/doc/man/nvme_eg_critical_warning_flags.2
+++ b/doc/man/nvme_eg_critical_warning_flags.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_eg_critical_warning_flags" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_eg_critical_warning_flags" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_eg_critical_warning_flags \- Endurance Group Information Log - Critical Warning
.SH SYNOPSIS
diff --git a/doc/man/nvme_eg_event_aggregate_log.2 b/doc/man/nvme_eg_event_aggregate_log.2
index 443257d..912c8b1 100644
--- a/doc/man/nvme_eg_event_aggregate_log.2
+++ b/doc/man/nvme_eg_event_aggregate_log.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_eg_event_aggregate_log" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_eg_event_aggregate_log" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_eg_event_aggregate_log \- Endurance Group Event Aggregate
.SH SYNOPSIS
diff --git a/doc/man/nvme_end_grp_chan_desc.2 b/doc/man/nvme_end_grp_chan_desc.2
index 169cb24..086c6c5 100644
--- a/doc/man/nvme_end_grp_chan_desc.2
+++ b/doc/man/nvme_end_grp_chan_desc.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_end_grp_chan_desc" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_end_grp_chan_desc" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_end_grp_chan_desc \- Endurance Group Channel Configuration Descriptor
.SH SYNOPSIS
diff --git a/doc/man/nvme_end_grp_config_desc.2 b/doc/man/nvme_end_grp_config_desc.2
index 25bf2cd..6ff63fc 100644
--- a/doc/man/nvme_end_grp_config_desc.2
+++ b/doc/man/nvme_end_grp_config_desc.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_end_grp_config_desc" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_end_grp_config_desc" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_end_grp_config_desc \- Endurance Group Configuration Descriptor
.SH SYNOPSIS
diff --git a/doc/man/nvme_endurance_group_log.2 b/doc/man/nvme_endurance_group_log.2
index ccf7ecc..4944260 100644
--- a/doc/man/nvme_endurance_group_log.2
+++ b/doc/man/nvme_endurance_group_log.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_endurance_group_log" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_endurance_group_log" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_endurance_group_log \- Endurance Group Information Log
.SH SYNOPSIS
@@ -6,7 +6,9 @@ struct nvme_endurance_group_log {
.br
.BI " __u8 critical_warning;"
.br
-.BI " __u8 rsvd1[2];"
+.BI " __u8 endurance_group_features;"
+.br
+.BI " __u8 rsvd2;"
.br
.BI " __u8 avl_spare;"
.br
@@ -14,7 +16,9 @@ struct nvme_endurance_group_log {
.br
.BI " __u8 percent_used;"
.br
-.BI " __u8 rsvd6[26];"
+.BI " __le16 domain_identifier;"
+.br
+.BI " __u8 rsvd8[24];"
.br
.BI " __u8 endurance_estimate[16];"
.br
@@ -32,7 +36,11 @@ struct nvme_endurance_group_log {
.br
.BI " __u8 num_err_info_log_entries[16];"
.br
-.BI " __u8 rsvd160[352];"
+.BI " __u8 total_end_grp_cap[16];"
+.br
+.BI " __u8 unalloc_end_grp_cap[16];"
+.br
+.BI " __u8 rsvd192[320];"
.br
.BI "
};
@@ -41,7 +49,9 @@ struct nvme_endurance_group_log {
.SH Members
.IP "critical_warning" 12
Critical Warning
-.IP "rsvd1" 12
+.IP "endurance_group_features" 12
+Endurance Group Features
+.IP "rsvd2" 12
Reserved
.IP "avl_spare" 12
Available Spare
@@ -49,7 +59,9 @@ Available Spare
Available Spare Threshold
.IP "percent_used" 12
Percentage Used
-.IP "rsvd6" 12
+.IP "domain_identifier" 12
+Domain Identifier
+.IP "rsvd8" 12
Reserved
.IP "endurance_estimate" 12
Endurance Estimate
@@ -67,5 +79,9 @@ Host Write Commands
Media and Data Integrity Errors
.IP "num_err_info_log_entries" 12
Number of Error Information Log Entries
-.IP "rsvd160" 12
+.IP "total_end_grp_cap" 12
+Total Endurance Group Capacity
+.IP "unalloc_end_grp_cap" 12
+Unallocated Endurance Group Capacity
+.IP "rsvd192" 12
Reserved
diff --git a/doc/man/nvme_eom_lane_desc.2 b/doc/man/nvme_eom_lane_desc.2
new file mode 100644
index 0000000..687bd6d
--- /dev/null
+++ b/doc/man/nvme_eom_lane_desc.2
@@ -0,0 +1,63 @@
+.TH "libnvme" 9 "struct nvme_eom_lane_desc" "December 2023" "API Manual" LINUX
+.SH NAME
+struct nvme_eom_lane_desc \- EOM Lane Descriptor
+.SH SYNOPSIS
+struct nvme_eom_lane_desc {
+.br
+.BI " __u8 rsvd0;"
+.br
+.BI " __u8 mstatus;"
+.br
+.BI " __u8 lane;"
+.br
+.BI " __u8 eye;"
+.br
+.BI " __le16 top;"
+.br
+.BI " __le16 bottom;"
+.br
+.BI " __le16 left;"
+.br
+.BI " __le16 right;"
+.br
+.BI " __le16 nrows;"
+.br
+.BI " __le16 ncols;"
+.br
+.BI " __le16 edlen;"
+.br
+.BI " __u8 rsvd18[14];"
+.br
+.BI " __u8 eye_desc[];"
+.br
+.BI "
+};
+.br
+
+.SH Members
+.IP "rsvd0" 12
+Reserved
+.IP "mstatus" 12
+Measurement Status
+.IP "lane" 12
+Lane number
+.IP "eye" 12
+Eye number
+.IP "top" 12
+Absolute number of rows from center to top edge of eye
+.IP "bottom" 12
+Absolute number of rows from center to bottom edge of eye
+.IP "left" 12
+Absolute number of rows from center to left edge of eye
+.IP "right" 12
+Absolute number of rows from center to right edge of eye
+.IP "nrows" 12
+Number of Rows
+.IP "ncols" 12
+Number of Columns
+.IP "edlen" 12
+Eye Data Length
+.IP "rsvd18" 12
+Reserved
+.IP "eye_desc" 12
+Printable Eye, Eye Data, and any Padding
diff --git a/doc/man/nvme_eom_optional_data.2 b/doc/man/nvme_eom_optional_data.2
new file mode 100644
index 0000000..99123af
--- /dev/null
+++ b/doc/man/nvme_eom_optional_data.2
@@ -0,0 +1,18 @@
+.TH "libnvme" 9 "enum nvme_eom_optional_data" "December 2023" "API Manual" LINUX
+.SH NAME
+enum nvme_eom_optional_data \- EOM Optional Data Present Fields
+.SH SYNOPSIS
+enum nvme_eom_optional_data {
+.br
+.BI " NVME_EOM_EYE_DATA_PRESENT"
+,
+.br
+.br
+.BI " NVME_EOM_PRINTABLE_EYE_PRESENT"
+
+};
+.SH Constants
+.IP "NVME_EOM_EYE_DATA_PRESENT" 12
+Eye Data Present
+.IP "NVME_EOM_PRINTABLE_EYE_PRESENT" 12
+Printable Eye Present
diff --git a/doc/man/nvme_errno_to_string.2 b/doc/man/nvme_errno_to_string.2
index f0b2839..c0b5755 100644
--- a/doc/man/nvme_errno_to_string.2
+++ b/doc/man/nvme_errno_to_string.2
@@ -1,4 +1,4 @@
-.TH "nvme_errno_to_string" 9 "nvme_errno_to_string" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_errno_to_string" 9 "nvme_errno_to_string" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_errno_to_string \- Returns string describing nvme connect failures
.SH SYNOPSIS
diff --git a/doc/man/nvme_error_log_page.2 b/doc/man/nvme_error_log_page.2
index d11eff3..b06b493 100644
--- a/doc/man/nvme_error_log_page.2
+++ b/doc/man/nvme_error_log_page.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_error_log_page" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_error_log_page" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_error_log_page \- Error Information Log Entry (Log Identifier 01h)
.SH SYNOPSIS
diff --git a/doc/man/nvme_fabrics_config.2 b/doc/man/nvme_fabrics_config.2
index 6a80747..1deab12 100644
--- a/doc/man/nvme_fabrics_config.2
+++ b/doc/man/nvme_fabrics_config.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_fabrics_config" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_fabrics_config" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_fabrics_config \- Defines all linux nvme fabrics initiator options
.SH SYNOPSIS
diff --git a/doc/man/nvme_fctype.2 b/doc/man/nvme_fctype.2
index 3e8fc4f..7b058f5 100644
--- a/doc/man/nvme_fctype.2
+++ b/doc/man/nvme_fctype.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_fctype" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_fctype" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_fctype \- Fabrics Command Types
.SH SYNOPSIS
diff --git a/doc/man/nvme_fdp_config_desc.2 b/doc/man/nvme_fdp_config_desc.2
index a00ac72..ffbb582 100644
--- a/doc/man/nvme_fdp_config_desc.2
+++ b/doc/man/nvme_fdp_config_desc.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_fdp_config_desc" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_fdp_config_desc" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_fdp_config_desc \- FDP Configuration Descriptor
.SH SYNOPSIS
diff --git a/doc/man/nvme_fdp_config_fdpa.2 b/doc/man/nvme_fdp_config_fdpa.2
index 4a2796a..12965d7 100644
--- a/doc/man/nvme_fdp_config_fdpa.2
+++ b/doc/man/nvme_fdp_config_fdpa.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_fdp_config_fdpa" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_fdp_config_fdpa" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_fdp_config_fdpa \- FDP Attributes
.SH SYNOPSIS
diff --git a/doc/man/nvme_fdp_config_log.2 b/doc/man/nvme_fdp_config_log.2
index d839eb1..02c9e8c 100644
--- a/doc/man/nvme_fdp_config_log.2
+++ b/doc/man/nvme_fdp_config_log.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_fdp_config_log" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_fdp_config_log" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_fdp_config_log \- FDP Configurations Log Page
.SH SYNOPSIS
diff --git a/doc/man/nvme_fdp_event.2 b/doc/man/nvme_fdp_event.2
index f310d53..6cfe6c5 100644
--- a/doc/man/nvme_fdp_event.2
+++ b/doc/man/nvme_fdp_event.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_fdp_event" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_fdp_event" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_fdp_event \- FDP Event
.SH SYNOPSIS
diff --git a/doc/man/nvme_fdp_event_flags.2 b/doc/man/nvme_fdp_event_flags.2
index f7e7387..f545776 100644
--- a/doc/man/nvme_fdp_event_flags.2
+++ b/doc/man/nvme_fdp_event_flags.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_fdp_event_flags" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_fdp_event_flags" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_fdp_event_flags \- FDP Event Flags
.SH SYNOPSIS
diff --git a/doc/man/nvme_fdp_event_realloc.2 b/doc/man/nvme_fdp_event_realloc.2
index e32e2aa..5ca2f1e 100644
--- a/doc/man/nvme_fdp_event_realloc.2
+++ b/doc/man/nvme_fdp_event_realloc.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_fdp_event_realloc" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_fdp_event_realloc" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_fdp_event_realloc \- Media Reallocated Event Type Specific Information
.SH SYNOPSIS
diff --git a/doc/man/nvme_fdp_event_realloc_flags.2 b/doc/man/nvme_fdp_event_realloc_flags.2
index 3072bc3..fdff873 100644
--- a/doc/man/nvme_fdp_event_realloc_flags.2
+++ b/doc/man/nvme_fdp_event_realloc_flags.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_fdp_event_realloc_flags" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_fdp_event_realloc_flags" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_fdp_event_realloc_flags \- Media Reallocated Event Type Specific Flags
.SH SYNOPSIS
diff --git a/doc/man/nvme_fdp_event_type.2 b/doc/man/nvme_fdp_event_type.2
index 8ddbcbd..f115e34 100644
--- a/doc/man/nvme_fdp_event_type.2
+++ b/doc/man/nvme_fdp_event_type.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_fdp_event_type" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_fdp_event_type" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_fdp_event_type \- FDP Event Types
.SH SYNOPSIS
diff --git a/doc/man/nvme_fdp_events_log.2 b/doc/man/nvme_fdp_events_log.2
index cbc6021..7d6c1b7 100644
--- a/doc/man/nvme_fdp_events_log.2
+++ b/doc/man/nvme_fdp_events_log.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_fdp_events_log" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_fdp_events_log" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_fdp_events_log \- FDP Events Log Page
.SH SYNOPSIS
diff --git a/doc/man/nvme_fdp_reclaim_unit_handle_status.2 b/doc/man/nvme_fdp_reclaim_unit_handle_status.2
index 5b25da2..c70cb03 100644
--- a/doc/man/nvme_fdp_reclaim_unit_handle_status.2
+++ b/doc/man/nvme_fdp_reclaim_unit_handle_status.2
@@ -1,4 +1,4 @@
-.TH "nvme_fdp_reclaim_unit_handle_status" 9 "nvme_fdp_reclaim_unit_handle_status" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_fdp_reclaim_unit_handle_status" 9 "nvme_fdp_reclaim_unit_handle_status" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_fdp_reclaim_unit_handle_status \- Get reclaim unit handle status
.SH SYNOPSIS
diff --git a/doc/man/nvme_fdp_reclaim_unit_handle_update.2 b/doc/man/nvme_fdp_reclaim_unit_handle_update.2
index 8459a3c..5e42aa5 100644
--- a/doc/man/nvme_fdp_reclaim_unit_handle_update.2
+++ b/doc/man/nvme_fdp_reclaim_unit_handle_update.2
@@ -1,4 +1,4 @@
-.TH "nvme_fdp_reclaim_unit_handle_update" 9 "nvme_fdp_reclaim_unit_handle_update" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_fdp_reclaim_unit_handle_update" 9 "nvme_fdp_reclaim_unit_handle_update" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_fdp_reclaim_unit_handle_update \- Update a list of reclaim unit handles
.SH SYNOPSIS
diff --git a/doc/man/nvme_fdp_ruh_desc.2 b/doc/man/nvme_fdp_ruh_desc.2
index 9072eea..57979ec 100644
--- a/doc/man/nvme_fdp_ruh_desc.2
+++ b/doc/man/nvme_fdp_ruh_desc.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_fdp_ruh_desc" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_fdp_ruh_desc" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_fdp_ruh_desc \- Reclaim Unit Handle Descriptor
.SH SYNOPSIS
diff --git a/doc/man/nvme_fdp_ruh_status.2 b/doc/man/nvme_fdp_ruh_status.2
index 7378076..31cd820 100644
--- a/doc/man/nvme_fdp_ruh_status.2
+++ b/doc/man/nvme_fdp_ruh_status.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_fdp_ruh_status" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_fdp_ruh_status" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_fdp_ruh_status \- Reclaim Unit Handle Status
.SH SYNOPSIS
diff --git a/doc/man/nvme_fdp_ruh_status_desc.2 b/doc/man/nvme_fdp_ruh_status_desc.2
index 17adbbd..da40653 100644
--- a/doc/man/nvme_fdp_ruh_status_desc.2
+++ b/doc/man/nvme_fdp_ruh_status_desc.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_fdp_ruh_status_desc" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_fdp_ruh_status_desc" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_fdp_ruh_status_desc \- Reclaim Unit Handle Status Descriptor
.SH SYNOPSIS
diff --git a/doc/man/nvme_fdp_ruh_type.2 b/doc/man/nvme_fdp_ruh_type.2
index 7fb5c73..a8bfbff 100644
--- a/doc/man/nvme_fdp_ruh_type.2
+++ b/doc/man/nvme_fdp_ruh_type.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_fdp_ruh_type" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_fdp_ruh_type" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_fdp_ruh_type \- Reclaim Unit Handle Type
.SH SYNOPSIS
diff --git a/doc/man/nvme_fdp_ruha.2 b/doc/man/nvme_fdp_ruha.2
index 509f0b7..b0d5705 100644
--- a/doc/man/nvme_fdp_ruha.2
+++ b/doc/man/nvme_fdp_ruha.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_fdp_ruha" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_fdp_ruha" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_fdp_ruha \- Reclaim Unit Handle Attributes
.SH SYNOPSIS
diff --git a/doc/man/nvme_fdp_ruhu_desc.2 b/doc/man/nvme_fdp_ruhu_desc.2
index 53ed484..3f7cb3d 100644
--- a/doc/man/nvme_fdp_ruhu_desc.2
+++ b/doc/man/nvme_fdp_ruhu_desc.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_fdp_ruhu_desc" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_fdp_ruhu_desc" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_fdp_ruhu_desc \- Reclaim Unit Handle Usage Descriptor
.SH SYNOPSIS
diff --git a/doc/man/nvme_fdp_ruhu_log.2 b/doc/man/nvme_fdp_ruhu_log.2
index 25c1813..8fdb728 100644
--- a/doc/man/nvme_fdp_ruhu_log.2
+++ b/doc/man/nvme_fdp_ruhu_log.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_fdp_ruhu_log" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_fdp_ruhu_log" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_fdp_ruhu_log \- Reclaim Unit Handle Usage Log Page
.SH SYNOPSIS
diff --git a/doc/man/nvme_fdp_stats_log.2 b/doc/man/nvme_fdp_stats_log.2
index 11f3dd6..b9efdff 100644
--- a/doc/man/nvme_fdp_stats_log.2
+++ b/doc/man/nvme_fdp_stats_log.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_fdp_stats_log" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_fdp_stats_log" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_fdp_stats_log \- FDP Statistics Log Page
.SH SYNOPSIS
diff --git a/doc/man/nvme_fdp_supported_event_attributes.2 b/doc/man/nvme_fdp_supported_event_attributes.2
index 83e350f..ae79de3 100644
--- a/doc/man/nvme_fdp_supported_event_attributes.2
+++ b/doc/man/nvme_fdp_supported_event_attributes.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_fdp_supported_event_attributes" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_fdp_supported_event_attributes" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_fdp_supported_event_attributes \- Supported FDP Event Attributes
.SH SYNOPSIS
diff --git a/doc/man/nvme_fdp_supported_event_desc.2 b/doc/man/nvme_fdp_supported_event_desc.2
index d18673f..5eaa6d1 100644
--- a/doc/man/nvme_fdp_supported_event_desc.2
+++ b/doc/man/nvme_fdp_supported_event_desc.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_fdp_supported_event_desc" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_fdp_supported_event_desc" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_fdp_supported_event_desc \- Supported FDP Event Descriptor
.SH SYNOPSIS
diff --git a/doc/man/nvme_feat.2 b/doc/man/nvme_feat.2
index b758af5..b820817 100644
--- a/doc/man/nvme_feat.2
+++ b/doc/man/nvme_feat.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_feat" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_feat" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_feat \- Features Access Shifts/Masks values
.SH SYNOPSIS
diff --git a/doc/man/nvme_feat_auto_pst.2 b/doc/man/nvme_feat_auto_pst.2
index 90c8a9b..841691b 100644
--- a/doc/man/nvme_feat_auto_pst.2
+++ b/doc/man/nvme_feat_auto_pst.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_feat_auto_pst" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_feat_auto_pst" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_feat_auto_pst \- Autonomous Power State Transition
.SH SYNOPSIS
diff --git a/doc/man/nvme_feat_fdp_events_cdw11.2 b/doc/man/nvme_feat_fdp_events_cdw11.2
index b1ef1ab..baabac0 100644
--- a/doc/man/nvme_feat_fdp_events_cdw11.2
+++ b/doc/man/nvme_feat_fdp_events_cdw11.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_feat_fdp_events_cdw11" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_feat_fdp_events_cdw11" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_feat_fdp_events_cdw11 \- FDP Events Feature Command Dword 11
.SH SYNOPSIS
diff --git a/doc/man/nvme_feat_host_behavior.2 b/doc/man/nvme_feat_host_behavior.2
index 4c4afd7..c0cf6d7 100644
--- a/doc/man/nvme_feat_host_behavior.2
+++ b/doc/man/nvme_feat_host_behavior.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_feat_host_behavior" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_feat_host_behavior" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_feat_host_behavior \- Host Behavior Support - Data Structure
.SH SYNOPSIS
@@ -6,7 +6,15 @@ struct nvme_feat_host_behavior {
.br
.BI " __u8 acre;"
.br
-.BI " __u8 rsvd1[511];"
+.BI " __u8 etdas;"
+.br
+.BI " __u8 lbafee;"
+.br
+.BI " __u8 rsvd3;"
+.br
+.BI " __u16 cdfe;"
+.br
+.BI " __u8 rsvd6[506];"
.br
.BI "
};
@@ -15,5 +23,13 @@ struct nvme_feat_host_behavior {
.SH Members
.IP "acre" 12
Advanced Command Retry Enable
-.IP "rsvd1" 12
+.IP "etdas" 12
+Extended Telemetry Data Area 4 Supported
+.IP "lbafee" 12
+LBA Format Extension Enable
+.IP "rsvd3" 12
+Reserved
+.IP "cdfe" 12
+Copy Descriptor Formats Enable
+.IP "rsvd6" 12
Reserved
diff --git a/doc/man/nvme_feat_nswpcfg_state.2 b/doc/man/nvme_feat_nswpcfg_state.2
index 102043b..d7d3cc8 100644
--- a/doc/man/nvme_feat_nswpcfg_state.2
+++ b/doc/man/nvme_feat_nswpcfg_state.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_feat_nswpcfg_state" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_feat_nswpcfg_state" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_feat_nswpcfg_state \- Write Protection - Write Protection State
.SH SYNOPSIS
diff --git a/doc/man/nvme_feat_plm_window_select.2 b/doc/man/nvme_feat_plm_window_select.2
index ff3d979..ab12316 100644
--- a/doc/man/nvme_feat_plm_window_select.2
+++ b/doc/man/nvme_feat_plm_window_select.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_feat_plm_window_select" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_feat_plm_window_select" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_feat_plm_window_select \- Predictable Latency Per NVM Set Log
.SH SYNOPSIS
diff --git a/doc/man/nvme_feat_resv_notify_flags.2 b/doc/man/nvme_feat_resv_notify_flags.2
index 341331e..bf6174a 100644
--- a/doc/man/nvme_feat_resv_notify_flags.2
+++ b/doc/man/nvme_feat_resv_notify_flags.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_feat_resv_notify_flags" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_feat_resv_notify_flags" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_feat_resv_notify_flags \- Reservation Notification Configuration
.SH SYNOPSIS
diff --git a/doc/man/nvme_feat_tmpthresh_thsel.2 b/doc/man/nvme_feat_tmpthresh_thsel.2
index de1bc85..5281f99 100644
--- a/doc/man/nvme_feat_tmpthresh_thsel.2
+++ b/doc/man/nvme_feat_tmpthresh_thsel.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_feat_tmpthresh_thsel" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_feat_tmpthresh_thsel" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_feat_tmpthresh_thsel \- Temperature Threshold - Threshold Type Select
.SH SYNOPSIS
diff --git a/doc/man/nvme_features_async_event_config_flags.2 b/doc/man/nvme_features_async_event_config_flags.2
index 0e3be08..ea8e8bd 100644
--- a/doc/man/nvme_features_async_event_config_flags.2
+++ b/doc/man/nvme_features_async_event_config_flags.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_features_async_event_config_flags" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_features_async_event_config_flags" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_features_async_event_config_flags \- Asynchronous Event Configuration configuration flags
.SH SYNOPSIS
diff --git a/doc/man/nvme_features_id.2 b/doc/man/nvme_features_id.2
index dbbb7ef..12d6dae 100644
--- a/doc/man/nvme_features_id.2
+++ b/doc/man/nvme_features_id.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_features_id" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_features_id" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_features_id \- Features - Feature Identifiers
.SH SYNOPSIS
diff --git a/doc/man/nvme_fid_supported_effects.2 b/doc/man/nvme_fid_supported_effects.2
index 43b31f8..3e8f229 100644
--- a/doc/man/nvme_fid_supported_effects.2
+++ b/doc/man/nvme_fid_supported_effects.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_fid_supported_effects" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_fid_supported_effects" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_fid_supported_effects \- FID Supported and Effects Data Structure definitions
.SH SYNOPSIS
diff --git a/doc/man/nvme_fid_supported_effects_log.2 b/doc/man/nvme_fid_supported_effects_log.2
index b1a6fba..7aea249 100644
--- a/doc/man/nvme_fid_supported_effects_log.2
+++ b/doc/man/nvme_fid_supported_effects_log.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_fid_supported_effects_log" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_fid_supported_effects_log" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_fid_supported_effects_log \- Feature Identifiers Supported and Effects
.SH SYNOPSIS
diff --git a/doc/man/nvme_firmware_slot.2 b/doc/man/nvme_firmware_slot.2
index 259fcf9..4069b70 100644
--- a/doc/man/nvme_firmware_slot.2
+++ b/doc/man/nvme_firmware_slot.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_firmware_slot" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_firmware_slot" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_firmware_slot \- Firmware Slot Information Log
.SH SYNOPSIS
diff --git a/doc/man/nvme_first_host.2 b/doc/man/nvme_first_host.2
index 41e8582..d9b4d97 100644
--- a/doc/man/nvme_first_host.2
+++ b/doc/man/nvme_first_host.2
@@ -1,4 +1,4 @@
-.TH "nvme_first_host" 9 "nvme_first_host" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_first_host" 9 "nvme_first_host" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_first_host \- Start host iterator
.SH SYNOPSIS
diff --git a/doc/man/nvme_first_subsystem.2 b/doc/man/nvme_first_subsystem.2
index 292d6d0..99c7aa5 100644
--- a/doc/man/nvme_first_subsystem.2
+++ b/doc/man/nvme_first_subsystem.2
@@ -1,4 +1,4 @@
-.TH "nvme_first_subsystem" 9 "nvme_first_subsystem" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_first_subsystem" 9 "nvme_first_subsystem" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_first_subsystem \- Start subsystem iterator
.SH SYNOPSIS
diff --git a/doc/man/nvme_flush.2 b/doc/man/nvme_flush.2
index e10af5b..21b9867 100644
--- a/doc/man/nvme_flush.2
+++ b/doc/man/nvme_flush.2
@@ -1,4 +1,4 @@
-.TH "nvme_flush" 9 "nvme_flush" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_flush" 9 "nvme_flush" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_flush \- Send an nvme flush command
.SH SYNOPSIS
diff --git a/doc/man/nvme_for_each_host.2 b/doc/man/nvme_for_each_host.2
index bec20b3..6aa0219 100644
--- a/doc/man/nvme_for_each_host.2
+++ b/doc/man/nvme_for_each_host.2
@@ -1,4 +1,4 @@
-.TH "nvme_for_each_host" 9 "nvme_for_each_host" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_for_each_host" 9 "nvme_for_each_host" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_for_each_host \- Traverse host list
.SH SYNOPSIS
diff --git a/doc/man/nvme_for_each_host_safe.2 b/doc/man/nvme_for_each_host_safe.2
index 2b5764c..ea05e30 100644
--- a/doc/man/nvme_for_each_host_safe.2
+++ b/doc/man/nvme_for_each_host_safe.2
@@ -1,4 +1,4 @@
-.TH "nvme_for_each_host_safe" 9 "nvme_for_each_host_safe" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_for_each_host_safe" 9 "nvme_for_each_host_safe" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_for_each_host_safe \- Traverse host list
.SH SYNOPSIS
diff --git a/doc/man/nvme_for_each_subsystem.2 b/doc/man/nvme_for_each_subsystem.2
index c85cbbe..afe926f 100644
--- a/doc/man/nvme_for_each_subsystem.2
+++ b/doc/man/nvme_for_each_subsystem.2
@@ -1,4 +1,4 @@
-.TH "nvme_for_each_subsystem" 9 "nvme_for_each_subsystem" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_for_each_subsystem" 9 "nvme_for_each_subsystem" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_for_each_subsystem \- Traverse subsystems
.SH SYNOPSIS
diff --git a/doc/man/nvme_for_each_subsystem_safe.2 b/doc/man/nvme_for_each_subsystem_safe.2
index e05ea41..ef1dbbf 100644
--- a/doc/man/nvme_for_each_subsystem_safe.2
+++ b/doc/man/nvme_for_each_subsystem_safe.2
@@ -1,4 +1,4 @@
-.TH "nvme_for_each_subsystem_safe" 9 "nvme_for_each_subsystem_safe" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_for_each_subsystem_safe" 9 "nvme_for_each_subsystem_safe" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_for_each_subsystem_safe \- Traverse subsystems
.SH SYNOPSIS
diff --git a/doc/man/nvme_format_nvm.2 b/doc/man/nvme_format_nvm.2
index 144ba44..960f2cb 100644
--- a/doc/man/nvme_format_nvm.2
+++ b/doc/man/nvme_format_nvm.2
@@ -1,4 +1,4 @@
-.TH "nvme_format_nvm" 9 "nvme_format_nvm" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_format_nvm" 9 "nvme_format_nvm" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_format_nvm \- Format nvme namespace(s)
.SH SYNOPSIS
diff --git a/doc/man/nvme_format_nvm_compln_event.2 b/doc/man/nvme_format_nvm_compln_event.2
index 82fd397..d2289cc 100644
--- a/doc/man/nvme_format_nvm_compln_event.2
+++ b/doc/man/nvme_format_nvm_compln_event.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_format_nvm_compln_event" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_format_nvm_compln_event" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_format_nvm_compln_event \- Format NVM Completion Event Data
.SH SYNOPSIS
diff --git a/doc/man/nvme_format_nvm_start_event.2 b/doc/man/nvme_format_nvm_start_event.2
index 2d3607b..d18d6e7 100644
--- a/doc/man/nvme_format_nvm_start_event.2
+++ b/doc/man/nvme_format_nvm_start_event.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_format_nvm_start_event" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_format_nvm_start_event" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_format_nvm_start_event \- Format NVM Start Event Data
.SH SYNOPSIS
diff --git a/doc/man/nvme_free_ctrl.2 b/doc/man/nvme_free_ctrl.2
index 2f4a593..b34bfa2 100644
--- a/doc/man/nvme_free_ctrl.2
+++ b/doc/man/nvme_free_ctrl.2
@@ -1,4 +1,4 @@
-.TH "nvme_free_ctrl" 9 "nvme_free_ctrl" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_free_ctrl" 9 "nvme_free_ctrl" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_free_ctrl \- Free controller
.SH SYNOPSIS
diff --git a/doc/man/nvme_free_host.2 b/doc/man/nvme_free_host.2
index 75ce5c4..da4ea5a 100644
--- a/doc/man/nvme_free_host.2
+++ b/doc/man/nvme_free_host.2
@@ -1,4 +1,4 @@
-.TH "nvme_free_host" 9 "nvme_free_host" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_free_host" 9 "nvme_free_host" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_free_host \- Free nvme_host_t object
.SH SYNOPSIS
diff --git a/doc/man/nvme_free_ns.2 b/doc/man/nvme_free_ns.2
index 9844898..83fa1de 100644
--- a/doc/man/nvme_free_ns.2
+++ b/doc/man/nvme_free_ns.2
@@ -1,4 +1,4 @@
-.TH "nvme_free_ns" 9 "nvme_free_ns" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_free_ns" 9 "nvme_free_ns" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_free_ns \- Free a namespace object
.SH SYNOPSIS
diff --git a/doc/man/nvme_free_subsystem.2 b/doc/man/nvme_free_subsystem.2
index 2f8cf6c..6425669 100644
--- a/doc/man/nvme_free_subsystem.2
+++ b/doc/man/nvme_free_subsystem.2
@@ -1,4 +1,4 @@
-.TH "nvme_free_subsystem" 9 "nvme_free_subsystem" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_free_subsystem" 9 "nvme_free_subsystem" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_free_subsystem \- Free a subsystem
.SH SYNOPSIS
diff --git a/doc/man/nvme_free_tree.2 b/doc/man/nvme_free_tree.2
index a493818..bd6fce9 100644
--- a/doc/man/nvme_free_tree.2
+++ b/doc/man/nvme_free_tree.2
@@ -1,4 +1,4 @@
-.TH "nvme_free_tree" 9 "nvme_free_tree" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_free_tree" 9 "nvme_free_tree" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_free_tree \- Free root object
.SH SYNOPSIS
diff --git a/doc/man/nvme_fw_commit.2 b/doc/man/nvme_fw_commit.2
index 66c1ab3..4bcfe12 100644
--- a/doc/man/nvme_fw_commit.2
+++ b/doc/man/nvme_fw_commit.2
@@ -1,4 +1,4 @@
-.TH "nvme_fw_commit" 9 "nvme_fw_commit" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_fw_commit" 9 "nvme_fw_commit" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_fw_commit \- Commit firmware using the specified action
.SH SYNOPSIS
diff --git a/doc/man/nvme_fw_commit_ca.2 b/doc/man/nvme_fw_commit_ca.2
index b3c4acb..bafeb6f 100644
--- a/doc/man/nvme_fw_commit_ca.2
+++ b/doc/man/nvme_fw_commit_ca.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_fw_commit_ca" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_fw_commit_ca" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_fw_commit_ca \- Firmware Commit - Commit Action
.SH SYNOPSIS
diff --git a/doc/man/nvme_fw_commit_event.2 b/doc/man/nvme_fw_commit_event.2
index f1fa3b0..bcb6910 100644
--- a/doc/man/nvme_fw_commit_event.2
+++ b/doc/man/nvme_fw_commit_event.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_fw_commit_event" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_fw_commit_event" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_fw_commit_event \- Firmware Commit Event Data
.SH SYNOPSIS
diff --git a/doc/man/nvme_fw_download.2 b/doc/man/nvme_fw_download.2
index 319370e..03bb8a2 100644
--- a/doc/man/nvme_fw_download.2
+++ b/doc/man/nvme_fw_download.2
@@ -1,4 +1,4 @@
-.TH "nvme_fw_download" 9 "nvme_fw_download" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_fw_download" 9 "nvme_fw_download" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_fw_download \- Download part or all of a firmware image to the controller
.SH SYNOPSIS
diff --git a/doc/man/nvme_fw_download_seq.2 b/doc/man/nvme_fw_download_seq.2
index 614e51b..6c95302 100644
--- a/doc/man/nvme_fw_download_seq.2
+++ b/doc/man/nvme_fw_download_seq.2
@@ -1,4 +1,4 @@
-.TH "nvme_fw_download_seq" 9 "nvme_fw_download_seq" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_fw_download_seq" 9 "nvme_fw_download_seq" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_fw_download_seq \- Firmware download sequence
.SH SYNOPSIS
diff --git a/doc/man/nvme_gen_dhchap_key.2 b/doc/man/nvme_gen_dhchap_key.2
index 93980cc..294af0c 100644
--- a/doc/man/nvme_gen_dhchap_key.2
+++ b/doc/man/nvme_gen_dhchap_key.2
@@ -1,4 +1,4 @@
-.TH "nvme_gen_dhchap_key" 9 "nvme_gen_dhchap_key" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_gen_dhchap_key" 9 "nvme_gen_dhchap_key" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_gen_dhchap_key \- DH-HMAC-CHAP key generation
.SH SYNOPSIS
diff --git a/doc/man/nvme_generate_tls_key_identity.2 b/doc/man/nvme_generate_tls_key_identity.2
new file mode 100644
index 0000000..f903c6e
--- /dev/null
+++ b/doc/man/nvme_generate_tls_key_identity.2
@@ -0,0 +1,30 @@
+.TH "nvme_generate_tls_key_identity" 9 "nvme_generate_tls_key_identity" "December 2023" "libnvme API manual" LINUX
+.SH NAME
+nvme_generate_tls_key_identity \- Generate the TLS key identity
+.SH SYNOPSIS
+.B "char *" nvme_generate_tls_key_identity
+.BI "(const char *hostnqn " ","
+.BI "const char *subsysnqn " ","
+.BI "int version " ","
+.BI "int hmac " ","
+.BI "unsigned char *configured_key " ","
+.BI "int key_len " ");"
+.SH ARGUMENTS
+.IP "hostnqn" 12
+Host NVMe Qualified Name
+.IP "subsysnqn" 12
+Subsystem NVMe Qualified Name
+.IP "version" 12
+Key version to use
+.IP "hmac" 12
+HMAC algorithm
+.IP "configured_key" 12
+Configured key data to derive the key from
+.IP "key_len" 12
+Length of \fIconfigured_key\fP
+.SH "DESCRIPTION"
+Derives a 'retained' TLS key as specified in NVMe TCP and
+generate the corresponding TLs identity.
+.SH "RETURN"
+The string containing the TLS identity. It is the responsibility
+of the caller to free the returned string.
diff --git a/doc/man/nvme_get_ana_log_len.2 b/doc/man/nvme_get_ana_log_len.2
index d9076c3..a96dd28 100644
--- a/doc/man/nvme_get_ana_log_len.2
+++ b/doc/man/nvme_get_ana_log_len.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_ana_log_len" 9 "nvme_get_ana_log_len" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_ana_log_len" 9 "nvme_get_ana_log_len" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_ana_log_len \- Retrieve size of the current ANA log
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_attr.2 b/doc/man/nvme_get_attr.2
index 0250c1e..dddd5c4 100644
--- a/doc/man/nvme_get_attr.2
+++ b/doc/man/nvme_get_attr.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_attr" 9 "nvme_get_attr" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_attr" 9 "nvme_get_attr" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_attr \- Read sysfs attribute
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_ctrl_attr.2 b/doc/man/nvme_get_ctrl_attr.2
index dc6ddc2..82567c9 100644
--- a/doc/man/nvme_get_ctrl_attr.2
+++ b/doc/man/nvme_get_ctrl_attr.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_ctrl_attr" 9 "nvme_get_ctrl_attr" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_ctrl_attr" 9 "nvme_get_ctrl_attr" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_ctrl_attr \- Read controller sysfs attribute
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_ctrl_telemetry.2 b/doc/man/nvme_get_ctrl_telemetry.2
index ba520be..292f6b1 100644
--- a/doc/man/nvme_get_ctrl_telemetry.2
+++ b/doc/man/nvme_get_ctrl_telemetry.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_ctrl_telemetry" 9 "nvme_get_ctrl_telemetry" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_ctrl_telemetry" 9 "nvme_get_ctrl_telemetry" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_ctrl_telemetry \- Get controller telemetry log
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_directive_receive_length.2 b/doc/man/nvme_get_directive_receive_length.2
index e7d00a3..b0ce709 100644
--- a/doc/man/nvme_get_directive_receive_length.2
+++ b/doc/man/nvme_get_directive_receive_length.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_directive_receive_length" 9 "nvme_get_directive_receive_length" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_directive_receive_length" 9 "nvme_get_directive_receive_length" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_directive_receive_length \- Get directive receive length
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_discovery_args.2 b/doc/man/nvme_get_discovery_args.2
index ca7a25b..84588da 100644
--- a/doc/man/nvme_get_discovery_args.2
+++ b/doc/man/nvme_get_discovery_args.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_get_discovery_args" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_get_discovery_args" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_get_discovery_args \- Arguments for nvmf_get_discovery_wargs()
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_feature_length.2 b/doc/man/nvme_get_feature_length.2
index ffe518e..f9cd48c 100644
--- a/doc/man/nvme_get_feature_length.2
+++ b/doc/man/nvme_get_feature_length.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_feature_length" 9 "nvme_get_feature_length" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_feature_length" 9 "nvme_get_feature_length" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_feature_length \- Retreive the command payload length for a specific feature identifier
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_feature_length2.2 b/doc/man/nvme_get_feature_length2.2
index eb1d7f4..b9cf1ba 100644
--- a/doc/man/nvme_get_feature_length2.2
+++ b/doc/man/nvme_get_feature_length2.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_feature_length2" 9 "nvme_get_feature_length2" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_feature_length2" 9 "nvme_get_feature_length2" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_feature_length2 \- Retreive the command payload length for a specific feature identifier
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_features.2 b/doc/man/nvme_get_features.2
index 4e336d1..c5e0219 100644
--- a/doc/man/nvme_get_features.2
+++ b/doc/man/nvme_get_features.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_features" 9 "nvme_get_features" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_features" 9 "nvme_get_features" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_features \- Retrieve a feature attribute
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_features_arbitration.2 b/doc/man/nvme_get_features_arbitration.2
index 627e7f5..fca8a81 100644
--- a/doc/man/nvme_get_features_arbitration.2
+++ b/doc/man/nvme_get_features_arbitration.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_features_arbitration" 9 "nvme_get_features_arbitration" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_features_arbitration" 9 "nvme_get_features_arbitration" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_features_arbitration \- Get arbitration feature
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_features_async_event.2 b/doc/man/nvme_get_features_async_event.2
index 01f9b78..5f78508 100644
--- a/doc/man/nvme_get_features_async_event.2
+++ b/doc/man/nvme_get_features_async_event.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_features_async_event" 9 "nvme_get_features_async_event" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_features_async_event" 9 "nvme_get_features_async_event" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_features_async_event \- Get asynchronous event feature
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_features_auto_pst.2 b/doc/man/nvme_get_features_auto_pst.2
index 38d2115..04152dd 100644
--- a/doc/man/nvme_get_features_auto_pst.2
+++ b/doc/man/nvme_get_features_auto_pst.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_features_auto_pst" 9 "nvme_get_features_auto_pst" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_features_auto_pst" 9 "nvme_get_features_auto_pst" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_features_auto_pst \- Get autonomous power state feature
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_features_data.2 b/doc/man/nvme_get_features_data.2
index 7c69998..6487176 100644
--- a/doc/man/nvme_get_features_data.2
+++ b/doc/man/nvme_get_features_data.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_features_data" 9 "nvme_get_features_data" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_features_data" 9 "nvme_get_features_data" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_features_data \- Helper function for @nvme_get_features()
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_features_endurance_event_cfg.2 b/doc/man/nvme_get_features_endurance_event_cfg.2
index 765dfb4..d2a5345 100644
--- a/doc/man/nvme_get_features_endurance_event_cfg.2
+++ b/doc/man/nvme_get_features_endurance_event_cfg.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_features_endurance_event_cfg" 9 "nvme_get_features_endurance_event_cfg" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_features_endurance_event_cfg" 9 "nvme_get_features_endurance_event_cfg" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_features_endurance_event_cfg \- Get endurance event config feature
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_features_err_recovery.2 b/doc/man/nvme_get_features_err_recovery.2
index 8bf2508..abbb181 100644
--- a/doc/man/nvme_get_features_err_recovery.2
+++ b/doc/man/nvme_get_features_err_recovery.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_features_err_recovery" 9 "nvme_get_features_err_recovery" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_features_err_recovery" 9 "nvme_get_features_err_recovery" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_features_err_recovery \- Get error recovery feature
.SH SYNOPSIS
@@ -13,6 +13,10 @@ File descriptor of nvme device
Select which type of attribute to return, see \fIenum nvme_get_features_sel\fP
.IP "result" 12
The command completion result from CQE dword0
+.SH "DESCRIPTION"
+
+Deprecated: doesn't support specifying a NSID.
+Use \fBnvme_get_features_err_recovery2\fP instead.
.SH "RETURN"
The nvme command status if a response was received (see
\fIenum nvme_status_field\fP) or -1 with errno set otherwise.
diff --git a/doc/man/nvme_get_features_err_recovery2.2 b/doc/man/nvme_get_features_err_recovery2.2
new file mode 100644
index 0000000..8544d3a
--- /dev/null
+++ b/doc/man/nvme_get_features_err_recovery2.2
@@ -0,0 +1,21 @@
+.TH "nvme_get_features_err_recovery2" 9 "nvme_get_features_err_recovery2" "December 2023" "libnvme API manual" LINUX
+.SH NAME
+nvme_get_features_err_recovery2 \- Get error recovery feature
+.SH SYNOPSIS
+.B "int" nvme_get_features_err_recovery2
+.BI "(int fd " ","
+.BI "enum nvme_get_features_sel sel " ","
+.BI "__u32 nsid " ","
+.BI "__u32 *result " ");"
+.SH ARGUMENTS
+.IP "fd" 12
+File descriptor of nvme device
+.IP "sel" 12
+Select which type of attribute to return, see \fIenum nvme_get_features_sel\fP
+.IP "nsid" 12
+Namespace ID
+.IP "result" 12
+The command completion result from CQE dword0
+.SH "RETURN"
+The nvme command status if a response was received (see
+\fIenum nvme_status_field\fP) or -1 with errno set otherwise.
diff --git a/doc/man/nvme_get_features_hctm.2 b/doc/man/nvme_get_features_hctm.2
index 0b8a66f..13f01a2 100644
--- a/doc/man/nvme_get_features_hctm.2
+++ b/doc/man/nvme_get_features_hctm.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_features_hctm" 9 "nvme_get_features_hctm" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_features_hctm" 9 "nvme_get_features_hctm" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_features_hctm \- Get thermal management feature
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_features_host_behavior.2 b/doc/man/nvme_get_features_host_behavior.2
index 1268f24..c4b7b89 100644
--- a/doc/man/nvme_get_features_host_behavior.2
+++ b/doc/man/nvme_get_features_host_behavior.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_features_host_behavior" 9 "nvme_get_features_host_behavior" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_features_host_behavior" 9 "nvme_get_features_host_behavior" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_features_host_behavior \- Get host behavior feature
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_features_host_id.2 b/doc/man/nvme_get_features_host_id.2
index 98b1e53..2f43786 100644
--- a/doc/man/nvme_get_features_host_id.2
+++ b/doc/man/nvme_get_features_host_id.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_features_host_id" 9 "nvme_get_features_host_id" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_features_host_id" 9 "nvme_get_features_host_id" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_features_host_id \- Get host id feature
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_features_host_mem_buf.2 b/doc/man/nvme_get_features_host_mem_buf.2
index 0c07f14..bfba5e7 100644
--- a/doc/man/nvme_get_features_host_mem_buf.2
+++ b/doc/man/nvme_get_features_host_mem_buf.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_features_host_mem_buf" 9 "nvme_get_features_host_mem_buf" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_features_host_mem_buf" 9 "nvme_get_features_host_mem_buf" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_features_host_mem_buf \- Get host memory buffer feature
.SH SYNOPSIS
@@ -13,6 +13,10 @@ File descriptor of nvme device
Select which type of attribute to return, see \fIenum nvme_get_features_sel\fP
.IP "result" 12
The command completion result from CQE dword0
+.SH "DESCRIPTION"
+
+Deprecated: doesn't fetch the Host Memory Buffer Attributes data structure.
+Use \fBnvme_get_features_host_mem_buf2\fP instead.
.SH "RETURN"
The nvme command status if a response was received (see
\fIenum nvme_status_field\fP) or -1 with errno set otherwise.
diff --git a/doc/man/nvme_get_features_host_mem_buf2.2 b/doc/man/nvme_get_features_host_mem_buf2.2
new file mode 100644
index 0000000..cb7fd45
--- /dev/null
+++ b/doc/man/nvme_get_features_host_mem_buf2.2
@@ -0,0 +1,21 @@
+.TH "nvme_get_features_host_mem_buf2" 9 "nvme_get_features_host_mem_buf2" "December 2023" "libnvme API manual" LINUX
+.SH NAME
+nvme_get_features_host_mem_buf2 \- Get host memory buffer feature
+.SH SYNOPSIS
+.B "int" nvme_get_features_host_mem_buf2
+.BI "(int fd " ","
+.BI "enum nvme_get_features_sel sel " ","
+.BI "struct nvme_host_mem_buf_attrs *attrs " ","
+.BI "__u32 *result " ");"
+.SH ARGUMENTS
+.IP "fd" 12
+File descriptor of nvme device
+.IP "sel" 12
+Select which type of attribute to return, see \fIenum nvme_get_features_sel\fP
+.IP "attrs" 12
+Buffer for returned Host Memory Buffer Attributes
+.IP "result" 12
+The command completion result from CQE dword0
+.SH "RETURN"
+The nvme command status if a response was received (see
+\fIenum nvme_status_field\fP) or -1 with errno set otherwise.
diff --git a/doc/man/nvme_get_features_iocs_profile.2 b/doc/man/nvme_get_features_iocs_profile.2
index 525be94..8d2afed 100644
--- a/doc/man/nvme_get_features_iocs_profile.2
+++ b/doc/man/nvme_get_features_iocs_profile.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_features_iocs_profile" 9 "nvme_get_features_iocs_profile" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_features_iocs_profile" 9 "nvme_get_features_iocs_profile" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_features_iocs_profile \- Get IOCS profile feature
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_features_irq_coalesce.2 b/doc/man/nvme_get_features_irq_coalesce.2
index c5e9ba6..f9635a8 100644
--- a/doc/man/nvme_get_features_irq_coalesce.2
+++ b/doc/man/nvme_get_features_irq_coalesce.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_features_irq_coalesce" 9 "nvme_get_features_irq_coalesce" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_features_irq_coalesce" 9 "nvme_get_features_irq_coalesce" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_features_irq_coalesce \- Get IRQ coalesce feature
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_features_irq_config.2 b/doc/man/nvme_get_features_irq_config.2
index dd10ae8..e80f777 100644
--- a/doc/man/nvme_get_features_irq_config.2
+++ b/doc/man/nvme_get_features_irq_config.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_features_irq_config" 9 "nvme_get_features_irq_config" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_features_irq_config" 9 "nvme_get_features_irq_config" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_features_irq_config \- Get IRQ config feature
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_features_kato.2 b/doc/man/nvme_get_features_kato.2
index 63c7552..a85a95a 100644
--- a/doc/man/nvme_get_features_kato.2
+++ b/doc/man/nvme_get_features_kato.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_features_kato" 9 "nvme_get_features_kato" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_features_kato" 9 "nvme_get_features_kato" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_features_kato \- Get keep alive timeout feature
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_features_lba_range.2 b/doc/man/nvme_get_features_lba_range.2
index 3ef9561..037b441 100644
--- a/doc/man/nvme_get_features_lba_range.2
+++ b/doc/man/nvme_get_features_lba_range.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_features_lba_range" 9 "nvme_get_features_lba_range" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_features_lba_range" 9 "nvme_get_features_lba_range" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_features_lba_range \- Get LBA range feature
.SH SYNOPSIS
@@ -16,6 +16,10 @@ Select which type of attribute to return, see \fIenum nvme_get_features_sel\fP
User address of feature data, if applicable
.IP "result" 12
The command completion result from CQE dword0
+.SH "DESCRIPTION"
+
+Deprecated: doesn't support specifying a NSID.
+Use \fBnvme_get_features_lba_range2\fP instead.
.SH "RETURN"
The nvme command status if a response was received (see
\fIenum nvme_status_field\fP) or -1 with errno set otherwise.
diff --git a/doc/man/nvme_get_features_lba_range2.2 b/doc/man/nvme_get_features_lba_range2.2
new file mode 100644
index 0000000..dc1edd9
--- /dev/null
+++ b/doc/man/nvme_get_features_lba_range2.2
@@ -0,0 +1,24 @@
+.TH "nvme_get_features_lba_range2" 9 "nvme_get_features_lba_range2" "December 2023" "libnvme API manual" LINUX
+.SH NAME
+nvme_get_features_lba_range2 \- Get LBA range feature
+.SH SYNOPSIS
+.B "int" nvme_get_features_lba_range2
+.BI "(int fd " ","
+.BI "enum nvme_get_features_sel sel " ","
+.BI "__u32 nsid " ","
+.BI "struct nvme_lba_range_type *data " ","
+.BI "__u32 *result " ");"
+.SH ARGUMENTS
+.IP "fd" 12
+File descriptor of nvme device
+.IP "sel" 12
+Select which type of attribute to return, see \fIenum nvme_get_features_sel\fP
+.IP "nsid" 12
+Namespace ID
+.IP "data" 12
+Buffer to receive LBA Range Type data structure
+.IP "result" 12
+The command completion result from CQE dword0
+.SH "RETURN"
+The nvme command status if a response was received (see
+\fIenum nvme_status_field\fP) or -1 with errno set otherwise.
diff --git a/doc/man/nvme_get_features_lba_sts_interval.2 b/doc/man/nvme_get_features_lba_sts_interval.2
index 5bd6cc0..6984f82 100644
--- a/doc/man/nvme_get_features_lba_sts_interval.2
+++ b/doc/man/nvme_get_features_lba_sts_interval.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_features_lba_sts_interval" 9 "nvme_get_features_lba_sts_interval" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_features_lba_sts_interval" 9 "nvme_get_features_lba_sts_interval" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_features_lba_sts_interval \- Get LBA status information feature
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_features_nopsc.2 b/doc/man/nvme_get_features_nopsc.2
index 59bcbba..2638628 100644
--- a/doc/man/nvme_get_features_nopsc.2
+++ b/doc/man/nvme_get_features_nopsc.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_features_nopsc" 9 "nvme_get_features_nopsc" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_features_nopsc" 9 "nvme_get_features_nopsc" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_features_nopsc \- Get non-operational power state feature
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_features_num_queues.2 b/doc/man/nvme_get_features_num_queues.2
index b5775b7..e566396 100644
--- a/doc/man/nvme_get_features_num_queues.2
+++ b/doc/man/nvme_get_features_num_queues.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_features_num_queues" 9 "nvme_get_features_num_queues" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_features_num_queues" 9 "nvme_get_features_num_queues" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_features_num_queues \- Get number of queues feature
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_features_plm_config.2 b/doc/man/nvme_get_features_plm_config.2
index ccb53d2..3c18cd9 100644
--- a/doc/man/nvme_get_features_plm_config.2
+++ b/doc/man/nvme_get_features_plm_config.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_features_plm_config" 9 "nvme_get_features_plm_config" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_features_plm_config" 9 "nvme_get_features_plm_config" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_features_plm_config \- Get predictable latency feature
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_features_plm_window.2 b/doc/man/nvme_get_features_plm_window.2
index 5a15532..9031d0c 100644
--- a/doc/man/nvme_get_features_plm_window.2
+++ b/doc/man/nvme_get_features_plm_window.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_features_plm_window" 9 "nvme_get_features_plm_window" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_features_plm_window" 9 "nvme_get_features_plm_window" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_features_plm_window \- Get window select feature
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_features_power_mgmt.2 b/doc/man/nvme_get_features_power_mgmt.2
index cbd1434..c707c50 100644
--- a/doc/man/nvme_get_features_power_mgmt.2
+++ b/doc/man/nvme_get_features_power_mgmt.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_features_power_mgmt" 9 "nvme_get_features_power_mgmt" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_features_power_mgmt" 9 "nvme_get_features_power_mgmt" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_features_power_mgmt \- Get power management feature
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_features_resv_mask.2 b/doc/man/nvme_get_features_resv_mask.2
index f9d4d5d..607c574 100644
--- a/doc/man/nvme_get_features_resv_mask.2
+++ b/doc/man/nvme_get_features_resv_mask.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_features_resv_mask" 9 "nvme_get_features_resv_mask" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_features_resv_mask" 9 "nvme_get_features_resv_mask" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_features_resv_mask \- Get reservation mask feature
.SH SYNOPSIS
@@ -13,6 +13,10 @@ File descriptor of nvme device
Select which type of attribute to return, see \fIenum nvme_get_features_sel\fP
.IP "result" 12
The command completion result from CQE dword0
+.SH "DESCRIPTION"
+
+Deprecated: doesn't support specifying a NSID.
+Use \fBnvme_get_features_resv_mask2\fP instead.
.SH "RETURN"
The nvme command status if a response was received (see
\fIenum nvme_status_field\fP) or -1 with errno set otherwise.
diff --git a/doc/man/nvme_get_features_resv_mask2.2 b/doc/man/nvme_get_features_resv_mask2.2
new file mode 100644
index 0000000..0f1f4bc
--- /dev/null
+++ b/doc/man/nvme_get_features_resv_mask2.2
@@ -0,0 +1,21 @@
+.TH "nvme_get_features_resv_mask2" 9 "nvme_get_features_resv_mask2" "December 2023" "libnvme API manual" LINUX
+.SH NAME
+nvme_get_features_resv_mask2 \- Get reservation mask feature
+.SH SYNOPSIS
+.B "int" nvme_get_features_resv_mask2
+.BI "(int fd " ","
+.BI "enum nvme_get_features_sel sel " ","
+.BI "__u32 nsid " ","
+.BI "__u32 *result " ");"
+.SH ARGUMENTS
+.IP "fd" 12
+File descriptor of nvme device
+.IP "sel" 12
+Select which type of attribute to return, see \fIenum nvme_get_features_sel\fP
+.IP "nsid" 12
+Namespace ID
+.IP "result" 12
+The command completion result from CQE dword0
+.SH "RETURN"
+The nvme command status if a response was received (see
+\fIenum nvme_status_field\fP) or -1 with errno set otherwise.
diff --git a/doc/man/nvme_get_features_resv_persist.2 b/doc/man/nvme_get_features_resv_persist.2
index 3fb53ff..a75d329 100644
--- a/doc/man/nvme_get_features_resv_persist.2
+++ b/doc/man/nvme_get_features_resv_persist.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_features_resv_persist" 9 "nvme_get_features_resv_persist" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_features_resv_persist" 9 "nvme_get_features_resv_persist" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_features_resv_persist \- Get reservation persist feature
.SH SYNOPSIS
@@ -13,6 +13,10 @@ File descriptor of nvme device
Select which type of attribute to return, see \fIenum nvme_get_features_sel\fP
.IP "result" 12
The command completion result from CQE dword0
+.SH "DESCRIPTION"
+
+Deprecated: doesn't support specifying a NSID.
+Use \fBnvme_get_features_resv_persist2\fP instead.
.SH "RETURN"
The nvme command status if a response was received (see
\fIenum nvme_status_field\fP) or -1 with errno set otherwise.
diff --git a/doc/man/nvme_get_features_resv_persist2.2 b/doc/man/nvme_get_features_resv_persist2.2
new file mode 100644
index 0000000..cb5ff9d
--- /dev/null
+++ b/doc/man/nvme_get_features_resv_persist2.2
@@ -0,0 +1,21 @@
+.TH "nvme_get_features_resv_persist2" 9 "nvme_get_features_resv_persist2" "December 2023" "libnvme API manual" LINUX
+.SH NAME
+nvme_get_features_resv_persist2 \- Get reservation persist feature
+.SH SYNOPSIS
+.B "int" nvme_get_features_resv_persist2
+.BI "(int fd " ","
+.BI "enum nvme_get_features_sel sel " ","
+.BI "__u32 nsid " ","
+.BI "__u32 *result " ");"
+.SH ARGUMENTS
+.IP "fd" 12
+File descriptor of nvme device
+.IP "sel" 12
+Select which type of attribute to return, see \fIenum nvme_get_features_sel\fP
+.IP "nsid" 12
+Namespace ID
+.IP "result" 12
+The command completion result from CQE dword0
+.SH "RETURN"
+The nvme command status if a response was received (see
+\fIenum nvme_status_field\fP) or -1 with errno set otherwise.
diff --git a/doc/man/nvme_get_features_rrl.2 b/doc/man/nvme_get_features_rrl.2
index 2241ce6..9755ce8 100644
--- a/doc/man/nvme_get_features_rrl.2
+++ b/doc/man/nvme_get_features_rrl.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_features_rrl" 9 "nvme_get_features_rrl" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_features_rrl" 9 "nvme_get_features_rrl" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_features_rrl \- Get read recovery level feature
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_features_sanitize.2 b/doc/man/nvme_get_features_sanitize.2
index ded28cc..1215192 100644
--- a/doc/man/nvme_get_features_sanitize.2
+++ b/doc/man/nvme_get_features_sanitize.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_features_sanitize" 9 "nvme_get_features_sanitize" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_features_sanitize" 9 "nvme_get_features_sanitize" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_features_sanitize \- Get sanitize feature
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_features_sel.2 b/doc/man/nvme_get_features_sel.2
index 10ffefb..bcd1e13 100644
--- a/doc/man/nvme_get_features_sel.2
+++ b/doc/man/nvme_get_features_sel.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_get_features_sel" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_get_features_sel" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_get_features_sel \- Get Features - Select
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_features_simple.2 b/doc/man/nvme_get_features_simple.2
index fab3cf6..6f18234 100644
--- a/doc/man/nvme_get_features_simple.2
+++ b/doc/man/nvme_get_features_simple.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_features_simple" 9 "nvme_get_features_simple" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_features_simple" 9 "nvme_get_features_simple" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_features_simple \- Helper function for @nvme_get_features()
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_features_sw_progress.2 b/doc/man/nvme_get_features_sw_progress.2
index c33482a..584f66c 100644
--- a/doc/man/nvme_get_features_sw_progress.2
+++ b/doc/man/nvme_get_features_sw_progress.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_features_sw_progress" 9 "nvme_get_features_sw_progress" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_features_sw_progress" 9 "nvme_get_features_sw_progress" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_features_sw_progress \- Get software progress feature
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_features_temp_thresh.2 b/doc/man/nvme_get_features_temp_thresh.2
index 2d6ca44..93aab80 100644
--- a/doc/man/nvme_get_features_temp_thresh.2
+++ b/doc/man/nvme_get_features_temp_thresh.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_features_temp_thresh" 9 "nvme_get_features_temp_thresh" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_features_temp_thresh" 9 "nvme_get_features_temp_thresh" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_features_temp_thresh \- Get temperature threshold feature
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_features_timestamp.2 b/doc/man/nvme_get_features_timestamp.2
index fc8ef10..6871b4b 100644
--- a/doc/man/nvme_get_features_timestamp.2
+++ b/doc/man/nvme_get_features_timestamp.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_features_timestamp" 9 "nvme_get_features_timestamp" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_features_timestamp" 9 "nvme_get_features_timestamp" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_features_timestamp \- Get timestamp feature
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_features_volatile_wc.2 b/doc/man/nvme_get_features_volatile_wc.2
index f951648..de1dc75 100644
--- a/doc/man/nvme_get_features_volatile_wc.2
+++ b/doc/man/nvme_get_features_volatile_wc.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_features_volatile_wc" 9 "nvme_get_features_volatile_wc" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_features_volatile_wc" 9 "nvme_get_features_volatile_wc" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_features_volatile_wc \- Get volatile write cache feature
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_features_write_atomic.2 b/doc/man/nvme_get_features_write_atomic.2
index d540755..6bc983c 100644
--- a/doc/man/nvme_get_features_write_atomic.2
+++ b/doc/man/nvme_get_features_write_atomic.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_features_write_atomic" 9 "nvme_get_features_write_atomic" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_features_write_atomic" 9 "nvme_get_features_write_atomic" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_features_write_atomic \- Get write atomic feature
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_features_write_protect.2 b/doc/man/nvme_get_features_write_protect.2
index f1a2d4e..446d23f 100644
--- a/doc/man/nvme_get_features_write_protect.2
+++ b/doc/man/nvme_get_features_write_protect.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_features_write_protect" 9 "nvme_get_features_write_protect" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_features_write_protect" 9 "nvme_get_features_write_protect" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_features_write_protect \- Get write protect feature
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_host_telemetry.2 b/doc/man/nvme_get_host_telemetry.2
index b2f90b0..4c2d85f 100644
--- a/doc/man/nvme_get_host_telemetry.2
+++ b/doc/man/nvme_get_host_telemetry.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_host_telemetry" 9 "nvme_get_host_telemetry" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_host_telemetry" 9 "nvme_get_host_telemetry" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_host_telemetry \- Get host telemetry log
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_lba_status.2 b/doc/man/nvme_get_lba_status.2
index 7a929d1..335fe45 100644
--- a/doc/man/nvme_get_lba_status.2
+++ b/doc/man/nvme_get_lba_status.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_lba_status" 9 "nvme_get_lba_status" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_lba_status" 9 "nvme_get_lba_status" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_lba_status \- Retrieve information on possibly unrecoverable LBAs
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_lba_status_log.2 b/doc/man/nvme_get_lba_status_log.2
index 8bc8071..c1836d2 100644
--- a/doc/man/nvme_get_lba_status_log.2
+++ b/doc/man/nvme_get_lba_status_log.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_lba_status_log" 9 "nvme_get_lba_status_log" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_lba_status_log" 9 "nvme_get_lba_status_log" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_lba_status_log \- Retrieve the LBA Status log page
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_log.2 b/doc/man/nvme_get_log.2
index 5803bc5..aa8be70 100644
--- a/doc/man/nvme_get_log.2
+++ b/doc/man/nvme_get_log.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_log" 9 "nvme_get_log" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_log" 9 "nvme_get_log" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_log \- NVMe Admin Get Log command
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_log_ana.2 b/doc/man/nvme_get_log_ana.2
index 54ee397..2ab1e0f 100644
--- a/doc/man/nvme_get_log_ana.2
+++ b/doc/man/nvme_get_log_ana.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_log_ana" 9 "nvme_get_log_ana" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_log_ana" 9 "nvme_get_log_ana" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_log_ana \- Retrieve Asymmetric Namespace Access log page
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_log_ana_groups.2 b/doc/man/nvme_get_log_ana_groups.2
index a7c805d..e2b98f0 100644
--- a/doc/man/nvme_get_log_ana_groups.2
+++ b/doc/man/nvme_get_log_ana_groups.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_log_ana_groups" 9 "nvme_get_log_ana_groups" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_log_ana_groups" 9 "nvme_get_log_ana_groups" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_log_ana_groups \- Retrieve Asymmetric Namespace Access groups only log page
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_log_boot_partition.2 b/doc/man/nvme_get_log_boot_partition.2
index 94f2b4c..cfd2bd2 100644
--- a/doc/man/nvme_get_log_boot_partition.2
+++ b/doc/man/nvme_get_log_boot_partition.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_log_boot_partition" 9 "nvme_get_log_boot_partition" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_log_boot_partition" 9 "nvme_get_log_boot_partition" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_log_boot_partition \- Retrieve Boot Partition
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_log_changed_ns_list.2 b/doc/man/nvme_get_log_changed_ns_list.2
index 0605818..72e99e3 100644
--- a/doc/man/nvme_get_log_changed_ns_list.2
+++ b/doc/man/nvme_get_log_changed_ns_list.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_log_changed_ns_list" 9 "nvme_get_log_changed_ns_list" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_log_changed_ns_list" 9 "nvme_get_log_changed_ns_list" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_log_changed_ns_list \- Retrieve namespace changed list
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_log_cmd_effects.2 b/doc/man/nvme_get_log_cmd_effects.2
index d826f3e..6ac23e2 100644
--- a/doc/man/nvme_get_log_cmd_effects.2
+++ b/doc/man/nvme_get_log_cmd_effects.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_log_cmd_effects" 9 "nvme_get_log_cmd_effects" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_log_cmd_effects" 9 "nvme_get_log_cmd_effects" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_log_cmd_effects \- Retrieve nvme command effects log
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_log_create_telemetry_host.2 b/doc/man/nvme_get_log_create_telemetry_host.2
index ca23c83..5041e5b 100644
--- a/doc/man/nvme_get_log_create_telemetry_host.2
+++ b/doc/man/nvme_get_log_create_telemetry_host.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_log_create_telemetry_host" 9 "nvme_get_log_create_telemetry_host" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_log_create_telemetry_host" 9 "nvme_get_log_create_telemetry_host" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_log_create_telemetry_host \- Create host telemetry log
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_log_device_self_test.2 b/doc/man/nvme_get_log_device_self_test.2
index 84a1625..ccc33d3 100644
--- a/doc/man/nvme_get_log_device_self_test.2
+++ b/doc/man/nvme_get_log_device_self_test.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_log_device_self_test" 9 "nvme_get_log_device_self_test" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_log_device_self_test" 9 "nvme_get_log_device_self_test" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_log_device_self_test \- Retrieve the device self test log
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_log_discovery.2 b/doc/man/nvme_get_log_discovery.2
index e490786..84c61c7 100644
--- a/doc/man/nvme_get_log_discovery.2
+++ b/doc/man/nvme_get_log_discovery.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_log_discovery" 9 "nvme_get_log_discovery" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_log_discovery" 9 "nvme_get_log_discovery" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_log_discovery \- Retrieve Discovery log page
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_log_endurance_group.2 b/doc/man/nvme_get_log_endurance_group.2
index 9f1abe0..6339993 100644
--- a/doc/man/nvme_get_log_endurance_group.2
+++ b/doc/man/nvme_get_log_endurance_group.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_log_endurance_group" 9 "nvme_get_log_endurance_group" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_log_endurance_group" 9 "nvme_get_log_endurance_group" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_log_endurance_group \- Get Endurance Group log
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_log_endurance_grp_evt.2 b/doc/man/nvme_get_log_endurance_grp_evt.2
index 241cc0d..f9d2a0f 100644
--- a/doc/man/nvme_get_log_endurance_grp_evt.2
+++ b/doc/man/nvme_get_log_endurance_grp_evt.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_log_endurance_grp_evt" 9 "nvme_get_log_endurance_grp_evt" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_log_endurance_grp_evt" 9 "nvme_get_log_endurance_grp_evt" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_log_endurance_grp_evt \- Retrieve Rotational Media Information
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_log_error.2 b/doc/man/nvme_get_log_error.2
index 5943dfc..0e9d783 100644
--- a/doc/man/nvme_get_log_error.2
+++ b/doc/man/nvme_get_log_error.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_log_error" 9 "nvme_get_log_error" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_log_error" 9 "nvme_get_log_error" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_log_error \- Retrieve nvme error log
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_log_fdp_configurations.2 b/doc/man/nvme_get_log_fdp_configurations.2
index 9468abb..f19c170 100644
--- a/doc/man/nvme_get_log_fdp_configurations.2
+++ b/doc/man/nvme_get_log_fdp_configurations.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_log_fdp_configurations" 9 "nvme_get_log_fdp_configurations" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_log_fdp_configurations" 9 "nvme_get_log_fdp_configurations" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_log_fdp_configurations \- Get list of Flexible Data Placement configurations
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_log_fdp_events.2 b/doc/man/nvme_get_log_fdp_events.2
index 8936ed6..7c9e9e9 100644
--- a/doc/man/nvme_get_log_fdp_events.2
+++ b/doc/man/nvme_get_log_fdp_events.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_log_fdp_events" 9 "nvme_get_log_fdp_events" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_log_fdp_events" 9 "nvme_get_log_fdp_events" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_log_fdp_events \- Get Flexible Data Placement events
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_log_fdp_stats.2 b/doc/man/nvme_get_log_fdp_stats.2
index 24c4cab..db2b4ff 100644
--- a/doc/man/nvme_get_log_fdp_stats.2
+++ b/doc/man/nvme_get_log_fdp_stats.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_log_fdp_stats" 9 "nvme_get_log_fdp_stats" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_log_fdp_stats" 9 "nvme_get_log_fdp_stats" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_log_fdp_stats \- Get Flexible Data Placement statistics
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_log_fid_supported_effects.2 b/doc/man/nvme_get_log_fid_supported_effects.2
index 45e3ac5..7093d3b 100644
--- a/doc/man/nvme_get_log_fid_supported_effects.2
+++ b/doc/man/nvme_get_log_fid_supported_effects.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_log_fid_supported_effects" 9 "nvme_get_log_fid_supported_effects" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_log_fid_supported_effects" 9 "nvme_get_log_fid_supported_effects" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_log_fid_supported_effects \- Retrieve Feature Identifiers Supported and Effects
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_log_fw_slot.2 b/doc/man/nvme_get_log_fw_slot.2
index 8271510..3edf687 100644
--- a/doc/man/nvme_get_log_fw_slot.2
+++ b/doc/man/nvme_get_log_fw_slot.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_log_fw_slot" 9 "nvme_get_log_fw_slot" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_log_fw_slot" 9 "nvme_get_log_fw_slot" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_log_fw_slot \- Retrieves the controller firmware log
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_log_lba_status.2 b/doc/man/nvme_get_log_lba_status.2
index 2b64d70..08a49da 100644
--- a/doc/man/nvme_get_log_lba_status.2
+++ b/doc/man/nvme_get_log_lba_status.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_log_lba_status" 9 "nvme_get_log_lba_status" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_log_lba_status" 9 "nvme_get_log_lba_status" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_log_lba_status \- Retrieve LBA Status
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_log_media_unit_stat.2 b/doc/man/nvme_get_log_media_unit_stat.2
index 8fec753..e7bb2ef 100644
--- a/doc/man/nvme_get_log_media_unit_stat.2
+++ b/doc/man/nvme_get_log_media_unit_stat.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_log_media_unit_stat" 9 "nvme_get_log_media_unit_stat" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_log_media_unit_stat" 9 "nvme_get_log_media_unit_stat" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_log_media_unit_stat \- Retrieve Media Unit Status
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_log_mi_cmd_supported_effects.2 b/doc/man/nvme_get_log_mi_cmd_supported_effects.2
index f5d8f55..360f2ae 100644
--- a/doc/man/nvme_get_log_mi_cmd_supported_effects.2
+++ b/doc/man/nvme_get_log_mi_cmd_supported_effects.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_log_mi_cmd_supported_effects" 9 "nvme_get_log_mi_cmd_supported_effects" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_log_mi_cmd_supported_effects" 9 "nvme_get_log_mi_cmd_supported_effects" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_log_mi_cmd_supported_effects \- displays the MI Commands Supported by the controller
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_log_page.2 b/doc/man/nvme_get_log_page.2
index 4a8b85d..434b6e7 100644
--- a/doc/man/nvme_get_log_page.2
+++ b/doc/man/nvme_get_log_page.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_log_page" 9 "nvme_get_log_page" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_log_page" 9 "nvme_get_log_page" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_log_page \- Get log page data
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_log_persistent_event.2 b/doc/man/nvme_get_log_persistent_event.2
index 2ad5e5e..8b6d707 100644
--- a/doc/man/nvme_get_log_persistent_event.2
+++ b/doc/man/nvme_get_log_persistent_event.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_log_persistent_event" 9 "nvme_get_log_persistent_event" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_log_persistent_event" 9 "nvme_get_log_persistent_event" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_log_persistent_event \- Retrieve Persistent Event Log
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_log_phy_rx_eom.2 b/doc/man/nvme_get_log_phy_rx_eom.2
new file mode 100644
index 0000000..dd96626
--- /dev/null
+++ b/doc/man/nvme_get_log_phy_rx_eom.2
@@ -0,0 +1,25 @@
+.TH "nvme_get_log_phy_rx_eom" 9 "nvme_get_log_phy_rx_eom" "December 2023" "libnvme API manual" LINUX
+.SH NAME
+nvme_get_log_phy_rx_eom \- Retrieve Physical Interface Receiver Eye Opening Measurement Log
+.SH SYNOPSIS
+.B "int" nvme_get_log_phy_rx_eom
+.BI "(int fd " ","
+.BI "__u8 lsp " ","
+.BI "__u16 controller " ","
+.BI "__u32 len " ","
+.BI "struct nvme_phy_rx_eom_log *log " ");"
+.SH ARGUMENTS
+.IP "fd" 12
+File descriptor of nvme device
+.IP "lsp" 12
+Log specific, controls action and measurement quality
+.IP "controller" 12
+Target controller ID
+.IP "len" 12
+The allocated size, minimum
+struct nvme_phy_rx_eom_log
+.IP "log" 12
+User address to store the log page
+.SH "RETURN"
+The nvme command status if a response was received (see
+\fIenum nvme_status_field\fP) or -1 with errno set otherwise
diff --git a/doc/man/nvme_get_log_predictable_lat_event.2 b/doc/man/nvme_get_log_predictable_lat_event.2
index edfeaf1..1305266 100644
--- a/doc/man/nvme_get_log_predictable_lat_event.2
+++ b/doc/man/nvme_get_log_predictable_lat_event.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_log_predictable_lat_event" 9 "nvme_get_log_predictable_lat_event" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_log_predictable_lat_event" 9 "nvme_get_log_predictable_lat_event" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_log_predictable_lat_event \- Retrieve Predictable Latency Event Aggregate Log Page
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_log_predictable_lat_nvmset.2 b/doc/man/nvme_get_log_predictable_lat_nvmset.2
index 4a6763d..09142c4 100644
--- a/doc/man/nvme_get_log_predictable_lat_nvmset.2
+++ b/doc/man/nvme_get_log_predictable_lat_nvmset.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_log_predictable_lat_nvmset" 9 "nvme_get_log_predictable_lat_nvmset" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_log_predictable_lat_nvmset" 9 "nvme_get_log_predictable_lat_nvmset" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_log_predictable_lat_nvmset \- Predictable Latency Per NVM Set
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_log_reclaim_unit_handle_usage.2 b/doc/man/nvme_get_log_reclaim_unit_handle_usage.2
index 008085b..6b4f51a 100644
--- a/doc/man/nvme_get_log_reclaim_unit_handle_usage.2
+++ b/doc/man/nvme_get_log_reclaim_unit_handle_usage.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_log_reclaim_unit_handle_usage" 9 "nvme_get_log_reclaim_unit_handle_usage" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_log_reclaim_unit_handle_usage" 9 "nvme_get_log_reclaim_unit_handle_usage" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_log_reclaim_unit_handle_usage \- Get reclaim unit handle usage
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_log_reservation.2 b/doc/man/nvme_get_log_reservation.2
index abd304e..484e916 100644
--- a/doc/man/nvme_get_log_reservation.2
+++ b/doc/man/nvme_get_log_reservation.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_log_reservation" 9 "nvme_get_log_reservation" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_log_reservation" 9 "nvme_get_log_reservation" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_log_reservation \- Retrieve Reservation Notification
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_log_sanitize.2 b/doc/man/nvme_get_log_sanitize.2
index b498f14..25ce042 100644
--- a/doc/man/nvme_get_log_sanitize.2
+++ b/doc/man/nvme_get_log_sanitize.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_log_sanitize" 9 "nvme_get_log_sanitize" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_log_sanitize" 9 "nvme_get_log_sanitize" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_log_sanitize \- Retrieve Sanitize Status
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_log_smart.2 b/doc/man/nvme_get_log_smart.2
index 1476351..74758dc 100644
--- a/doc/man/nvme_get_log_smart.2
+++ b/doc/man/nvme_get_log_smart.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_log_smart" 9 "nvme_get_log_smart" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_log_smart" 9 "nvme_get_log_smart" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_log_smart \- Retrieve nvme smart log
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_log_support_cap_config_list.2 b/doc/man/nvme_get_log_support_cap_config_list.2
index a8aeb41..7a127c3 100644
--- a/doc/man/nvme_get_log_support_cap_config_list.2
+++ b/doc/man/nvme_get_log_support_cap_config_list.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_log_support_cap_config_list" 9 "nvme_get_log_support_cap_config_list" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_log_support_cap_config_list" 9 "nvme_get_log_support_cap_config_list" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_log_support_cap_config_list \- Retrieve Supported Capacity Configuration List
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_log_supported_log_pages.2 b/doc/man/nvme_get_log_supported_log_pages.2
index 8ee0e81..1bdd4bb 100644
--- a/doc/man/nvme_get_log_supported_log_pages.2
+++ b/doc/man/nvme_get_log_supported_log_pages.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_log_supported_log_pages" 9 "nvme_get_log_supported_log_pages" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_log_supported_log_pages" 9 "nvme_get_log_supported_log_pages" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_log_supported_log_pages \- Retrieve nmve supported log pages
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_log_telemetry_ctrl.2 b/doc/man/nvme_get_log_telemetry_ctrl.2
index abb8c2f..3eab558 100644
--- a/doc/man/nvme_get_log_telemetry_ctrl.2
+++ b/doc/man/nvme_get_log_telemetry_ctrl.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_log_telemetry_ctrl" 9 "nvme_get_log_telemetry_ctrl" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_log_telemetry_ctrl" 9 "nvme_get_log_telemetry_ctrl" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_log_telemetry_ctrl \- Get Telemetry Controller-Initiated log page
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_log_telemetry_host.2 b/doc/man/nvme_get_log_telemetry_host.2
index 4857624..d8c7970 100644
--- a/doc/man/nvme_get_log_telemetry_host.2
+++ b/doc/man/nvme_get_log_telemetry_host.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_log_telemetry_host" 9 "nvme_get_log_telemetry_host" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_log_telemetry_host" 9 "nvme_get_log_telemetry_host" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_log_telemetry_host \- Get Telemetry Host-Initiated log page
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_log_zns_changed_zones.2 b/doc/man/nvme_get_log_zns_changed_zones.2
index 46fb4f4..fb7f7dc 100644
--- a/doc/man/nvme_get_log_zns_changed_zones.2
+++ b/doc/man/nvme_get_log_zns_changed_zones.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_log_zns_changed_zones" 9 "nvme_get_log_zns_changed_zones" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_log_zns_changed_zones" 9 "nvme_get_log_zns_changed_zones" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_log_zns_changed_zones \- Retrieve list of zones that have changed
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_logical_block_size.2 b/doc/man/nvme_get_logical_block_size.2
index 0fe0984..e0e34d6 100644
--- a/doc/man/nvme_get_logical_block_size.2
+++ b/doc/man/nvme_get_logical_block_size.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_logical_block_size" 9 "nvme_get_logical_block_size" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_logical_block_size" 9 "nvme_get_logical_block_size" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_logical_block_size \- Retrieve block size
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_new_host_telemetry.2 b/doc/man/nvme_get_new_host_telemetry.2
index e6f0954..3b0a1f0 100644
--- a/doc/man/nvme_get_new_host_telemetry.2
+++ b/doc/man/nvme_get_new_host_telemetry.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_new_host_telemetry" 9 "nvme_get_new_host_telemetry" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_new_host_telemetry" 9 "nvme_get_new_host_telemetry" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_new_host_telemetry \- Get new host telemetry log
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_ns_attr.2 b/doc/man/nvme_get_ns_attr.2
index 62898ff..d1dc447 100644
--- a/doc/man/nvme_get_ns_attr.2
+++ b/doc/man/nvme_get_ns_attr.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_ns_attr" 9 "nvme_get_ns_attr" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_ns_attr" 9 "nvme_get_ns_attr" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_ns_attr \- Read namespace sysfs attribute
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_nsid.2 b/doc/man/nvme_get_nsid.2
index d1656f5..79ce3d7 100644
--- a/doc/man/nvme_get_nsid.2
+++ b/doc/man/nvme_get_nsid.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_nsid" 9 "nvme_get_nsid" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_nsid" 9 "nvme_get_nsid" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_nsid \- Retrieve the NSID from a namespace file descriptor
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_path_attr.2 b/doc/man/nvme_get_path_attr.2
index 921b339..577847e 100644
--- a/doc/man/nvme_get_path_attr.2
+++ b/doc/man/nvme_get_path_attr.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_path_attr" 9 "nvme_get_path_attr" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_path_attr" 9 "nvme_get_path_attr" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_path_attr \- Read path sysfs attribute
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_property.2 b/doc/man/nvme_get_property.2
index d88155c..b0f77e0 100644
--- a/doc/man/nvme_get_property.2
+++ b/doc/man/nvme_get_property.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_property" 9 "nvme_get_property" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_property" 9 "nvme_get_property" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_property \- Get a controller property
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_subsys_attr.2 b/doc/man/nvme_get_subsys_attr.2
index 5b8db80..04791b6 100644
--- a/doc/man/nvme_get_subsys_attr.2
+++ b/doc/man/nvme_get_subsys_attr.2
@@ -1,4 +1,4 @@
-.TH "nvme_get_subsys_attr" 9 "nvme_get_subsys_attr" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_get_subsys_attr" 9 "nvme_get_subsys_attr" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_get_subsys_attr \- Read subsystem sysfs attribute
.SH SYNOPSIS
diff --git a/doc/man/nvme_get_telemetry_log.2 b/doc/man/nvme_get_telemetry_log.2
new file mode 100644
index 0000000..c7f2840
--- /dev/null
+++ b/doc/man/nvme_get_telemetry_log.2
@@ -0,0 +1,36 @@
+.TH "nvme_get_telemetry_log" 9 "nvme_get_telemetry_log" "December 2023" "libnvme API manual" LINUX
+.SH NAME
+nvme_get_telemetry_log \- Get specified telemetry log
+.SH SYNOPSIS
+.B "int" nvme_get_telemetry_log
+.BI "(int fd " ","
+.BI "bool create " ","
+.BI "bool ctrl " ","
+.BI "bool rae " ","
+.BI "size_t max_data_tx " ","
+.BI "enum nvme_telemetry_da da " ","
+.BI "struct nvme_telemetry_log **log " ","
+.BI "size_t *size " ");"
+.SH ARGUMENTS
+.IP "fd" 12
+File descriptor of nvme device
+.IP "create" 12
+Generate new host initated telemetry capture
+.IP "ctrl" 12
+Get controller Initiated log
+.IP "rae" 12
+Retain asynchronous events
+.IP "max_data_tx" 12
+Set the max data transfer size to be used retrieving telemetry.
+.IP "da" 12
+Log page data area, valid values: \fIenum nvme_telemetry_da\fP.
+.IP "log" 12
+On success, set to the value of the allocated and retrieved log.
+.IP "size" 12
+Ptr to the telemetry log size, so it can be returned
+.SH "DESCRIPTION"
+The total size allocated can be calculated as:
+(nvme_telemetry_log da size + 1) * NVME_LOG_TELEM_BLOCK_SIZE.
+.SH "RETURN"
+The nvme command status if a response was received (see
+\fIenum nvme_status_field\fP) or -1 with errno set otherwise.
diff --git a/doc/man/nvme_get_telemetry_max.2 b/doc/man/nvme_get_telemetry_max.2
new file mode 100644
index 0000000..a350c1b
--- /dev/null
+++ b/doc/man/nvme_get_telemetry_max.2
@@ -0,0 +1,18 @@
+.TH "nvme_get_telemetry_max" 9 "nvme_get_telemetry_max" "December 2023" "libnvme API manual" LINUX
+.SH NAME
+nvme_get_telemetry_max \- Get telemetry limits
+.SH SYNOPSIS
+.B "int" nvme_get_telemetry_max
+.BI "(int fd " ","
+.BI "enum nvme_telemetry_da *da " ","
+.BI "size_t *max_data_tx " ");"
+.SH ARGUMENTS
+.IP "fd" 12
+File descriptor of nvme device
+.IP "da" 12
+On success return max supported data area
+.IP "max_data_tx" 12
+On success set to max transfer chunk supported by the controller
+.SH "RETURN"
+The nvme command status if a response was received (see
+\fIenum nvme_status_field\fP) or -1 with errno set otherwise.
diff --git a/doc/man/nvme_hmac_alg.2 b/doc/man/nvme_hmac_alg.2
index 19d4a6d..82424bb 100644
--- a/doc/man/nvme_hmac_alg.2
+++ b/doc/man/nvme_hmac_alg.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_hmac_alg" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_hmac_alg" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_hmac_alg \- HMAC algorithm
.SH SYNOPSIS
diff --git a/doc/man/nvme_host_behavior_support.2 b/doc/man/nvme_host_behavior_support.2
index a883d01..c84c49d 100644
--- a/doc/man/nvme_host_behavior_support.2
+++ b/doc/man/nvme_host_behavior_support.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_host_behavior_support" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_host_behavior_support" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_host_behavior_support \- Enable Advanced Command
.SH SYNOPSIS
diff --git a/doc/man/nvme_host_get_dhchap_key.2 b/doc/man/nvme_host_get_dhchap_key.2
index 8b428bc..d862d5b 100644
--- a/doc/man/nvme_host_get_dhchap_key.2
+++ b/doc/man/nvme_host_get_dhchap_key.2
@@ -1,4 +1,4 @@
-.TH "nvme_host_get_dhchap_key" 9 "nvme_host_get_dhchap_key" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_host_get_dhchap_key" 9 "nvme_host_get_dhchap_key" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_host_get_dhchap_key \- Return host key
.SH SYNOPSIS
diff --git a/doc/man/nvme_host_get_hostid.2 b/doc/man/nvme_host_get_hostid.2
index 0c6f6dd..7ae8708 100644
--- a/doc/man/nvme_host_get_hostid.2
+++ b/doc/man/nvme_host_get_hostid.2
@@ -1,4 +1,4 @@
-.TH "nvme_host_get_hostid" 9 "nvme_host_get_hostid" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_host_get_hostid" 9 "nvme_host_get_hostid" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_host_get_hostid \- Host ID of an nvme_host_t object
.SH SYNOPSIS
diff --git a/doc/man/nvme_host_get_hostnqn.2 b/doc/man/nvme_host_get_hostnqn.2
index 93b6a91..968e468 100644
--- a/doc/man/nvme_host_get_hostnqn.2
+++ b/doc/man/nvme_host_get_hostnqn.2
@@ -1,4 +1,4 @@
-.TH "nvme_host_get_hostnqn" 9 "nvme_host_get_hostnqn" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_host_get_hostnqn" 9 "nvme_host_get_hostnqn" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_host_get_hostnqn \- Host NQN of an nvme_host_t object
.SH SYNOPSIS
diff --git a/doc/man/nvme_host_get_hostsymname.2 b/doc/man/nvme_host_get_hostsymname.2
index 399eca9..b76703e 100644
--- a/doc/man/nvme_host_get_hostsymname.2
+++ b/doc/man/nvme_host_get_hostsymname.2
@@ -1,4 +1,4 @@
-.TH "nvme_host_get_hostsymname" 9 "nvme_host_get_hostsymname" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_host_get_hostsymname" 9 "nvme_host_get_hostsymname" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_host_get_hostsymname \- Get the host's symbolic name
.SH SYNOPSIS
diff --git a/doc/man/nvme_host_get_root.2 b/doc/man/nvme_host_get_root.2
index 35102a7..0997c5d 100644
--- a/doc/man/nvme_host_get_root.2
+++ b/doc/man/nvme_host_get_root.2
@@ -1,4 +1,4 @@
-.TH "nvme_host_get_root" 9 "nvme_host_get_root" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_host_get_root" 9 "nvme_host_get_root" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_host_get_root \- Returns nvme_root_t object
.SH SYNOPSIS
diff --git a/doc/man/nvme_host_is_pdc_enabled.2 b/doc/man/nvme_host_is_pdc_enabled.2
index f76f290..714d891 100644
--- a/doc/man/nvme_host_is_pdc_enabled.2
+++ b/doc/man/nvme_host_is_pdc_enabled.2
@@ -1,4 +1,4 @@
-.TH "nvme_host_is_pdc_enabled" 9 "nvme_host_is_pdc_enabled" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_host_is_pdc_enabled" 9 "nvme_host_is_pdc_enabled" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_host_is_pdc_enabled \- Is Persistenct Discovery Controller enabled
.SH SYNOPSIS
diff --git a/doc/man/nvme_host_mem_buf_attrs.2 b/doc/man/nvme_host_mem_buf_attrs.2
index 624d189..78d0a67 100644
--- a/doc/man/nvme_host_mem_buf_attrs.2
+++ b/doc/man/nvme_host_mem_buf_attrs.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_host_mem_buf_attrs" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_host_mem_buf_attrs" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_host_mem_buf_attrs \- Host Memory Buffer - Attributes Data Structure
.SH SYNOPSIS
diff --git a/doc/man/nvme_host_metadata.2 b/doc/man/nvme_host_metadata.2
index f7b7d9e..39713b0 100644
--- a/doc/man/nvme_host_metadata.2
+++ b/doc/man/nvme_host_metadata.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_host_metadata" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_host_metadata" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_host_metadata \- Host Metadata Data Structure
.SH SYNOPSIS
diff --git a/doc/man/nvme_host_release_fds.2 b/doc/man/nvme_host_release_fds.2
new file mode 100644
index 0000000..0d09ba1
--- /dev/null
+++ b/doc/man/nvme_host_release_fds.2
@@ -0,0 +1,13 @@
+.TH "nvme_host_release_fds" 9 "nvme_host_release_fds" "December 2023" "libnvme API manual" LINUX
+.SH NAME
+nvme_host_release_fds \- Close all opened file descriptors under host
+.SH SYNOPSIS
+.B "void" nvme_host_release_fds
+.BI "(struct nvme_host *h " ");"
+.SH ARGUMENTS
+.IP "h" 12
+nvme_host_t object
+.SH "DESCRIPTION"
+Controller and Namespace objects cache the file descriptors
+of opened nvme devices. This API can be used to close and
+clear all cached fds under this host.
diff --git a/doc/man/nvme_host_set_dhchap_key.2 b/doc/man/nvme_host_set_dhchap_key.2
index c453841..804f33c 100644
--- a/doc/man/nvme_host_set_dhchap_key.2
+++ b/doc/man/nvme_host_set_dhchap_key.2
@@ -1,4 +1,4 @@
-.TH "nvme_host_set_dhchap_key" 9 "nvme_host_set_dhchap_key" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_host_set_dhchap_key" 9 "nvme_host_set_dhchap_key" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_host_set_dhchap_key \- set host key
.SH SYNOPSIS
diff --git a/doc/man/nvme_host_set_hostsymname.2 b/doc/man/nvme_host_set_hostsymname.2
index 01bdd94..7166bc3 100644
--- a/doc/man/nvme_host_set_hostsymname.2
+++ b/doc/man/nvme_host_set_hostsymname.2
@@ -1,4 +1,4 @@
-.TH "nvme_host_set_hostsymname" 9 "nvme_host_set_hostsymname" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_host_set_hostsymname" 9 "nvme_host_set_hostsymname" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_host_set_hostsymname \- Set the host's symbolic name
.SH SYNOPSIS
diff --git a/doc/man/nvme_host_set_pdc_enabled.2 b/doc/man/nvme_host_set_pdc_enabled.2
index ed512be..fa17d27 100644
--- a/doc/man/nvme_host_set_pdc_enabled.2
+++ b/doc/man/nvme_host_set_pdc_enabled.2
@@ -1,4 +1,4 @@
-.TH "nvme_host_set_pdc_enabled" 9 "nvme_host_set_pdc_enabled" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_host_set_pdc_enabled" 9 "nvme_host_set_pdc_enabled" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_host_set_pdc_enabled \- Set Persistent Discovery Controller flag
.SH SYNOPSIS
diff --git a/doc/man/nvme_id_ctrl.2 b/doc/man/nvme_id_ctrl.2
index 664ebd3..4ce391c 100644
--- a/doc/man/nvme_id_ctrl.2
+++ b/doc/man/nvme_id_ctrl.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_id_ctrl" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_id_ctrl" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_id_ctrl \- Identify Controller data structure
.SH SYNOPSIS
@@ -168,7 +168,9 @@ struct nvme_id_ctrl {
.br
.BI " __le32 maxcna;"
.br
-.BI " __u8 rsvd564[204];"
+.BI " __le32 oaqd;"
+.br
+.BI " __u8 rsvd568[200];"
.br
.BI " char subnqn[NVME_NQN_LENGTH];"
.br
@@ -469,7 +471,11 @@ controller in the Domain.
Maximum I/O Controller Namespace Attachments indicates the
maximum number of namespaces that are allowed to be attached to
this I/O controller.
-.IP "rsvd564" 12
+.IP "oaqd" 12
+Optimal Aggregated Queue Depth indicates the recommended maximum
+total number of outstanding I/O commands across all I/O queues
+on the controller for optimal operation.
+.IP "rsvd568" 12
Reserved
.IP "subnqn" 12
NVM Subsystem NVMe Qualified Name, UTF-8 null terminated string
diff --git a/doc/man/nvme_id_ctrl_anacap.2 b/doc/man/nvme_id_ctrl_anacap.2
index abe0dc8..1eb5829 100644
--- a/doc/man/nvme_id_ctrl_anacap.2
+++ b/doc/man/nvme_id_ctrl_anacap.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_id_ctrl_anacap" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_id_ctrl_anacap" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_id_ctrl_anacap \- This field indicates the capabilities associated with Asymmetric Namespace Access Reporting.
.SH SYNOPSIS
diff --git a/doc/man/nvme_id_ctrl_apsta.2 b/doc/man/nvme_id_ctrl_apsta.2
index 342e66a..819241c 100644
--- a/doc/man/nvme_id_ctrl_apsta.2
+++ b/doc/man/nvme_id_ctrl_apsta.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_id_ctrl_apsta" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_id_ctrl_apsta" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_id_ctrl_apsta \- Flags indicating the attributes of the autonomous power state transition feature.
.SH SYNOPSIS
diff --git a/doc/man/nvme_id_ctrl_avscc.2 b/doc/man/nvme_id_ctrl_avscc.2
index b5995fc..d7cbf09 100644
--- a/doc/man/nvme_id_ctrl_avscc.2
+++ b/doc/man/nvme_id_ctrl_avscc.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_id_ctrl_avscc" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_id_ctrl_avscc" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_id_ctrl_avscc \- Flags indicating the configuration settings for Admin Vendor Specific command handling.
.SH SYNOPSIS
diff --git a/doc/man/nvme_id_ctrl_cmic.2 b/doc/man/nvme_id_ctrl_cmic.2
index 6ec3467..bcece00 100644
--- a/doc/man/nvme_id_ctrl_cmic.2
+++ b/doc/man/nvme_id_ctrl_cmic.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_id_ctrl_cmic" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_id_ctrl_cmic" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_id_ctrl_cmic \- Controller Multipath IO and Namespace Sharing Capabilities of the controller and NVM subsystem.
.SH SYNOPSIS
diff --git a/doc/man/nvme_id_ctrl_cntrltype.2 b/doc/man/nvme_id_ctrl_cntrltype.2
index 8f3898c..c5e6312 100644
--- a/doc/man/nvme_id_ctrl_cntrltype.2
+++ b/doc/man/nvme_id_ctrl_cntrltype.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_id_ctrl_cntrltype" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_id_ctrl_cntrltype" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_id_ctrl_cntrltype \- Controller types
.SH SYNOPSIS
diff --git a/doc/man/nvme_id_ctrl_cqes.2 b/doc/man/nvme_id_ctrl_cqes.2
index af5ec84..2c2ddf8 100644
--- a/doc/man/nvme_id_ctrl_cqes.2
+++ b/doc/man/nvme_id_ctrl_cqes.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_id_ctrl_cqes" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_id_ctrl_cqes" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_id_ctrl_cqes \- Defines the required and maximum Completion Queue entry size when using the NVM Command Set.
.SH SYNOPSIS
diff --git a/doc/man/nvme_id_ctrl_ctratt.2 b/doc/man/nvme_id_ctrl_ctratt.2
index 92590f9..311e9ab 100644
--- a/doc/man/nvme_id_ctrl_ctratt.2
+++ b/doc/man/nvme_id_ctrl_ctratt.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_id_ctrl_ctratt" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_id_ctrl_ctratt" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_id_ctrl_ctratt \- Controller attributes
.SH SYNOPSIS
diff --git a/doc/man/nvme_id_ctrl_dctype.2 b/doc/man/nvme_id_ctrl_dctype.2
index edd5eb4..a2fa3d8 100644
--- a/doc/man/nvme_id_ctrl_dctype.2
+++ b/doc/man/nvme_id_ctrl_dctype.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_id_ctrl_dctype" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_id_ctrl_dctype" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_id_ctrl_dctype \- Discovery Controller types
.SH SYNOPSIS
diff --git a/doc/man/nvme_id_ctrl_dsto.2 b/doc/man/nvme_id_ctrl_dsto.2
index d179317..d91576d 100644
--- a/doc/man/nvme_id_ctrl_dsto.2
+++ b/doc/man/nvme_id_ctrl_dsto.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_id_ctrl_dsto" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_id_ctrl_dsto" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_id_ctrl_dsto \- Flags indicating the optional Device Self-test command or operation behaviors supported by the controller or NVM subsystem.
.SH SYNOPSIS
diff --git a/doc/man/nvme_id_ctrl_fcatt.2 b/doc/man/nvme_id_ctrl_fcatt.2
index 9a610e5..6e7bc2a 100644
--- a/doc/man/nvme_id_ctrl_fcatt.2
+++ b/doc/man/nvme_id_ctrl_fcatt.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_id_ctrl_fcatt" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_id_ctrl_fcatt" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_id_ctrl_fcatt \- This field indicates attributes of the controller that are specific to NVMe over Fabrics.
.SH SYNOPSIS
diff --git a/doc/man/nvme_id_ctrl_fna.2 b/doc/man/nvme_id_ctrl_fna.2
index 4dab325..c34374c 100644
--- a/doc/man/nvme_id_ctrl_fna.2
+++ b/doc/man/nvme_id_ctrl_fna.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_id_ctrl_fna" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_id_ctrl_fna" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_id_ctrl_fna \- This field indicates attributes for the Format NVM command.
.SH SYNOPSIS
diff --git a/doc/man/nvme_id_ctrl_frmw.2 b/doc/man/nvme_id_ctrl_frmw.2
index f4dad4d..bc4f7a8 100644
--- a/doc/man/nvme_id_ctrl_frmw.2
+++ b/doc/man/nvme_id_ctrl_frmw.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_id_ctrl_frmw" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_id_ctrl_frmw" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_id_ctrl_frmw \- Flags and values indicates capabilities regarding firmware updates from &struct nvme_id_ctrl.frmw.
.SH SYNOPSIS
diff --git a/doc/man/nvme_id_ctrl_fuses.2 b/doc/man/nvme_id_ctrl_fuses.2
index e34fa04..f83cf32 100644
--- a/doc/man/nvme_id_ctrl_fuses.2
+++ b/doc/man/nvme_id_ctrl_fuses.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_id_ctrl_fuses" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_id_ctrl_fuses" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_id_ctrl_fuses \- This field indicates the fused operations that the controller supports.
.SH SYNOPSIS
diff --git a/doc/man/nvme_id_ctrl_hctm.2 b/doc/man/nvme_id_ctrl_hctm.2
index c4e549f..be8de7c 100644
--- a/doc/man/nvme_id_ctrl_hctm.2
+++ b/doc/man/nvme_id_ctrl_hctm.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_id_ctrl_hctm" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_id_ctrl_hctm" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_id_ctrl_hctm \- Flags indicate the attributes of the host controlled thermal management feature
.SH SYNOPSIS
diff --git a/doc/man/nvme_id_ctrl_lpa.2 b/doc/man/nvme_id_ctrl_lpa.2
index 5c6cc4b..1b37e37 100644
--- a/doc/man/nvme_id_ctrl_lpa.2
+++ b/doc/man/nvme_id_ctrl_lpa.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_id_ctrl_lpa" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_id_ctrl_lpa" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_id_ctrl_lpa \- Flags indicating optional attributes for log pages that are accessed via the Get Log Page command.
.SH SYNOPSIS
diff --git a/doc/man/nvme_id_ctrl_mec.2 b/doc/man/nvme_id_ctrl_mec.2
index 68875bb..e197ab5 100644
--- a/doc/man/nvme_id_ctrl_mec.2
+++ b/doc/man/nvme_id_ctrl_mec.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_id_ctrl_mec" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_id_ctrl_mec" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_id_ctrl_mec \- Flags indicating the capabilities of the Management Endpoint in the Controller, &struct nvme_id_ctrl.mec.
.SH SYNOPSIS
diff --git a/doc/man/nvme_id_ctrl_nvm.2 b/doc/man/nvme_id_ctrl_nvm.2
index 2611957..5103aa6 100644
--- a/doc/man/nvme_id_ctrl_nvm.2
+++ b/doc/man/nvme_id_ctrl_nvm.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_id_ctrl_nvm" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_id_ctrl_nvm" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_id_ctrl_nvm \- I/O Command Set Specific Identify Controller data structure
.SH SYNOPSIS
diff --git a/doc/man/nvme_id_ctrl_nvmsr.2 b/doc/man/nvme_id_ctrl_nvmsr.2
index 2effe80..1b4fb50 100644
--- a/doc/man/nvme_id_ctrl_nvmsr.2
+++ b/doc/man/nvme_id_ctrl_nvmsr.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_id_ctrl_nvmsr" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_id_ctrl_nvmsr" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_id_ctrl_nvmsr \- This field reports information associated with the NVM Subsystem, see &struct nvme_id_ctrl.nvmsr.
.SH SYNOPSIS
diff --git a/doc/man/nvme_id_ctrl_nvscc.2 b/doc/man/nvme_id_ctrl_nvscc.2
index 0b3a3f6..1ce71df 100644
--- a/doc/man/nvme_id_ctrl_nvscc.2
+++ b/doc/man/nvme_id_ctrl_nvscc.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_id_ctrl_nvscc" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_id_ctrl_nvscc" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_id_ctrl_nvscc \- This field indicates the configuration settings for NVM Vendor Specific command handling.
.SH SYNOPSIS
diff --git a/doc/man/nvme_id_ctrl_nwpc.2 b/doc/man/nvme_id_ctrl_nwpc.2
index 012f34b..b9742b5 100644
--- a/doc/man/nvme_id_ctrl_nwpc.2
+++ b/doc/man/nvme_id_ctrl_nwpc.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_id_ctrl_nwpc" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_id_ctrl_nwpc" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_id_ctrl_nwpc \- This field indicates the optional namespace write protection capabilities supported by the controller.
.SH SYNOPSIS
diff --git a/doc/man/nvme_id_ctrl_oacs.2 b/doc/man/nvme_id_ctrl_oacs.2
index a151fb2..224c1be 100644
--- a/doc/man/nvme_id_ctrl_oacs.2
+++ b/doc/man/nvme_id_ctrl_oacs.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_id_ctrl_oacs" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_id_ctrl_oacs" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_id_ctrl_oacs \- Flags indicating the optional Admin commands and features supported by the controller, see &struct nvme_id_ctrl.oacs.
.SH SYNOPSIS
diff --git a/doc/man/nvme_id_ctrl_oaes.2 b/doc/man/nvme_id_ctrl_oaes.2
index dff5e29..8ce148b 100644
--- a/doc/man/nvme_id_ctrl_oaes.2
+++ b/doc/man/nvme_id_ctrl_oaes.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_id_ctrl_oaes" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_id_ctrl_oaes" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_id_ctrl_oaes \- Optional Asynchronous Events Supported
.SH SYNOPSIS
diff --git a/doc/man/nvme_id_ctrl_ofcs.2 b/doc/man/nvme_id_ctrl_ofcs.2
index b83606e..abf5f0a 100644
--- a/doc/man/nvme_id_ctrl_ofcs.2
+++ b/doc/man/nvme_id_ctrl_ofcs.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_id_ctrl_ofcs" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_id_ctrl_ofcs" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_id_ctrl_ofcs \- Indicate whether the controller supports optional fabric commands.
.SH SYNOPSIS
diff --git a/doc/man/nvme_id_ctrl_oncs.2 b/doc/man/nvme_id_ctrl_oncs.2
index d51e63f..3e4c59f 100644
--- a/doc/man/nvme_id_ctrl_oncs.2
+++ b/doc/man/nvme_id_ctrl_oncs.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_id_ctrl_oncs" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_id_ctrl_oncs" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_id_ctrl_oncs \- This field indicates the optional NVM commands and features supported by the controller.
.SH SYNOPSIS
@@ -37,6 +37,14 @@ enum nvme_id_ctrl_oncs {
.br
.br
.BI " NVME_CTRL_ONCS_COPY"
+,
+.br
+.br
+.BI " NVME_CTRL_ONCS_COPY_SINGLE_ATOMICITY"
+,
+.br
+.br
+.BI " NVME_CTRL_ONCS_ALL_FAST_COPY"
};
.SH Constants
@@ -70,3 +78,13 @@ the Verify command.
.IP "NVME_CTRL_ONCS_COPY" 12
If set, then the controller supports
the copy command.
+.IP "NVME_CTRL_ONCS_COPY_SINGLE_ATOMICITY" 12
+If set, then the write portion of a
+Copy command is performed as a single
+write command to which the same
+atomicity requirements that apply to
+a write command apply.
+.IP "NVME_CTRL_ONCS_ALL_FAST_COPY" 12
+If set, then all copy operations for
+the Copy command are fast copy
+operations.
diff --git a/doc/man/nvme_id_ctrl_rpmbs.2 b/doc/man/nvme_id_ctrl_rpmbs.2
index 169c457..067c218 100644
--- a/doc/man/nvme_id_ctrl_rpmbs.2
+++ b/doc/man/nvme_id_ctrl_rpmbs.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_id_ctrl_rpmbs" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_id_ctrl_rpmbs" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_id_ctrl_rpmbs \- This field indicates if the controller supports one or more Replay Protected Memory Blocks, from &struct nvme_id_ctrl.rpmbs.
.SH SYNOPSIS
diff --git a/doc/man/nvme_id_ctrl_sanicap.2 b/doc/man/nvme_id_ctrl_sanicap.2
index 7f09750..06a89e5 100644
--- a/doc/man/nvme_id_ctrl_sanicap.2
+++ b/doc/man/nvme_id_ctrl_sanicap.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_id_ctrl_sanicap" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_id_ctrl_sanicap" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_id_ctrl_sanicap \- Indicates attributes for sanitize operations.
.SH SYNOPSIS
diff --git a/doc/man/nvme_id_ctrl_sgls.2 b/doc/man/nvme_id_ctrl_sgls.2
index 444234a..5445491 100644
--- a/doc/man/nvme_id_ctrl_sgls.2
+++ b/doc/man/nvme_id_ctrl_sgls.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_id_ctrl_sgls" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_id_ctrl_sgls" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_id_ctrl_sgls \- This field indicates if SGLs are supported for the NVM Command Set and the particular SGL types supported.
.SH SYNOPSIS
diff --git a/doc/man/nvme_id_ctrl_sqes.2 b/doc/man/nvme_id_ctrl_sqes.2
index 1fae8db..9f18a54 100644
--- a/doc/man/nvme_id_ctrl_sqes.2
+++ b/doc/man/nvme_id_ctrl_sqes.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_id_ctrl_sqes" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_id_ctrl_sqes" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_id_ctrl_sqes \- Defines the required and maximum Submission Queue entry size when using the NVM Command Set.
.SH SYNOPSIS
diff --git a/doc/man/nvme_id_ctrl_vwc.2 b/doc/man/nvme_id_ctrl_vwc.2
index caf1f64..607a6d9 100644
--- a/doc/man/nvme_id_ctrl_vwc.2
+++ b/doc/man/nvme_id_ctrl_vwc.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_id_ctrl_vwc" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_id_ctrl_vwc" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_id_ctrl_vwc \- Volatile write cache
.SH SYNOPSIS
diff --git a/doc/man/nvme_id_ctrl_vwci.2 b/doc/man/nvme_id_ctrl_vwci.2
index 0e9d8b1..a6aa26b 100644
--- a/doc/man/nvme_id_ctrl_vwci.2
+++ b/doc/man/nvme_id_ctrl_vwci.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_id_ctrl_vwci" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_id_ctrl_vwci" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_id_ctrl_vwci \- This field indicates information about remaining number of times that VPD contents are able to be updated using the VPD Write command, see &struct nvme_id_ctrl.vwci.
.SH SYNOPSIS
diff --git a/doc/man/nvme_id_directives.2 b/doc/man/nvme_id_directives.2
index ccbd468..2260c5b 100644
--- a/doc/man/nvme_id_directives.2
+++ b/doc/man/nvme_id_directives.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_id_directives" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_id_directives" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_id_directives \- Identify Directive - Return Parameters Data Structure
.SH SYNOPSIS
diff --git a/doc/man/nvme_id_domain_attr.2 b/doc/man/nvme_id_domain_attr.2
index a3b55c0..27d6962 100644
--- a/doc/man/nvme_id_domain_attr.2
+++ b/doc/man/nvme_id_domain_attr.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_id_domain_attr" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_id_domain_attr" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_id_domain_attr \- Domain Attributes Entry
.SH SYNOPSIS
diff --git a/doc/man/nvme_id_domain_list.2 b/doc/man/nvme_id_domain_list.2
index cb9c2f9..6dbb934 100644
--- a/doc/man/nvme_id_domain_list.2
+++ b/doc/man/nvme_id_domain_list.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_id_domain_list" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_id_domain_list" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_id_domain_list \- Domain List
.SH SYNOPSIS
diff --git a/doc/man/nvme_id_endurance_group_list.2 b/doc/man/nvme_id_endurance_group_list.2
index 2285100..07aa1ca 100644
--- a/doc/man/nvme_id_endurance_group_list.2
+++ b/doc/man/nvme_id_endurance_group_list.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_id_endurance_group_list" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_id_endurance_group_list" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_id_endurance_group_list \- Endurance Group List
.SH SYNOPSIS
diff --git a/doc/man/nvme_id_independent_id_ns.2 b/doc/man/nvme_id_independent_id_ns.2
index cc01f38..54e0d77 100644
--- a/doc/man/nvme_id_independent_id_ns.2
+++ b/doc/man/nvme_id_independent_id_ns.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_id_independent_id_ns" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_id_independent_id_ns" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_id_independent_id_ns \- Identify - I/O Command Set Independent Identify Namespace Data Structure
.SH SYNOPSIS
diff --git a/doc/man/nvme_id_iocs.2 b/doc/man/nvme_id_iocs.2
index 68d056a..a74ab3c 100644
--- a/doc/man/nvme_id_iocs.2
+++ b/doc/man/nvme_id_iocs.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_id_iocs" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_id_iocs" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_id_iocs \- NVMe Identify IO Command Set data structure
.SH SYNOPSIS
diff --git a/doc/man/nvme_id_ns.2 b/doc/man/nvme_id_ns.2
index 82d68d5..27aebbc 100644
--- a/doc/man/nvme_id_ns.2
+++ b/doc/man/nvme_id_ns.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_id_ns" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_id_ns" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_id_ns \- Identify Namespace data structure
.SH SYNOPSIS
@@ -84,9 +84,7 @@ struct nvme_id_ns {
.br
.BI " struct nvme_lbaf lbaf[64];"
.br
-.BI " __le64 lbstm;"
-.br
-.BI " __u8 vs[3704];"
+.BI " __u8 vs[3712];"
.br
.BI "
};
@@ -231,7 +229,5 @@ remains fixed throughout the life of the namespace and is
preserved across namespace and controller operations
.IP "lbaf" 12
LBA Format, see \fIstruct nvme_lbaf\fP.
-.IP "lbstm" 12
-Logical Block Storage Tag Mask for end-to-end protection
.IP "vs" 12
Vendor Specific
diff --git a/doc/man/nvme_id_ns_attr.2 b/doc/man/nvme_id_ns_attr.2
index 6401c8e..0236021 100644
--- a/doc/man/nvme_id_ns_attr.2
+++ b/doc/man/nvme_id_ns_attr.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_id_ns_attr" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_id_ns_attr" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_id_ns_attr \- Specifies attributes of the namespace.
.SH SYNOPSIS
diff --git a/doc/man/nvme_id_ns_dlfeat.2 b/doc/man/nvme_id_ns_dlfeat.2
index 93ff84c..86bfb1c 100644
--- a/doc/man/nvme_id_ns_dlfeat.2
+++ b/doc/man/nvme_id_ns_dlfeat.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_id_ns_dlfeat" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_id_ns_dlfeat" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_id_ns_dlfeat \- This field indicates information about features that affect deallocating logical blocks for this namespace.
.SH SYNOPSIS
diff --git a/doc/man/nvme_id_ns_dpc.2 b/doc/man/nvme_id_ns_dpc.2
index f9ec8f9..fc523e8 100644
--- a/doc/man/nvme_id_ns_dpc.2
+++ b/doc/man/nvme_id_ns_dpc.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_id_ns_dpc" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_id_ns_dpc" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_id_ns_dpc \- This field indicates the capabilities for the end-to-end data protection feature.
.SH SYNOPSIS
diff --git a/doc/man/nvme_id_ns_dps.2 b/doc/man/nvme_id_ns_dps.2
index 11c20ac..97309c5 100644
--- a/doc/man/nvme_id_ns_dps.2
+++ b/doc/man/nvme_id_ns_dps.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_id_ns_dps" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_id_ns_dps" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_id_ns_dps \- This field indicates the Type settings for the end-to-end data protection feature.
.SH SYNOPSIS
diff --git a/doc/man/nvme_id_ns_flbas.2 b/doc/man/nvme_id_ns_flbas.2
index cc40af0..5dbe573 100644
--- a/doc/man/nvme_id_ns_flbas.2
+++ b/doc/man/nvme_id_ns_flbas.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_id_ns_flbas" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_id_ns_flbas" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_id_ns_flbas \- This field indicates the LBA data size & metadata size combination that the namespace has been formatted with
.SH SYNOPSIS
diff --git a/doc/man/nvme_id_ns_granularity_desc.2 b/doc/man/nvme_id_ns_granularity_desc.2
index 7e94e5d..5f361b8 100644
--- a/doc/man/nvme_id_ns_granularity_desc.2
+++ b/doc/man/nvme_id_ns_granularity_desc.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_id_ns_granularity_desc" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_id_ns_granularity_desc" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_id_ns_granularity_desc \- Namespace Granularity Descriptor
.SH SYNOPSIS
diff --git a/doc/man/nvme_id_ns_granularity_list.2 b/doc/man/nvme_id_ns_granularity_list.2
index 7dfe503..dc2ae16 100644
--- a/doc/man/nvme_id_ns_granularity_list.2
+++ b/doc/man/nvme_id_ns_granularity_list.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_id_ns_granularity_list" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_id_ns_granularity_list" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_id_ns_granularity_list \- Namespace Granularity List
.SH SYNOPSIS
diff --git a/doc/man/nvme_id_ns_mc.2 b/doc/man/nvme_id_ns_mc.2
index 859d8d6..6658a2d 100644
--- a/doc/man/nvme_id_ns_mc.2
+++ b/doc/man/nvme_id_ns_mc.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_id_ns_mc" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_id_ns_mc" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_id_ns_mc \- This field indicates the capabilities for metadata.
.SH SYNOPSIS
diff --git a/doc/man/nvme_id_ns_nmic.2 b/doc/man/nvme_id_ns_nmic.2
index 1ef4a83..5517caa 100644
--- a/doc/man/nvme_id_ns_nmic.2
+++ b/doc/man/nvme_id_ns_nmic.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_id_ns_nmic" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_id_ns_nmic" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_id_ns_nmic \- This field specifies multi-path I/O and namespace sharing capabilities of the namespace.
.SH SYNOPSIS
diff --git a/doc/man/nvme_id_ns_rescap.2 b/doc/man/nvme_id_ns_rescap.2
index 77f5ee8..333c9e9 100644
--- a/doc/man/nvme_id_ns_rescap.2
+++ b/doc/man/nvme_id_ns_rescap.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_id_ns_rescap" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_id_ns_rescap" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_id_ns_rescap \- This field indicates the reservation capabilities of the namespace.
.SH SYNOPSIS
diff --git a/doc/man/nvme_id_nsfeat.2 b/doc/man/nvme_id_nsfeat.2
index 7d8a3a2..671d54b 100644
--- a/doc/man/nvme_id_nsfeat.2
+++ b/doc/man/nvme_id_nsfeat.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_id_nsfeat" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_id_nsfeat" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_id_nsfeat \- This field defines features of the namespace.
.SH SYNOPSIS
diff --git a/doc/man/nvme_id_nvmset_list.2 b/doc/man/nvme_id_nvmset_list.2
index 6a9f281..32a9810 100644
--- a/doc/man/nvme_id_nvmset_list.2
+++ b/doc/man/nvme_id_nvmset_list.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_id_nvmset_list" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_id_nvmset_list" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_id_nvmset_list \- NVM set list
.SH SYNOPSIS
diff --git a/doc/man/nvme_id_psd.2 b/doc/man/nvme_id_psd.2
index 7b23b4b..3585515 100644
--- a/doc/man/nvme_id_psd.2
+++ b/doc/man/nvme_id_psd.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_id_psd" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_id_psd" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_id_psd \- Power Management data structure
.SH SYNOPSIS
diff --git a/doc/man/nvme_id_uuid.2 b/doc/man/nvme_id_uuid.2
index 80ffdf6..8653334 100644
--- a/doc/man/nvme_id_uuid.2
+++ b/doc/man/nvme_id_uuid.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_id_uuid" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_id_uuid" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_id_uuid \- Identifier Association
.SH SYNOPSIS
diff --git a/doc/man/nvme_id_uuid_list.2 b/doc/man/nvme_id_uuid_list.2
index 0983c18..916a4f9 100644
--- a/doc/man/nvme_id_uuid_list.2
+++ b/doc/man/nvme_id_uuid_list.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_id_uuid_list" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_id_uuid_list" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_id_uuid_list \- UUID list
.SH SYNOPSIS
diff --git a/doc/man/nvme_id_uuid_list_entry.2 b/doc/man/nvme_id_uuid_list_entry.2
index 5debce4..498b445 100644
--- a/doc/man/nvme_id_uuid_list_entry.2
+++ b/doc/man/nvme_id_uuid_list_entry.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_id_uuid_list_entry" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_id_uuid_list_entry" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_id_uuid_list_entry \- UUID List Entry
.SH SYNOPSIS
diff --git a/doc/man/nvme_identify.2 b/doc/man/nvme_identify.2
index c3a4645..0d81fe9 100644
--- a/doc/man/nvme_identify.2
+++ b/doc/man/nvme_identify.2
@@ -1,4 +1,4 @@
-.TH "nvme_identify" 9 "nvme_identify" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_identify" 9 "nvme_identify" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_identify \- Send the NVMe Identify command
.SH SYNOPSIS
diff --git a/doc/man/nvme_identify_active_ns_list.2 b/doc/man/nvme_identify_active_ns_list.2
index d04827d..06ab259 100644
--- a/doc/man/nvme_identify_active_ns_list.2
+++ b/doc/man/nvme_identify_active_ns_list.2
@@ -1,4 +1,4 @@
-.TH "nvme_identify_active_ns_list" 9 "nvme_identify_active_ns_list" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_identify_active_ns_list" 9 "nvme_identify_active_ns_list" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_identify_active_ns_list \- Retrieves active namespaces id list
.SH SYNOPSIS
diff --git a/doc/man/nvme_identify_active_ns_list_csi.2 b/doc/man/nvme_identify_active_ns_list_csi.2
index 39c859d..2bff937 100644
--- a/doc/man/nvme_identify_active_ns_list_csi.2
+++ b/doc/man/nvme_identify_active_ns_list_csi.2
@@ -1,4 +1,4 @@
-.TH "nvme_identify_active_ns_list_csi" 9 "nvme_identify_active_ns_list_csi" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_identify_active_ns_list_csi" 9 "nvme_identify_active_ns_list_csi" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_identify_active_ns_list_csi \- Active namespace ID list associated with a specified I/O command set
.SH SYNOPSIS
diff --git a/doc/man/nvme_identify_allocated_ns.2 b/doc/man/nvme_identify_allocated_ns.2
index 7fe2ce7..c18ea48 100644
--- a/doc/man/nvme_identify_allocated_ns.2
+++ b/doc/man/nvme_identify_allocated_ns.2
@@ -1,4 +1,4 @@
-.TH "nvme_identify_allocated_ns" 9 "nvme_identify_allocated_ns" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_identify_allocated_ns" 9 "nvme_identify_allocated_ns" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_identify_allocated_ns \- Same as nvme_identify_ns, but only for allocated namespaces
.SH SYNOPSIS
diff --git a/doc/man/nvme_identify_allocated_ns_list.2 b/doc/man/nvme_identify_allocated_ns_list.2
index 7540578..80770f2 100644
--- a/doc/man/nvme_identify_allocated_ns_list.2
+++ b/doc/man/nvme_identify_allocated_ns_list.2
@@ -1,4 +1,4 @@
-.TH "nvme_identify_allocated_ns_list" 9 "nvme_identify_allocated_ns_list" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_identify_allocated_ns_list" 9 "nvme_identify_allocated_ns_list" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_identify_allocated_ns_list \- Retrieves allocated namespace id list
.SH SYNOPSIS
diff --git a/doc/man/nvme_identify_allocated_ns_list_csi.2 b/doc/man/nvme_identify_allocated_ns_list_csi.2
index 3f936f6..963d165 100644
--- a/doc/man/nvme_identify_allocated_ns_list_csi.2
+++ b/doc/man/nvme_identify_allocated_ns_list_csi.2
@@ -1,4 +1,4 @@
-.TH "nvme_identify_allocated_ns_list_csi" 9 "nvme_identify_allocated_ns_list_csi" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_identify_allocated_ns_list_csi" 9 "nvme_identify_allocated_ns_list_csi" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_identify_allocated_ns_list_csi \- Allocated namespace ID list associated with a specified I/O command set
.SH SYNOPSIS
diff --git a/doc/man/nvme_identify_cns.2 b/doc/man/nvme_identify_cns.2
index 7f2b02c..570b9b0 100644
--- a/doc/man/nvme_identify_cns.2
+++ b/doc/man/nvme_identify_cns.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_identify_cns" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_identify_cns" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_identify_cns \- Identify - CNS Values
.SH SYNOPSIS
diff --git a/doc/man/nvme_identify_ctrl.2 b/doc/man/nvme_identify_ctrl.2
index f1541f0..33d5a35 100644
--- a/doc/man/nvme_identify_ctrl.2
+++ b/doc/man/nvme_identify_ctrl.2
@@ -1,4 +1,4 @@
-.TH "nvme_identify_ctrl" 9 "nvme_identify_ctrl" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_identify_ctrl" 9 "nvme_identify_ctrl" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_identify_ctrl \- Retrieves nvme identify controller
.SH SYNOPSIS
diff --git a/doc/man/nvme_identify_ctrl_csi.2 b/doc/man/nvme_identify_ctrl_csi.2
index c501497..3bc4e76 100644
--- a/doc/man/nvme_identify_ctrl_csi.2
+++ b/doc/man/nvme_identify_ctrl_csi.2
@@ -1,4 +1,4 @@
-.TH "nvme_identify_ctrl_csi" 9 "nvme_identify_ctrl_csi" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_identify_ctrl_csi" 9 "nvme_identify_ctrl_csi" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_identify_ctrl_csi \- I/O command set specific Identify Controller data
.SH SYNOPSIS
diff --git a/doc/man/nvme_identify_ctrl_list.2 b/doc/man/nvme_identify_ctrl_list.2
index 16907a6..9c8e3cc 100644
--- a/doc/man/nvme_identify_ctrl_list.2
+++ b/doc/man/nvme_identify_ctrl_list.2
@@ -1,4 +1,4 @@
-.TH "nvme_identify_ctrl_list" 9 "nvme_identify_ctrl_list" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_identify_ctrl_list" 9 "nvme_identify_ctrl_list" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_identify_ctrl_list \- Retrieves identify controller list
.SH SYNOPSIS
diff --git a/doc/man/nvme_identify_domain_list.2 b/doc/man/nvme_identify_domain_list.2
index c6eaa03..bb5983c 100644
--- a/doc/man/nvme_identify_domain_list.2
+++ b/doc/man/nvme_identify_domain_list.2
@@ -1,4 +1,4 @@
-.TH "nvme_identify_domain_list" 9 "nvme_identify_domain_list" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_identify_domain_list" 9 "nvme_identify_domain_list" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_identify_domain_list \- Domain list data
.SH SYNOPSIS
diff --git a/doc/man/nvme_identify_endurance_group_list.2 b/doc/man/nvme_identify_endurance_group_list.2
index 575b477..6437daa 100644
--- a/doc/man/nvme_identify_endurance_group_list.2
+++ b/doc/man/nvme_identify_endurance_group_list.2
@@ -1,4 +1,4 @@
-.TH "nvme_identify_endurance_group_list" 9 "nvme_identify_endurance_group_list" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_identify_endurance_group_list" 9 "nvme_identify_endurance_group_list" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_identify_endurance_group_list \- Endurance group list data
.SH SYNOPSIS
diff --git a/doc/man/nvme_identify_independent_identify_ns.2 b/doc/man/nvme_identify_independent_identify_ns.2
index 0863437..06966b4 100644
--- a/doc/man/nvme_identify_independent_identify_ns.2
+++ b/doc/man/nvme_identify_independent_identify_ns.2
@@ -1,4 +1,4 @@
-.TH "nvme_identify_independent_identify_ns" 9 "nvme_identify_independent_identify_ns" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_identify_independent_identify_ns" 9 "nvme_identify_independent_identify_ns" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_identify_independent_identify_ns \- I/O command set independent Identify namespace data
.SH SYNOPSIS
diff --git a/doc/man/nvme_identify_iocs.2 b/doc/man/nvme_identify_iocs.2
index 57db606..ac871a5 100644
--- a/doc/man/nvme_identify_iocs.2
+++ b/doc/man/nvme_identify_iocs.2
@@ -1,4 +1,4 @@
-.TH "nvme_identify_iocs" 9 "nvme_identify_iocs" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_identify_iocs" 9 "nvme_identify_iocs" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_identify_iocs \- I/O command set data structure
.SH SYNOPSIS
diff --git a/doc/man/nvme_identify_iocs_ns_csi_user_data_format.2 b/doc/man/nvme_identify_iocs_ns_csi_user_data_format.2
index b1a4caa..5ad6251 100644
--- a/doc/man/nvme_identify_iocs_ns_csi_user_data_format.2
+++ b/doc/man/nvme_identify_iocs_ns_csi_user_data_format.2
@@ -1,4 +1,4 @@
-.TH "nvme_identify_iocs_ns_csi_user_data_format" 9 "nvme_identify_iocs_ns_csi_user_data_format" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_identify_iocs_ns_csi_user_data_format" 9 "nvme_identify_iocs_ns_csi_user_data_format" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_identify_iocs_ns_csi_user_data_format \- Identify I/O command set namespace data structure
.SH SYNOPSIS
diff --git a/doc/man/nvme_identify_ns.2 b/doc/man/nvme_identify_ns.2
index c1c12de..84a8e3a 100644
--- a/doc/man/nvme_identify_ns.2
+++ b/doc/man/nvme_identify_ns.2
@@ -1,4 +1,4 @@
-.TH "nvme_identify_ns" 9 "nvme_identify_ns" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_identify_ns" 9 "nvme_identify_ns" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_identify_ns \- Retrieves nvme identify namespace
.SH SYNOPSIS
diff --git a/doc/man/nvme_identify_ns_csi.2 b/doc/man/nvme_identify_ns_csi.2
index ad4e743..2135a21 100644
--- a/doc/man/nvme_identify_ns_csi.2
+++ b/doc/man/nvme_identify_ns_csi.2
@@ -1,4 +1,4 @@
-.TH "nvme_identify_ns_csi" 9 "nvme_identify_ns_csi" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_identify_ns_csi" 9 "nvme_identify_ns_csi" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_identify_ns_csi \- I/O command set specific identify namespace data
.SH SYNOPSIS
diff --git a/doc/man/nvme_identify_ns_csi_user_data_format.2 b/doc/man/nvme_identify_ns_csi_user_data_format.2
index 2368d39..6c6d482 100644
--- a/doc/man/nvme_identify_ns_csi_user_data_format.2
+++ b/doc/man/nvme_identify_ns_csi_user_data_format.2
@@ -1,4 +1,4 @@
-.TH "nvme_identify_ns_csi_user_data_format" 9 "nvme_identify_ns_csi_user_data_format" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_identify_ns_csi_user_data_format" 9 "nvme_identify_ns_csi_user_data_format" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_identify_ns_csi_user_data_format \- Identify namespace user data format
.SH SYNOPSIS
diff --git a/doc/man/nvme_identify_ns_descs.2 b/doc/man/nvme_identify_ns_descs.2
index 7c68564..5962561 100644
--- a/doc/man/nvme_identify_ns_descs.2
+++ b/doc/man/nvme_identify_ns_descs.2
@@ -1,4 +1,4 @@
-.TH "nvme_identify_ns_descs" 9 "nvme_identify_ns_descs" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_identify_ns_descs" 9 "nvme_identify_ns_descs" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_identify_ns_descs \- Retrieves namespace descriptor list
.SH SYNOPSIS
diff --git a/doc/man/nvme_identify_ns_granularity.2 b/doc/man/nvme_identify_ns_granularity.2
index eecd5ac..58eeb73 100644
--- a/doc/man/nvme_identify_ns_granularity.2
+++ b/doc/man/nvme_identify_ns_granularity.2
@@ -1,4 +1,4 @@
-.TH "nvme_identify_ns_granularity" 9 "nvme_identify_ns_granularity" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_identify_ns_granularity" 9 "nvme_identify_ns_granularity" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_identify_ns_granularity \- Retrieves namespace granularity identification
.SH SYNOPSIS
diff --git a/doc/man/nvme_identify_nsid_ctrl_list.2 b/doc/man/nvme_identify_nsid_ctrl_list.2
index eb6492b..e474882 100644
--- a/doc/man/nvme_identify_nsid_ctrl_list.2
+++ b/doc/man/nvme_identify_nsid_ctrl_list.2
@@ -1,4 +1,4 @@
-.TH "nvme_identify_nsid_ctrl_list" 9 "nvme_identify_nsid_ctrl_list" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_identify_nsid_ctrl_list" 9 "nvme_identify_nsid_ctrl_list" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_identify_nsid_ctrl_list \- Retrieves controller list attached to an nsid
.SH SYNOPSIS
diff --git a/doc/man/nvme_identify_nvmset_list.2 b/doc/man/nvme_identify_nvmset_list.2
index f8e90c5..a5f66ad 100644
--- a/doc/man/nvme_identify_nvmset_list.2
+++ b/doc/man/nvme_identify_nvmset_list.2
@@ -1,4 +1,4 @@
-.TH "nvme_identify_nvmset_list" 9 "nvme_identify_nvmset_list" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_identify_nvmset_list" 9 "nvme_identify_nvmset_list" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_identify_nvmset_list \- Retrieves NVM Set List
.SH SYNOPSIS
diff --git a/doc/man/nvme_identify_primary_ctrl.2 b/doc/man/nvme_identify_primary_ctrl.2
index 7be8839..dd63a5f 100644
--- a/doc/man/nvme_identify_primary_ctrl.2
+++ b/doc/man/nvme_identify_primary_ctrl.2
@@ -1,4 +1,4 @@
-.TH "nvme_identify_primary_ctrl" 9 "nvme_identify_primary_ctrl" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_identify_primary_ctrl" 9 "nvme_identify_primary_ctrl" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_identify_primary_ctrl \- Retrieve NVMe Primary Controller identification
.SH SYNOPSIS
diff --git a/doc/man/nvme_identify_secondary_ctrl_list.2 b/doc/man/nvme_identify_secondary_ctrl_list.2
index 2778705..3223e8e 100644
--- a/doc/man/nvme_identify_secondary_ctrl_list.2
+++ b/doc/man/nvme_identify_secondary_ctrl_list.2
@@ -1,17 +1,14 @@
-.TH "nvme_identify_secondary_ctrl_list" 9 "nvme_identify_secondary_ctrl_list" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_identify_secondary_ctrl_list" 9 "nvme_identify_secondary_ctrl_list" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_identify_secondary_ctrl_list \- Retrieves secondary controller list
.SH SYNOPSIS
.B "int" nvme_identify_secondary_ctrl_list
.BI "(int fd " ","
-.BI "__u32 nsid " ","
.BI "__u16 cntid " ","
.BI "struct nvme_secondary_ctrl_list *sc_list " ");"
.SH ARGUMENTS
.IP "fd" 12
File descriptor of nvme device
-.IP "nsid" 12
-Namespace identifier
.IP "cntid" 12
Return controllers starting at this identifier
.IP "sc_list" 12
diff --git a/doc/man/nvme_identify_uuid.2 b/doc/man/nvme_identify_uuid.2
index e150845..9c52a71 100644
--- a/doc/man/nvme_identify_uuid.2
+++ b/doc/man/nvme_identify_uuid.2
@@ -1,4 +1,4 @@
-.TH "nvme_identify_uuid" 9 "nvme_identify_uuid" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_identify_uuid" 9 "nvme_identify_uuid" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_identify_uuid \- Retrieves device's UUIDs
.SH SYNOPSIS
diff --git a/doc/man/nvme_init_copy_range.2 b/doc/man/nvme_init_copy_range.2
index f47e1f5..4c81523 100644
--- a/doc/man/nvme_init_copy_range.2
+++ b/doc/man/nvme_init_copy_range.2
@@ -1,4 +1,4 @@
-.TH "nvme_init_copy_range" 9 "nvme_init_copy_range" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_init_copy_range" 9 "nvme_init_copy_range" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_init_copy_range \- Constructs a copy range structure
.SH SYNOPSIS
diff --git a/doc/man/nvme_init_copy_range_f1.2 b/doc/man/nvme_init_copy_range_f1.2
index 5a981ce..36fd44e 100644
--- a/doc/man/nvme_init_copy_range_f1.2
+++ b/doc/man/nvme_init_copy_range_f1.2
@@ -1,4 +1,4 @@
-.TH "nvme_init_copy_range_f1" 9 "nvme_init_copy_range_f1" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_init_copy_range_f1" 9 "nvme_init_copy_range_f1" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_init_copy_range_f1 \- Constructs a copy range f1 structure
.SH SYNOPSIS
diff --git a/doc/man/nvme_init_copy_range_f2.2 b/doc/man/nvme_init_copy_range_f2.2
new file mode 100644
index 0000000..15ee6d5
--- /dev/null
+++ b/doc/man/nvme_init_copy_range_f2.2
@@ -0,0 +1,33 @@
+.TH "nvme_init_copy_range_f2" 9 "nvme_init_copy_range_f2" "December 2023" "libnvme API manual" LINUX
+.SH NAME
+nvme_init_copy_range_f2 \- Constructs a copy range f2 structure
+.SH SYNOPSIS
+.B "void" nvme_init_copy_range_f2
+.BI "(struct nvme_copy_range_f2 *copy " ","
+.BI "__u32 *snsids " ","
+.BI "__u16 *nlbs " ","
+.BI "__u64 *slbas " ","
+.BI "__u16 *sopts " ","
+.BI "__u32 *eilbrts " ","
+.BI "__u32 *elbatms " ","
+.BI "__u32 *elbats " ","
+.BI "__u16 nr " ");"
+.SH ARGUMENTS
+.IP "copy" 12
+Copy range array
+.IP "snsids" 12
+Source namespace identifier
+.IP "nlbs" 12
+Number of logical blocks
+.IP "slbas" 12
+Starting LBA
+.IP "sopts" 12
+Source options
+.IP "eilbrts" 12
+Expected initial logical block reference tag
+.IP "elbatms" 12
+Expected logical block application tag mask
+.IP "elbats" 12
+Expected logical block application tag
+.IP "nr" 12
+Number of descriptors to construct
diff --git a/doc/man/nvme_init_copy_range_f3.2 b/doc/man/nvme_init_copy_range_f3.2
new file mode 100644
index 0000000..9acdb15
--- /dev/null
+++ b/doc/man/nvme_init_copy_range_f3.2
@@ -0,0 +1,33 @@
+.TH "nvme_init_copy_range_f3" 9 "nvme_init_copy_range_f3" "December 2023" "libnvme API manual" LINUX
+.SH NAME
+nvme_init_copy_range_f3 \- Constructs a copy range f3 structure
+.SH SYNOPSIS
+.B "void" nvme_init_copy_range_f3
+.BI "(struct nvme_copy_range_f3 *copy " ","
+.BI "__u32 *snsids " ","
+.BI "__u16 *nlbs " ","
+.BI "__u64 *slbas " ","
+.BI "__u16 *sopts " ","
+.BI "__u64 *eilbrts " ","
+.BI "__u32 *elbatms " ","
+.BI "__u32 *elbats " ","
+.BI "__u16 nr " ");"
+.SH ARGUMENTS
+.IP "copy" 12
+Copy range array
+.IP "snsids" 12
+Source namespace identifier
+.IP "nlbs" 12
+Number of logical blocks
+.IP "slbas" 12
+Starting LBA
+.IP "sopts" 12
+Source options
+.IP "eilbrts" 12
+Expected initial logical block reference tag
+.IP "elbatms" 12
+Expected logical block application tag mask
+.IP "elbats" 12
+Expected logical block application tag
+.IP "nr" 12
+Number of descriptors to construct
diff --git a/doc/man/nvme_init_ctrl.2 b/doc/man/nvme_init_ctrl.2
index 44739a9..1bf35b9 100644
--- a/doc/man/nvme_init_ctrl.2
+++ b/doc/man/nvme_init_ctrl.2
@@ -1,4 +1,4 @@
-.TH "nvme_init_ctrl" 9 "nvme_init_ctrl" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_init_ctrl" 9 "nvme_init_ctrl" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_init_ctrl \- Initialize nvme_ctrl_t object for an existing controller.
.SH SYNOPSIS
diff --git a/doc/man/nvme_init_ctrl_list.2 b/doc/man/nvme_init_ctrl_list.2
index 5ba6df6..48877e1 100644
--- a/doc/man/nvme_init_ctrl_list.2
+++ b/doc/man/nvme_init_ctrl_list.2
@@ -1,4 +1,4 @@
-.TH "nvme_init_ctrl_list" 9 "nvme_init_ctrl_list" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_init_ctrl_list" 9 "nvme_init_ctrl_list" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_init_ctrl_list \- Initialize an nvme_ctrl_list structure from an array.
.SH SYNOPSIS
diff --git a/doc/man/nvme_init_dsm_range.2 b/doc/man/nvme_init_dsm_range.2
index b6cf225..5831d57 100644
--- a/doc/man/nvme_init_dsm_range.2
+++ b/doc/man/nvme_init_dsm_range.2
@@ -1,4 +1,4 @@
-.TH "nvme_init_dsm_range" 9 "nvme_init_dsm_range" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_init_dsm_range" 9 "nvme_init_dsm_range" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_init_dsm_range \- Constructs a data set range structure
.SH SYNOPSIS
diff --git a/doc/man/nvme_init_logging.2 b/doc/man/nvme_init_logging.2
index d47c379..997a226 100644
--- a/doc/man/nvme_init_logging.2
+++ b/doc/man/nvme_init_logging.2
@@ -1,4 +1,4 @@
-.TH "nvme_init_logging" 9 "nvme_init_logging" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_init_logging" 9 "nvme_init_logging" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_init_logging \- Initialize logging
.SH SYNOPSIS
diff --git a/doc/man/nvme_insert_tls_key.2 b/doc/man/nvme_insert_tls_key.2
index f0614bf..e7073e7 100644
--- a/doc/man/nvme_insert_tls_key.2
+++ b/doc/man/nvme_insert_tls_key.2
@@ -1,4 +1,4 @@
-.TH "nvme_insert_tls_key" 9 "nvme_insert_tls_key" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_insert_tls_key" 9 "nvme_insert_tls_key" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_insert_tls_key \- Derive and insert TLS key
.SH SYNOPSIS
diff --git a/doc/man/nvme_insert_tls_key_versioned.2 b/doc/man/nvme_insert_tls_key_versioned.2
new file mode 100644
index 0000000..31ef626
--- /dev/null
+++ b/doc/man/nvme_insert_tls_key_versioned.2
@@ -0,0 +1,37 @@
+.TH "nvme_insert_tls_key_versioned" 9 "nvme_insert_tls_key_versioned" "December 2023" "libnvme API manual" LINUX
+.SH NAME
+nvme_insert_tls_key_versioned \- Derive and insert TLS key
+.SH SYNOPSIS
+.B "long" nvme_insert_tls_key_versioned
+.BI "(const char *keyring " ","
+.BI "const char *key_type " ","
+.BI "const char *hostnqn " ","
+.BI "const char *subsysnqn " ","
+.BI "int version " ","
+.BI "int hmac " ","
+.BI "unsigned char *configured_key " ","
+.BI "int key_len " ");"
+.SH ARGUMENTS
+.IP "keyring" 12
+Keyring to use
+.IP "key_type" 12
+Type of the resulting key
+.IP "hostnqn" 12
+Host NVMe Qualified Name
+.IP "subsysnqn" 12
+Subsystem NVMe Qualified Name
+.IP "version" 12
+Key version to use
+.IP "hmac" 12
+HMAC algorithm
+.IP "configured_key" 12
+Configured key data to derive the key from
+.IP "key_len" 12
+Length of \fIconfigured_key\fP
+.SH "DESCRIPTION"
+Derives a 'retained' TLS key as specified in NVMe TCP 1.0a (if
+\fIversion\fP s set to '0') or NVMe TP8028 (if \fIversion\fP is set to '1) and
+stores it as type \fIkey_type\fP in the keyring specified by \fIkeyring\fP.
+.SH "RETURN"
+The key serial number if the key could be inserted into
+the keyring or 0 with errno otherwise.
diff --git a/doc/man/nvme_io.2 b/doc/man/nvme_io.2
index b4f2ca6..2bb1bc0 100644
--- a/doc/man/nvme_io.2
+++ b/doc/man/nvme_io.2
@@ -1,4 +1,4 @@
-.TH "nvme_io" 9 "nvme_io" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_io" 9 "nvme_io" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_io \- Submit an nvme user I/O command
.SH SYNOPSIS
diff --git a/doc/man/nvme_io_control_flags.2 b/doc/man/nvme_io_control_flags.2
index 04beddc..ff7b3f2 100644
--- a/doc/man/nvme_io_control_flags.2
+++ b/doc/man/nvme_io_control_flags.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_io_control_flags" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_io_control_flags" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_io_control_flags \- I/O control flags
.SH SYNOPSIS
diff --git a/doc/man/nvme_io_dsm_flags.2 b/doc/man/nvme_io_dsm_flags.2
index 575faa4..e3d6fac 100644
--- a/doc/man/nvme_io_dsm_flags.2
+++ b/doc/man/nvme_io_dsm_flags.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_io_dsm_flags" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_io_dsm_flags" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_io_dsm_flags \- Dataset Management flags
.SH SYNOPSIS
diff --git a/doc/man/nvme_io_mgmt_recv.2 b/doc/man/nvme_io_mgmt_recv.2
index 00ab695..7405eb3 100644
--- a/doc/man/nvme_io_mgmt_recv.2
+++ b/doc/man/nvme_io_mgmt_recv.2
@@ -1,4 +1,4 @@
-.TH "nvme_io_mgmt_recv" 9 "nvme_io_mgmt_recv" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_io_mgmt_recv" 9 "nvme_io_mgmt_recv" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_io_mgmt_recv \- I/O Management Receive command
.SH SYNOPSIS
diff --git a/doc/man/nvme_io_mgmt_recv_mo.2 b/doc/man/nvme_io_mgmt_recv_mo.2
index 07bb97b..3cad109 100644
--- a/doc/man/nvme_io_mgmt_recv_mo.2
+++ b/doc/man/nvme_io_mgmt_recv_mo.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_io_mgmt_recv_mo" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_io_mgmt_recv_mo" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_io_mgmt_recv_mo \- I/O Management Receive - Management Operation
.SH SYNOPSIS
diff --git a/doc/man/nvme_io_mgmt_send.2 b/doc/man/nvme_io_mgmt_send.2
index a1e1727..5c31891 100644
--- a/doc/man/nvme_io_mgmt_send.2
+++ b/doc/man/nvme_io_mgmt_send.2
@@ -1,4 +1,4 @@
-.TH "nvme_io_mgmt_send" 9 "nvme_io_mgmt_send" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_io_mgmt_send" 9 "nvme_io_mgmt_send" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_io_mgmt_send \- I/O Management Send command
.SH SYNOPSIS
diff --git a/doc/man/nvme_io_mgmt_send_mo.2 b/doc/man/nvme_io_mgmt_send_mo.2
index df588ca..329cede 100644
--- a/doc/man/nvme_io_mgmt_send_mo.2
+++ b/doc/man/nvme_io_mgmt_send_mo.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_io_mgmt_send_mo" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_io_mgmt_send_mo" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_io_mgmt_send_mo \- I/O Management Send - Management Operation
.SH SYNOPSIS
diff --git a/doc/man/nvme_io_opcode.2 b/doc/man/nvme_io_opcode.2
index 3c4a995..bb91743 100644
--- a/doc/man/nvme_io_opcode.2
+++ b/doc/man/nvme_io_opcode.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_io_opcode" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_io_opcode" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_io_opcode \- Opcodes for I/O Commands
.SH SYNOPSIS
diff --git a/doc/man/nvme_io_passthru.2 b/doc/man/nvme_io_passthru.2
index 7f9ab81..738cec5 100644
--- a/doc/man/nvme_io_passthru.2
+++ b/doc/man/nvme_io_passthru.2
@@ -1,4 +1,4 @@
-.TH "nvme_io_passthru" 9 "nvme_io_passthru" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_io_passthru" 9 "nvme_io_passthru" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_io_passthru \- Submit an nvme io passthrough command
.SH SYNOPSIS
diff --git a/doc/man/nvme_io_passthru64.2 b/doc/man/nvme_io_passthru64.2
index 970c238..655463f 100644
--- a/doc/man/nvme_io_passthru64.2
+++ b/doc/man/nvme_io_passthru64.2
@@ -1,4 +1,4 @@
-.TH "nvme_io_passthru64" 9 "nvme_io_passthru64" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_io_passthru64" 9 "nvme_io_passthru64" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_io_passthru64 \- Submit an nvme io passthrough command
.SH SYNOPSIS
diff --git a/doc/man/nvme_is_64bit_reg.2 b/doc/man/nvme_is_64bit_reg.2
index 426274d..0e5d965 100644
--- a/doc/man/nvme_is_64bit_reg.2
+++ b/doc/man/nvme_is_64bit_reg.2
@@ -1,4 +1,4 @@
-.TH "nvme_is_64bit_reg" 9 "nvme_is_64bit_reg" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_is_64bit_reg" 9 "nvme_is_64bit_reg" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_is_64bit_reg \- Checks if offset of the controller register is a know 64bit value.
.SH SYNOPSIS
diff --git a/doc/man/nvme_lba_range_type.2 b/doc/man/nvme_lba_range_type.2
index 7a00145..0353406 100644
--- a/doc/man/nvme_lba_range_type.2
+++ b/doc/man/nvme_lba_range_type.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_lba_range_type" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_lba_range_type" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_lba_range_type \- LBA Range Type
.SH SYNOPSIS
diff --git a/doc/man/nvme_lba_range_type_entry.2 b/doc/man/nvme_lba_range_type_entry.2
index 6c8c883..9c094af 100644
--- a/doc/man/nvme_lba_range_type_entry.2
+++ b/doc/man/nvme_lba_range_type_entry.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_lba_range_type_entry" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_lba_range_type_entry" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_lba_range_type_entry \- LBA Range Type - Data Structure Entry
.SH SYNOPSIS
diff --git a/doc/man/nvme_lba_rd.2 b/doc/man/nvme_lba_rd.2
index 3d75ee6..62e383e 100644
--- a/doc/man/nvme_lba_rd.2
+++ b/doc/man/nvme_lba_rd.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_lba_rd" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_lba_rd" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_lba_rd \- LBA Range Descriptor
.SH SYNOPSIS
diff --git a/doc/man/nvme_lba_status.2 b/doc/man/nvme_lba_status.2
index ca60c7b..5c5972d 100644
--- a/doc/man/nvme_lba_status.2
+++ b/doc/man/nvme_lba_status.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_lba_status" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_lba_status" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_lba_status \- LBA Status Descriptor List
.SH SYNOPSIS
diff --git a/doc/man/nvme_lba_status_atype.2 b/doc/man/nvme_lba_status_atype.2
index 7d55382..41fd749 100644
--- a/doc/man/nvme_lba_status_atype.2
+++ b/doc/man/nvme_lba_status_atype.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_lba_status_atype" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_lba_status_atype" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_lba_status_atype \- Potentially Unrecoverable LBAs
.SH SYNOPSIS
diff --git a/doc/man/nvme_lba_status_desc.2 b/doc/man/nvme_lba_status_desc.2
index 2457296..c186767 100644
--- a/doc/man/nvme_lba_status_desc.2
+++ b/doc/man/nvme_lba_status_desc.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_lba_status_desc" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_lba_status_desc" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_lba_status_desc \- LBA Status Descriptor Entry
.SH SYNOPSIS
diff --git a/doc/man/nvme_lba_status_log.2 b/doc/man/nvme_lba_status_log.2
index 7c3339f..aec23b0 100644
--- a/doc/man/nvme_lba_status_log.2
+++ b/doc/man/nvme_lba_status_log.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_lba_status_log" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_lba_status_log" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_lba_status_log \- LBA Status Information Log
.SH SYNOPSIS
diff --git a/doc/man/nvme_lbaf.2 b/doc/man/nvme_lbaf.2
index 620df2e..bb7166f 100644
--- a/doc/man/nvme_lbaf.2
+++ b/doc/man/nvme_lbaf.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_lbaf" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_lbaf" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_lbaf \- LBA Format Data Structure
.SH SYNOPSIS
diff --git a/doc/man/nvme_lbaf_rp.2 b/doc/man/nvme_lbaf_rp.2
index 942c269..15ab339 100644
--- a/doc/man/nvme_lbaf_rp.2
+++ b/doc/man/nvme_lbaf_rp.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_lbaf_rp" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_lbaf_rp" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_lbaf_rp \- This field indicates the relative performance of the LBA format indicated relative to other LBA formats supported by the controller.
.SH SYNOPSIS
diff --git a/doc/man/nvme_lbart.2 b/doc/man/nvme_lbart.2
index 1c6f66f..17b46d6 100644
--- a/doc/man/nvme_lbart.2
+++ b/doc/man/nvme_lbart.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_lbart" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_lbart" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_lbart \- LBA Range Type - Data Structure Entry
.SH SYNOPSIS
diff --git a/doc/man/nvme_lbas_ns_element.2 b/doc/man/nvme_lbas_ns_element.2
index 6efab64..d4590ed 100644
--- a/doc/man/nvme_lbas_ns_element.2
+++ b/doc/man/nvme_lbas_ns_element.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_lbas_ns_element" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_lbas_ns_element" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_lbas_ns_element \- LBA Status Log Namespace Element
.SH SYNOPSIS
diff --git a/doc/man/nvme_lockdown.2 b/doc/man/nvme_lockdown.2
index 6a101a5..6ca9d94 100644
--- a/doc/man/nvme_lockdown.2
+++ b/doc/man/nvme_lockdown.2
@@ -1,4 +1,4 @@
-.TH "nvme_lockdown" 9 "nvme_lockdown" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_lockdown" 9 "nvme_lockdown" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_lockdown \- Issue lockdown command
.SH SYNOPSIS
diff --git a/doc/man/nvme_log_ana_lsp.2 b/doc/man/nvme_log_ana_lsp.2
index 9ccb3ef..ce59f3b 100644
--- a/doc/man/nvme_log_ana_lsp.2
+++ b/doc/man/nvme_log_ana_lsp.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_log_ana_lsp" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_log_ana_lsp" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_log_ana_lsp \- Asymmetric Namespace Access - Return Groups Only
.SH SYNOPSIS
diff --git a/doc/man/nvme_log_phy_rx_eom_action.2 b/doc/man/nvme_log_phy_rx_eom_action.2
new file mode 100644
index 0000000..e350b53
--- /dev/null
+++ b/doc/man/nvme_log_phy_rx_eom_action.2
@@ -0,0 +1,24 @@
+.TH "libnvme" 9 "enum nvme_log_phy_rx_eom_action" "December 2023" "API Manual" LINUX
+.SH NAME
+enum nvme_log_phy_rx_eom_action \- Physical Interface Receiver Eye Opening Measurement Action
+.SH SYNOPSIS
+enum nvme_log_phy_rx_eom_action {
+.br
+.BI " NVME_LOG_PHY_RX_EOM_READ"
+,
+.br
+.br
+.BI " NVME_LOG_PHY_RX_EOM_START_READ"
+,
+.br
+.br
+.BI " NVME_LOG_PHY_RX_EOM_ABORT_CLEAR"
+
+};
+.SH Constants
+.IP "NVME_LOG_PHY_RX_EOM_READ" 12
+Read Log Data
+.IP "NVME_LOG_PHY_RX_EOM_START_READ" 12
+Start Measurement and Read Log Data
+.IP "NVME_LOG_PHY_RX_EOM_ABORT_CLEAR" 12
+Abort Measurement and Clear Log Data
diff --git a/doc/man/nvme_log_phy_rx_eom_quality.2 b/doc/man/nvme_log_phy_rx_eom_quality.2
new file mode 100644
index 0000000..7582334
--- /dev/null
+++ b/doc/man/nvme_log_phy_rx_eom_quality.2
@@ -0,0 +1,24 @@
+.TH "libnvme" 9 "enum nvme_log_phy_rx_eom_quality" "December 2023" "API Manual" LINUX
+.SH NAME
+enum nvme_log_phy_rx_eom_quality \- Physical Interface Receiver Eye Opening Measurement Quality
+.SH SYNOPSIS
+enum nvme_log_phy_rx_eom_quality {
+.br
+.BI " NVME_LOG_PHY_RX_EOM_GOOD"
+,
+.br
+.br
+.BI " NVME_LOG_PHY_RX_EOM_BETTER"
+,
+.br
+.br
+.BI " NVME_LOG_PHY_RX_EOM_BEST"
+
+};
+.SH Constants
+.IP "NVME_LOG_PHY_RX_EOM_GOOD" 12
+<= Better Quality
+.IP "NVME_LOG_PHY_RX_EOM_BETTER" 12
+<= Best Quality, >= Good Quality
+.IP "NVME_LOG_PHY_RX_EOM_BEST" 12
+>= Better Quality
diff --git a/doc/man/nvme_lookup_ctrl.2 b/doc/man/nvme_lookup_ctrl.2
index 410cf85..d086873 100644
--- a/doc/man/nvme_lookup_ctrl.2
+++ b/doc/man/nvme_lookup_ctrl.2
@@ -1,4 +1,4 @@
-.TH "nvme_lookup_ctrl" 9 "nvme_lookup_ctrl" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_lookup_ctrl" 9 "nvme_lookup_ctrl" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_lookup_ctrl \- Lookup nvme_ctrl_t object
.SH SYNOPSIS
diff --git a/doc/man/nvme_lookup_host.2 b/doc/man/nvme_lookup_host.2
index ca85e6d..42f7949 100644
--- a/doc/man/nvme_lookup_host.2
+++ b/doc/man/nvme_lookup_host.2
@@ -1,4 +1,4 @@
-.TH "nvme_lookup_host" 9 "nvme_lookup_host" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_lookup_host" 9 "nvme_lookup_host" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_lookup_host \- Lookup nvme_host_t object
.SH SYNOPSIS
diff --git a/doc/man/nvme_lookup_key.2 b/doc/man/nvme_lookup_key.2
index e6d3665..1718bb3 100644
--- a/doc/man/nvme_lookup_key.2
+++ b/doc/man/nvme_lookup_key.2
@@ -1,4 +1,4 @@
-.TH "nvme_lookup_key" 9 "nvme_lookup_key" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_lookup_key" 9 "nvme_lookup_key" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_lookup_key \- Lookup key serial number
.SH SYNOPSIS
diff --git a/doc/man/nvme_lookup_keyring.2 b/doc/man/nvme_lookup_keyring.2
index e2be918..643ddd8 100644
--- a/doc/man/nvme_lookup_keyring.2
+++ b/doc/man/nvme_lookup_keyring.2
@@ -1,4 +1,4 @@
-.TH "nvme_lookup_keyring" 9 "nvme_lookup_keyring" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_lookup_keyring" 9 "nvme_lookup_keyring" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_lookup_keyring \- Lookup keyring serial number
.SH SYNOPSIS
diff --git a/doc/man/nvme_lookup_subsystem.2 b/doc/man/nvme_lookup_subsystem.2
index a782a1e..ce039fc 100644
--- a/doc/man/nvme_lookup_subsystem.2
+++ b/doc/man/nvme_lookup_subsystem.2
@@ -1,4 +1,4 @@
-.TH "nvme_lookup_subsystem" 9 "nvme_lookup_subsystem" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_lookup_subsystem" 9 "nvme_lookup_subsystem" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_lookup_subsystem \- Lookup nvme_subsystem_t object
.SH SYNOPSIS
diff --git a/doc/man/nvme_media_unit_config_desc.2 b/doc/man/nvme_media_unit_config_desc.2
index 79b0a6d..28546a4 100644
--- a/doc/man/nvme_media_unit_config_desc.2
+++ b/doc/man/nvme_media_unit_config_desc.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_media_unit_config_desc" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_media_unit_config_desc" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_media_unit_config_desc \- Media Unit Configuration Descriptor
.SH SYNOPSIS
diff --git a/doc/man/nvme_media_unit_stat_desc.2 b/doc/man/nvme_media_unit_stat_desc.2
index d95df72..25ea8eb 100644
--- a/doc/man/nvme_media_unit_stat_desc.2
+++ b/doc/man/nvme_media_unit_stat_desc.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_media_unit_stat_desc" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_media_unit_stat_desc" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_media_unit_stat_desc \- Media Unit Status Descriptor
.SH SYNOPSIS
diff --git a/doc/man/nvme_media_unit_stat_log.2 b/doc/man/nvme_media_unit_stat_log.2
index 8493bff..41a122f 100644
--- a/doc/man/nvme_media_unit_stat_log.2
+++ b/doc/man/nvme_media_unit_stat_log.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_media_unit_stat_log" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_media_unit_stat_log" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_media_unit_stat_log \- Media Unit Status
.SH SYNOPSIS
diff --git a/doc/man/nvme_metadata_element_desc.2 b/doc/man/nvme_metadata_element_desc.2
index 098b235..1a27a6f 100644
--- a/doc/man/nvme_metadata_element_desc.2
+++ b/doc/man/nvme_metadata_element_desc.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_metadata_element_desc" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_metadata_element_desc" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_metadata_element_desc \- Metadata Element Descriptor
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_admin_admin_passthru.2 b/doc/man/nvme_mi_admin_admin_passthru.2
index e72e6f7..2a31d18 100644
--- a/doc/man/nvme_mi_admin_admin_passthru.2
+++ b/doc/man/nvme_mi_admin_admin_passthru.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_admin_admin_passthru" 9 "nvme_mi_admin_admin_passthru" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_admin_admin_passthru" 9 "nvme_mi_admin_admin_passthru" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_admin_admin_passthru \- Submit an nvme admin passthrough command
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_admin_format_nvm.2 b/doc/man/nvme_mi_admin_format_nvm.2
index b3862b1..7b4b0b2 100644
--- a/doc/man/nvme_mi_admin_format_nvm.2
+++ b/doc/man/nvme_mi_admin_format_nvm.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_admin_format_nvm" 9 "nvme_mi_admin_format_nvm" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_admin_format_nvm" 9 "nvme_mi_admin_format_nvm" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_admin_format_nvm \- Format NVMe namespace
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_admin_fw_commit.2 b/doc/man/nvme_mi_admin_fw_commit.2
index 30b536d..98e37ab 100644
--- a/doc/man/nvme_mi_admin_fw_commit.2
+++ b/doc/man/nvme_mi_admin_fw_commit.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_admin_fw_commit" 9 "nvme_mi_admin_fw_commit" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_admin_fw_commit" 9 "nvme_mi_admin_fw_commit" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_admin_fw_commit \- Commit firmware using the specified action
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_admin_fw_download.2 b/doc/man/nvme_mi_admin_fw_download.2
index 2a87321..1572cd4 100644
--- a/doc/man/nvme_mi_admin_fw_download.2
+++ b/doc/man/nvme_mi_admin_fw_download.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_admin_fw_download" 9 "nvme_mi_admin_fw_download" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_admin_fw_download" 9 "nvme_mi_admin_fw_download" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_admin_fw_download \- Download part or all of a firmware image to the controller
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_admin_get_features_data.2 b/doc/man/nvme_mi_admin_get_features_data.2
index 7edf756..d257c7b 100644
--- a/doc/man/nvme_mi_admin_get_features_data.2
+++ b/doc/man/nvme_mi_admin_get_features_data.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_admin_get_features_data" 9 "nvme_mi_admin_get_features_data" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_admin_get_features_data" 9 "nvme_mi_admin_get_features_data" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_admin_get_features_data \- Helper function for &nvme_mi_admin_get_features()
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_admin_get_log.2 b/doc/man/nvme_mi_admin_get_log.2
index 4b28da3..e349d09 100644
--- a/doc/man/nvme_mi_admin_get_log.2
+++ b/doc/man/nvme_mi_admin_get_log.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_admin_get_log" 9 "nvme_mi_admin_get_log" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_admin_get_log" 9 "nvme_mi_admin_get_log" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_admin_get_log \- Retrieve log page data from controller
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_admin_get_log_ana.2 b/doc/man/nvme_mi_admin_get_log_ana.2
index 9f8739a..55e8521 100644
--- a/doc/man/nvme_mi_admin_get_log_ana.2
+++ b/doc/man/nvme_mi_admin_get_log_ana.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_admin_get_log_ana" 9 "nvme_mi_admin_get_log_ana" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_admin_get_log_ana" 9 "nvme_mi_admin_get_log_ana" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_admin_get_log_ana \- Retrieve Asymmetric Namespace Access log page
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_admin_get_log_ana_groups.2 b/doc/man/nvme_mi_admin_get_log_ana_groups.2
index 820794b..5f49ad0 100644
--- a/doc/man/nvme_mi_admin_get_log_ana_groups.2
+++ b/doc/man/nvme_mi_admin_get_log_ana_groups.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_admin_get_log_ana_groups" 9 "nvme_mi_admin_get_log_ana_groups" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_admin_get_log_ana_groups" 9 "nvme_mi_admin_get_log_ana_groups" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_admin_get_log_ana_groups \- Retrieve Asymmetric Namespace Access groups only log page
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_admin_get_log_boot_partition.2 b/doc/man/nvme_mi_admin_get_log_boot_partition.2
index 4fa7cf0..7fa1e93 100644
--- a/doc/man/nvme_mi_admin_get_log_boot_partition.2
+++ b/doc/man/nvme_mi_admin_get_log_boot_partition.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_admin_get_log_boot_partition" 9 "nvme_mi_admin_get_log_boot_partition" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_admin_get_log_boot_partition" 9 "nvme_mi_admin_get_log_boot_partition" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_admin_get_log_boot_partition \- Retrieve Boot Partition
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_admin_get_log_changed_ns_list.2 b/doc/man/nvme_mi_admin_get_log_changed_ns_list.2
index c4b9073..4860128 100644
--- a/doc/man/nvme_mi_admin_get_log_changed_ns_list.2
+++ b/doc/man/nvme_mi_admin_get_log_changed_ns_list.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_admin_get_log_changed_ns_list" 9 "nvme_mi_admin_get_log_changed_ns_list" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_admin_get_log_changed_ns_list" 9 "nvme_mi_admin_get_log_changed_ns_list" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_admin_get_log_changed_ns_list \- Retrieve namespace changed list
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_admin_get_log_cmd_effects.2 b/doc/man/nvme_mi_admin_get_log_cmd_effects.2
index dd575e4..0ba8386 100644
--- a/doc/man/nvme_mi_admin_get_log_cmd_effects.2
+++ b/doc/man/nvme_mi_admin_get_log_cmd_effects.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_admin_get_log_cmd_effects" 9 "nvme_mi_admin_get_log_cmd_effects" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_admin_get_log_cmd_effects" 9 "nvme_mi_admin_get_log_cmd_effects" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_admin_get_log_cmd_effects \- Retrieve nvme command effects log
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_admin_get_log_create_telemetry_host.2 b/doc/man/nvme_mi_admin_get_log_create_telemetry_host.2
index 12cc91e..bb95935 100644
--- a/doc/man/nvme_mi_admin_get_log_create_telemetry_host.2
+++ b/doc/man/nvme_mi_admin_get_log_create_telemetry_host.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_admin_get_log_create_telemetry_host" 9 "nvme_mi_admin_get_log_create_telemetry_host" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_admin_get_log_create_telemetry_host" 9 "nvme_mi_admin_get_log_create_telemetry_host" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_admin_get_log_create_telemetry_host \- Create host telemetry log
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_admin_get_log_device_self_test.2 b/doc/man/nvme_mi_admin_get_log_device_self_test.2
index 794bd6b..3f3748d 100644
--- a/doc/man/nvme_mi_admin_get_log_device_self_test.2
+++ b/doc/man/nvme_mi_admin_get_log_device_self_test.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_admin_get_log_device_self_test" 9 "nvme_mi_admin_get_log_device_self_test" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_admin_get_log_device_self_test" 9 "nvme_mi_admin_get_log_device_self_test" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_admin_get_log_device_self_test \- Retrieve the device self test log
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_admin_get_log_discovery.2 b/doc/man/nvme_mi_admin_get_log_discovery.2
index c8033e3..cac9b51 100644
--- a/doc/man/nvme_mi_admin_get_log_discovery.2
+++ b/doc/man/nvme_mi_admin_get_log_discovery.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_admin_get_log_discovery" 9 "nvme_mi_admin_get_log_discovery" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_admin_get_log_discovery" 9 "nvme_mi_admin_get_log_discovery" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_admin_get_log_discovery \- Retrieve Discovery log page
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_admin_get_log_endurance_group.2 b/doc/man/nvme_mi_admin_get_log_endurance_group.2
index d3355d3..cec3a1a 100644
--- a/doc/man/nvme_mi_admin_get_log_endurance_group.2
+++ b/doc/man/nvme_mi_admin_get_log_endurance_group.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_admin_get_log_endurance_group" 9 "nvme_mi_admin_get_log_endurance_group" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_admin_get_log_endurance_group" 9 "nvme_mi_admin_get_log_endurance_group" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_admin_get_log_endurance_group \- Get Endurance Group log
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_admin_get_log_endurance_grp_evt.2 b/doc/man/nvme_mi_admin_get_log_endurance_grp_evt.2
index ea1bacc..2e284ab 100644
--- a/doc/man/nvme_mi_admin_get_log_endurance_grp_evt.2
+++ b/doc/man/nvme_mi_admin_get_log_endurance_grp_evt.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_admin_get_log_endurance_grp_evt" 9 "nvme_mi_admin_get_log_endurance_grp_evt" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_admin_get_log_endurance_grp_evt" 9 "nvme_mi_admin_get_log_endurance_grp_evt" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_admin_get_log_endurance_grp_evt \- Retrieve Rotational Media Information
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_admin_get_log_error.2 b/doc/man/nvme_mi_admin_get_log_error.2
index 427e836..bb57780 100644
--- a/doc/man/nvme_mi_admin_get_log_error.2
+++ b/doc/man/nvme_mi_admin_get_log_error.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_admin_get_log_error" 9 "nvme_mi_admin_get_log_error" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_admin_get_log_error" 9 "nvme_mi_admin_get_log_error" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_admin_get_log_error \- Retrieve nvme error log
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_admin_get_log_fid_supported_effects.2 b/doc/man/nvme_mi_admin_get_log_fid_supported_effects.2
index d6a85b2..dd56304 100644
--- a/doc/man/nvme_mi_admin_get_log_fid_supported_effects.2
+++ b/doc/man/nvme_mi_admin_get_log_fid_supported_effects.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_admin_get_log_fid_supported_effects" 9 "nvme_mi_admin_get_log_fid_supported_effects" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_admin_get_log_fid_supported_effects" 9 "nvme_mi_admin_get_log_fid_supported_effects" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_admin_get_log_fid_supported_effects \- Retrieve Feature Identifiers Supported and Effects
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_admin_get_log_fw_slot.2 b/doc/man/nvme_mi_admin_get_log_fw_slot.2
index 87b3b9d..ada0494 100644
--- a/doc/man/nvme_mi_admin_get_log_fw_slot.2
+++ b/doc/man/nvme_mi_admin_get_log_fw_slot.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_admin_get_log_fw_slot" 9 "nvme_mi_admin_get_log_fw_slot" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_admin_get_log_fw_slot" 9 "nvme_mi_admin_get_log_fw_slot" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_admin_get_log_fw_slot \- Retrieves the controller firmware log
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_admin_get_log_lba_status.2 b/doc/man/nvme_mi_admin_get_log_lba_status.2
index 3849dee..c908dca 100644
--- a/doc/man/nvme_mi_admin_get_log_lba_status.2
+++ b/doc/man/nvme_mi_admin_get_log_lba_status.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_admin_get_log_lba_status" 9 "nvme_mi_admin_get_log_lba_status" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_admin_get_log_lba_status" 9 "nvme_mi_admin_get_log_lba_status" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_admin_get_log_lba_status \- Retrieve LBA Status
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_admin_get_log_media_unit_stat.2 b/doc/man/nvme_mi_admin_get_log_media_unit_stat.2
index c01e486..ba8e1c5 100644
--- a/doc/man/nvme_mi_admin_get_log_media_unit_stat.2
+++ b/doc/man/nvme_mi_admin_get_log_media_unit_stat.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_admin_get_log_media_unit_stat" 9 "nvme_mi_admin_get_log_media_unit_stat" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_admin_get_log_media_unit_stat" 9 "nvme_mi_admin_get_log_media_unit_stat" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_admin_get_log_media_unit_stat \- Retrieve Media Unit Status
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_admin_get_log_mi_cmd_supported_effects.2 b/doc/man/nvme_mi_admin_get_log_mi_cmd_supported_effects.2
index b9b5123..14339fb 100644
--- a/doc/man/nvme_mi_admin_get_log_mi_cmd_supported_effects.2
+++ b/doc/man/nvme_mi_admin_get_log_mi_cmd_supported_effects.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_admin_get_log_mi_cmd_supported_effects" 9 "nvme_mi_admin_get_log_mi_cmd_supported_effects" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_admin_get_log_mi_cmd_supported_effects" 9 "nvme_mi_admin_get_log_mi_cmd_supported_effects" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_admin_get_log_mi_cmd_supported_effects \- displays the MI Commands Supported by the controller
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_admin_get_log_page.2 b/doc/man/nvme_mi_admin_get_log_page.2
index 5388830..cc18080 100644
--- a/doc/man/nvme_mi_admin_get_log_page.2
+++ b/doc/man/nvme_mi_admin_get_log_page.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_admin_get_log_page" 9 "nvme_mi_admin_get_log_page" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_admin_get_log_page" 9 "nvme_mi_admin_get_log_page" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_admin_get_log_page \- Retrieve log page data from controller
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_admin_get_log_persistent_event.2 b/doc/man/nvme_mi_admin_get_log_persistent_event.2
index 00b4cb4..b3784a1 100644
--- a/doc/man/nvme_mi_admin_get_log_persistent_event.2
+++ b/doc/man/nvme_mi_admin_get_log_persistent_event.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_admin_get_log_persistent_event" 9 "nvme_mi_admin_get_log_persistent_event" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_admin_get_log_persistent_event" 9 "nvme_mi_admin_get_log_persistent_event" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_admin_get_log_persistent_event \- Retrieve Persistent Event Log
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_admin_get_log_phy_rx_eom.2 b/doc/man/nvme_mi_admin_get_log_phy_rx_eom.2
new file mode 100644
index 0000000..adc8576
--- /dev/null
+++ b/doc/man/nvme_mi_admin_get_log_phy_rx_eom.2
@@ -0,0 +1,25 @@
+.TH "nvme_mi_admin_get_log_phy_rx_eom" 9 "nvme_mi_admin_get_log_phy_rx_eom" "December 2023" "libnvme API manual" LINUX
+.SH NAME
+nvme_mi_admin_get_log_phy_rx_eom \- Retrieve Physical Interface Receiver Eye Opening Measurement Log
+.SH SYNOPSIS
+.B "int" nvme_mi_admin_get_log_phy_rx_eom
+.BI "(nvme_mi_ctrl_t ctrl " ","
+.BI "__u8 lsp " ","
+.BI "__u16 controller " ","
+.BI "__u32 len " ","
+.BI "struct nvme_phy_rx_eom_log *log " ");"
+.SH ARGUMENTS
+.IP "ctrl" 12
+Controller to query
+.IP "lsp" 12
+Log specific, controls action and measurement quality
+.IP "controller" 12
+Target controller ID
+.IP "len" 12
+The allocated size, minimum
+struct nvme_phy_rx_eom_log
+.IP "log" 12
+User address to store the log page
+.SH "RETURN"
+The nvme command status if a response was received (see
+\fIenum nvme_status_field\fP) or -1 with errno set otherwise
diff --git a/doc/man/nvme_mi_admin_get_log_predictable_lat_event.2 b/doc/man/nvme_mi_admin_get_log_predictable_lat_event.2
index 303d65e..ef424a1 100644
--- a/doc/man/nvme_mi_admin_get_log_predictable_lat_event.2
+++ b/doc/man/nvme_mi_admin_get_log_predictable_lat_event.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_admin_get_log_predictable_lat_event" 9 "nvme_mi_admin_get_log_predictable_lat_event" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_admin_get_log_predictable_lat_event" 9 "nvme_mi_admin_get_log_predictable_lat_event" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_admin_get_log_predictable_lat_event \- Retrieve Predictable Latency Event Aggregate Log Page
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_admin_get_log_predictable_lat_nvmset.2 b/doc/man/nvme_mi_admin_get_log_predictable_lat_nvmset.2
index 2b44bef..e9bbf27 100644
--- a/doc/man/nvme_mi_admin_get_log_predictable_lat_nvmset.2
+++ b/doc/man/nvme_mi_admin_get_log_predictable_lat_nvmset.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_admin_get_log_predictable_lat_nvmset" 9 "nvme_mi_admin_get_log_predictable_lat_nvmset" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_admin_get_log_predictable_lat_nvmset" 9 "nvme_mi_admin_get_log_predictable_lat_nvmset" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_admin_get_log_predictable_lat_nvmset \- Predictable Latency Per NVM Set
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_admin_get_log_reservation.2 b/doc/man/nvme_mi_admin_get_log_reservation.2
index 9b95c32..a1bcd0d 100644
--- a/doc/man/nvme_mi_admin_get_log_reservation.2
+++ b/doc/man/nvme_mi_admin_get_log_reservation.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_admin_get_log_reservation" 9 "nvme_mi_admin_get_log_reservation" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_admin_get_log_reservation" 9 "nvme_mi_admin_get_log_reservation" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_admin_get_log_reservation \- Retrieve Reservation Notification
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_admin_get_log_sanitize.2 b/doc/man/nvme_mi_admin_get_log_sanitize.2
index 92d0d39..d4bb654 100644
--- a/doc/man/nvme_mi_admin_get_log_sanitize.2
+++ b/doc/man/nvme_mi_admin_get_log_sanitize.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_admin_get_log_sanitize" 9 "nvme_mi_admin_get_log_sanitize" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_admin_get_log_sanitize" 9 "nvme_mi_admin_get_log_sanitize" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_admin_get_log_sanitize \- Retrieve Sanitize Status
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_admin_get_log_simple.2 b/doc/man/nvme_mi_admin_get_log_simple.2
index edfbdd3..aebb307 100644
--- a/doc/man/nvme_mi_admin_get_log_simple.2
+++ b/doc/man/nvme_mi_admin_get_log_simple.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_admin_get_log_simple" 9 "nvme_mi_admin_get_log_simple" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_admin_get_log_simple" 9 "nvme_mi_admin_get_log_simple" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_admin_get_log_simple \- Helper for Get Log Page functions with no NSID or RAE requirements
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_admin_get_log_smart.2 b/doc/man/nvme_mi_admin_get_log_smart.2
index 02505d2..9f5cd92 100644
--- a/doc/man/nvme_mi_admin_get_log_smart.2
+++ b/doc/man/nvme_mi_admin_get_log_smart.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_admin_get_log_smart" 9 "nvme_mi_admin_get_log_smart" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_admin_get_log_smart" 9 "nvme_mi_admin_get_log_smart" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_admin_get_log_smart \- Retrieve nvme smart log
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_admin_get_log_support_cap_config_list.2 b/doc/man/nvme_mi_admin_get_log_support_cap_config_list.2
index 35b94ae..5d90369 100644
--- a/doc/man/nvme_mi_admin_get_log_support_cap_config_list.2
+++ b/doc/man/nvme_mi_admin_get_log_support_cap_config_list.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_admin_get_log_support_cap_config_list" 9 "nvme_mi_admin_get_log_support_cap_config_list" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_admin_get_log_support_cap_config_list" 9 "nvme_mi_admin_get_log_support_cap_config_list" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_admin_get_log_support_cap_config_list \- Retrieve Supported Capacity Configuration List
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_admin_get_log_supported_log_pages.2 b/doc/man/nvme_mi_admin_get_log_supported_log_pages.2
index 4a22e29..a6d6c4a 100644
--- a/doc/man/nvme_mi_admin_get_log_supported_log_pages.2
+++ b/doc/man/nvme_mi_admin_get_log_supported_log_pages.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_admin_get_log_supported_log_pages" 9 "nvme_mi_admin_get_log_supported_log_pages" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_admin_get_log_supported_log_pages" 9 "nvme_mi_admin_get_log_supported_log_pages" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_admin_get_log_supported_log_pages \- Retrieve nmve supported log pages
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_admin_get_log_telemetry_ctrl.2 b/doc/man/nvme_mi_admin_get_log_telemetry_ctrl.2
index 1482e97..a95010f 100644
--- a/doc/man/nvme_mi_admin_get_log_telemetry_ctrl.2
+++ b/doc/man/nvme_mi_admin_get_log_telemetry_ctrl.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_admin_get_log_telemetry_ctrl" 9 "nvme_mi_admin_get_log_telemetry_ctrl" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_admin_get_log_telemetry_ctrl" 9 "nvme_mi_admin_get_log_telemetry_ctrl" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_admin_get_log_telemetry_ctrl \- Get Telemetry Controller-Initiated log page
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_admin_get_log_telemetry_host.2 b/doc/man/nvme_mi_admin_get_log_telemetry_host.2
index 3fc91ca..2dbfd0c 100644
--- a/doc/man/nvme_mi_admin_get_log_telemetry_host.2
+++ b/doc/man/nvme_mi_admin_get_log_telemetry_host.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_admin_get_log_telemetry_host" 9 "nvme_mi_admin_get_log_telemetry_host" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_admin_get_log_telemetry_host" 9 "nvme_mi_admin_get_log_telemetry_host" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_admin_get_log_telemetry_host \- Get Telemetry Host-Initiated log page
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_admin_get_log_zns_changed_zones.2 b/doc/man/nvme_mi_admin_get_log_zns_changed_zones.2
index 73bc6fa..1a78124 100644
--- a/doc/man/nvme_mi_admin_get_log_zns_changed_zones.2
+++ b/doc/man/nvme_mi_admin_get_log_zns_changed_zones.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_admin_get_log_zns_changed_zones" 9 "nvme_mi_admin_get_log_zns_changed_zones" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_admin_get_log_zns_changed_zones" 9 "nvme_mi_admin_get_log_zns_changed_zones" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_admin_get_log_zns_changed_zones \- Retrieve list of zones that have changed
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_admin_get_nsid_log.2 b/doc/man/nvme_mi_admin_get_nsid_log.2
index cd2f29d..afaafb1 100644
--- a/doc/man/nvme_mi_admin_get_nsid_log.2
+++ b/doc/man/nvme_mi_admin_get_nsid_log.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_admin_get_nsid_log" 9 "nvme_mi_admin_get_nsid_log" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_admin_get_nsid_log" 9 "nvme_mi_admin_get_nsid_log" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_admin_get_nsid_log \- Helper for Get Log Page functions
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_admin_identify.2 b/doc/man/nvme_mi_admin_identify.2
index cde41dc..c81459b 100644
--- a/doc/man/nvme_mi_admin_identify.2
+++ b/doc/man/nvme_mi_admin_identify.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_admin_identify" 9 "nvme_mi_admin_identify" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_admin_identify" 9 "nvme_mi_admin_identify" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_admin_identify \- Perform an Admin identify command.
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_admin_identify_active_ns_list.2 b/doc/man/nvme_mi_admin_identify_active_ns_list.2
index 64f034d..4ec04e2 100644
--- a/doc/man/nvme_mi_admin_identify_active_ns_list.2
+++ b/doc/man/nvme_mi_admin_identify_active_ns_list.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_admin_identify_active_ns_list" 9 "nvme_mi_admin_identify_active_ns_list" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_admin_identify_active_ns_list" 9 "nvme_mi_admin_identify_active_ns_list" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_admin_identify_active_ns_list \- Perform an Admin identify for an active namespace list
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_admin_identify_allocated_ns.2 b/doc/man/nvme_mi_admin_identify_allocated_ns.2
index e76c411..7934df7 100644
--- a/doc/man/nvme_mi_admin_identify_allocated_ns.2
+++ b/doc/man/nvme_mi_admin_identify_allocated_ns.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_admin_identify_allocated_ns" 9 "nvme_mi_admin_identify_allocated_ns" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_admin_identify_allocated_ns" 9 "nvme_mi_admin_identify_allocated_ns" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_admin_identify_allocated_ns \- Perform an Admin identify command for an allocated namespace
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_admin_identify_allocated_ns_list.2 b/doc/man/nvme_mi_admin_identify_allocated_ns_list.2
index 2089b6a..c173ff6 100644
--- a/doc/man/nvme_mi_admin_identify_allocated_ns_list.2
+++ b/doc/man/nvme_mi_admin_identify_allocated_ns_list.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_admin_identify_allocated_ns_list" 9 "nvme_mi_admin_identify_allocated_ns_list" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_admin_identify_allocated_ns_list" 9 "nvme_mi_admin_identify_allocated_ns_list" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_admin_identify_allocated_ns_list \- Perform an Admin identify for an allocated namespace list
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_admin_identify_cns_nsid.2 b/doc/man/nvme_mi_admin_identify_cns_nsid.2
index 26dc3f2..9fa997d 100644
--- a/doc/man/nvme_mi_admin_identify_cns_nsid.2
+++ b/doc/man/nvme_mi_admin_identify_cns_nsid.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_admin_identify_cns_nsid" 9 "nvme_mi_admin_identify_cns_nsid" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_admin_identify_cns_nsid" 9 "nvme_mi_admin_identify_cns_nsid" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_admin_identify_cns_nsid \- Perform an Admin identify command using specific CNS/NSID parameters.
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_admin_identify_ctrl.2 b/doc/man/nvme_mi_admin_identify_ctrl.2
index 57f935a..0f422ed 100644
--- a/doc/man/nvme_mi_admin_identify_ctrl.2
+++ b/doc/man/nvme_mi_admin_identify_ctrl.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_admin_identify_ctrl" 9 "nvme_mi_admin_identify_ctrl" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_admin_identify_ctrl" 9 "nvme_mi_admin_identify_ctrl" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_admin_identify_ctrl \- Perform an Admin identify for a controller
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_admin_identify_ctrl_list.2 b/doc/man/nvme_mi_admin_identify_ctrl_list.2
index 2eccfa3..ad4f894 100644
--- a/doc/man/nvme_mi_admin_identify_ctrl_list.2
+++ b/doc/man/nvme_mi_admin_identify_ctrl_list.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_admin_identify_ctrl_list" 9 "nvme_mi_admin_identify_ctrl_list" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_admin_identify_ctrl_list" 9 "nvme_mi_admin_identify_ctrl_list" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_admin_identify_ctrl_list \- Perform an Admin identify for a controller list.
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_admin_identify_ns.2 b/doc/man/nvme_mi_admin_identify_ns.2
index 1b9bc17..e097cc3 100644
--- a/doc/man/nvme_mi_admin_identify_ns.2
+++ b/doc/man/nvme_mi_admin_identify_ns.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_admin_identify_ns" 9 "nvme_mi_admin_identify_ns" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_admin_identify_ns" 9 "nvme_mi_admin_identify_ns" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_admin_identify_ns \- Perform an Admin identify command for a namespace
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_admin_identify_ns_descs.2 b/doc/man/nvme_mi_admin_identify_ns_descs.2
index 63928af..7cc93c2 100644
--- a/doc/man/nvme_mi_admin_identify_ns_descs.2
+++ b/doc/man/nvme_mi_admin_identify_ns_descs.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_admin_identify_ns_descs" 9 "nvme_mi_admin_identify_ns_descs" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_admin_identify_ns_descs" 9 "nvme_mi_admin_identify_ns_descs" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_admin_identify_ns_descs \- Perform an Admin identify Namespace Identification Descriptor list command for a namespace
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_admin_identify_nsid_ctrl_list.2 b/doc/man/nvme_mi_admin_identify_nsid_ctrl_list.2
index dca8c61..a8ef8f2 100644
--- a/doc/man/nvme_mi_admin_identify_nsid_ctrl_list.2
+++ b/doc/man/nvme_mi_admin_identify_nsid_ctrl_list.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_admin_identify_nsid_ctrl_list" 9 "nvme_mi_admin_identify_nsid_ctrl_list" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_admin_identify_nsid_ctrl_list" 9 "nvme_mi_admin_identify_nsid_ctrl_list" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_admin_identify_nsid_ctrl_list \- Perform an Admin identify for a controller list with specific namespace ID
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_admin_identify_partial.2 b/doc/man/nvme_mi_admin_identify_partial.2
index fa640bb..928daa4 100644
--- a/doc/man/nvme_mi_admin_identify_partial.2
+++ b/doc/man/nvme_mi_admin_identify_partial.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_admin_identify_partial" 9 "nvme_mi_admin_identify_partial" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_admin_identify_partial" 9 "nvme_mi_admin_identify_partial" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_admin_identify_partial \- Perform an Admin identify command, and retrieve partial response data.
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_admin_identify_primary_ctrl.2 b/doc/man/nvme_mi_admin_identify_primary_ctrl.2
index a44437b..b98c488 100644
--- a/doc/man/nvme_mi_admin_identify_primary_ctrl.2
+++ b/doc/man/nvme_mi_admin_identify_primary_ctrl.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_admin_identify_primary_ctrl" 9 "nvme_mi_admin_identify_primary_ctrl" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_admin_identify_primary_ctrl" 9 "nvme_mi_admin_identify_primary_ctrl" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_admin_identify_primary_ctrl \- Perform an Admin identify for primary controller capabilities data structure.
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_admin_identify_secondary_ctrl_list.2 b/doc/man/nvme_mi_admin_identify_secondary_ctrl_list.2
index 1ae7f4f..233d43a 100644
--- a/doc/man/nvme_mi_admin_identify_secondary_ctrl_list.2
+++ b/doc/man/nvme_mi_admin_identify_secondary_ctrl_list.2
@@ -1,17 +1,14 @@
-.TH "nvme_mi_admin_identify_secondary_ctrl_list" 9 "nvme_mi_admin_identify_secondary_ctrl_list" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_admin_identify_secondary_ctrl_list" 9 "nvme_mi_admin_identify_secondary_ctrl_list" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_admin_identify_secondary_ctrl_list \- Perform an Admin identify for a secondary controller list.
.SH SYNOPSIS
.B "int" nvme_mi_admin_identify_secondary_ctrl_list
.BI "(nvme_mi_ctrl_t ctrl " ","
-.BI "__u32 nsid " ","
.BI "__u16 cntid " ","
.BI "struct nvme_secondary_ctrl_list *list " ");"
.SH ARGUMENTS
.IP "ctrl" 12
Controller to process identify command
-.IP "nsid" 12
-Namespace ID to specify list start
.IP "cntid" 12
Controller ID to specify list start
.IP "list" 12
diff --git a/doc/man/nvme_mi_admin_ns_attach.2 b/doc/man/nvme_mi_admin_ns_attach.2
index a522d86..43fcc5f 100644
--- a/doc/man/nvme_mi_admin_ns_attach.2
+++ b/doc/man/nvme_mi_admin_ns_attach.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_admin_ns_attach" 9 "nvme_mi_admin_ns_attach" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_admin_ns_attach" 9 "nvme_mi_admin_ns_attach" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_admin_ns_attach \- Attach or detach namespace to controller(s)
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_admin_ns_attach_ctrls.2 b/doc/man/nvme_mi_admin_ns_attach_ctrls.2
index 1a16039..478cecf 100644
--- a/doc/man/nvme_mi_admin_ns_attach_ctrls.2
+++ b/doc/man/nvme_mi_admin_ns_attach_ctrls.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_admin_ns_attach_ctrls" 9 "nvme_mi_admin_ns_attach_ctrls" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_admin_ns_attach_ctrls" 9 "nvme_mi_admin_ns_attach_ctrls" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_admin_ns_attach_ctrls \- Attach namespace to controllers
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_admin_ns_detach_ctrls.2 b/doc/man/nvme_mi_admin_ns_detach_ctrls.2
index 9d84979..ad31755 100644
--- a/doc/man/nvme_mi_admin_ns_detach_ctrls.2
+++ b/doc/man/nvme_mi_admin_ns_detach_ctrls.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_admin_ns_detach_ctrls" 9 "nvme_mi_admin_ns_detach_ctrls" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_admin_ns_detach_ctrls" 9 "nvme_mi_admin_ns_detach_ctrls" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_admin_ns_detach_ctrls \- Detach namespace from controllers
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_admin_req_hdr.2 b/doc/man/nvme_mi_admin_req_hdr.2
index ccc482b..38b53b3 100644
--- a/doc/man/nvme_mi_admin_req_hdr.2
+++ b/doc/man/nvme_mi_admin_req_hdr.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_mi_admin_req_hdr" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_mi_admin_req_hdr" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_mi_admin_req_hdr \- Admin command request header.
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_admin_resp_hdr.2 b/doc/man/nvme_mi_admin_resp_hdr.2
index 4309c4a..f31c5f8 100644
--- a/doc/man/nvme_mi_admin_resp_hdr.2
+++ b/doc/man/nvme_mi_admin_resp_hdr.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_mi_admin_resp_hdr" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_mi_admin_resp_hdr" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_mi_admin_resp_hdr \- Admin command response header.
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_admin_sanitize_nvm.2 b/doc/man/nvme_mi_admin_sanitize_nvm.2
index c213d19..6ec8cf9 100644
--- a/doc/man/nvme_mi_admin_sanitize_nvm.2
+++ b/doc/man/nvme_mi_admin_sanitize_nvm.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_admin_sanitize_nvm" 9 "nvme_mi_admin_sanitize_nvm" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_admin_sanitize_nvm" 9 "nvme_mi_admin_sanitize_nvm" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_admin_sanitize_nvm \- Start a subsystem Sanitize operation
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_admin_security_recv.2 b/doc/man/nvme_mi_admin_security_recv.2
index 89431f1..08aab1d 100644
--- a/doc/man/nvme_mi_admin_security_recv.2
+++ b/doc/man/nvme_mi_admin_security_recv.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_admin_security_recv" 9 "nvme_mi_admin_security_recv" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_admin_security_recv" 9 "nvme_mi_admin_security_recv" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_admin_security_recv \- Perform a Security Receive command on a controller.
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_admin_security_send.2 b/doc/man/nvme_mi_admin_security_send.2
index aa3a34e..d74bcac 100644
--- a/doc/man/nvme_mi_admin_security_send.2
+++ b/doc/man/nvme_mi_admin_security_send.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_admin_security_send" 9 "nvme_mi_admin_security_send" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_admin_security_send" 9 "nvme_mi_admin_security_send" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_admin_security_send \- Perform a Security Send command on a controller.
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_admin_xfer.2 b/doc/man/nvme_mi_admin_xfer.2
index 6574c1b..f596e45 100644
--- a/doc/man/nvme_mi_admin_xfer.2
+++ b/doc/man/nvme_mi_admin_xfer.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_admin_xfer" 9 "nvme_mi_admin_xfer" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_admin_xfer" 9 "nvme_mi_admin_xfer" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_admin_xfer \- Raw admin transfer interface.
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_ccs.2 b/doc/man/nvme_mi_ccs.2
index 5fbd342..829984c 100644
--- a/doc/man/nvme_mi_ccs.2
+++ b/doc/man/nvme_mi_ccs.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_mi_ccs" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_mi_ccs" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_mi_ccs \- Get State Control Primitive Success Response Fields - Control Primitive Specific Response
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_close.2 b/doc/man/nvme_mi_close.2
index a30ff6e..e4e5bdd 100644
--- a/doc/man/nvme_mi_close.2
+++ b/doc/man/nvme_mi_close.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_close" 9 "nvme_mi_close" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_close" 9 "nvme_mi_close" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_close \- Close an endpoint connection and release resources, including controller objects.
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_close_ctrl.2 b/doc/man/nvme_mi_close_ctrl.2
index 296b158..39bef17 100644
--- a/doc/man/nvme_mi_close_ctrl.2
+++ b/doc/man/nvme_mi_close_ctrl.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_close_ctrl" 9 "nvme_mi_close_ctrl" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_close_ctrl" 9 "nvme_mi_close_ctrl" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_close_ctrl \- free a controller
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_cmd_supported_effects.2 b/doc/man/nvme_mi_cmd_supported_effects.2
index c94c326..56d51c8 100644
--- a/doc/man/nvme_mi_cmd_supported_effects.2
+++ b/doc/man/nvme_mi_cmd_supported_effects.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_mi_cmd_supported_effects" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_mi_cmd_supported_effects" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_mi_cmd_supported_effects \- MI Command Supported and Effects Data Structure
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_cmd_supported_effects_log.2 b/doc/man/nvme_mi_cmd_supported_effects_log.2
index e6cd59e..0e2e7b9 100644
--- a/doc/man/nvme_mi_cmd_supported_effects_log.2
+++ b/doc/man/nvme_mi_cmd_supported_effects_log.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_mi_cmd_supported_effects_log" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_mi_cmd_supported_effects_log" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_mi_cmd_supported_effects_log \- NVMe-MI Commands Supported and Effects Log
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_config_id.2 b/doc/man/nvme_mi_config_id.2
index a0c1494..12ce20e 100644
--- a/doc/man/nvme_mi_config_id.2
+++ b/doc/man/nvme_mi_config_id.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_mi_config_id" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_mi_config_id" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_mi_config_id \- NVMe-MI Configuration identifier.
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_config_smbus_freq.2 b/doc/man/nvme_mi_config_smbus_freq.2
index 159674e..6d4e769 100644
--- a/doc/man/nvme_mi_config_smbus_freq.2
+++ b/doc/man/nvme_mi_config_smbus_freq.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_mi_config_smbus_freq" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_mi_config_smbus_freq" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_mi_config_smbus_freq \- SMBus/I2C frequency values
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_create_root.2 b/doc/man/nvme_mi_create_root.2
index f534272..6c6eeb0 100644
--- a/doc/man/nvme_mi_create_root.2
+++ b/doc/man/nvme_mi_create_root.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_create_root" 9 "nvme_mi_create_root" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_create_root" 9 "nvme_mi_create_root" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_create_root \- Create top-level MI (root) handle.
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_csts.2 b/doc/man/nvme_mi_csts.2
index 491531b..7e75028 100644
--- a/doc/man/nvme_mi_csts.2
+++ b/doc/man/nvme_mi_csts.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_mi_csts" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_mi_csts" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_mi_csts \- Controller Health Data Structure (CHDS) - Controller Status (CSTS)
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_ctrl_health_status.2 b/doc/man/nvme_mi_ctrl_health_status.2
index 1876dcc..5b25af6 100644
--- a/doc/man/nvme_mi_ctrl_health_status.2
+++ b/doc/man/nvme_mi_ctrl_health_status.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_mi_ctrl_health_status" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_mi_ctrl_health_status" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_mi_ctrl_health_status \- Controller Health Data Structure (CHDS)
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_ctrl_id.2 b/doc/man/nvme_mi_ctrl_id.2
index 2207e92..378624f 100644
--- a/doc/man/nvme_mi_ctrl_id.2
+++ b/doc/man/nvme_mi_ctrl_id.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_ctrl_id" 9 "nvme_mi_ctrl_id" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_ctrl_id" 9 "nvme_mi_ctrl_id" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_ctrl_id \- get the ID of a controller
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_cwarn.2 b/doc/man/nvme_mi_cwarn.2
index 5bbf73e..af6b721 100644
--- a/doc/man/nvme_mi_cwarn.2
+++ b/doc/man/nvme_mi_cwarn.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_mi_cwarn" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_mi_cwarn" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_mi_cwarn \- Controller Health Data Structure (CHDS) - Critical Warning (CWARN)
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_dtyp.2 b/doc/man/nvme_mi_dtyp.2
index 3e70e9a..773fc24 100644
--- a/doc/man/nvme_mi_dtyp.2
+++ b/doc/man/nvme_mi_dtyp.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_mi_dtyp" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_mi_dtyp" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_mi_dtyp \- Data Structure Type field.
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_elem.2 b/doc/man/nvme_mi_elem.2
index 533ffb3..c93ece0 100644
--- a/doc/man/nvme_mi_elem.2
+++ b/doc/man/nvme_mi_elem.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_mi_elem" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_mi_elem" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_mi_elem \- Element Descriptor Types
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_free_root.2 b/doc/man/nvme_mi_free_root.2
index 742278d..1692c82 100644
--- a/doc/man/nvme_mi_free_root.2
+++ b/doc/man/nvme_mi_free_root.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_free_root" 9 "nvme_mi_free_root" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_free_root" 9 "nvme_mi_free_root" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_free_root \- Free root object.
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_init_ctrl.2 b/doc/man/nvme_mi_init_ctrl.2
index bacee80..96762dd 100644
--- a/doc/man/nvme_mi_init_ctrl.2
+++ b/doc/man/nvme_mi_init_ctrl.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_init_ctrl" 9 "nvme_mi_init_ctrl" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_init_ctrl" 9 "nvme_mi_init_ctrl" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_init_ctrl \- initialise a NVMe controller.
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_message_type.2 b/doc/man/nvme_mi_message_type.2
index a7294af..49f424e 100644
--- a/doc/man/nvme_mi_message_type.2
+++ b/doc/man/nvme_mi_message_type.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_mi_message_type" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_mi_message_type" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_mi_message_type \- NVMe-MI message type field.
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_mi_opcode.2 b/doc/man/nvme_mi_mi_opcode.2
index 3565a55..4784744 100644
--- a/doc/man/nvme_mi_mi_opcode.2
+++ b/doc/man/nvme_mi_mi_opcode.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_mi_mi_opcode" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_mi_mi_opcode" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_mi_mi_opcode \- Operation code for supported NVMe-MI commands.
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_mi_read_mi_data_ctrl.2 b/doc/man/nvme_mi_mi_read_mi_data_ctrl.2
index f528989..aff9442 100644
--- a/doc/man/nvme_mi_mi_read_mi_data_ctrl.2
+++ b/doc/man/nvme_mi_mi_read_mi_data_ctrl.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_mi_read_mi_data_ctrl" 9 "nvme_mi_mi_read_mi_data_ctrl" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_mi_read_mi_data_ctrl" 9 "nvme_mi_mi_read_mi_data_ctrl" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_mi_read_mi_data_ctrl \- Perform a Read MI Data Structure command, retrieving controller information
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_mi_read_mi_data_ctrl_list.2 b/doc/man/nvme_mi_mi_read_mi_data_ctrl_list.2
index 0953b33..0477f96 100644
--- a/doc/man/nvme_mi_mi_read_mi_data_ctrl_list.2
+++ b/doc/man/nvme_mi_mi_read_mi_data_ctrl_list.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_mi_read_mi_data_ctrl_list" 9 "nvme_mi_mi_read_mi_data_ctrl_list" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_mi_read_mi_data_ctrl_list" 9 "nvme_mi_mi_read_mi_data_ctrl_list" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_mi_read_mi_data_ctrl_list \- Perform a Read MI Data Structure command, retrieving the list of attached controllers.
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_mi_read_mi_data_port.2 b/doc/man/nvme_mi_mi_read_mi_data_port.2
index 8a04102..ae6e440 100644
--- a/doc/man/nvme_mi_mi_read_mi_data_port.2
+++ b/doc/man/nvme_mi_mi_read_mi_data_port.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_mi_read_mi_data_port" 9 "nvme_mi_mi_read_mi_data_port" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_mi_read_mi_data_port" 9 "nvme_mi_mi_read_mi_data_port" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_mi_read_mi_data_port \- Perform a Read MI Data Structure command, retrieving port data.
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_mi_read_mi_data_subsys.2 b/doc/man/nvme_mi_mi_read_mi_data_subsys.2
index 00578e9..99b7b98 100644
--- a/doc/man/nvme_mi_mi_read_mi_data_subsys.2
+++ b/doc/man/nvme_mi_mi_read_mi_data_subsys.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_mi_read_mi_data_subsys" 9 "nvme_mi_mi_read_mi_data_subsys" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_mi_read_mi_data_subsys" 9 "nvme_mi_mi_read_mi_data_subsys" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_mi_read_mi_data_subsys \- Perform a Read MI Data Structure command, retrieving subsystem data.
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_mi_req_hdr.2 b/doc/man/nvme_mi_mi_req_hdr.2
index 9475c41..fc0f54e 100644
--- a/doc/man/nvme_mi_mi_req_hdr.2
+++ b/doc/man/nvme_mi_mi_req_hdr.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_mi_mi_req_hdr" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_mi_mi_req_hdr" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_mi_mi_req_hdr \- MI request message header.
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_mi_resp_hdr.2 b/doc/man/nvme_mi_mi_resp_hdr.2
index 47ac73b..11aa0cb 100644
--- a/doc/man/nvme_mi_mi_resp_hdr.2
+++ b/doc/man/nvme_mi_mi_resp_hdr.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_mi_mi_resp_hdr" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_mi_mi_resp_hdr" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_mi_mi_resp_hdr \- MI response message header.
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_mi_subsystem_health_status_poll.2 b/doc/man/nvme_mi_mi_subsystem_health_status_poll.2
index b601a97..e69ff02 100644
--- a/doc/man/nvme_mi_mi_subsystem_health_status_poll.2
+++ b/doc/man/nvme_mi_mi_subsystem_health_status_poll.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_mi_subsystem_health_status_poll" 9 "nvme_mi_mi_subsystem_health_status_poll" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_mi_subsystem_health_status_poll" 9 "nvme_mi_mi_subsystem_health_status_poll" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_mi_subsystem_health_status_poll \- Read the Subsystem Health Data Structure from the NVM subsystem
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_msg_hdr.2 b/doc/man/nvme_mi_msg_hdr.2
index bad5afe..42440b2 100644
--- a/doc/man/nvme_mi_msg_hdr.2
+++ b/doc/man/nvme_mi_msg_hdr.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_mi_msg_hdr" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_mi_msg_hdr" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_mi_msg_hdr \- General MI message header.
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_msg_resp.2 b/doc/man/nvme_mi_msg_resp.2
index c51ea53..b5e9bab 100644
--- a/doc/man/nvme_mi_msg_resp.2
+++ b/doc/man/nvme_mi_msg_resp.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_mi_msg_resp" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_mi_msg_resp" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_mi_msg_resp \- Generic response type.
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_nvm_ss_health_status.2 b/doc/man/nvme_mi_nvm_ss_health_status.2
index f66e82e..7898d7c 100644
--- a/doc/man/nvme_mi_nvm_ss_health_status.2
+++ b/doc/man/nvme_mi_nvm_ss_health_status.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_mi_nvm_ss_health_status" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_mi_nvm_ss_health_status" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_mi_nvm_ss_health_status \- Subsystem Management Data Structure
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_open_mctp.2 b/doc/man/nvme_mi_open_mctp.2
index ceff350..52c4f4f 100644
--- a/doc/man/nvme_mi_open_mctp.2
+++ b/doc/man/nvme_mi_open_mctp.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_open_mctp" 9 "nvme_mi_open_mctp" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_open_mctp" 9 "nvme_mi_open_mctp" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_open_mctp \- Create an endpoint using a MCTP connection.
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_osc.2 b/doc/man/nvme_mi_osc.2
index 3217aa1..61d0b1e 100644
--- a/doc/man/nvme_mi_osc.2
+++ b/doc/man/nvme_mi_osc.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_mi_osc" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_mi_osc" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_mi_osc \- Optionally Supported Command Data Structure
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_port_pcie.2 b/doc/man/nvme_mi_port_pcie.2
index 76e4463..dcb4636 100644
--- a/doc/man/nvme_mi_port_pcie.2
+++ b/doc/man/nvme_mi_port_pcie.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_mi_port_pcie" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_mi_port_pcie" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_mi_port_pcie \- PCIe Port Specific Data
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_port_smb.2 b/doc/man/nvme_mi_port_smb.2
index ef7c6c9..1199aa7 100644
--- a/doc/man/nvme_mi_port_smb.2
+++ b/doc/man/nvme_mi_port_smb.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_mi_port_smb" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_mi_port_smb" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_mi_port_smb \- SMBus Port Specific Data
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_read_ctrl_info.2 b/doc/man/nvme_mi_read_ctrl_info.2
index 2b8d5e4..9f40eba 100644
--- a/doc/man/nvme_mi_read_ctrl_info.2
+++ b/doc/man/nvme_mi_read_ctrl_info.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_mi_read_ctrl_info" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_mi_read_ctrl_info" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_mi_read_ctrl_info \- Controller Information Data Structure
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_read_nvm_ss_info.2 b/doc/man/nvme_mi_read_nvm_ss_info.2
index 2fcd925..3fbdeac 100644
--- a/doc/man/nvme_mi_read_nvm_ss_info.2
+++ b/doc/man/nvme_mi_read_nvm_ss_info.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_mi_read_nvm_ss_info" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_mi_read_nvm_ss_info" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_mi_read_nvm_ss_info \- NVM Subsystem Information Data Structure
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_read_port_info.2 b/doc/man/nvme_mi_read_port_info.2
index b14e8ac..6f59922 100644
--- a/doc/man/nvme_mi_read_port_info.2
+++ b/doc/man/nvme_mi_read_port_info.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_mi_read_port_info" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_mi_read_port_info" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_mi_read_port_info \- Port Information Data Structure
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_read_sc_list.2 b/doc/man/nvme_mi_read_sc_list.2
index 5f3f6b2..e9621a6 100644
--- a/doc/man/nvme_mi_read_sc_list.2
+++ b/doc/man/nvme_mi_read_sc_list.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_mi_read_sc_list" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_mi_read_sc_list" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_mi_read_sc_list \- Management Endpoint Buffer Supported Command List Data Structure
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_resp_status.2 b/doc/man/nvme_mi_resp_status.2
index 253d114..643bb03 100644
--- a/doc/man/nvme_mi_resp_status.2
+++ b/doc/man/nvme_mi_resp_status.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_mi_resp_status" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_mi_resp_status" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_mi_resp_status \- values for the response status field
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_set_probe_enabled.2 b/doc/man/nvme_mi_set_probe_enabled.2
index 05ce08a..6520c35 100644
--- a/doc/man/nvme_mi_set_probe_enabled.2
+++ b/doc/man/nvme_mi_set_probe_enabled.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_set_probe_enabled" 9 "nvme_mi_set_probe_enabled" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_set_probe_enabled" 9 "nvme_mi_set_probe_enabled" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_set_probe_enabled \- enable/disable the probe for new endpoints
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_status_to_string.2 b/doc/man/nvme_mi_status_to_string.2
index cb494ce..53ad200 100644
--- a/doc/man/nvme_mi_status_to_string.2
+++ b/doc/man/nvme_mi_status_to_string.2
@@ -1,4 +1,4 @@
-.TH "nvme_mi_status_to_string" 9 "nvme_mi_status_to_string" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_mi_status_to_string" 9 "nvme_mi_status_to_string" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_mi_status_to_string \- return a string representation of the MI status.
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_vpd_hdr.2 b/doc/man/nvme_mi_vpd_hdr.2
index d0ba148..a39416f 100644
--- a/doc/man/nvme_mi_vpd_hdr.2
+++ b/doc/man/nvme_mi_vpd_hdr.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_mi_vpd_hdr" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_mi_vpd_hdr" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_mi_vpd_hdr \- Vital Product Data Common Header
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_vpd_mr_common.2 b/doc/man/nvme_mi_vpd_mr_common.2
index 2d8ab54..6fba15d 100644
--- a/doc/man/nvme_mi_vpd_mr_common.2
+++ b/doc/man/nvme_mi_vpd_mr_common.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_mi_vpd_mr_common" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_mi_vpd_mr_common" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_mi_vpd_mr_common \- NVMe MultiRecord Area
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_vpd_mra.2 b/doc/man/nvme_mi_vpd_mra.2
index 1533262..ecee45e 100644
--- a/doc/man/nvme_mi_vpd_mra.2
+++ b/doc/man/nvme_mi_vpd_mra.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_mi_vpd_mra" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_mi_vpd_mra" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_mi_vpd_mra \- NVMe MultiRecord Area
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_vpd_ppmra.2 b/doc/man/nvme_mi_vpd_ppmra.2
index 37e0966..24cc34f 100644
--- a/doc/man/nvme_mi_vpd_ppmra.2
+++ b/doc/man/nvme_mi_vpd_ppmra.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_mi_vpd_ppmra" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_mi_vpd_ppmra" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_mi_vpd_ppmra \- NVMe PCIe Port MultiRecord Area
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_vpd_telem.2 b/doc/man/nvme_mi_vpd_telem.2
index b73e9f3..9b9aace 100644
--- a/doc/man/nvme_mi_vpd_telem.2
+++ b/doc/man/nvme_mi_vpd_telem.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_mi_vpd_telem" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_mi_vpd_telem" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_mi_vpd_telem \- Vital Product Data Element Descriptor
.SH SYNOPSIS
diff --git a/doc/man/nvme_mi_vpd_tra.2 b/doc/man/nvme_mi_vpd_tra.2
index c7fbff2..9d52315 100644
--- a/doc/man/nvme_mi_vpd_tra.2
+++ b/doc/man/nvme_mi_vpd_tra.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_mi_vpd_tra" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_mi_vpd_tra" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_mi_vpd_tra \- Vital Product Data Topology MultiRecord
.SH SYNOPSIS
diff --git a/doc/man/nvme_namespace_attach_ctrls.2 b/doc/man/nvme_namespace_attach_ctrls.2
index 40be8fc..d19e0e1 100644
--- a/doc/man/nvme_namespace_attach_ctrls.2
+++ b/doc/man/nvme_namespace_attach_ctrls.2
@@ -1,4 +1,4 @@
-.TH "nvme_namespace_attach_ctrls" 9 "nvme_namespace_attach_ctrls" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_namespace_attach_ctrls" 9 "nvme_namespace_attach_ctrls" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_namespace_attach_ctrls \- Attach namespace to controller(s)
.SH SYNOPSIS
diff --git a/doc/man/nvme_namespace_detach_ctrls.2 b/doc/man/nvme_namespace_detach_ctrls.2
index fdaf0d7..5fe8831 100644
--- a/doc/man/nvme_namespace_detach_ctrls.2
+++ b/doc/man/nvme_namespace_detach_ctrls.2
@@ -1,4 +1,4 @@
-.TH "nvme_namespace_detach_ctrls" 9 "nvme_namespace_detach_ctrls" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_namespace_detach_ctrls" 9 "nvme_namespace_detach_ctrls" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_namespace_detach_ctrls \- Detach namespace from controller(s)
.SH SYNOPSIS
diff --git a/doc/man/nvme_namespace_filter.2 b/doc/man/nvme_namespace_filter.2
index 41dbc2b..aca48cf 100644
--- a/doc/man/nvme_namespace_filter.2
+++ b/doc/man/nvme_namespace_filter.2
@@ -1,4 +1,4 @@
-.TH "nvme_namespace_filter" 9 "nvme_namespace_filter" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_namespace_filter" 9 "nvme_namespace_filter" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_namespace_filter \- Filter for namespaces
.SH SYNOPSIS
diff --git a/doc/man/nvme_namespace_first_path.2 b/doc/man/nvme_namespace_first_path.2
index b3fbd61..335cf37 100644
--- a/doc/man/nvme_namespace_first_path.2
+++ b/doc/man/nvme_namespace_first_path.2
@@ -1,4 +1,4 @@
-.TH "nvme_namespace_first_path" 9 "nvme_namespace_first_path" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_namespace_first_path" 9 "nvme_namespace_first_path" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_namespace_first_path \- Start path iterator
.SH SYNOPSIS
diff --git a/doc/man/nvme_namespace_for_each_path.2 b/doc/man/nvme_namespace_for_each_path.2
index 6094a21..7c94511 100644
--- a/doc/man/nvme_namespace_for_each_path.2
+++ b/doc/man/nvme_namespace_for_each_path.2
@@ -1,4 +1,4 @@
-.TH "nvme_namespace_for_each_path" 9 "nvme_namespace_for_each_path" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_namespace_for_each_path" 9 "nvme_namespace_for_each_path" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_namespace_for_each_path \- Traverse paths
.SH SYNOPSIS
diff --git a/doc/man/nvme_namespace_for_each_path_safe.2 b/doc/man/nvme_namespace_for_each_path_safe.2
index f75bea9..b853dce 100644
--- a/doc/man/nvme_namespace_for_each_path_safe.2
+++ b/doc/man/nvme_namespace_for_each_path_safe.2
@@ -1,4 +1,4 @@
-.TH "nvme_namespace_for_each_path_safe" 9 "nvme_namespace_for_each_path_safe" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_namespace_for_each_path_safe" 9 "nvme_namespace_for_each_path_safe" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_namespace_for_each_path_safe \- Traverse paths
.SH SYNOPSIS
diff --git a/doc/man/nvme_namespace_next_path.2 b/doc/man/nvme_namespace_next_path.2
index 7e5f843..dc76cb2 100644
--- a/doc/man/nvme_namespace_next_path.2
+++ b/doc/man/nvme_namespace_next_path.2
@@ -1,4 +1,4 @@
-.TH "nvme_namespace_next_path" 9 "nvme_namespace_next_path" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_namespace_next_path" 9 "nvme_namespace_next_path" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_namespace_next_path \- Next path iterator
.SH SYNOPSIS
diff --git a/doc/man/nvme_nbft_free.2 b/doc/man/nvme_nbft_free.2
index 53c921e..9498474 100644
--- a/doc/man/nvme_nbft_free.2
+++ b/doc/man/nvme_nbft_free.2
@@ -1,4 +1,4 @@
-.TH "nvme_nbft_free" 9 "nvme_nbft_free" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_nbft_free" 9 "nvme_nbft_free" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_nbft_free \- Free the struct nbft_info and its contents
.SH SYNOPSIS
diff --git a/doc/man/nvme_nbft_read.2 b/doc/man/nvme_nbft_read.2
index 0c8534a..ea42445 100644
--- a/doc/man/nvme_nbft_read.2
+++ b/doc/man/nvme_nbft_read.2
@@ -1,4 +1,4 @@
-.TH "nvme_nbft_read" 9 "nvme_nbft_read" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_nbft_read" 9 "nvme_nbft_read" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_nbft_read \- Read and parse contents of an ACPI NBFT table
.SH SYNOPSIS
diff --git a/doc/man/nvme_nd_ns_fpi.2 b/doc/man/nvme_nd_ns_fpi.2
index eaafcfa..7699436 100644
--- a/doc/man/nvme_nd_ns_fpi.2
+++ b/doc/man/nvme_nd_ns_fpi.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_nd_ns_fpi" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_nd_ns_fpi" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_nd_ns_fpi \- If a format operation is in progress, this field indicates the percentage of the namespace that remains to be formatted.
.SH SYNOPSIS
diff --git a/doc/man/nvme_next_host.2 b/doc/man/nvme_next_host.2
index 4964e70..f499f64 100644
--- a/doc/man/nvme_next_host.2
+++ b/doc/man/nvme_next_host.2
@@ -1,4 +1,4 @@
-.TH "nvme_next_host" 9 "nvme_next_host" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_next_host" 9 "nvme_next_host" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_next_host \- Next host iterator
.SH SYNOPSIS
diff --git a/doc/man/nvme_next_subsystem.2 b/doc/man/nvme_next_subsystem.2
index 08fa802..66c4694 100644
--- a/doc/man/nvme_next_subsystem.2
+++ b/doc/man/nvme_next_subsystem.2
@@ -1,4 +1,4 @@
-.TH "nvme_next_subsystem" 9 "nvme_next_subsystem" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_next_subsystem" 9 "nvme_next_subsystem" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_next_subsystem \- Next subsystem iterator
.SH SYNOPSIS
diff --git a/doc/man/nvme_ns_attach.2 b/doc/man/nvme_ns_attach.2
index d435197..a52a779 100644
--- a/doc/man/nvme_ns_attach.2
+++ b/doc/man/nvme_ns_attach.2
@@ -1,4 +1,4 @@
-.TH "nvme_ns_attach" 9 "nvme_ns_attach" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ns_attach" 9 "nvme_ns_attach" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ns_attach \- Attach or detach namespace to controller(s)
.SH SYNOPSIS
diff --git a/doc/man/nvme_ns_attach_ctrls.2 b/doc/man/nvme_ns_attach_ctrls.2
index 98f6c55..8815dc8 100644
--- a/doc/man/nvme_ns_attach_ctrls.2
+++ b/doc/man/nvme_ns_attach_ctrls.2
@@ -1,4 +1,4 @@
-.TH "nvme_ns_attach_ctrls" 9 "nvme_ns_attach_ctrls" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ns_attach_ctrls" 9 "nvme_ns_attach_ctrls" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ns_attach_ctrls \- Attach namespace to controllers
.SH SYNOPSIS
diff --git a/doc/man/nvme_ns_attach_sel.2 b/doc/man/nvme_ns_attach_sel.2
index 6ed3541..7a69771 100644
--- a/doc/man/nvme_ns_attach_sel.2
+++ b/doc/man/nvme_ns_attach_sel.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_ns_attach_sel" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_ns_attach_sel" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_ns_attach_sel \- Namespace Attachment - Select
.SH SYNOPSIS
diff --git a/doc/man/nvme_ns_compare.2 b/doc/man/nvme_ns_compare.2
index 89ffdc8..482e544 100644
--- a/doc/man/nvme_ns_compare.2
+++ b/doc/man/nvme_ns_compare.2
@@ -1,4 +1,4 @@
-.TH "nvme_ns_compare" 9 "nvme_ns_compare" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ns_compare" 9 "nvme_ns_compare" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ns_compare \- Compare data on a namespace
.SH SYNOPSIS
diff --git a/doc/man/nvme_ns_detach_ctrls.2 b/doc/man/nvme_ns_detach_ctrls.2
index b1d5313..606f65b 100644
--- a/doc/man/nvme_ns_detach_ctrls.2
+++ b/doc/man/nvme_ns_detach_ctrls.2
@@ -1,4 +1,4 @@
-.TH "nvme_ns_detach_ctrls" 9 "nvme_ns_detach_ctrls" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ns_detach_ctrls" 9 "nvme_ns_detach_ctrls" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ns_detach_ctrls \- Detach namespace from controllers
.SH SYNOPSIS
diff --git a/doc/man/nvme_ns_flush.2 b/doc/man/nvme_ns_flush.2
index c19f1ee..5140159 100644
--- a/doc/man/nvme_ns_flush.2
+++ b/doc/man/nvme_ns_flush.2
@@ -1,4 +1,4 @@
-.TH "nvme_ns_flush" 9 "nvme_ns_flush" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ns_flush" 9 "nvme_ns_flush" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ns_flush \- Flush data to a namespace
.SH SYNOPSIS
diff --git a/doc/man/nvme_ns_get_csi.2 b/doc/man/nvme_ns_get_csi.2
index 5a8e279..0e69fd8 100644
--- a/doc/man/nvme_ns_get_csi.2
+++ b/doc/man/nvme_ns_get_csi.2
@@ -1,4 +1,4 @@
-.TH "nvme_ns_get_csi" 9 "nvme_ns_get_csi" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ns_get_csi" 9 "nvme_ns_get_csi" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ns_get_csi \- Command set identifier of a namespace
.SH SYNOPSIS
diff --git a/doc/man/nvme_ns_get_ctrl.2 b/doc/man/nvme_ns_get_ctrl.2
index af12b9c..c231066 100644
--- a/doc/man/nvme_ns_get_ctrl.2
+++ b/doc/man/nvme_ns_get_ctrl.2
@@ -1,4 +1,4 @@
-.TH "nvme_ns_get_ctrl" 9 "nvme_ns_get_ctrl" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ns_get_ctrl" 9 "nvme_ns_get_ctrl" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ns_get_ctrl \- &nvme_ctrl_t of a namespace
.SH SYNOPSIS
diff --git a/doc/man/nvme_ns_get_eui64.2 b/doc/man/nvme_ns_get_eui64.2
index 29129f7..8ee77d5 100644
--- a/doc/man/nvme_ns_get_eui64.2
+++ b/doc/man/nvme_ns_get_eui64.2
@@ -1,4 +1,4 @@
-.TH "nvme_ns_get_eui64" 9 "nvme_ns_get_eui64" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ns_get_eui64" 9 "nvme_ns_get_eui64" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ns_get_eui64 \- 64-bit eui of a namespace
.SH SYNOPSIS
diff --git a/doc/man/nvme_ns_get_fd.2 b/doc/man/nvme_ns_get_fd.2
index c58e71e..aac4306 100644
--- a/doc/man/nvme_ns_get_fd.2
+++ b/doc/man/nvme_ns_get_fd.2
@@ -1,4 +1,4 @@
-.TH "nvme_ns_get_fd" 9 "nvme_ns_get_fd" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ns_get_fd" 9 "nvme_ns_get_fd" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ns_get_fd \- Get associated file descriptor
.SH SYNOPSIS
@@ -7,5 +7,12 @@ nvme_ns_get_fd \- Get associated file descriptor
.SH ARGUMENTS
.IP "n" 12
Namespace instance
+.SH "DESCRIPTION"
+libnvme will \fBopen\fP 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 ns object is deleted or
+\fBnvme_ns_release_fd\fP is called.
.SH "RETURN"
File descriptor associated with \fIn\fP or -1
diff --git a/doc/man/nvme_ns_get_firmware.2 b/doc/man/nvme_ns_get_firmware.2
index 82cd548..fefa576 100644
--- a/doc/man/nvme_ns_get_firmware.2
+++ b/doc/man/nvme_ns_get_firmware.2
@@ -1,4 +1,4 @@
-.TH "nvme_ns_get_firmware" 9 "nvme_ns_get_firmware" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ns_get_firmware" 9 "nvme_ns_get_firmware" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ns_get_firmware \- Firmware string of a namespace
.SH SYNOPSIS
diff --git a/doc/man/nvme_ns_get_generic_name.2 b/doc/man/nvme_ns_get_generic_name.2
index 3bfc4f7..f5b9ba4 100644
--- a/doc/man/nvme_ns_get_generic_name.2
+++ b/doc/man/nvme_ns_get_generic_name.2
@@ -1,4 +1,4 @@
-.TH "nvme_ns_get_generic_name" 9 "nvme_ns_get_generic_name" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ns_get_generic_name" 9 "nvme_ns_get_generic_name" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ns_get_generic_name \- Returns name of generic namespace chardev.
.SH SYNOPSIS
diff --git a/doc/man/nvme_ns_get_lba_count.2 b/doc/man/nvme_ns_get_lba_count.2
index 41394b5..8d80552 100644
--- a/doc/man/nvme_ns_get_lba_count.2
+++ b/doc/man/nvme_ns_get_lba_count.2
@@ -1,4 +1,4 @@
-.TH "nvme_ns_get_lba_count" 9 "nvme_ns_get_lba_count" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ns_get_lba_count" 9 "nvme_ns_get_lba_count" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ns_get_lba_count \- LBA count of a namespace
.SH SYNOPSIS
diff --git a/doc/man/nvme_ns_get_lba_size.2 b/doc/man/nvme_ns_get_lba_size.2
index 3c97f48..3d1a591 100644
--- a/doc/man/nvme_ns_get_lba_size.2
+++ b/doc/man/nvme_ns_get_lba_size.2
@@ -1,4 +1,4 @@
-.TH "nvme_ns_get_lba_size" 9 "nvme_ns_get_lba_size" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ns_get_lba_size" 9 "nvme_ns_get_lba_size" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ns_get_lba_size \- LBA size of a namespace
.SH SYNOPSIS
diff --git a/doc/man/nvme_ns_get_lba_util.2 b/doc/man/nvme_ns_get_lba_util.2
index 01199ac..0cc6866 100644
--- a/doc/man/nvme_ns_get_lba_util.2
+++ b/doc/man/nvme_ns_get_lba_util.2
@@ -1,4 +1,4 @@
-.TH "nvme_ns_get_lba_util" 9 "nvme_ns_get_lba_util" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ns_get_lba_util" 9 "nvme_ns_get_lba_util" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ns_get_lba_util \- LBA utilization of a namespace
.SH SYNOPSIS
diff --git a/doc/man/nvme_ns_get_meta_size.2 b/doc/man/nvme_ns_get_meta_size.2
index c348c7e..8a42e75 100644
--- a/doc/man/nvme_ns_get_meta_size.2
+++ b/doc/man/nvme_ns_get_meta_size.2
@@ -1,4 +1,4 @@
-.TH "nvme_ns_get_meta_size" 9 "nvme_ns_get_meta_size" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ns_get_meta_size" 9 "nvme_ns_get_meta_size" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ns_get_meta_size \- Metadata size of a namespace
.SH SYNOPSIS
diff --git a/doc/man/nvme_ns_get_model.2 b/doc/man/nvme_ns_get_model.2
index 67ac637..13e35fc 100644
--- a/doc/man/nvme_ns_get_model.2
+++ b/doc/man/nvme_ns_get_model.2
@@ -1,4 +1,4 @@
-.TH "nvme_ns_get_model" 9 "nvme_ns_get_model" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ns_get_model" 9 "nvme_ns_get_model" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ns_get_model \- Model of a namespace
.SH SYNOPSIS
diff --git a/doc/man/nvme_ns_get_name.2 b/doc/man/nvme_ns_get_name.2
index 31662ad..510b736 100644
--- a/doc/man/nvme_ns_get_name.2
+++ b/doc/man/nvme_ns_get_name.2
@@ -1,4 +1,4 @@
-.TH "nvme_ns_get_name" 9 "nvme_ns_get_name" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ns_get_name" 9 "nvme_ns_get_name" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ns_get_name \- sysfs name of a namespace
.SH SYNOPSIS
diff --git a/doc/man/nvme_ns_get_nguid.2 b/doc/man/nvme_ns_get_nguid.2
index adef802..81b8965 100644
--- a/doc/man/nvme_ns_get_nguid.2
+++ b/doc/man/nvme_ns_get_nguid.2
@@ -1,4 +1,4 @@
-.TH "nvme_ns_get_nguid" 9 "nvme_ns_get_nguid" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ns_get_nguid" 9 "nvme_ns_get_nguid" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ns_get_nguid \- 128-bit nguid of a namespace
.SH SYNOPSIS
diff --git a/doc/man/nvme_ns_get_nsid.2 b/doc/man/nvme_ns_get_nsid.2
index e5312c9..516647f 100644
--- a/doc/man/nvme_ns_get_nsid.2
+++ b/doc/man/nvme_ns_get_nsid.2
@@ -1,4 +1,4 @@
-.TH "nvme_ns_get_nsid" 9 "nvme_ns_get_nsid" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ns_get_nsid" 9 "nvme_ns_get_nsid" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ns_get_nsid \- NSID of a namespace
.SH SYNOPSIS
diff --git a/doc/man/nvme_ns_get_serial.2 b/doc/man/nvme_ns_get_serial.2
index 3c081ff..219531b 100644
--- a/doc/man/nvme_ns_get_serial.2
+++ b/doc/man/nvme_ns_get_serial.2
@@ -1,4 +1,4 @@
-.TH "nvme_ns_get_serial" 9 "nvme_ns_get_serial" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ns_get_serial" 9 "nvme_ns_get_serial" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ns_get_serial \- Serial number of a namespace
.SH SYNOPSIS
diff --git a/doc/man/nvme_ns_get_subsystem.2 b/doc/man/nvme_ns_get_subsystem.2
index 05b5afb..3dad500 100644
--- a/doc/man/nvme_ns_get_subsystem.2
+++ b/doc/man/nvme_ns_get_subsystem.2
@@ -1,4 +1,4 @@
-.TH "nvme_ns_get_subsystem" 9 "nvme_ns_get_subsystem" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ns_get_subsystem" 9 "nvme_ns_get_subsystem" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ns_get_subsystem \- &nvme_subsystem_t of a namespace
.SH SYNOPSIS
diff --git a/doc/man/nvme_ns_get_sysfs_dir.2 b/doc/man/nvme_ns_get_sysfs_dir.2
index a04f4c9..d1cdd7c 100644
--- a/doc/man/nvme_ns_get_sysfs_dir.2
+++ b/doc/man/nvme_ns_get_sysfs_dir.2
@@ -1,4 +1,4 @@
-.TH "nvme_ns_get_sysfs_dir" 9 "nvme_ns_get_sysfs_dir" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ns_get_sysfs_dir" 9 "nvme_ns_get_sysfs_dir" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ns_get_sysfs_dir \- sysfs directory of a namespace
.SH SYNOPSIS
diff --git a/doc/man/nvme_ns_get_uuid.2 b/doc/man/nvme_ns_get_uuid.2
index d268c54..ba8b207 100644
--- a/doc/man/nvme_ns_get_uuid.2
+++ b/doc/man/nvme_ns_get_uuid.2
@@ -1,4 +1,4 @@
-.TH "nvme_ns_get_uuid" 9 "nvme_ns_get_uuid" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ns_get_uuid" 9 "nvme_ns_get_uuid" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ns_get_uuid \- UUID of a namespace
.SH SYNOPSIS
diff --git a/doc/man/nvme_ns_id_desc.2 b/doc/man/nvme_ns_id_desc.2
index 80415ab..c005f91 100644
--- a/doc/man/nvme_ns_id_desc.2
+++ b/doc/man/nvme_ns_id_desc.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_ns_id_desc" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_ns_id_desc" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_ns_id_desc \- Namespace identifier type descriptor
.SH SYNOPSIS
diff --git a/doc/man/nvme_ns_id_desc_nidt.2 b/doc/man/nvme_ns_id_desc_nidt.2
index 1ae314d..004bf1d 100644
--- a/doc/man/nvme_ns_id_desc_nidt.2
+++ b/doc/man/nvme_ns_id_desc_nidt.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_ns_id_desc_nidt" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_ns_id_desc_nidt" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_ns_id_desc_nidt \- Known namespace identifier types
.SH SYNOPSIS
diff --git a/doc/man/nvme_ns_identify.2 b/doc/man/nvme_ns_identify.2
index ca44156..8171518 100644
--- a/doc/man/nvme_ns_identify.2
+++ b/doc/man/nvme_ns_identify.2
@@ -1,4 +1,4 @@
-.TH "nvme_ns_identify" 9 "nvme_ns_identify" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ns_identify" 9 "nvme_ns_identify" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ns_identify \- Issue an 'identify namespace' command
.SH SYNOPSIS
diff --git a/doc/man/nvme_ns_identify_descs.2 b/doc/man/nvme_ns_identify_descs.2
index 64ee0da..b7400a4 100644
--- a/doc/man/nvme_ns_identify_descs.2
+++ b/doc/man/nvme_ns_identify_descs.2
@@ -1,4 +1,4 @@
-.TH "nvme_ns_identify_descs" 9 "nvme_ns_identify_descs" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ns_identify_descs" 9 "nvme_ns_identify_descs" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ns_identify_descs \- Issue an 'identify descriptors' command
.SH SYNOPSIS
diff --git a/doc/man/nvme_ns_list.2 b/doc/man/nvme_ns_list.2
index 6bffd4b..bd3b280 100644
--- a/doc/man/nvme_ns_list.2
+++ b/doc/man/nvme_ns_list.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_ns_list" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_ns_list" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_ns_list \- Namespace List
.SH SYNOPSIS
diff --git a/doc/man/nvme_ns_metadata_type.2 b/doc/man/nvme_ns_metadata_type.2
index ef90a67..4aaed69 100644
--- a/doc/man/nvme_ns_metadata_type.2
+++ b/doc/man/nvme_ns_metadata_type.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_ns_metadata_type" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_ns_metadata_type" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_ns_metadata_type \- Namespace Metadata Element Types
.SH SYNOPSIS
diff --git a/doc/man/nvme_ns_mgmt.2 b/doc/man/nvme_ns_mgmt.2
index e7bdfd9..549acd0 100644
--- a/doc/man/nvme_ns_mgmt.2
+++ b/doc/man/nvme_ns_mgmt.2
@@ -1,4 +1,4 @@
-.TH "nvme_ns_mgmt" 9 "nvme_ns_mgmt" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ns_mgmt" 9 "nvme_ns_mgmt" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ns_mgmt \- Issue a Namespace management command
.SH SYNOPSIS
diff --git a/doc/man/nvme_ns_mgmt_create.2 b/doc/man/nvme_ns_mgmt_create.2
index 057f60b..b2dccac 100644
--- a/doc/man/nvme_ns_mgmt_create.2
+++ b/doc/man/nvme_ns_mgmt_create.2
@@ -1,4 +1,4 @@
-.TH "nvme_ns_mgmt_create" 9 "nvme_ns_mgmt_create" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ns_mgmt_create" 9 "nvme_ns_mgmt_create" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ns_mgmt_create \- Create a non attached namespace
.SH SYNOPSIS
diff --git a/doc/man/nvme_ns_mgmt_delete.2 b/doc/man/nvme_ns_mgmt_delete.2
index 83970ae..a8eddce 100644
--- a/doc/man/nvme_ns_mgmt_delete.2
+++ b/doc/man/nvme_ns_mgmt_delete.2
@@ -1,4 +1,4 @@
-.TH "nvme_ns_mgmt_delete" 9 "nvme_ns_mgmt_delete" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ns_mgmt_delete" 9 "nvme_ns_mgmt_delete" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ns_mgmt_delete \- Delete a non attached namespace
.SH SYNOPSIS
diff --git a/doc/man/nvme_ns_mgmt_host_sw_specified.2 b/doc/man/nvme_ns_mgmt_host_sw_specified.2
index 46c9f9c..455a235 100644
--- a/doc/man/nvme_ns_mgmt_host_sw_specified.2
+++ b/doc/man/nvme_ns_mgmt_host_sw_specified.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_ns_mgmt_host_sw_specified" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_ns_mgmt_host_sw_specified" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_ns_mgmt_host_sw_specified \- Namespace management Host Software Specified Fields.
.SH SYNOPSIS
diff --git a/doc/man/nvme_ns_mgmt_sel.2 b/doc/man/nvme_ns_mgmt_sel.2
index 68eb862..5d9ee16 100644
--- a/doc/man/nvme_ns_mgmt_sel.2
+++ b/doc/man/nvme_ns_mgmt_sel.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_ns_mgmt_sel" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_ns_mgmt_sel" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_ns_mgmt_sel \- Namespace Management - Select
.SH SYNOPSIS
diff --git a/doc/man/nvme_ns_read.2 b/doc/man/nvme_ns_read.2
index c2697d7..c426c41 100644
--- a/doc/man/nvme_ns_read.2
+++ b/doc/man/nvme_ns_read.2
@@ -1,4 +1,4 @@
-.TH "nvme_ns_read" 9 "nvme_ns_read" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ns_read" 9 "nvme_ns_read" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ns_read \- Read from a namespace
.SH SYNOPSIS
diff --git a/doc/man/nvme_ns_release_fd.2 b/doc/man/nvme_ns_release_fd.2
new file mode 100644
index 0000000..b1c1b68
--- /dev/null
+++ b/doc/man/nvme_ns_release_fd.2
@@ -0,0 +1,9 @@
+.TH "nvme_ns_release_fd" 9 "nvme_ns_release_fd" "December 2023" "libnvme API manual" LINUX
+.SH NAME
+nvme_ns_release_fd \- Close fd and clear fd from ns object
+.SH SYNOPSIS
+.B "void" nvme_ns_release_fd
+.BI "(nvme_ns_t n " ");"
+.SH ARGUMENTS
+.IP "n" 12
+Namespace instance
diff --git a/doc/man/nvme_ns_rescan.2 b/doc/man/nvme_ns_rescan.2
index 3f88875..458d111 100644
--- a/doc/man/nvme_ns_rescan.2
+++ b/doc/man/nvme_ns_rescan.2
@@ -1,4 +1,4 @@
-.TH "nvme_ns_rescan" 9 "nvme_ns_rescan" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ns_rescan" 9 "nvme_ns_rescan" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ns_rescan \- Initiate a controller rescan
.SH SYNOPSIS
diff --git a/doc/man/nvme_ns_verify.2 b/doc/man/nvme_ns_verify.2
index 0b3ff46..4d9cda3 100644
--- a/doc/man/nvme_ns_verify.2
+++ b/doc/man/nvme_ns_verify.2
@@ -1,4 +1,4 @@
-.TH "nvme_ns_verify" 9 "nvme_ns_verify" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ns_verify" 9 "nvme_ns_verify" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ns_verify \- Verify data on a namespace
.SH SYNOPSIS
diff --git a/doc/man/nvme_ns_write.2 b/doc/man/nvme_ns_write.2
index 290c0c6..e864cdf 100644
--- a/doc/man/nvme_ns_write.2
+++ b/doc/man/nvme_ns_write.2
@@ -1,4 +1,4 @@
-.TH "nvme_ns_write" 9 "nvme_ns_write" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ns_write" 9 "nvme_ns_write" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ns_write \- Write to a namespace
.SH SYNOPSIS
diff --git a/doc/man/nvme_ns_write_protect_cfg.2 b/doc/man/nvme_ns_write_protect_cfg.2
index 96f0fa9..3a645aa 100644
--- a/doc/man/nvme_ns_write_protect_cfg.2
+++ b/doc/man/nvme_ns_write_protect_cfg.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_ns_write_protect_cfg" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_ns_write_protect_cfg" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_ns_write_protect_cfg \- Write Protection - Write Protection State
.SH SYNOPSIS
diff --git a/doc/man/nvme_ns_write_uncorrectable.2 b/doc/man/nvme_ns_write_uncorrectable.2
index ff3cedf..5de6f4e 100644
--- a/doc/man/nvme_ns_write_uncorrectable.2
+++ b/doc/man/nvme_ns_write_uncorrectable.2
@@ -1,4 +1,4 @@
-.TH "nvme_ns_write_uncorrectable" 9 "nvme_ns_write_uncorrectable" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ns_write_uncorrectable" 9 "nvme_ns_write_uncorrectable" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ns_write_uncorrectable \- Issus a 'write uncorrectable' command
.SH SYNOPSIS
diff --git a/doc/man/nvme_ns_write_zeros.2 b/doc/man/nvme_ns_write_zeros.2
index 4469c6c..d14921f 100644
--- a/doc/man/nvme_ns_write_zeros.2
+++ b/doc/man/nvme_ns_write_zeros.2
@@ -1,4 +1,4 @@
-.TH "nvme_ns_write_zeros" 9 "nvme_ns_write_zeros" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_ns_write_zeros" 9 "nvme_ns_write_zeros" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_ns_write_zeros \- Write zeros to a namespace
.SH SYNOPSIS
diff --git a/doc/man/nvme_nss_hw_err_event.2 b/doc/man/nvme_nss_hw_err_event.2
index b34dff9..92d44fd 100644
--- a/doc/man/nvme_nss_hw_err_event.2
+++ b/doc/man/nvme_nss_hw_err_event.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_nss_hw_err_event" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_nss_hw_err_event" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_nss_hw_err_event \- NVM Subsystem Hardware Error Event
.SH SYNOPSIS
diff --git a/doc/man/nvme_nvm_id_ns.2 b/doc/man/nvme_nvm_id_ns.2
index 5ee4066..3dbb175 100644
--- a/doc/man/nvme_nvm_id_ns.2
+++ b/doc/man/nvme_nvm_id_ns.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_nvm_id_ns" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_nvm_id_ns" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_nvm_id_ns \- NVME Command Set I/O Command Set Specific Identify Namespace Data Structure
.SH SYNOPSIS
diff --git a/doc/man/nvme_nvm_id_ns_elbaf.2 b/doc/man/nvme_nvm_id_ns_elbaf.2
index 56bc5ea..a9808f3 100644
--- a/doc/man/nvme_nvm_id_ns_elbaf.2
+++ b/doc/man/nvme_nvm_id_ns_elbaf.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_nvm_id_ns_elbaf" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_nvm_id_ns_elbaf" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_nvm_id_ns_elbaf \- This field indicates the extended LBA format
.SH SYNOPSIS
diff --git a/doc/man/nvme_nvm_identify_ctrl.2 b/doc/man/nvme_nvm_identify_ctrl.2
index b6aa4d4..6e49693 100644
--- a/doc/man/nvme_nvm_identify_ctrl.2
+++ b/doc/man/nvme_nvm_identify_ctrl.2
@@ -1,4 +1,4 @@
-.TH "nvme_nvm_identify_ctrl" 9 "nvme_nvm_identify_ctrl" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_nvm_identify_ctrl" 9 "nvme_nvm_identify_ctrl" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_nvm_identify_ctrl \- Identify controller data
.SH SYNOPSIS
diff --git a/doc/man/nvme_nvmeset_pl_status.2 b/doc/man/nvme_nvmeset_pl_status.2
index ffe0737..9c166cb 100644
--- a/doc/man/nvme_nvmeset_pl_status.2
+++ b/doc/man/nvme_nvmeset_pl_status.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_nvmeset_pl_status" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_nvmeset_pl_status" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_nvmeset_pl_status \- Predictable Latency Per NVM Set Log - Status
.SH SYNOPSIS
diff --git a/doc/man/nvme_nvmset_attr.2 b/doc/man/nvme_nvmset_attr.2
index be4b38d..844ada9 100644
--- a/doc/man/nvme_nvmset_attr.2
+++ b/doc/man/nvme_nvmset_attr.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_nvmset_attr" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_nvmset_attr" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_nvmset_attr \- NVM Set Attributes Entry
.SH SYNOPSIS
diff --git a/doc/man/nvme_nvmset_pl_events.2 b/doc/man/nvme_nvmset_pl_events.2
index 5099602..a26b38d 100644
--- a/doc/man/nvme_nvmset_pl_events.2
+++ b/doc/man/nvme_nvmset_pl_events.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_nvmset_pl_events" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_nvmset_pl_events" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_nvmset_pl_events \- Predictable Latency Per NVM Set Log - Event Type
.SH SYNOPSIS
diff --git a/doc/man/nvme_nvmset_predictable_lat_log.2 b/doc/man/nvme_nvmset_predictable_lat_log.2
index 582999d..5b5a2e3 100644
--- a/doc/man/nvme_nvmset_predictable_lat_log.2
+++ b/doc/man/nvme_nvmset_predictable_lat_log.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_nvmset_predictable_lat_log" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_nvmset_predictable_lat_log" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_nvmset_predictable_lat_log \- Predictable Latency Mode - Deterministic Threshold Configuration Data
.SH SYNOPSIS
diff --git a/doc/man/nvme_open.2 b/doc/man/nvme_open.2
index 628afa4..c87dfa5 100644
--- a/doc/man/nvme_open.2
+++ b/doc/man/nvme_open.2
@@ -1,4 +1,4 @@
-.TH "nvme_open" 9 "nvme_open" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_open" 9 "nvme_open" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_open \- Open an nvme controller or namespace device
.SH SYNOPSIS
diff --git a/doc/man/nvme_passthru_cmd.2 b/doc/man/nvme_passthru_cmd.2
index 81ccb2b..aeb0285 100644
--- a/doc/man/nvme_passthru_cmd.2
+++ b/doc/man/nvme_passthru_cmd.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_passthru_cmd" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_passthru_cmd" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_passthru_cmd \- nvme passthrough command structure
.SH SYNOPSIS
diff --git a/doc/man/nvme_passthru_cmd64.2 b/doc/man/nvme_passthru_cmd64.2
index d34cb92..f6699b4 100644
--- a/doc/man/nvme_passthru_cmd64.2
+++ b/doc/man/nvme_passthru_cmd64.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_passthru_cmd64" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_passthru_cmd64" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_passthru_cmd64 \- 64-bit nvme passthrough command structure
.SH SYNOPSIS
diff --git a/doc/man/nvme_path_get_ana_state.2 b/doc/man/nvme_path_get_ana_state.2
index d00d4b4..2fb15c6 100644
--- a/doc/man/nvme_path_get_ana_state.2
+++ b/doc/man/nvme_path_get_ana_state.2
@@ -1,4 +1,4 @@
-.TH "nvme_path_get_ana_state" 9 "nvme_path_get_ana_state" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_path_get_ana_state" 9 "nvme_path_get_ana_state" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_path_get_ana_state \- ANA state of an nvme_path_t object
.SH SYNOPSIS
diff --git a/doc/man/nvme_path_get_ctrl.2 b/doc/man/nvme_path_get_ctrl.2
index da682c7..70d16d3 100644
--- a/doc/man/nvme_path_get_ctrl.2
+++ b/doc/man/nvme_path_get_ctrl.2
@@ -1,4 +1,4 @@
-.TH "nvme_path_get_ctrl" 9 "nvme_path_get_ctrl" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_path_get_ctrl" 9 "nvme_path_get_ctrl" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_path_get_ctrl \- Parent controller of an nvme_path_t object
.SH SYNOPSIS
diff --git a/doc/man/nvme_path_get_name.2 b/doc/man/nvme_path_get_name.2
index b99892c..41a1cb0 100644
--- a/doc/man/nvme_path_get_name.2
+++ b/doc/man/nvme_path_get_name.2
@@ -1,4 +1,4 @@
-.TH "nvme_path_get_name" 9 "nvme_path_get_name" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_path_get_name" 9 "nvme_path_get_name" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_path_get_name \- sysfs name of an &nvme_path_t object
.SH SYNOPSIS
diff --git a/doc/man/nvme_path_get_ns.2 b/doc/man/nvme_path_get_ns.2
index 9680b6c..de038b1 100644
--- a/doc/man/nvme_path_get_ns.2
+++ b/doc/man/nvme_path_get_ns.2
@@ -1,4 +1,4 @@
-.TH "nvme_path_get_ns" 9 "nvme_path_get_ns" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_path_get_ns" 9 "nvme_path_get_ns" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_path_get_ns \- Parent namespace of an nvme_path_t object
.SH SYNOPSIS
diff --git a/doc/man/nvme_path_get_sysfs_dir.2 b/doc/man/nvme_path_get_sysfs_dir.2
index ae262b9..8d9f898 100644
--- a/doc/man/nvme_path_get_sysfs_dir.2
+++ b/doc/man/nvme_path_get_sysfs_dir.2
@@ -1,4 +1,4 @@
-.TH "nvme_path_get_sysfs_dir" 9 "nvme_path_get_sysfs_dir" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_path_get_sysfs_dir" 9 "nvme_path_get_sysfs_dir" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_path_get_sysfs_dir \- sysfs directory of an nvme_path_t object
.SH SYNOPSIS
diff --git a/doc/man/nvme_paths_filter.2 b/doc/man/nvme_paths_filter.2
index 69f25bc..1050912 100644
--- a/doc/man/nvme_paths_filter.2
+++ b/doc/man/nvme_paths_filter.2
@@ -1,4 +1,4 @@
-.TH "nvme_paths_filter" 9 "nvme_paths_filter" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_paths_filter" 9 "nvme_paths_filter" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_paths_filter \- Filter for paths
.SH SYNOPSIS
diff --git a/doc/man/nvme_persistent_event_entry.2 b/doc/man/nvme_persistent_event_entry.2
index 1fb0bd1..f39fd93 100644
--- a/doc/man/nvme_persistent_event_entry.2
+++ b/doc/man/nvme_persistent_event_entry.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_persistent_event_entry" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_persistent_event_entry" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_persistent_event_entry \- Persistent Event
.SH SYNOPSIS
diff --git a/doc/man/nvme_persistent_event_log.2 b/doc/man/nvme_persistent_event_log.2
index e5c042b..2aa724e 100644
--- a/doc/man/nvme_persistent_event_log.2
+++ b/doc/man/nvme_persistent_event_log.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_persistent_event_log" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_persistent_event_log" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_persistent_event_log \- Persistent Event Log
.SH SYNOPSIS
diff --git a/doc/man/nvme_persistent_event_types.2 b/doc/man/nvme_persistent_event_types.2
index 67be426..31cd645 100644
--- a/doc/man/nvme_persistent_event_types.2
+++ b/doc/man/nvme_persistent_event_types.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_persistent_event_types" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_persistent_event_types" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_persistent_event_types \- Persistent event log events
.SH SYNOPSIS
diff --git a/doc/man/nvme_pevent_log_action.2 b/doc/man/nvme_pevent_log_action.2
index c84d51c..41506b8 100644
--- a/doc/man/nvme_pevent_log_action.2
+++ b/doc/man/nvme_pevent_log_action.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_pevent_log_action" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_pevent_log_action" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_pevent_log_action \- Persistent Event Log - Action
.SH SYNOPSIS
diff --git a/doc/man/nvme_phy_rx_eom_log.2 b/doc/man/nvme_phy_rx_eom_log.2
new file mode 100644
index 0000000..b66f68c
--- /dev/null
+++ b/doc/man/nvme_phy_rx_eom_log.2
@@ -0,0 +1,99 @@
+.TH "libnvme" 9 "struct nvme_phy_rx_eom_log" "December 2023" "API Manual" LINUX
+.SH NAME
+struct nvme_phy_rx_eom_log \- Physical Interface Receiver Eye Opening Measurement Log
+.SH SYNOPSIS
+struct nvme_phy_rx_eom_log {
+.br
+.BI " __u8 lid;"
+.br
+.BI " __u8 eomip;"
+.br
+.BI " __le16 hsize;"
+.br
+.BI " __le32 rsize;"
+.br
+.BI " __u8 eomdgn;"
+.br
+.BI " __u8 lr;"
+.br
+.BI " __u8 odp;"
+.br
+.BI " __u8 lanes;"
+.br
+.BI " __u8 epl;"
+.br
+.BI " __u8 lspfc;"
+.br
+.BI " __u8 li;"
+.br
+.BI " __u8 rsvd15[3];"
+.br
+.BI " __le16 lsic;"
+.br
+.BI " __le32 dsize;"
+.br
+.BI " __le16 nd;"
+.br
+.BI " __le16 maxtb;"
+.br
+.BI " __le16 maxlr;"
+.br
+.BI " __le16 etgood;"
+.br
+.BI " __le16 etbetter;"
+.br
+.BI " __le16 etbest;"
+.br
+.BI " __u8 rsvd36[28];"
+.br
+.BI " struct nvme_eom_lane_desc descs[];"
+.br
+.BI "
+};
+.br
+
+.SH Members
+.IP "lid" 12
+Log Identifier
+.IP "eomip" 12
+EOM In Progress
+.IP "hsize" 12
+Header Size
+.IP "rsize" 12
+Result Size
+.IP "eomdgn" 12
+EOM Data Generation Number
+.IP "lr" 12
+Log Revision
+.IP "odp" 12
+Optional Data Present
+.IP "lanes" 12
+Number of lanes configured for this port
+.IP "epl" 12
+Eyes Per Lane
+.IP "lspfc" 12
+Log Specific Parameter Field Copy
+.IP "li" 12
+Link Information
+.IP "rsvd15" 12
+Reserved
+.IP "lsic" 12
+Log Specific Identifier Copy
+.IP "dsize" 12
+Descriptor Size
+.IP "nd" 12
+Number of Descriptors
+.IP "maxtb" 12
+Maximum Top Bottom
+.IP "maxlr" 12
+Maximum Left Right
+.IP "etgood" 12
+Estimated Time for Good Quality
+.IP "etbetter" 12
+Estimated Time for Better Quality
+.IP "etbest" 12
+Estimated Time for Best Quality
+.IP "rsvd36" 12
+Reserved
+.IP "descs" 12
+EOM Lane Descriptors
diff --git a/doc/man/nvme_phy_rx_eom_progress.2 b/doc/man/nvme_phy_rx_eom_progress.2
new file mode 100644
index 0000000..79f46db
--- /dev/null
+++ b/doc/man/nvme_phy_rx_eom_progress.2
@@ -0,0 +1,24 @@
+.TH "libnvme" 9 "enum nvme_phy_rx_eom_progress" "December 2023" "API Manual" LINUX
+.SH NAME
+enum nvme_phy_rx_eom_progress \- EOM In Progress Values
+.SH SYNOPSIS
+enum nvme_phy_rx_eom_progress {
+.br
+.BI " NVME_PHY_RX_EOM_NOT_STARTED"
+,
+.br
+.br
+.BI " NVME_PHY_RX_EOM_IN_PROGRESS"
+,
+.br
+.br
+.BI " NVME_PHY_RX_EOM_COMPLETED"
+
+};
+.SH Constants
+.IP "NVME_PHY_RX_EOM_NOT_STARTED" 12
+EOM Not Started
+.IP "NVME_PHY_RX_EOM_IN_PROGRESS" 12
+EOM In Progress
+.IP "NVME_PHY_RX_EOM_COMPLETED" 12
+EOM Completed
diff --git a/doc/man/nvme_plm_config.2 b/doc/man/nvme_plm_config.2
index c0886fd..7e80c10 100644
--- a/doc/man/nvme_plm_config.2
+++ b/doc/man/nvme_plm_config.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_plm_config" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_plm_config" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_plm_config \- Predictable Latency Mode - Deterministic Threshold Configuration Data Structure
.SH SYNOPSIS
diff --git a/doc/man/nvme_pmr_size.2 b/doc/man/nvme_pmr_size.2
index bf6aad9..0935cd6 100644
--- a/doc/man/nvme_pmr_size.2
+++ b/doc/man/nvme_pmr_size.2
@@ -1,4 +1,4 @@
-.TH "nvme_pmr_size" 9 "nvme_pmr_size" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_pmr_size" 9 "nvme_pmr_size" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_pmr_size \- Calculate size of persistent memory region elasticity buffer
.SH SYNOPSIS
diff --git a/doc/man/nvme_pmr_throughput.2 b/doc/man/nvme_pmr_throughput.2
index d0df4d6..1c187dd 100644
--- a/doc/man/nvme_pmr_throughput.2
+++ b/doc/man/nvme_pmr_throughput.2
@@ -1,4 +1,4 @@
-.TH "nvme_pmr_throughput" 9 "nvme_pmr_throughput" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_pmr_throughput" 9 "nvme_pmr_throughput" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_pmr_throughput \- Calculate throughput of persistent memory buffer
.SH SYNOPSIS
diff --git a/doc/man/nvme_power_on_reset_info_list.2 b/doc/man/nvme_power_on_reset_info_list.2
index 834b032..42349a2 100644
--- a/doc/man/nvme_power_on_reset_info_list.2
+++ b/doc/man/nvme_power_on_reset_info_list.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_power_on_reset_info_list" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_power_on_reset_info_list" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_power_on_reset_info_list \- Controller Reset Information
.SH SYNOPSIS
diff --git a/doc/man/nvme_primary_ctrl_cap.2 b/doc/man/nvme_primary_ctrl_cap.2
index 9ab721b..051b4af 100644
--- a/doc/man/nvme_primary_ctrl_cap.2
+++ b/doc/man/nvme_primary_ctrl_cap.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_primary_ctrl_cap" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_primary_ctrl_cap" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_primary_ctrl_cap \- Identify - Controller Capabilities Structure
.SH SYNOPSIS
diff --git a/doc/man/nvme_psd_flags.2 b/doc/man/nvme_psd_flags.2
index b7d24c4..3a362cc 100644
--- a/doc/man/nvme_psd_flags.2
+++ b/doc/man/nvme_psd_flags.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_psd_flags" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_psd_flags" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_psd_flags \- Possible flag values in nvme power state descriptor
.SH SYNOPSIS
diff --git a/doc/man/nvme_psd_power_scale.2 b/doc/man/nvme_psd_power_scale.2
index 27d28aa..2af4b51 100644
--- a/doc/man/nvme_psd_power_scale.2
+++ b/doc/man/nvme_psd_power_scale.2
@@ -1,4 +1,4 @@
-.TH "nvme_psd_power_scale" 9 "nvme_psd_power_scale" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_psd_power_scale" 9 "nvme_psd_power_scale" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_psd_power_scale \- power scale occupies the upper 3 bits
.SH SYNOPSIS
diff --git a/doc/man/nvme_psd_ps.2 b/doc/man/nvme_psd_ps.2
index 2f9d3f3..b10232c 100644
--- a/doc/man/nvme_psd_ps.2
+++ b/doc/man/nvme_psd_ps.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_psd_ps" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_psd_ps" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_psd_ps \- Known values for &struct nvme_psd %ips and %aps. Use with nvme_psd_power_scale() to extract the power scale field to match this enum.
.SH SYNOPSIS
diff --git a/doc/man/nvme_psd_workload.2 b/doc/man/nvme_psd_workload.2
index dddb9d3..b7ff7fa 100644
--- a/doc/man/nvme_psd_workload.2
+++ b/doc/man/nvme_psd_workload.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_psd_workload" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_psd_workload" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_psd_workload \- Specifies a workload hint in the Power Management Feature (see &struct nvme_psd.apw) to inform the NVM subsystem or indicate the conditions for the active power level.
.SH SYNOPSIS
diff --git a/doc/man/nvme_read.2 b/doc/man/nvme_read.2
index ec2f3ec..56e87a0 100644
--- a/doc/man/nvme_read.2
+++ b/doc/man/nvme_read.2
@@ -1,4 +1,4 @@
-.TH "nvme_read" 9 "nvme_read" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_read" 9 "nvme_read" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_read \- Submit an nvme user read command
.SH SYNOPSIS
diff --git a/doc/man/nvme_read_config.2 b/doc/man/nvme_read_config.2
index 75200ef..9353b63 100644
--- a/doc/man/nvme_read_config.2
+++ b/doc/man/nvme_read_config.2
@@ -1,4 +1,4 @@
-.TH "nvme_read_config" 9 "nvme_read_config" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_read_config" 9 "nvme_read_config" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_read_config \- Read NVMe JSON configuration file
.SH SYNOPSIS
diff --git a/doc/man/nvme_refresh_topology.2 b/doc/man/nvme_refresh_topology.2
index d14cf6a..d4c6b64 100644
--- a/doc/man/nvme_refresh_topology.2
+++ b/doc/man/nvme_refresh_topology.2
@@ -1,4 +1,4 @@
-.TH "nvme_refresh_topology" 9 "nvme_refresh_topology" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_refresh_topology" 9 "nvme_refresh_topology" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_refresh_topology \- Refresh nvme_root_t object contents
.SH SYNOPSIS
diff --git a/doc/man/nvme_register_offsets.2 b/doc/man/nvme_register_offsets.2
index 605d67d..c0f7ef3 100644
--- a/doc/man/nvme_register_offsets.2
+++ b/doc/man/nvme_register_offsets.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_register_offsets" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_register_offsets" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_register_offsets \- controller registers for all transports. This is the layout of BAR0/1 for PCIe, and properties for fabrics.
.SH SYNOPSIS
diff --git a/doc/man/nvme_registered_ctrl.2 b/doc/man/nvme_registered_ctrl.2
index bf10ec0..5728eff 100644
--- a/doc/man/nvme_registered_ctrl.2
+++ b/doc/man/nvme_registered_ctrl.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_registered_ctrl" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_registered_ctrl" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_registered_ctrl \- Registered Controller Data Structure
.SH SYNOPSIS
diff --git a/doc/man/nvme_registered_ctrl_ext.2 b/doc/man/nvme_registered_ctrl_ext.2
index 351d011..c9795de 100644
--- a/doc/man/nvme_registered_ctrl_ext.2
+++ b/doc/man/nvme_registered_ctrl_ext.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_registered_ctrl_ext" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_registered_ctrl_ext" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_registered_ctrl_ext \- Registered Controller Extended Data Structure
.SH SYNOPSIS
diff --git a/doc/man/nvme_rescan_ctrl.2 b/doc/man/nvme_rescan_ctrl.2
index e634ed5..ff27f48 100644
--- a/doc/man/nvme_rescan_ctrl.2
+++ b/doc/man/nvme_rescan_ctrl.2
@@ -1,4 +1,4 @@
-.TH "nvme_rescan_ctrl" 9 "nvme_rescan_ctrl" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_rescan_ctrl" 9 "nvme_rescan_ctrl" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_rescan_ctrl \- Rescan an existing controller
.SH SYNOPSIS
diff --git a/doc/man/nvme_resv_acquire.2 b/doc/man/nvme_resv_acquire.2
index 7453c59..0323e69 100644
--- a/doc/man/nvme_resv_acquire.2
+++ b/doc/man/nvme_resv_acquire.2
@@ -1,4 +1,4 @@
-.TH "nvme_resv_acquire" 9 "nvme_resv_acquire" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_resv_acquire" 9 "nvme_resv_acquire" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_resv_acquire \- Send an nvme reservation acquire
.SH SYNOPSIS
diff --git a/doc/man/nvme_resv_cptpl.2 b/doc/man/nvme_resv_cptpl.2
index 09da5c7..e1f7da8 100644
--- a/doc/man/nvme_resv_cptpl.2
+++ b/doc/man/nvme_resv_cptpl.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_resv_cptpl" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_resv_cptpl" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_resv_cptpl \- Reservation Register - Change Persist Through Power Loss State
.SH SYNOPSIS
diff --git a/doc/man/nvme_resv_notification_log.2 b/doc/man/nvme_resv_notification_log.2
index 78d7770..6799fbc 100644
--- a/doc/man/nvme_resv_notification_log.2
+++ b/doc/man/nvme_resv_notification_log.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_resv_notification_log" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_resv_notification_log" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_resv_notification_log \- Reservation Notification Log
.SH SYNOPSIS
diff --git a/doc/man/nvme_resv_notify_rnlpt.2 b/doc/man/nvme_resv_notify_rnlpt.2
index 218f7fd..29914e4 100644
--- a/doc/man/nvme_resv_notify_rnlpt.2
+++ b/doc/man/nvme_resv_notify_rnlpt.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_resv_notify_rnlpt" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_resv_notify_rnlpt" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_resv_notify_rnlpt \- Reservation Notification Log - Reservation Notification Log Page Type
.SH SYNOPSIS
diff --git a/doc/man/nvme_resv_racqa.2 b/doc/man/nvme_resv_racqa.2
index 462849d..5dd5dec 100644
--- a/doc/man/nvme_resv_racqa.2
+++ b/doc/man/nvme_resv_racqa.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_resv_racqa" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_resv_racqa" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_resv_racqa \- Reservation Acquire - Reservation Acquire Action
.SH SYNOPSIS
diff --git a/doc/man/nvme_resv_register.2 b/doc/man/nvme_resv_register.2
index b9a9c62..0ae94e6 100644
--- a/doc/man/nvme_resv_register.2
+++ b/doc/man/nvme_resv_register.2
@@ -1,4 +1,4 @@
-.TH "nvme_resv_register" 9 "nvme_resv_register" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_resv_register" 9 "nvme_resv_register" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_resv_register \- Send an nvme reservation register
.SH SYNOPSIS
diff --git a/doc/man/nvme_resv_release.2 b/doc/man/nvme_resv_release.2
index 6c5a711..5b17049 100644
--- a/doc/man/nvme_resv_release.2
+++ b/doc/man/nvme_resv_release.2
@@ -1,4 +1,4 @@
-.TH "nvme_resv_release" 9 "nvme_resv_release" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_resv_release" 9 "nvme_resv_release" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_resv_release \- Send an nvme reservation release
.SH SYNOPSIS
diff --git a/doc/man/nvme_resv_report.2 b/doc/man/nvme_resv_report.2
index 9053502..8a16bc9 100644
--- a/doc/man/nvme_resv_report.2
+++ b/doc/man/nvme_resv_report.2
@@ -1,4 +1,4 @@
-.TH "nvme_resv_report" 9 "nvme_resv_report" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_resv_report" 9 "nvme_resv_report" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_resv_report \- Send an nvme reservation report
.SH SYNOPSIS
diff --git a/doc/man/nvme_resv_rrega.2 b/doc/man/nvme_resv_rrega.2
index 0d994c7..16a40a8 100644
--- a/doc/man/nvme_resv_rrega.2
+++ b/doc/man/nvme_resv_rrega.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_resv_rrega" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_resv_rrega" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_resv_rrega \- Reservation Register - Reservation Register Action
.SH SYNOPSIS
diff --git a/doc/man/nvme_resv_rrela.2 b/doc/man/nvme_resv_rrela.2
index 1163c2b..277d255 100644
--- a/doc/man/nvme_resv_rrela.2
+++ b/doc/man/nvme_resv_rrela.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_resv_rrela" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_resv_rrela" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_resv_rrela \- Reservation Release - Reservation Release Action
.SH SYNOPSIS
diff --git a/doc/man/nvme_resv_rtype.2 b/doc/man/nvme_resv_rtype.2
index 53d1bd7..83d6bb2 100644
--- a/doc/man/nvme_resv_rtype.2
+++ b/doc/man/nvme_resv_rtype.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_resv_rtype" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_resv_rtype" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_resv_rtype \- Reservation Type Encoding
.SH SYNOPSIS
diff --git a/doc/man/nvme_resv_status.2 b/doc/man/nvme_resv_status.2
index e61190a..35c08b1 100644
--- a/doc/man/nvme_resv_status.2
+++ b/doc/man/nvme_resv_status.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_resv_status" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_resv_status" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_resv_status \- Reservation Status Data Structure
.SH SYNOPSIS
diff --git a/doc/man/nvme_sanitize_compln_event.2 b/doc/man/nvme_sanitize_compln_event.2
index cee384b..2ea1361 100644
--- a/doc/man/nvme_sanitize_compln_event.2
+++ b/doc/man/nvme_sanitize_compln_event.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_sanitize_compln_event" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_sanitize_compln_event" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_sanitize_compln_event \- Sanitize Completion Event Data
.SH SYNOPSIS
diff --git a/doc/man/nvme_sanitize_log_page.2 b/doc/man/nvme_sanitize_log_page.2
index 1f5bf66..dc4730a 100644
--- a/doc/man/nvme_sanitize_log_page.2
+++ b/doc/man/nvme_sanitize_log_page.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_sanitize_log_page" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_sanitize_log_page" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_sanitize_log_page \- Sanitize Status (Log Identifier 81h)
.SH SYNOPSIS
diff --git a/doc/man/nvme_sanitize_nvm.2 b/doc/man/nvme_sanitize_nvm.2
index 359856a..3dfed95 100644
--- a/doc/man/nvme_sanitize_nvm.2
+++ b/doc/man/nvme_sanitize_nvm.2
@@ -1,4 +1,4 @@
-.TH "nvme_sanitize_nvm" 9 "nvme_sanitize_nvm" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_sanitize_nvm" 9 "nvme_sanitize_nvm" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_sanitize_nvm \- Start a sanitize operation
.SH SYNOPSIS
diff --git a/doc/man/nvme_sanitize_sanact.2 b/doc/man/nvme_sanitize_sanact.2
index 9a37206..959c06b 100644
--- a/doc/man/nvme_sanitize_sanact.2
+++ b/doc/man/nvme_sanitize_sanact.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_sanitize_sanact" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_sanitize_sanact" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_sanitize_sanact \- Sanitize Action
.SH SYNOPSIS
diff --git a/doc/man/nvme_sanitize_sstat.2 b/doc/man/nvme_sanitize_sstat.2
index 15eb25e..3cbafb9 100644
--- a/doc/man/nvme_sanitize_sstat.2
+++ b/doc/man/nvme_sanitize_sstat.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_sanitize_sstat" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_sanitize_sstat" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_sanitize_sstat \- Sanitize Status (SSTAT)
.SH SYNOPSIS
diff --git a/doc/man/nvme_sanitize_start_event.2 b/doc/man/nvme_sanitize_start_event.2
index e80dbcf..1ddcba9 100644
--- a/doc/man/nvme_sanitize_start_event.2
+++ b/doc/man/nvme_sanitize_start_event.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_sanitize_start_event" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_sanitize_start_event" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_sanitize_start_event \- Sanitize Start Event Data
.SH SYNOPSIS
diff --git a/doc/man/nvme_scan.2 b/doc/man/nvme_scan.2
index 0d51726..6aeaa99 100644
--- a/doc/man/nvme_scan.2
+++ b/doc/man/nvme_scan.2
@@ -1,4 +1,4 @@
-.TH "nvme_scan" 9 "nvme_scan" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_scan" 9 "nvme_scan" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_scan \- Scan NVMe topology
.SH SYNOPSIS
diff --git a/doc/man/nvme_scan_ctrl.2 b/doc/man/nvme_scan_ctrl.2
index b3c4363..598618f 100644
--- a/doc/man/nvme_scan_ctrl.2
+++ b/doc/man/nvme_scan_ctrl.2
@@ -1,4 +1,4 @@
-.TH "nvme_scan_ctrl" 9 "nvme_scan_ctrl" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_scan_ctrl" 9 "nvme_scan_ctrl" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_scan_ctrl \- Scan on a controller
.SH SYNOPSIS
diff --git a/doc/man/nvme_scan_ctrl_namespace_paths.2 b/doc/man/nvme_scan_ctrl_namespace_paths.2
index 950c429..b1cf3e9 100644
--- a/doc/man/nvme_scan_ctrl_namespace_paths.2
+++ b/doc/man/nvme_scan_ctrl_namespace_paths.2
@@ -1,4 +1,4 @@
-.TH "nvme_scan_ctrl_namespace_paths" 9 "nvme_scan_ctrl_namespace_paths" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_scan_ctrl_namespace_paths" 9 "nvme_scan_ctrl_namespace_paths" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_scan_ctrl_namespace_paths \- Scan for namespace paths in a controller
.SH SYNOPSIS
diff --git a/doc/man/nvme_scan_ctrl_namespaces.2 b/doc/man/nvme_scan_ctrl_namespaces.2
index ea73d72..d3d2fa8 100644
--- a/doc/man/nvme_scan_ctrl_namespaces.2
+++ b/doc/man/nvme_scan_ctrl_namespaces.2
@@ -1,4 +1,4 @@
-.TH "nvme_scan_ctrl_namespaces" 9 "nvme_scan_ctrl_namespaces" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_scan_ctrl_namespaces" 9 "nvme_scan_ctrl_namespaces" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_scan_ctrl_namespaces \- Scan for namespaces in a controller
.SH SYNOPSIS
diff --git a/doc/man/nvme_scan_ctrls.2 b/doc/man/nvme_scan_ctrls.2
index 43bc789..6da462e 100644
--- a/doc/man/nvme_scan_ctrls.2
+++ b/doc/man/nvme_scan_ctrls.2
@@ -1,4 +1,4 @@
-.TH "nvme_scan_ctrls" 9 "nvme_scan_ctrls" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_scan_ctrls" 9 "nvme_scan_ctrls" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_scan_ctrls \- Scan for controllers
.SH SYNOPSIS
diff --git a/doc/man/nvme_scan_namespace.2 b/doc/man/nvme_scan_namespace.2
index b5ca690..7933bf9 100644
--- a/doc/man/nvme_scan_namespace.2
+++ b/doc/man/nvme_scan_namespace.2
@@ -1,4 +1,4 @@
-.TH "nvme_scan_namespace" 9 "nvme_scan_namespace" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_scan_namespace" 9 "nvme_scan_namespace" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_scan_namespace \- scan namespace based on sysfs name
.SH SYNOPSIS
diff --git a/doc/man/nvme_scan_subsystem_namespaces.2 b/doc/man/nvme_scan_subsystem_namespaces.2
index ad74f8a..66d1ae3 100644
--- a/doc/man/nvme_scan_subsystem_namespaces.2
+++ b/doc/man/nvme_scan_subsystem_namespaces.2
@@ -1,4 +1,4 @@
-.TH "nvme_scan_subsystem_namespaces" 9 "nvme_scan_subsystem_namespaces" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_scan_subsystem_namespaces" 9 "nvme_scan_subsystem_namespaces" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_scan_subsystem_namespaces \- Scan for namespaces in a subsystem
.SH SYNOPSIS
diff --git a/doc/man/nvme_scan_subsystems.2 b/doc/man/nvme_scan_subsystems.2
index 794caf8..10f04e4 100644
--- a/doc/man/nvme_scan_subsystems.2
+++ b/doc/man/nvme_scan_subsystems.2
@@ -1,4 +1,4 @@
-.TH "nvme_scan_subsystems" 9 "nvme_scan_subsystems" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_scan_subsystems" 9 "nvme_scan_subsystems" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_scan_subsystems \- Scan for subsystems
.SH SYNOPSIS
diff --git a/doc/man/nvme_scan_topology.2 b/doc/man/nvme_scan_topology.2
index 4cd6bf7..965c9f4 100644
--- a/doc/man/nvme_scan_topology.2
+++ b/doc/man/nvme_scan_topology.2
@@ -1,4 +1,4 @@
-.TH "nvme_scan_topology" 9 "nvme_scan_topology" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_scan_topology" 9 "nvme_scan_topology" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_scan_topology \- Scan NVMe topology and apply filter
.SH SYNOPSIS
diff --git a/doc/man/nvme_secondary_ctrl.2 b/doc/man/nvme_secondary_ctrl.2
index 91516a4..b77bbce 100644
--- a/doc/man/nvme_secondary_ctrl.2
+++ b/doc/man/nvme_secondary_ctrl.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_secondary_ctrl" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_secondary_ctrl" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_secondary_ctrl \- Secondary Controller Entry
.SH SYNOPSIS
diff --git a/doc/man/nvme_secondary_ctrl_list.2 b/doc/man/nvme_secondary_ctrl_list.2
index 1a67f7a..28fb948 100644
--- a/doc/man/nvme_secondary_ctrl_list.2
+++ b/doc/man/nvme_secondary_ctrl_list.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_secondary_ctrl_list" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_secondary_ctrl_list" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_secondary_ctrl_list \- Secondary Controller List
.SH SYNOPSIS
diff --git a/doc/man/nvme_security_receive.2 b/doc/man/nvme_security_receive.2
index cbbb0af..2e4a53f 100644
--- a/doc/man/nvme_security_receive.2
+++ b/doc/man/nvme_security_receive.2
@@ -1,4 +1,4 @@
-.TH "nvme_security_receive" 9 "nvme_security_receive" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_security_receive" 9 "nvme_security_receive" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_security_receive \- Security Receive command
.SH SYNOPSIS
diff --git a/doc/man/nvme_security_send.2 b/doc/man/nvme_security_send.2
index dc889d6..4507c27 100644
--- a/doc/man/nvme_security_send.2
+++ b/doc/man/nvme_security_send.2
@@ -1,4 +1,4 @@
-.TH "nvme_security_send" 9 "nvme_security_send" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_security_send" 9 "nvme_security_send" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_security_send \- Security Send command
.SH SYNOPSIS
diff --git a/doc/man/nvme_self_test_log.2 b/doc/man/nvme_self_test_log.2
index 2117bb5..75466bf 100644
--- a/doc/man/nvme_self_test_log.2
+++ b/doc/man/nvme_self_test_log.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_self_test_log" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_self_test_log" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_self_test_log \- Device Self-test (Log Identifier 06h)
.SH SYNOPSIS
diff --git a/doc/man/nvme_set_feature_event.2 b/doc/man/nvme_set_feature_event.2
index 56e950f..3416e73 100644
--- a/doc/man/nvme_set_feature_event.2
+++ b/doc/man/nvme_set_feature_event.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_set_feature_event" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_set_feature_event" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_set_feature_event \- Set Feature Event Data
.SH SYNOPSIS
diff --git a/doc/man/nvme_set_features.2 b/doc/man/nvme_set_features.2
index f7d4afc..76ab6f9 100644
--- a/doc/man/nvme_set_features.2
+++ b/doc/man/nvme_set_features.2
@@ -1,4 +1,4 @@
-.TH "nvme_set_features" 9 "nvme_set_features" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_set_features" 9 "nvme_set_features" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_set_features \- Set a feature attribute
.SH SYNOPSIS
diff --git a/doc/man/nvme_set_features_arbitration.2 b/doc/man/nvme_set_features_arbitration.2
index 6b0d504..4146f7e 100644
--- a/doc/man/nvme_set_features_arbitration.2
+++ b/doc/man/nvme_set_features_arbitration.2
@@ -1,4 +1,4 @@
-.TH "nvme_set_features_arbitration" 9 "nvme_set_features_arbitration" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_set_features_arbitration" 9 "nvme_set_features_arbitration" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_set_features_arbitration \- Set arbitration features
.SH SYNOPSIS
diff --git a/doc/man/nvme_set_features_async_event.2 b/doc/man/nvme_set_features_async_event.2
index b9e365b..4e43de4 100644
--- a/doc/man/nvme_set_features_async_event.2
+++ b/doc/man/nvme_set_features_async_event.2
@@ -1,4 +1,4 @@
-.TH "nvme_set_features_async_event" 9 "nvme_set_features_async_event" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_set_features_async_event" 9 "nvme_set_features_async_event" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_set_features_async_event \- Set asynchronous event feature
.SH SYNOPSIS
diff --git a/doc/man/nvme_set_features_auto_pst.2 b/doc/man/nvme_set_features_auto_pst.2
index d983f6b..a533cad 100644
--- a/doc/man/nvme_set_features_auto_pst.2
+++ b/doc/man/nvme_set_features_auto_pst.2
@@ -1,4 +1,4 @@
-.TH "nvme_set_features_auto_pst" 9 "nvme_set_features_auto_pst" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_set_features_auto_pst" 9 "nvme_set_features_auto_pst" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_set_features_auto_pst \- Set autonomous power state feature
.SH SYNOPSIS
diff --git a/doc/man/nvme_set_features_data.2 b/doc/man/nvme_set_features_data.2
index 6723d92..ac662b6 100644
--- a/doc/man/nvme_set_features_data.2
+++ b/doc/man/nvme_set_features_data.2
@@ -1,4 +1,4 @@
-.TH "nvme_set_features_data" 9 "nvme_set_features_data" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_set_features_data" 9 "nvme_set_features_data" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_set_features_data \- Helper function for @nvme_set_features()
.SH SYNOPSIS
diff --git a/doc/man/nvme_set_features_endurance_evt_cfg.2 b/doc/man/nvme_set_features_endurance_evt_cfg.2
index d2e319a..4a998c3 100644
--- a/doc/man/nvme_set_features_endurance_evt_cfg.2
+++ b/doc/man/nvme_set_features_endurance_evt_cfg.2
@@ -1,4 +1,4 @@
-.TH "nvme_set_features_endurance_evt_cfg" 9 "nvme_set_features_endurance_evt_cfg" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_set_features_endurance_evt_cfg" 9 "nvme_set_features_endurance_evt_cfg" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_set_features_endurance_evt_cfg \- Set endurance event config feature
.SH SYNOPSIS
diff --git a/doc/man/nvme_set_features_err_recovery.2 b/doc/man/nvme_set_features_err_recovery.2
index 2cac43a..3bc82e9 100644
--- a/doc/man/nvme_set_features_err_recovery.2
+++ b/doc/man/nvme_set_features_err_recovery.2
@@ -1,4 +1,4 @@
-.TH "nvme_set_features_err_recovery" 9 "nvme_set_features_err_recovery" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_set_features_err_recovery" 9 "nvme_set_features_err_recovery" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_set_features_err_recovery \- Set error recovery feature
.SH SYNOPSIS
diff --git a/doc/man/nvme_set_features_hctm.2 b/doc/man/nvme_set_features_hctm.2
index 310a987..b8e539d 100644
--- a/doc/man/nvme_set_features_hctm.2
+++ b/doc/man/nvme_set_features_hctm.2
@@ -1,4 +1,4 @@
-.TH "nvme_set_features_hctm" 9 "nvme_set_features_hctm" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_set_features_hctm" 9 "nvme_set_features_hctm" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_set_features_hctm \- Set thermal management feature
.SH SYNOPSIS
diff --git a/doc/man/nvme_set_features_host_behavior.2 b/doc/man/nvme_set_features_host_behavior.2
index 995905b..dae2c71 100644
--- a/doc/man/nvme_set_features_host_behavior.2
+++ b/doc/man/nvme_set_features_host_behavior.2
@@ -1,4 +1,4 @@
-.TH "nvme_set_features_host_behavior" 9 "nvme_set_features_host_behavior" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_set_features_host_behavior" 9 "nvme_set_features_host_behavior" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_set_features_host_behavior \- Set host behavior feature
.SH SYNOPSIS
diff --git a/doc/man/nvme_set_features_host_id.2 b/doc/man/nvme_set_features_host_id.2
index f548497..d829ab8 100644
--- a/doc/man/nvme_set_features_host_id.2
+++ b/doc/man/nvme_set_features_host_id.2
@@ -1,4 +1,4 @@
-.TH "nvme_set_features_host_id" 9 "nvme_set_features_host_id" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_set_features_host_id" 9 "nvme_set_features_host_id" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_set_features_host_id \- Set enable extended host identifiers feature
.SH SYNOPSIS
diff --git a/doc/man/nvme_set_features_iocs_profile.2 b/doc/man/nvme_set_features_iocs_profile.2
new file mode 100644
index 0000000..d550bb3
--- /dev/null
+++ b/doc/man/nvme_set_features_iocs_profile.2
@@ -0,0 +1,18 @@
+.TH "nvme_set_features_iocs_profile" 9 "nvme_set_features_iocs_profile" "December 2023" "libnvme API manual" LINUX
+.SH NAME
+nvme_set_features_iocs_profile \- Set I/O command set profile feature
+.SH SYNOPSIS
+.B "int" nvme_set_features_iocs_profile
+.BI "(int fd " ","
+.BI "__u16 iocsi " ","
+.BI "bool save " ");"
+.SH ARGUMENTS
+.IP "fd" 12
+File descriptor of nvme device
+.IP "iocsi" 12
+I/O Command Set Combination Index
+.IP "save" 12
+Save value across power states
+.SH "RETURN"
+The nvme command status if a response was received (see
+\fIenum nvme_status_field\fP) or -1 with errno set otherwise.
diff --git a/doc/man/nvme_set_features_irq_coalesce.2 b/doc/man/nvme_set_features_irq_coalesce.2
index 89a57dc..d1fbfe6 100644
--- a/doc/man/nvme_set_features_irq_coalesce.2
+++ b/doc/man/nvme_set_features_irq_coalesce.2
@@ -1,4 +1,4 @@
-.TH "nvme_set_features_irq_coalesce" 9 "nvme_set_features_irq_coalesce" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_set_features_irq_coalesce" 9 "nvme_set_features_irq_coalesce" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_set_features_irq_coalesce \- Set IRQ coalesce feature
.SH SYNOPSIS
diff --git a/doc/man/nvme_set_features_irq_config.2 b/doc/man/nvme_set_features_irq_config.2
index 80c2e17..8a12acd 100644
--- a/doc/man/nvme_set_features_irq_config.2
+++ b/doc/man/nvme_set_features_irq_config.2
@@ -1,4 +1,4 @@
-.TH "nvme_set_features_irq_config" 9 "nvme_set_features_irq_config" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_set_features_irq_config" 9 "nvme_set_features_irq_config" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_set_features_irq_config \- Set IRQ config feature
.SH SYNOPSIS
diff --git a/doc/man/nvme_set_features_lba_range.2 b/doc/man/nvme_set_features_lba_range.2
index 133afe2..ea4b77a 100644
--- a/doc/man/nvme_set_features_lba_range.2
+++ b/doc/man/nvme_set_features_lba_range.2
@@ -1,11 +1,11 @@
-.TH "nvme_set_features_lba_range" 9 "nvme_set_features_lba_range" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_set_features_lba_range" 9 "nvme_set_features_lba_range" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_set_features_lba_range \- Set LBA range feature
.SH SYNOPSIS
.B "int" nvme_set_features_lba_range
.BI "(int fd " ","
.BI "__u32 nsid " ","
-.BI "__u32 nr_ranges " ","
+.BI "__u8 nr_ranges " ","
.BI "bool save " ","
.BI "struct nvme_lba_range_type *data " ","
.BI "__u32 *result " ");"
diff --git a/doc/man/nvme_set_features_lba_sts_interval.2 b/doc/man/nvme_set_features_lba_sts_interval.2
index 4f1d1d6..48daa5e 100644
--- a/doc/man/nvme_set_features_lba_sts_interval.2
+++ b/doc/man/nvme_set_features_lba_sts_interval.2
@@ -1,4 +1,4 @@
-.TH "nvme_set_features_lba_sts_interval" 9 "nvme_set_features_lba_sts_interval" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_set_features_lba_sts_interval" 9 "nvme_set_features_lba_sts_interval" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_set_features_lba_sts_interval \- Set LBA status information feature
.SH SYNOPSIS
diff --git a/doc/man/nvme_set_features_nopsc.2 b/doc/man/nvme_set_features_nopsc.2
index 58d642c..735f45b 100644
--- a/doc/man/nvme_set_features_nopsc.2
+++ b/doc/man/nvme_set_features_nopsc.2
@@ -1,4 +1,4 @@
-.TH "nvme_set_features_nopsc" 9 "nvme_set_features_nopsc" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_set_features_nopsc" 9 "nvme_set_features_nopsc" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_set_features_nopsc \- Set non-operational power state feature
.SH SYNOPSIS
diff --git a/doc/man/nvme_set_features_plm_config.2 b/doc/man/nvme_set_features_plm_config.2
index 637c071..df6361d 100644
--- a/doc/man/nvme_set_features_plm_config.2
+++ b/doc/man/nvme_set_features_plm_config.2
@@ -1,4 +1,4 @@
-.TH "nvme_set_features_plm_config" 9 "nvme_set_features_plm_config" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_set_features_plm_config" 9 "nvme_set_features_plm_config" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_set_features_plm_config \- Set predictable latency feature
.SH SYNOPSIS
diff --git a/doc/man/nvme_set_features_plm_window.2 b/doc/man/nvme_set_features_plm_window.2
index 64cc02c..9a3c278 100644
--- a/doc/man/nvme_set_features_plm_window.2
+++ b/doc/man/nvme_set_features_plm_window.2
@@ -1,4 +1,4 @@
-.TH "nvme_set_features_plm_window" 9 "nvme_set_features_plm_window" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_set_features_plm_window" 9 "nvme_set_features_plm_window" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_set_features_plm_window \- Set window select feature
.SH SYNOPSIS
diff --git a/doc/man/nvme_set_features_power_mgmt.2 b/doc/man/nvme_set_features_power_mgmt.2
index 51d6671..928bf13 100644
--- a/doc/man/nvme_set_features_power_mgmt.2
+++ b/doc/man/nvme_set_features_power_mgmt.2
@@ -1,4 +1,4 @@
-.TH "nvme_set_features_power_mgmt" 9 "nvme_set_features_power_mgmt" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_set_features_power_mgmt" 9 "nvme_set_features_power_mgmt" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_set_features_power_mgmt \- Set power management feature
.SH SYNOPSIS
diff --git a/doc/man/nvme_set_features_resv_mask.2 b/doc/man/nvme_set_features_resv_mask.2
index 395a42e..38c2d8f 100644
--- a/doc/man/nvme_set_features_resv_mask.2
+++ b/doc/man/nvme_set_features_resv_mask.2
@@ -1,4 +1,4 @@
-.TH "nvme_set_features_resv_mask" 9 "nvme_set_features_resv_mask" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_set_features_resv_mask" 9 "nvme_set_features_resv_mask" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_set_features_resv_mask \- Set reservation notification mask feature
.SH SYNOPSIS
@@ -16,6 +16,10 @@ Reservation Notification Mask Field
Save value across power states
.IP "result" 12
The command completion result from CQE dword0
+.SH "DESCRIPTION"
+
+Deprecated: doesn't support specifying a NSID.
+Use \fBnvme_set_features_resv_mask2\fP instead.
.SH "RETURN"
The nvme command status if a response was received (see
\fIenum nvme_status_field\fP) or -1 with errno set otherwise.
diff --git a/doc/man/nvme_set_features_resv_mask2.2 b/doc/man/nvme_set_features_resv_mask2.2
new file mode 100644
index 0000000..ea42407
--- /dev/null
+++ b/doc/man/nvme_set_features_resv_mask2.2
@@ -0,0 +1,24 @@
+.TH "nvme_set_features_resv_mask2" 9 "nvme_set_features_resv_mask2" "December 2023" "libnvme API manual" LINUX
+.SH NAME
+nvme_set_features_resv_mask2 \- Set reservation notification mask feature
+.SH SYNOPSIS
+.B "int" nvme_set_features_resv_mask2
+.BI "(int fd " ","
+.BI "__u32 nsid " ","
+.BI "__u32 mask " ","
+.BI "bool save " ","
+.BI "__u32 *result " ");"
+.SH ARGUMENTS
+.IP "fd" 12
+File descriptor of nvme device
+.IP "nsid" 12
+Namespace ID
+.IP "mask" 12
+Reservation Notification Mask Field
+.IP "save" 12
+Save value across power states
+.IP "result" 12
+The command completion result from CQE dword0
+.SH "RETURN"
+The nvme command status if a response was received (see
+\fIenum nvme_status_field\fP) or -1 with errno set otherwise.
diff --git a/doc/man/nvme_set_features_resv_persist.2 b/doc/man/nvme_set_features_resv_persist.2
index d83f670..19a3b9f 100644
--- a/doc/man/nvme_set_features_resv_persist.2
+++ b/doc/man/nvme_set_features_resv_persist.2
@@ -1,4 +1,4 @@
-.TH "nvme_set_features_resv_persist" 9 "nvme_set_features_resv_persist" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_set_features_resv_persist" 9 "nvme_set_features_resv_persist" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_set_features_resv_persist \- Set persist through power loss feature
.SH SYNOPSIS
@@ -16,6 +16,10 @@ Persist Through Power Loss
Save value across power states
.IP "result" 12
The command completion result from CQE dword0
+.SH "DESCRIPTION"
+
+Deprecated: doesn't support specifying a NSID.
+Use \fBnvme_set_features_resv_persist2\fP instead.
.SH "RETURN"
The nvme command status if a response was received (see
\fIenum nvme_status_field\fP) or -1 with errno set otherwise.
diff --git a/doc/man/nvme_set_features_resv_persist2.2 b/doc/man/nvme_set_features_resv_persist2.2
new file mode 100644
index 0000000..d781a1e
--- /dev/null
+++ b/doc/man/nvme_set_features_resv_persist2.2
@@ -0,0 +1,24 @@
+.TH "nvme_set_features_resv_persist2" 9 "nvme_set_features_resv_persist2" "December 2023" "libnvme API manual" LINUX
+.SH NAME
+nvme_set_features_resv_persist2 \- Set persist through power loss feature
+.SH SYNOPSIS
+.B "int" nvme_set_features_resv_persist2
+.BI "(int fd " ","
+.BI "__u32 nsid " ","
+.BI "bool ptpl " ","
+.BI "bool save " ","
+.BI "__u32 *result " ");"
+.SH ARGUMENTS
+.IP "fd" 12
+File descriptor of nvme device
+.IP "nsid" 12
+Namespace ID
+.IP "ptpl" 12
+Persist Through Power Loss
+.IP "save" 12
+Save value across power states
+.IP "result" 12
+The command completion result from CQE dword0
+.SH "RETURN"
+The nvme command status if a response was received (see
+\fIenum nvme_status_field\fP) or -1 with errno set otherwise.
diff --git a/doc/man/nvme_set_features_rrl.2 b/doc/man/nvme_set_features_rrl.2
index 736e272..f159bc4 100644
--- a/doc/man/nvme_set_features_rrl.2
+++ b/doc/man/nvme_set_features_rrl.2
@@ -1,4 +1,4 @@
-.TH "nvme_set_features_rrl" 9 "nvme_set_features_rrl" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_set_features_rrl" 9 "nvme_set_features_rrl" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_set_features_rrl \- Set read recovery level feature
.SH SYNOPSIS
diff --git a/doc/man/nvme_set_features_sanitize.2 b/doc/man/nvme_set_features_sanitize.2
index 7904355..5beb10c 100644
--- a/doc/man/nvme_set_features_sanitize.2
+++ b/doc/man/nvme_set_features_sanitize.2
@@ -1,4 +1,4 @@
-.TH "nvme_set_features_sanitize" 9 "nvme_set_features_sanitize" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_set_features_sanitize" 9 "nvme_set_features_sanitize" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_set_features_sanitize \- Set sanitize feature
.SH SYNOPSIS
diff --git a/doc/man/nvme_set_features_simple.2 b/doc/man/nvme_set_features_simple.2
index 288272c..902fa6e 100644
--- a/doc/man/nvme_set_features_simple.2
+++ b/doc/man/nvme_set_features_simple.2
@@ -1,4 +1,4 @@
-.TH "nvme_set_features_simple" 9 "nvme_set_features_simple" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_set_features_simple" 9 "nvme_set_features_simple" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_set_features_simple \- Helper function for @nvme_set_features()
.SH SYNOPSIS
diff --git a/doc/man/nvme_set_features_sw_progress.2 b/doc/man/nvme_set_features_sw_progress.2
index 8ce8ece..4190650 100644
--- a/doc/man/nvme_set_features_sw_progress.2
+++ b/doc/man/nvme_set_features_sw_progress.2
@@ -1,4 +1,4 @@
-.TH "nvme_set_features_sw_progress" 9 "nvme_set_features_sw_progress" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_set_features_sw_progress" 9 "nvme_set_features_sw_progress" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_set_features_sw_progress \- Set pre-boot software load count feature
.SH SYNOPSIS
diff --git a/doc/man/nvme_set_features_temp_thresh.2 b/doc/man/nvme_set_features_temp_thresh.2
index c91b1af..28555da 100644
--- a/doc/man/nvme_set_features_temp_thresh.2
+++ b/doc/man/nvme_set_features_temp_thresh.2
@@ -1,4 +1,4 @@
-.TH "nvme_set_features_temp_thresh" 9 "nvme_set_features_temp_thresh" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_set_features_temp_thresh" 9 "nvme_set_features_temp_thresh" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_set_features_temp_thresh \- Set temperature threshold feature
.SH SYNOPSIS
diff --git a/doc/man/nvme_set_features_timestamp.2 b/doc/man/nvme_set_features_timestamp.2
index 33b06bc..6f3608e 100644
--- a/doc/man/nvme_set_features_timestamp.2
+++ b/doc/man/nvme_set_features_timestamp.2
@@ -1,4 +1,4 @@
-.TH "nvme_set_features_timestamp" 9 "nvme_set_features_timestamp" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_set_features_timestamp" 9 "nvme_set_features_timestamp" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_set_features_timestamp \- Set timestamp feature
.SH SYNOPSIS
diff --git a/doc/man/nvme_set_features_volatile_wc.2 b/doc/man/nvme_set_features_volatile_wc.2
index 415f3f1..d100d8b 100644
--- a/doc/man/nvme_set_features_volatile_wc.2
+++ b/doc/man/nvme_set_features_volatile_wc.2
@@ -1,4 +1,4 @@
-.TH "nvme_set_features_volatile_wc" 9 "nvme_set_features_volatile_wc" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_set_features_volatile_wc" 9 "nvme_set_features_volatile_wc" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_set_features_volatile_wc \- Set volatile write cache feature
.SH SYNOPSIS
diff --git a/doc/man/nvme_set_features_write_atomic.2 b/doc/man/nvme_set_features_write_atomic.2
index 4f9f691..a773bc1 100644
--- a/doc/man/nvme_set_features_write_atomic.2
+++ b/doc/man/nvme_set_features_write_atomic.2
@@ -1,4 +1,4 @@
-.TH "nvme_set_features_write_atomic" 9 "nvme_set_features_write_atomic" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_set_features_write_atomic" 9 "nvme_set_features_write_atomic" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_set_features_write_atomic \- Set write atomic feature
.SH SYNOPSIS
diff --git a/doc/man/nvme_set_features_write_protect.2 b/doc/man/nvme_set_features_write_protect.2
index aff3417..fbb0709 100644
--- a/doc/man/nvme_set_features_write_protect.2
+++ b/doc/man/nvme_set_features_write_protect.2
@@ -1,4 +1,4 @@
-.TH "nvme_set_features_write_protect" 9 "nvme_set_features_write_protect" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_set_features_write_protect" 9 "nvme_set_features_write_protect" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_set_features_write_protect \- Set write protect feature
.SH SYNOPSIS
@@ -16,6 +16,10 @@ Write Protection State
Save value across power states
.IP "result" 12
The command completion result from CQE dword0
+.SH "DESCRIPTION"
+
+Deprecated: doesn't support specifying a NSID.
+Use \fBnvme_set_features_write_protect2\fP instead.
.SH "RETURN"
The nvme command status if a response was received (see
\fIenum nvme_status_field\fP) or -1 with errno set otherwise.
diff --git a/doc/man/nvme_set_features_write_protect2.2 b/doc/man/nvme_set_features_write_protect2.2
new file mode 100644
index 0000000..178afdd
--- /dev/null
+++ b/doc/man/nvme_set_features_write_protect2.2
@@ -0,0 +1,24 @@
+.TH "nvme_set_features_write_protect2" 9 "nvme_set_features_write_protect2" "December 2023" "libnvme API manual" LINUX
+.SH NAME
+nvme_set_features_write_protect2 \- Set write protect feature
+.SH SYNOPSIS
+.B "int" nvme_set_features_write_protect2
+.BI "(int fd " ","
+.BI "__u32 nsid " ","
+.BI "enum nvme_feat_nswpcfg_state state " ","
+.BI "bool save " ","
+.BI "__u32 *result " ");"
+.SH ARGUMENTS
+.IP "fd" 12
+File descriptor of nvme device
+.IP "nsid" 12
+Namespace ID
+.IP "state" 12
+Write Protection State
+.IP "save" 12
+Save value across power states
+.IP "result" 12
+The command completion result from CQE dword0
+.SH "RETURN"
+The nvme command status if a response was received (see
+\fIenum nvme_status_field\fP) or -1 with errno set otherwise.
diff --git a/doc/man/nvme_set_keyring.2 b/doc/man/nvme_set_keyring.2
index a2f0ca7..1d890e3 100644
--- a/doc/man/nvme_set_keyring.2
+++ b/doc/man/nvme_set_keyring.2
@@ -1,4 +1,4 @@
-.TH "nvme_set_keyring" 9 "nvme_set_keyring" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_set_keyring" 9 "nvme_set_keyring" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_set_keyring \- Link keyring for lookup
.SH SYNOPSIS
diff --git a/doc/man/nvme_set_property.2 b/doc/man/nvme_set_property.2
index febbbed..d1ed6c8 100644
--- a/doc/man/nvme_set_property.2
+++ b/doc/man/nvme_set_property.2
@@ -1,4 +1,4 @@
-.TH "nvme_set_property" 9 "nvme_set_property" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_set_property" 9 "nvme_set_property" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_set_property \- Set controller property
.SH SYNOPSIS
diff --git a/doc/man/nvme_set_root.2 b/doc/man/nvme_set_root.2
new file mode 100644
index 0000000..78ca543
--- /dev/null
+++ b/doc/man/nvme_set_root.2
@@ -0,0 +1,16 @@
+.TH "nvme_set_root" 9 "nvme_set_root" "December 2023" "libnvme API manual" LINUX
+.SH NAME
+nvme_set_root \- Set nvme_root_t context
+.SH SYNOPSIS
+.B "void" nvme_set_root
+.BI "(nvme_root_t r " ");"
+.SH ARGUMENTS
+.IP "r" 12
+nvme_root_t context
+.SH "DESCRIPTION"
+In order to be able to log from code paths where no root object is passed in
+via the arguments use the the default one which can be set via this call.
+When creating a new root object with \fInvme_create_root\fP 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 \fInvme_free_tree\fP call will reset
+the global root object.
diff --git a/doc/man/nvme_smart_crit.2 b/doc/man/nvme_smart_crit.2
index f4a034f..745bb0b 100644
--- a/doc/man/nvme_smart_crit.2
+++ b/doc/man/nvme_smart_crit.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_smart_crit" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_smart_crit" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_smart_crit \- Critical Warning
.SH SYNOPSIS
diff --git a/doc/man/nvme_smart_egcw.2 b/doc/man/nvme_smart_egcw.2
index f3399c1..f5fb16c 100644
--- a/doc/man/nvme_smart_egcw.2
+++ b/doc/man/nvme_smart_egcw.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_smart_egcw" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_smart_egcw" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_smart_egcw \- Endurance Group Critical Warning Summary
.SH SYNOPSIS
diff --git a/doc/man/nvme_smart_log.2 b/doc/man/nvme_smart_log.2
index b2a80ee..ed19172 100644
--- a/doc/man/nvme_smart_log.2
+++ b/doc/man/nvme_smart_log.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_smart_log" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_smart_log" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_smart_log \- SMART / Health Information Log (Log Identifier 02h)
.SH SYNOPSIS
diff --git a/doc/man/nvme_st_code.2 b/doc/man/nvme_st_code.2
index bac55dc..227ffb8 100644
--- a/doc/man/nvme_st_code.2
+++ b/doc/man/nvme_st_code.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_st_code" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_st_code" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_st_code \- Self-test Code value
.SH SYNOPSIS
diff --git a/doc/man/nvme_st_curr_op.2 b/doc/man/nvme_st_curr_op.2
index 3c10880..f1782cf 100644
--- a/doc/man/nvme_st_curr_op.2
+++ b/doc/man/nvme_st_curr_op.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_st_curr_op" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_st_curr_op" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_st_curr_op \- Current Device Self-Test Operation
.SH SYNOPSIS
diff --git a/doc/man/nvme_st_result.2 b/doc/man/nvme_st_result.2
index e787d09..db515dd 100644
--- a/doc/man/nvme_st_result.2
+++ b/doc/man/nvme_st_result.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_st_result" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_st_result" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_st_result \- Self-test Result
.SH SYNOPSIS
diff --git a/doc/man/nvme_st_valid_diag_info.2 b/doc/man/nvme_st_valid_diag_info.2
index 174aaa3..5c8227e 100644
--- a/doc/man/nvme_st_valid_diag_info.2
+++ b/doc/man/nvme_st_valid_diag_info.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_st_valid_diag_info" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_st_valid_diag_info" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_st_valid_diag_info \- Valid Diagnostic Information
.SH SYNOPSIS
diff --git a/doc/man/nvme_status_code.2 b/doc/man/nvme_status_code.2
index 08d3ada..8d12ed7 100644
--- a/doc/man/nvme_status_code.2
+++ b/doc/man/nvme_status_code.2
@@ -1,4 +1,4 @@
-.TH "nvme_status_code" 9 "nvme_status_code" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_status_code" 9 "nvme_status_code" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_status_code \- Returns the NVMe Status Code
.SH SYNOPSIS
diff --git a/doc/man/nvme_status_code_type.2 b/doc/man/nvme_status_code_type.2
index 29a3631..cecfdc1 100644
--- a/doc/man/nvme_status_code_type.2
+++ b/doc/man/nvme_status_code_type.2
@@ -1,4 +1,4 @@
-.TH "nvme_status_code_type" 9 "nvme_status_code_type" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_status_code_type" 9 "nvme_status_code_type" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_status_code_type \- Returns the NVMe Status Code Type
.SH SYNOPSIS
diff --git a/doc/man/nvme_status_equals.2 b/doc/man/nvme_status_equals.2
index e46df00..468c602 100644
--- a/doc/man/nvme_status_equals.2
+++ b/doc/man/nvme_status_equals.2
@@ -1,4 +1,4 @@
-.TH "nvme_status_equals" 9 "nvme_status_equals" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_status_equals" 9 "nvme_status_equals" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_status_equals \- helper to check a status against a type and value
.SH SYNOPSIS
diff --git a/doc/man/nvme_status_field.2 b/doc/man/nvme_status_field.2
index 4f6d3ae..55a6c63 100644
--- a/doc/man/nvme_status_field.2
+++ b/doc/man/nvme_status_field.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_status_field" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_status_field" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_status_field \- Defines all parts of the nvme status field: status code, status code type, and additional flags.
.SH SYNOPSIS
@@ -432,6 +432,22 @@ enum nvme_status_field {
,
.br
.br
+.BI " NVME_SC_INCOMPATIBLE_NS"
+,
+.br
+.br
+.BI " NVME_SC_FAST_COPY_NOT_POSSIBLE"
+,
+.br
+.br
+.BI " NVME_SC_OVERLAPPING_IO_RANGE"
+,
+.br
+.br
+.BI " NVME_SC_INSUFFICIENT_RESOURCES"
+,
+.br
+.br
.BI " NVME_SC_CONNECT_FORMAT"
,
.br
@@ -1027,6 +1043,25 @@ Invalid Protection Information
Attempted Write to Read Only Range
.IP "NVME_SC_CMD_SIZE_LIMIT_EXCEEDED" 12
Command Size Limit Exceeded
+.IP "NVME_SC_INCOMPATIBLE_NS" 12
+Incompatible Namespace or Format: At
+least one source namespace and the
+destination namespace have incompatible
+formats.
+.IP "NVME_SC_FAST_COPY_NOT_POSSIBLE" 12
+Fast Copy Not Possible: The Fast Copy
+Only (FCO) bit was set to ‘1’ in a Source
+Range entry and the controller was not
+able to use fast copy operations to copy
+the specified data.
+.IP "NVME_SC_OVERLAPPING_IO_RANGE" 12
+Overlapping I/O Range: A source logical
+block range overlaps the destination
+logical block range.
+.IP "NVME_SC_INSUFFICIENT_RESOURCES" 12
+Insufficient Resources: A resource
+shortage prevented the controller from
+performing the requested copy.
.IP "NVME_SC_CONNECT_FORMAT" 12
Incompatible Format: The NVM subsystem
does not support the record format
diff --git a/doc/man/nvme_status_get_type.2 b/doc/man/nvme_status_get_type.2
index ded575d..6f575b4 100644
--- a/doc/man/nvme_status_get_type.2
+++ b/doc/man/nvme_status_get_type.2
@@ -1,4 +1,4 @@
-.TH "nvme_status_get_type" 9 "nvme_status_get_type" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_status_get_type" 9 "nvme_status_get_type" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_status_get_type \- extract the type from a nvme_* return value
.SH SYNOPSIS
diff --git a/doc/man/nvme_status_get_value.2 b/doc/man/nvme_status_get_value.2
index db09890..dd61f63 100644
--- a/doc/man/nvme_status_get_value.2
+++ b/doc/man/nvme_status_get_value.2
@@ -1,4 +1,4 @@
-.TH "nvme_status_get_value" 9 "nvme_status_get_value" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_status_get_value" 9 "nvme_status_get_value" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_status_get_value \- extract the status value from a nvme_* return value
.SH SYNOPSIS
diff --git a/doc/man/nvme_status_result.2 b/doc/man/nvme_status_result.2
index 55170ba..4758fe9 100644
--- a/doc/man/nvme_status_result.2
+++ b/doc/man/nvme_status_result.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_status_result" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_status_result" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_status_result \- Result of the device self-test operation
.SH SYNOPSIS
diff --git a/doc/man/nvme_status_to_errno.2 b/doc/man/nvme_status_to_errno.2
index e1f4c7c..5d418ff 100644
--- a/doc/man/nvme_status_to_errno.2
+++ b/doc/man/nvme_status_to_errno.2
@@ -1,4 +1,4 @@
-.TH "nvme_status_to_errno" 9 "nvme_status_to_errno" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_status_to_errno" 9 "nvme_status_to_errno" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_status_to_errno \- Converts nvme return status to errno
.SH SYNOPSIS
diff --git a/doc/man/nvme_status_to_string.2 b/doc/man/nvme_status_to_string.2
index f6d33da..b16f533 100644
--- a/doc/man/nvme_status_to_string.2
+++ b/doc/man/nvme_status_to_string.2
@@ -1,4 +1,4 @@
-.TH "nvme_status_to_string" 9 "nvme_status_to_string" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_status_to_string" 9 "nvme_status_to_string" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_status_to_string \- Returns string describing nvme return status.
.SH SYNOPSIS
diff --git a/doc/man/nvme_status_type.2 b/doc/man/nvme_status_type.2
index fa128ab..86e5bfe 100644
--- a/doc/man/nvme_status_type.2
+++ b/doc/man/nvme_status_type.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_status_type" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_status_type" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_status_type \- type encoding for NVMe return values, when represented as an int.
.SH SYNOPSIS
diff --git a/doc/man/nvme_streams_directive_params.2 b/doc/man/nvme_streams_directive_params.2
index 624ed47..57c0d20 100644
--- a/doc/man/nvme_streams_directive_params.2
+++ b/doc/man/nvme_streams_directive_params.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_streams_directive_params" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_streams_directive_params" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_streams_directive_params \- Streams Directive - Return Parameters Data Structure
.SH SYNOPSIS
diff --git a/doc/man/nvme_streams_directive_status.2 b/doc/man/nvme_streams_directive_status.2
index 4a4bbe0..f62e35b 100644
--- a/doc/man/nvme_streams_directive_status.2
+++ b/doc/man/nvme_streams_directive_status.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_streams_directive_status" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_streams_directive_status" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_streams_directive_status \- Streams Directive - Get Status Data Structure
.SH SYNOPSIS
diff --git a/doc/man/nvme_submit_admin_passthru.2 b/doc/man/nvme_submit_admin_passthru.2
index b726665..63a8d6f 100644
--- a/doc/man/nvme_submit_admin_passthru.2
+++ b/doc/man/nvme_submit_admin_passthru.2
@@ -1,4 +1,4 @@
-.TH "nvme_submit_admin_passthru" 9 "nvme_submit_admin_passthru" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_submit_admin_passthru" 9 "nvme_submit_admin_passthru" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_submit_admin_passthru \- Submit an nvme passthrough admin command
.SH SYNOPSIS
diff --git a/doc/man/nvme_submit_admin_passthru64.2 b/doc/man/nvme_submit_admin_passthru64.2
index 531e1a4..e6e46ba 100644
--- a/doc/man/nvme_submit_admin_passthru64.2
+++ b/doc/man/nvme_submit_admin_passthru64.2
@@ -1,4 +1,4 @@
-.TH "nvme_submit_admin_passthru64" 9 "nvme_submit_admin_passthru64" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_submit_admin_passthru64" 9 "nvme_submit_admin_passthru64" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_submit_admin_passthru64 \- Submit a 64-bit nvme passthrough admin command
.SH SYNOPSIS
diff --git a/doc/man/nvme_submit_io_passthru.2 b/doc/man/nvme_submit_io_passthru.2
index 4e00f8d..6a1382d 100644
--- a/doc/man/nvme_submit_io_passthru.2
+++ b/doc/man/nvme_submit_io_passthru.2
@@ -1,4 +1,4 @@
-.TH "nvme_submit_io_passthru" 9 "nvme_submit_io_passthru" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_submit_io_passthru" 9 "nvme_submit_io_passthru" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_submit_io_passthru \- Submit an nvme passthrough command
.SH SYNOPSIS
diff --git a/doc/man/nvme_submit_io_passthru64.2 b/doc/man/nvme_submit_io_passthru64.2
index bc0bebf..2087713 100644
--- a/doc/man/nvme_submit_io_passthru64.2
+++ b/doc/man/nvme_submit_io_passthru64.2
@@ -1,4 +1,4 @@
-.TH "nvme_submit_io_passthru64" 9 "nvme_submit_io_passthru64" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_submit_io_passthru64" 9 "nvme_submit_io_passthru64" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_submit_io_passthru64 \- Submit a 64-bit nvme passthrough command
.SH SYNOPSIS
diff --git a/doc/man/nvme_subsys_filter.2 b/doc/man/nvme_subsys_filter.2
index 98cde4f..1777d99 100644
--- a/doc/man/nvme_subsys_filter.2
+++ b/doc/man/nvme_subsys_filter.2
@@ -1,4 +1,4 @@
-.TH "nvme_subsys_filter" 9 "nvme_subsys_filter" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_subsys_filter" 9 "nvme_subsys_filter" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_subsys_filter \- Filter for subsystems
.SH SYNOPSIS
diff --git a/doc/man/nvme_subsys_type.2 b/doc/man/nvme_subsys_type.2
index 1b149c7..9d39430 100644
--- a/doc/man/nvme_subsys_type.2
+++ b/doc/man/nvme_subsys_type.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_subsys_type" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_subsys_type" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_subsys_type \- Type of the NVM subsystem.
.SH SYNOPSIS
diff --git a/doc/man/nvme_subsystem_first_ctrl.2 b/doc/man/nvme_subsystem_first_ctrl.2
index 0e026fc..06cf810 100644
--- a/doc/man/nvme_subsystem_first_ctrl.2
+++ b/doc/man/nvme_subsystem_first_ctrl.2
@@ -1,4 +1,4 @@
-.TH "nvme_subsystem_first_ctrl" 9 "nvme_subsystem_first_ctrl" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_subsystem_first_ctrl" 9 "nvme_subsystem_first_ctrl" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_subsystem_first_ctrl \- First ctrl iterator
.SH SYNOPSIS
diff --git a/doc/man/nvme_subsystem_first_ns.2 b/doc/man/nvme_subsystem_first_ns.2
index 06b2005..86273ac 100644
--- a/doc/man/nvme_subsystem_first_ns.2
+++ b/doc/man/nvme_subsystem_first_ns.2
@@ -1,4 +1,4 @@
-.TH "nvme_subsystem_first_ns" 9 "nvme_subsystem_first_ns" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_subsystem_first_ns" 9 "nvme_subsystem_first_ns" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_subsystem_first_ns \- Start namespace iterator
.SH SYNOPSIS
diff --git a/doc/man/nvme_subsystem_for_each_ctrl.2 b/doc/man/nvme_subsystem_for_each_ctrl.2
index 0747ce4..f3461a8 100644
--- a/doc/man/nvme_subsystem_for_each_ctrl.2
+++ b/doc/man/nvme_subsystem_for_each_ctrl.2
@@ -1,4 +1,4 @@
-.TH "nvme_subsystem_for_each_ctrl" 9 "nvme_subsystem_for_each_ctrl" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_subsystem_for_each_ctrl" 9 "nvme_subsystem_for_each_ctrl" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_subsystem_for_each_ctrl \- Traverse controllers
.SH SYNOPSIS
diff --git a/doc/man/nvme_subsystem_for_each_ctrl_safe.2 b/doc/man/nvme_subsystem_for_each_ctrl_safe.2
index d8babcf..bac192c 100644
--- a/doc/man/nvme_subsystem_for_each_ctrl_safe.2
+++ b/doc/man/nvme_subsystem_for_each_ctrl_safe.2
@@ -1,4 +1,4 @@
-.TH "nvme_subsystem_for_each_ctrl_safe" 9 "nvme_subsystem_for_each_ctrl_safe" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_subsystem_for_each_ctrl_safe" 9 "nvme_subsystem_for_each_ctrl_safe" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_subsystem_for_each_ctrl_safe \- Traverse controllers
.SH SYNOPSIS
diff --git a/doc/man/nvme_subsystem_for_each_ns.2 b/doc/man/nvme_subsystem_for_each_ns.2
index 3f40473..2382674 100644
--- a/doc/man/nvme_subsystem_for_each_ns.2
+++ b/doc/man/nvme_subsystem_for_each_ns.2
@@ -1,4 +1,4 @@
-.TH "nvme_subsystem_for_each_ns" 9 "nvme_subsystem_for_each_ns" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_subsystem_for_each_ns" 9 "nvme_subsystem_for_each_ns" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_subsystem_for_each_ns \- Traverse namespaces
.SH SYNOPSIS
diff --git a/doc/man/nvme_subsystem_for_each_ns_safe.2 b/doc/man/nvme_subsystem_for_each_ns_safe.2
index 9892225..c1bd4b0 100644
--- a/doc/man/nvme_subsystem_for_each_ns_safe.2
+++ b/doc/man/nvme_subsystem_for_each_ns_safe.2
@@ -1,4 +1,4 @@
-.TH "nvme_subsystem_for_each_ns_safe" 9 "nvme_subsystem_for_each_ns_safe" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_subsystem_for_each_ns_safe" 9 "nvme_subsystem_for_each_ns_safe" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_subsystem_for_each_ns_safe \- Traverse namespaces
.SH SYNOPSIS
diff --git a/doc/man/nvme_subsystem_get_application.2 b/doc/man/nvme_subsystem_get_application.2
index e94ccf7..45f1397 100644
--- a/doc/man/nvme_subsystem_get_application.2
+++ b/doc/man/nvme_subsystem_get_application.2
@@ -1,4 +1,4 @@
-.TH "nvme_subsystem_get_application" 9 "nvme_subsystem_get_application" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_subsystem_get_application" 9 "nvme_subsystem_get_application" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_subsystem_get_application \- Return the application string
.SH SYNOPSIS
diff --git a/doc/man/nvme_subsystem_get_host.2 b/doc/man/nvme_subsystem_get_host.2
index e52a4ab..494bb79 100644
--- a/doc/man/nvme_subsystem_get_host.2
+++ b/doc/man/nvme_subsystem_get_host.2
@@ -1,4 +1,4 @@
-.TH "nvme_subsystem_get_host" 9 "nvme_subsystem_get_host" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_subsystem_get_host" 9 "nvme_subsystem_get_host" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_subsystem_get_host \- Returns nvme_host_t object
.SH SYNOPSIS
diff --git a/doc/man/nvme_subsystem_get_iopolicy.2 b/doc/man/nvme_subsystem_get_iopolicy.2
new file mode 100644
index 0000000..cef6918
--- /dev/null
+++ b/doc/man/nvme_subsystem_get_iopolicy.2
@@ -0,0 +1,11 @@
+.TH "nvme_subsystem_get_iopolicy" 9 "nvme_subsystem_get_iopolicy" "December 2023" "libnvme API manual" LINUX
+.SH NAME
+nvme_subsystem_get_iopolicy \- Return the IO policy of subsytem
+.SH SYNOPSIS
+.B "const char *" nvme_subsystem_get_iopolicy
+.BI "(nvme_subsystem_t s " ");"
+.SH ARGUMENTS
+.IP "s" 12
+nvme_subsystem_t object
+.SH "RETURN"
+IO policy used by current subsystem
diff --git a/doc/man/nvme_subsystem_get_name.2 b/doc/man/nvme_subsystem_get_name.2
index 4430362..3e0d0a6 100644
--- a/doc/man/nvme_subsystem_get_name.2
+++ b/doc/man/nvme_subsystem_get_name.2
@@ -1,4 +1,4 @@
-.TH "nvme_subsystem_get_name" 9 "nvme_subsystem_get_name" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_subsystem_get_name" 9 "nvme_subsystem_get_name" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_subsystem_get_name \- sysfs name of an nvme_subsystem_t object
.SH SYNOPSIS
diff --git a/doc/man/nvme_subsystem_get_nqn.2 b/doc/man/nvme_subsystem_get_nqn.2
index 7d64aa3..238b060 100644
--- a/doc/man/nvme_subsystem_get_nqn.2
+++ b/doc/man/nvme_subsystem_get_nqn.2
@@ -1,4 +1,4 @@
-.TH "nvme_subsystem_get_nqn" 9 "nvme_subsystem_get_nqn" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_subsystem_get_nqn" 9 "nvme_subsystem_get_nqn" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_subsystem_get_nqn \- Retrieve NQN from subsystem
.SH SYNOPSIS
diff --git a/doc/man/nvme_subsystem_get_sysfs_dir.2 b/doc/man/nvme_subsystem_get_sysfs_dir.2
index b780f37..ce8c6b1 100644
--- a/doc/man/nvme_subsystem_get_sysfs_dir.2
+++ b/doc/man/nvme_subsystem_get_sysfs_dir.2
@@ -1,4 +1,4 @@
-.TH "nvme_subsystem_get_sysfs_dir" 9 "nvme_subsystem_get_sysfs_dir" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_subsystem_get_sysfs_dir" 9 "nvme_subsystem_get_sysfs_dir" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_subsystem_get_sysfs_dir \- sysfs directory of an nvme_subsystem_t object
.SH SYNOPSIS
diff --git a/doc/man/nvme_subsystem_get_type.2 b/doc/man/nvme_subsystem_get_type.2
index ef2e4e2..866d194 100644
--- a/doc/man/nvme_subsystem_get_type.2
+++ b/doc/man/nvme_subsystem_get_type.2
@@ -1,4 +1,4 @@
-.TH "nvme_subsystem_get_type" 9 "nvme_subsystem_get_type" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_subsystem_get_type" 9 "nvme_subsystem_get_type" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_subsystem_get_type \- Returns the type of a subsystem
.SH SYNOPSIS
diff --git a/doc/man/nvme_subsystem_lookup_namespace.2 b/doc/man/nvme_subsystem_lookup_namespace.2
index ca88701..a402c74 100644
--- a/doc/man/nvme_subsystem_lookup_namespace.2
+++ b/doc/man/nvme_subsystem_lookup_namespace.2
@@ -1,4 +1,4 @@
-.TH "nvme_subsystem_lookup_namespace" 9 "nvme_subsystem_lookup_namespace" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_subsystem_lookup_namespace" 9 "nvme_subsystem_lookup_namespace" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_subsystem_lookup_namespace \- lookup namespace by NSID
.SH SYNOPSIS
diff --git a/doc/man/nvme_subsystem_next_ctrl.2 b/doc/man/nvme_subsystem_next_ctrl.2
index 3df44c6..cb72890 100644
--- a/doc/man/nvme_subsystem_next_ctrl.2
+++ b/doc/man/nvme_subsystem_next_ctrl.2
@@ -1,4 +1,4 @@
-.TH "nvme_subsystem_next_ctrl" 9 "nvme_subsystem_next_ctrl" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_subsystem_next_ctrl" 9 "nvme_subsystem_next_ctrl" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_subsystem_next_ctrl \- Next ctrl iterator
.SH SYNOPSIS
diff --git a/doc/man/nvme_subsystem_next_ns.2 b/doc/man/nvme_subsystem_next_ns.2
index e14c98c..36b902b 100644
--- a/doc/man/nvme_subsystem_next_ns.2
+++ b/doc/man/nvme_subsystem_next_ns.2
@@ -1,4 +1,4 @@
-.TH "nvme_subsystem_next_ns" 9 "nvme_subsystem_next_ns" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_subsystem_next_ns" 9 "nvme_subsystem_next_ns" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_subsystem_next_ns \- Next namespace iterator
.SH SYNOPSIS
diff --git a/doc/man/nvme_subsystem_release_fds.2 b/doc/man/nvme_subsystem_release_fds.2
new file mode 100644
index 0000000..fc1eebc
--- /dev/null
+++ b/doc/man/nvme_subsystem_release_fds.2
@@ -0,0 +1,13 @@
+.TH "nvme_subsystem_release_fds" 9 "nvme_subsystem_release_fds" "December 2023" "libnvme API manual" LINUX
+.SH NAME
+nvme_subsystem_release_fds \- Close all opened fds under subsystem
+.SH SYNOPSIS
+.B "void" nvme_subsystem_release_fds
+.BI "(struct nvme_subsystem *s " ");"
+.SH ARGUMENTS
+.IP "s" 12
+nvme_subsystem_t object
+.SH "DESCRIPTION"
+Controller and Namespace objects cache the file descriptors
+of opened nvme devices. This API can be used to close and
+clear all cached fds under this subsystem.
diff --git a/doc/man/nvme_subsystem_reset.2 b/doc/man/nvme_subsystem_reset.2
index e2d1a5c..ee5ab97 100644
--- a/doc/man/nvme_subsystem_reset.2
+++ b/doc/man/nvme_subsystem_reset.2
@@ -1,4 +1,4 @@
-.TH "nvme_subsystem_reset" 9 "nvme_subsystem_reset" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_subsystem_reset" 9 "nvme_subsystem_reset" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_subsystem_reset \- Initiate a subsystem reset
.SH SYNOPSIS
diff --git a/doc/man/nvme_subsystem_set_application.2 b/doc/man/nvme_subsystem_set_application.2
index ab3ad8f..9109009 100644
--- a/doc/man/nvme_subsystem_set_application.2
+++ b/doc/man/nvme_subsystem_set_application.2
@@ -1,4 +1,4 @@
-.TH "nvme_subsystem_set_application" 9 "nvme_subsystem_set_application" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_subsystem_set_application" 9 "nvme_subsystem_set_application" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_subsystem_set_application \- Set the application string
.SH SYNOPSIS
diff --git a/doc/man/nvme_supported_cap_config_list_log.2 b/doc/man/nvme_supported_cap_config_list_log.2
index 60d2ac4..031bda0 100644
--- a/doc/man/nvme_supported_cap_config_list_log.2
+++ b/doc/man/nvme_supported_cap_config_list_log.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_supported_cap_config_list_log" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_supported_cap_config_list_log" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_supported_cap_config_list_log \- Supported Capacity Configuration list log page
.SH SYNOPSIS
diff --git a/doc/man/nvme_supported_log_pages.2 b/doc/man/nvme_supported_log_pages.2
index 57e0cbd..c4b3d08 100644
--- a/doc/man/nvme_supported_log_pages.2
+++ b/doc/man/nvme_supported_log_pages.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_supported_log_pages" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_supported_log_pages" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_supported_log_pages \- Supported Log Pages - Log
.SH SYNOPSIS
diff --git a/doc/man/nvme_telemetry_da.2 b/doc/man/nvme_telemetry_da.2
index 4096fa7..746733b 100644
--- a/doc/man/nvme_telemetry_da.2
+++ b/doc/man/nvme_telemetry_da.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_telemetry_da" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_telemetry_da" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_telemetry_da \- Telemetry Log Data Area
.SH SYNOPSIS
diff --git a/doc/man/nvme_telemetry_log.2 b/doc/man/nvme_telemetry_log.2
index d2885fb..1cc55a4 100644
--- a/doc/man/nvme_telemetry_log.2
+++ b/doc/man/nvme_telemetry_log.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_telemetry_log" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_telemetry_log" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_telemetry_log \- Retrieve internal data specific to the manufacturer.
.SH SYNOPSIS
diff --git a/doc/man/nvme_thermal_exc_event.2 b/doc/man/nvme_thermal_exc_event.2
index 62f431e..f368e0b 100644
--- a/doc/man/nvme_thermal_exc_event.2
+++ b/doc/man/nvme_thermal_exc_event.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_thermal_exc_event" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_thermal_exc_event" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_thermal_exc_event \- Thermal Excursion Event Data
.SH SYNOPSIS
diff --git a/doc/man/nvme_time_stamp_change_event.2 b/doc/man/nvme_time_stamp_change_event.2
index 66c1847..d4d6af4 100644
--- a/doc/man/nvme_time_stamp_change_event.2
+++ b/doc/man/nvme_time_stamp_change_event.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_time_stamp_change_event" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_time_stamp_change_event" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_time_stamp_change_event \- Timestamp Change Event
.SH SYNOPSIS
diff --git a/doc/man/nvme_timestamp.2 b/doc/man/nvme_timestamp.2
index 0e828bb..9e6abc3 100644
--- a/doc/man/nvme_timestamp.2
+++ b/doc/man/nvme_timestamp.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_timestamp" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_timestamp" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_timestamp \- Timestamp - Data Structure for Get Features
.SH SYNOPSIS
diff --git a/doc/man/nvme_unlink_ctrl.2 b/doc/man/nvme_unlink_ctrl.2
index c778c9c..7f14a15 100644
--- a/doc/man/nvme_unlink_ctrl.2
+++ b/doc/man/nvme_unlink_ctrl.2
@@ -1,4 +1,4 @@
-.TH "nvme_unlink_ctrl" 9 "nvme_unlink_ctrl" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_unlink_ctrl" 9 "nvme_unlink_ctrl" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_unlink_ctrl \- Unlink controller
.SH SYNOPSIS
diff --git a/doc/man/nvme_update_config.2 b/doc/man/nvme_update_config.2
index b99ef98..0fa3767 100644
--- a/doc/man/nvme_update_config.2
+++ b/doc/man/nvme_update_config.2
@@ -1,4 +1,4 @@
-.TH "nvme_update_config" 9 "nvme_update_config" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_update_config" 9 "nvme_update_config" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_update_config \- Update JSON configuration
.SH SYNOPSIS
diff --git a/doc/man/nvme_uring_cmd.2 b/doc/man/nvme_uring_cmd.2
index 1d205a3..3050dd5 100644
--- a/doc/man/nvme_uring_cmd.2
+++ b/doc/man/nvme_uring_cmd.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_uring_cmd" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_uring_cmd" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_uring_cmd \- nvme uring command structure
.SH SYNOPSIS
diff --git a/doc/man/nvme_verify.2 b/doc/man/nvme_verify.2
index d4f7cf7..6b7b645 100644
--- a/doc/man/nvme_verify.2
+++ b/doc/man/nvme_verify.2
@@ -1,4 +1,4 @@
-.TH "nvme_verify" 9 "nvme_verify" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_verify" 9 "nvme_verify" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_verify \- Send an nvme verify command
.SH SYNOPSIS
diff --git a/doc/man/nvme_version.2 b/doc/man/nvme_version.2
index d9fc700..df5cb05 100644
--- a/doc/man/nvme_version.2
+++ b/doc/man/nvme_version.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_version" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_version" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_version \- Selector for version to be returned by @nvme_get_version
.SH SYNOPSIS
diff --git a/doc/man/nvme_virt_mgmt_act.2 b/doc/man/nvme_virt_mgmt_act.2
index efa1bfa..38bc617 100644
--- a/doc/man/nvme_virt_mgmt_act.2
+++ b/doc/man/nvme_virt_mgmt_act.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_virt_mgmt_act" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_virt_mgmt_act" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_virt_mgmt_act \- Virtualization Management - Action
.SH SYNOPSIS
diff --git a/doc/man/nvme_virt_mgmt_rt.2 b/doc/man/nvme_virt_mgmt_rt.2
index 43e3f89..6bdfa70 100644
--- a/doc/man/nvme_virt_mgmt_rt.2
+++ b/doc/man/nvme_virt_mgmt_rt.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_virt_mgmt_rt" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_virt_mgmt_rt" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_virt_mgmt_rt \- Virtualization Management - Resource Type
.SH SYNOPSIS
diff --git a/doc/man/nvme_virtual_mgmt.2 b/doc/man/nvme_virtual_mgmt.2
index 1431851..d6725af 100644
--- a/doc/man/nvme_virtual_mgmt.2
+++ b/doc/man/nvme_virtual_mgmt.2
@@ -1,4 +1,4 @@
-.TH "nvme_virtual_mgmt" 9 "nvme_virtual_mgmt" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_virtual_mgmt" 9 "nvme_virtual_mgmt" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_virtual_mgmt \- Virtualization resource management
.SH SYNOPSIS
diff --git a/doc/man/nvme_write.2 b/doc/man/nvme_write.2
index 37edcbf..050f2d6 100644
--- a/doc/man/nvme_write.2
+++ b/doc/man/nvme_write.2
@@ -1,4 +1,4 @@
-.TH "nvme_write" 9 "nvme_write" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_write" 9 "nvme_write" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_write \- Submit an nvme user write command
.SH SYNOPSIS
diff --git a/doc/man/nvme_write_uncorrectable.2 b/doc/man/nvme_write_uncorrectable.2
index b0d838c..d58a73a 100644
--- a/doc/man/nvme_write_uncorrectable.2
+++ b/doc/man/nvme_write_uncorrectable.2
@@ -1,4 +1,4 @@
-.TH "nvme_write_uncorrectable" 9 "nvme_write_uncorrectable" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_write_uncorrectable" 9 "nvme_write_uncorrectable" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_write_uncorrectable \- Submit an nvme write uncorrectable command
.SH SYNOPSIS
diff --git a/doc/man/nvme_write_zeros.2 b/doc/man/nvme_write_zeros.2
index db35d2f..c555aba 100644
--- a/doc/man/nvme_write_zeros.2
+++ b/doc/man/nvme_write_zeros.2
@@ -1,4 +1,4 @@
-.TH "nvme_write_zeros" 9 "nvme_write_zeros" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_write_zeros" 9 "nvme_write_zeros" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_write_zeros \- Submit an nvme write zeroes command
.SH SYNOPSIS
diff --git a/doc/man/nvme_zns_append.2 b/doc/man/nvme_zns_append.2
index a818143..e2f1395 100644
--- a/doc/man/nvme_zns_append.2
+++ b/doc/man/nvme_zns_append.2
@@ -1,4 +1,4 @@
-.TH "nvme_zns_append" 9 "nvme_zns_append" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_zns_append" 9 "nvme_zns_append" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_zns_append \- Append data to a zone
.SH SYNOPSIS
diff --git a/doc/man/nvme_zns_changed_zone_log.2 b/doc/man/nvme_zns_changed_zone_log.2
index bd490e0..7dd3a40 100644
--- a/doc/man/nvme_zns_changed_zone_log.2
+++ b/doc/man/nvme_zns_changed_zone_log.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_zns_changed_zone_log" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_zns_changed_zone_log" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_zns_changed_zone_log \- ZNS Changed Zone List log
.SH SYNOPSIS
diff --git a/doc/man/nvme_zns_desc.2 b/doc/man/nvme_zns_desc.2
index d67c4ce..730436f 100644
--- a/doc/man/nvme_zns_desc.2
+++ b/doc/man/nvme_zns_desc.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_zns_desc" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_zns_desc" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_zns_desc \- Zone Descriptor Data Structure
.SH SYNOPSIS
diff --git a/doc/man/nvme_zns_id_ctrl.2 b/doc/man/nvme_zns_id_ctrl.2
index 29c920f..ff20322 100644
--- a/doc/man/nvme_zns_id_ctrl.2
+++ b/doc/man/nvme_zns_id_ctrl.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_zns_id_ctrl" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_zns_id_ctrl" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_zns_id_ctrl \- I/O Command Set Specific Identify Controller Data Structure for the Zoned Namespace Command Set
.SH SYNOPSIS
diff --git a/doc/man/nvme_zns_id_ns.2 b/doc/man/nvme_zns_id_ns.2
index 4629af3..e11b6ef 100644
--- a/doc/man/nvme_zns_id_ns.2
+++ b/doc/man/nvme_zns_id_ns.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_zns_id_ns" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_zns_id_ns" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_zns_id_ns \- Zoned Namespace Command Set Specific Identify Namespace Data Structure
.SH SYNOPSIS
diff --git a/doc/man/nvme_zns_identify_ctrl.2 b/doc/man/nvme_zns_identify_ctrl.2
index 81107ce..5c7286a 100644
--- a/doc/man/nvme_zns_identify_ctrl.2
+++ b/doc/man/nvme_zns_identify_ctrl.2
@@ -1,4 +1,4 @@
-.TH "nvme_zns_identify_ctrl" 9 "nvme_zns_identify_ctrl" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_zns_identify_ctrl" 9 "nvme_zns_identify_ctrl" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_zns_identify_ctrl \- ZNS identify controller data
.SH SYNOPSIS
diff --git a/doc/man/nvme_zns_identify_ns.2 b/doc/man/nvme_zns_identify_ns.2
index 21207f5..d74bc1c 100644
--- a/doc/man/nvme_zns_identify_ns.2
+++ b/doc/man/nvme_zns_identify_ns.2
@@ -1,4 +1,4 @@
-.TH "nvme_zns_identify_ns" 9 "nvme_zns_identify_ns" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_zns_identify_ns" 9 "nvme_zns_identify_ns" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_zns_identify_ns \- ZNS identify namespace data
.SH SYNOPSIS
diff --git a/doc/man/nvme_zns_lbafe.2 b/doc/man/nvme_zns_lbafe.2
index 42fb999..8c9a0cb 100644
--- a/doc/man/nvme_zns_lbafe.2
+++ b/doc/man/nvme_zns_lbafe.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_zns_lbafe" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_zns_lbafe" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_zns_lbafe \- LBA Format Extension Data Structure
.SH SYNOPSIS
diff --git a/doc/man/nvme_zns_mgmt_recv.2 b/doc/man/nvme_zns_mgmt_recv.2
index 2b3c995..321ad3d 100644
--- a/doc/man/nvme_zns_mgmt_recv.2
+++ b/doc/man/nvme_zns_mgmt_recv.2
@@ -1,4 +1,4 @@
-.TH "nvme_zns_mgmt_recv" 9 "nvme_zns_mgmt_recv" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_zns_mgmt_recv" 9 "nvme_zns_mgmt_recv" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_zns_mgmt_recv \- ZNS management receive command
.SH SYNOPSIS
diff --git a/doc/man/nvme_zns_mgmt_send.2 b/doc/man/nvme_zns_mgmt_send.2
index 01fe8d7..5d80f84 100644
--- a/doc/man/nvme_zns_mgmt_send.2
+++ b/doc/man/nvme_zns_mgmt_send.2
@@ -1,4 +1,4 @@
-.TH "nvme_zns_mgmt_send" 9 "nvme_zns_mgmt_send" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_zns_mgmt_send" 9 "nvme_zns_mgmt_send" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_zns_mgmt_send \- ZNS management send command
.SH SYNOPSIS
diff --git a/doc/man/nvme_zns_recv_action.2 b/doc/man/nvme_zns_recv_action.2
index 383b391..fa6d43f 100644
--- a/doc/man/nvme_zns_recv_action.2
+++ b/doc/man/nvme_zns_recv_action.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_zns_recv_action" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_zns_recv_action" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_zns_recv_action \- Zone Management Receive - Zone Receive Action Specific Features
.SH SYNOPSIS
diff --git a/doc/man/nvme_zns_report_options.2 b/doc/man/nvme_zns_report_options.2
index 1ba5c4c..2d4f5b4 100644
--- a/doc/man/nvme_zns_report_options.2
+++ b/doc/man/nvme_zns_report_options.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_zns_report_options" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_zns_report_options" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_zns_report_options \- Zone Management Receive - Zone Receive Action Specific Field
.SH SYNOPSIS
diff --git a/doc/man/nvme_zns_report_zones.2 b/doc/man/nvme_zns_report_zones.2
index 07386af..4fbfdf5 100644
--- a/doc/man/nvme_zns_report_zones.2
+++ b/doc/man/nvme_zns_report_zones.2
@@ -1,4 +1,4 @@
-.TH "nvme_zns_report_zones" 9 "nvme_zns_report_zones" "June 2023" "libnvme API manual" LINUX
+.TH "nvme_zns_report_zones" 9 "nvme_zns_report_zones" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvme_zns_report_zones \- Return the list of zones
.SH SYNOPSIS
diff --git a/doc/man/nvme_zns_send_action.2 b/doc/man/nvme_zns_send_action.2
index 3163fb2..64ff551 100644
--- a/doc/man/nvme_zns_send_action.2
+++ b/doc/man/nvme_zns_send_action.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_zns_send_action" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_zns_send_action" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_zns_send_action \- Zone Management Send - Zone Send Action
.SH SYNOPSIS
diff --git a/doc/man/nvme_zns_za.2 b/doc/man/nvme_zns_za.2
index 3f30ab6..20dd628 100644
--- a/doc/man/nvme_zns_za.2
+++ b/doc/man/nvme_zns_za.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_zns_za" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_zns_za" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_zns_za \- Zone Descriptor Data Structure
.SH SYNOPSIS
diff --git a/doc/man/nvme_zns_zs.2 b/doc/man/nvme_zns_zs.2
index ef586ba..85ba655 100644
--- a/doc/man/nvme_zns_zs.2
+++ b/doc/man/nvme_zns_zs.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_zns_zs" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_zns_zs" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_zns_zs \- Zone Descriptor Data Structure - Zone State
.SH SYNOPSIS
diff --git a/doc/man/nvme_zns_zt.2 b/doc/man/nvme_zns_zt.2
index 36bfa1d..90220a3 100644
--- a/doc/man/nvme_zns_zt.2
+++ b/doc/man/nvme_zns_zt.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvme_zns_zt" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvme_zns_zt" "December 2023" "API Manual" LINUX
.SH NAME
enum nvme_zns_zt \- Zone Descriptor Data Structure - Zone Type
.SH SYNOPSIS
diff --git a/doc/man/nvme_zone_report.2 b/doc/man/nvme_zone_report.2
index 461f0fe..11dc84e 100644
--- a/doc/man/nvme_zone_report.2
+++ b/doc/man/nvme_zone_report.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvme_zone_report" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvme_zone_report" "December 2023" "API Manual" LINUX
.SH NAME
struct nvme_zone_report \- Report Zones Data Structure
.SH SYNOPSIS
diff --git a/doc/man/nvmf_add_ctrl.2 b/doc/man/nvmf_add_ctrl.2
index 2f138b0..f4abff2 100644
--- a/doc/man/nvmf_add_ctrl.2
+++ b/doc/man/nvmf_add_ctrl.2
@@ -1,4 +1,4 @@
-.TH "nvmf_add_ctrl" 9 "nvmf_add_ctrl" "June 2023" "libnvme API manual" LINUX
+.TH "nvmf_add_ctrl" 9 "nvmf_add_ctrl" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvmf_add_ctrl \- Connect a controller and update topology
.SH SYNOPSIS
diff --git a/doc/man/nvmf_addr_family.2 b/doc/man/nvmf_addr_family.2
index af220fa..07b954d 100644
--- a/doc/man/nvmf_addr_family.2
+++ b/doc/man/nvmf_addr_family.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvmf_addr_family" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvmf_addr_family" "December 2023" "API Manual" LINUX
.SH NAME
enum nvmf_addr_family \- Address Family codes for Discovery Log Page entry ADRFAM field
.SH SYNOPSIS
diff --git a/doc/man/nvmf_adrfam_str.2 b/doc/man/nvmf_adrfam_str.2
index 654e71e..85d94ed 100644
--- a/doc/man/nvmf_adrfam_str.2
+++ b/doc/man/nvmf_adrfam_str.2
@@ -1,4 +1,4 @@
-.TH "nvmf_adrfam_str" 9 "nvmf_adrfam_str" "June 2023" "libnvme API manual" LINUX
+.TH "nvmf_adrfam_str" 9 "nvmf_adrfam_str" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvmf_adrfam_str \- Decode ADRFAM field
.SH SYNOPSIS
diff --git a/doc/man/nvmf_cms_str.2 b/doc/man/nvmf_cms_str.2
index a7ceccd..16b6933 100644
--- a/doc/man/nvmf_cms_str.2
+++ b/doc/man/nvmf_cms_str.2
@@ -1,4 +1,4 @@
-.TH "nvmf_cms_str" 9 "nvmf_cms_str" "June 2023" "libnvme API manual" LINUX
+.TH "nvmf_cms_str" 9 "nvmf_cms_str" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvmf_cms_str \- Decode RDMA connection management service field
.SH SYNOPSIS
diff --git a/doc/man/nvmf_connect_data.2 b/doc/man/nvmf_connect_data.2
index eebaf3f..7092e67 100644
--- a/doc/man/nvmf_connect_data.2
+++ b/doc/man/nvmf_connect_data.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvmf_connect_data" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvmf_connect_data" "December 2023" "API Manual" LINUX
.SH NAME
struct nvmf_connect_data \- Data payload for the 'connect' command
.SH SYNOPSIS
diff --git a/doc/man/nvmf_connect_disc_entry.2 b/doc/man/nvmf_connect_disc_entry.2
index ea6d1e4..f2e325a 100644
--- a/doc/man/nvmf_connect_disc_entry.2
+++ b/doc/man/nvmf_connect_disc_entry.2
@@ -1,4 +1,4 @@
-.TH "nvmf_connect_disc_entry" 9 "nvmf_connect_disc_entry" "June 2023" "libnvme API manual" LINUX
+.TH "nvmf_connect_disc_entry" 9 "nvmf_connect_disc_entry" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvmf_connect_disc_entry \- Connect controller based on the discovery log page entry
.SH SYNOPSIS
diff --git a/doc/man/nvmf_default_config.2 b/doc/man/nvmf_default_config.2
index 17d8853..85af740 100644
--- a/doc/man/nvmf_default_config.2
+++ b/doc/man/nvmf_default_config.2
@@ -1,4 +1,4 @@
-.TH "nvmf_default_config" 9 "nvmf_default_config" "June 2023" "libnvme API manual" LINUX
+.TH "nvmf_default_config" 9 "nvmf_default_config" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvmf_default_config \- Default values for fabrics configuration
.SH SYNOPSIS
diff --git a/doc/man/nvmf_dim_data.2 b/doc/man/nvmf_dim_data.2
index ec2a122..eb1fb31 100644
--- a/doc/man/nvmf_dim_data.2
+++ b/doc/man/nvmf_dim_data.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvmf_dim_data" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvmf_dim_data" "December 2023" "API Manual" LINUX
.SH NAME
struct nvmf_dim_data \- Discovery Information Management (DIM) - Data
.SH SYNOPSIS
diff --git a/doc/man/nvmf_dim_entfmt.2 b/doc/man/nvmf_dim_entfmt.2
index 0b1638b..f8ec14f 100644
--- a/doc/man/nvmf_dim_entfmt.2
+++ b/doc/man/nvmf_dim_entfmt.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvmf_dim_entfmt" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvmf_dim_entfmt" "December 2023" "API Manual" LINUX
.SH NAME
enum nvmf_dim_entfmt \- Discovery Information Management Entry Format
.SH SYNOPSIS
diff --git a/doc/man/nvmf_dim_etype.2 b/doc/man/nvmf_dim_etype.2
index 76f4f15..af0b066 100644
--- a/doc/man/nvmf_dim_etype.2
+++ b/doc/man/nvmf_dim_etype.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvmf_dim_etype" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvmf_dim_etype" "December 2023" "API Manual" LINUX
.SH NAME
enum nvmf_dim_etype \- Discovery Information Management Entity Type
.SH SYNOPSIS
diff --git a/doc/man/nvmf_dim_tas.2 b/doc/man/nvmf_dim_tas.2
index 153a65c..8f269e1 100644
--- a/doc/man/nvmf_dim_tas.2
+++ b/doc/man/nvmf_dim_tas.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvmf_dim_tas" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvmf_dim_tas" "December 2023" "API Manual" LINUX
.SH NAME
enum nvmf_dim_tas \- Discovery Information Management Task
.SH SYNOPSIS
diff --git a/doc/man/nvmf_disc_eflags.2 b/doc/man/nvmf_disc_eflags.2
index 282d6f7..f34deb0 100644
--- a/doc/man/nvmf_disc_eflags.2
+++ b/doc/man/nvmf_disc_eflags.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvmf_disc_eflags" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvmf_disc_eflags" "December 2023" "API Manual" LINUX
.SH NAME
enum nvmf_disc_eflags \- Discovery Log Page entry flags.
.SH SYNOPSIS
diff --git a/doc/man/nvmf_disc_log_entry.2 b/doc/man/nvmf_disc_log_entry.2
index f1a0616..c5e0735 100644
--- a/doc/man/nvmf_disc_log_entry.2
+++ b/doc/man/nvmf_disc_log_entry.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvmf_disc_log_entry" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvmf_disc_log_entry" "December 2023" "API Manual" LINUX
.SH NAME
struct nvmf_disc_log_entry \- Discovery Log Page entry
.SH SYNOPSIS
diff --git a/doc/man/nvmf_discovery_log.2 b/doc/man/nvmf_discovery_log.2
index 353c831..61ac93c 100644
--- a/doc/man/nvmf_discovery_log.2
+++ b/doc/man/nvmf_discovery_log.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvmf_discovery_log" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvmf_discovery_log" "December 2023" "API Manual" LINUX
.SH NAME
struct nvmf_discovery_log \- Discovery Log Page (Log Identifier 70h)
.SH SYNOPSIS
diff --git a/doc/man/nvmf_eflags_str.2 b/doc/man/nvmf_eflags_str.2
index 348b206..4cc5c0c 100644
--- a/doc/man/nvmf_eflags_str.2
+++ b/doc/man/nvmf_eflags_str.2
@@ -1,4 +1,4 @@
-.TH "nvmf_eflags_str" 9 "nvmf_eflags_str" "June 2023" "libnvme API manual" LINUX
+.TH "nvmf_eflags_str" 9 "nvmf_eflags_str" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvmf_eflags_str \- Decode EFLAGS field
.SH SYNOPSIS
diff --git a/doc/man/nvmf_exat_len.2 b/doc/man/nvmf_exat_len.2
index 3ab5f4a..cbf4b9e 100644
--- a/doc/man/nvmf_exat_len.2
+++ b/doc/man/nvmf_exat_len.2
@@ -1,4 +1,4 @@
-.TH "nvmf_exat_len" 9 "nvmf_exat_len" "June 2023" "libnvme API manual" LINUX
+.TH "nvmf_exat_len" 9 "nvmf_exat_len" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvmf_exat_len \- Return length rounded up by 4
.SH SYNOPSIS
diff --git a/doc/man/nvmf_exattype.2 b/doc/man/nvmf_exattype.2
index 55c7c5c..16e356d 100644
--- a/doc/man/nvmf_exattype.2
+++ b/doc/man/nvmf_exattype.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvmf_exattype" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvmf_exattype" "December 2023" "API Manual" LINUX
.SH NAME
enum nvmf_exattype \- Extended Attribute Type
.SH SYNOPSIS
diff --git a/doc/man/nvmf_ext_attr.2 b/doc/man/nvmf_ext_attr.2
index 7281c7b..d5d37f1 100644
--- a/doc/man/nvmf_ext_attr.2
+++ b/doc/man/nvmf_ext_attr.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvmf_ext_attr" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvmf_ext_attr" "December 2023" "API Manual" LINUX
.SH NAME
struct nvmf_ext_attr \- Extended Attribute (EXAT)
.SH SYNOPSIS
diff --git a/doc/man/nvmf_ext_die.2 b/doc/man/nvmf_ext_die.2
index be641af..0bdcbbc 100644
--- a/doc/man/nvmf_ext_die.2
+++ b/doc/man/nvmf_ext_die.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "struct nvmf_ext_die" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "struct nvmf_ext_die" "December 2023" "API Manual" LINUX
.SH NAME
struct nvmf_ext_die \- Extended Discovery Information Entry (DIE)
.SH SYNOPSIS
diff --git a/doc/man/nvmf_get_discovery_log.2 b/doc/man/nvmf_get_discovery_log.2
index 77adfb0..b14c487 100644
--- a/doc/man/nvmf_get_discovery_log.2
+++ b/doc/man/nvmf_get_discovery_log.2
@@ -1,4 +1,4 @@
-.TH "nvmf_get_discovery_log" 9 "nvmf_get_discovery_log" "June 2023" "libnvme API manual" LINUX
+.TH "nvmf_get_discovery_log" 9 "nvmf_get_discovery_log" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvmf_get_discovery_log \- Return the discovery log page
.SH SYNOPSIS
diff --git a/doc/man/nvmf_get_discovery_wargs.2 b/doc/man/nvmf_get_discovery_wargs.2
index ac0cdfb..e4b5960 100644
--- a/doc/man/nvmf_get_discovery_wargs.2
+++ b/doc/man/nvmf_get_discovery_wargs.2
@@ -1,4 +1,4 @@
-.TH "nvmf_get_discovery_wargs" 9 "nvmf_get_discovery_wargs" "June 2023" "libnvme API manual" LINUX
+.TH "nvmf_get_discovery_wargs" 9 "nvmf_get_discovery_wargs" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvmf_get_discovery_wargs \- Get the discovery log page with args
.SH SYNOPSIS
diff --git a/doc/man/nvmf_hostid_from_file.2 b/doc/man/nvmf_hostid_from_file.2
index 33eae9e..682a7da 100644
--- a/doc/man/nvmf_hostid_from_file.2
+++ b/doc/man/nvmf_hostid_from_file.2
@@ -1,4 +1,4 @@
-.TH "nvmf_hostid_from_file" 9 "nvmf_hostid_from_file" "June 2023" "libnvme API manual" LINUX
+.TH "nvmf_hostid_from_file" 9 "nvmf_hostid_from_file" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvmf_hostid_from_file \- Reads the host identifier from the config default location
.SH SYNOPSIS
diff --git a/doc/man/nvmf_hostnqn_from_file.2 b/doc/man/nvmf_hostnqn_from_file.2
index 98e0c40..2c93aaf 100644
--- a/doc/man/nvmf_hostnqn_from_file.2
+++ b/doc/man/nvmf_hostnqn_from_file.2
@@ -1,4 +1,4 @@
-.TH "nvmf_hostnqn_from_file" 9 "nvmf_hostnqn_from_file" "June 2023" "libnvme API manual" LINUX
+.TH "nvmf_hostnqn_from_file" 9 "nvmf_hostnqn_from_file" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvmf_hostnqn_from_file \- Reads the host nvm qualified name from the config default location
.SH SYNOPSIS
diff --git a/doc/man/nvmf_hostnqn_generate.2 b/doc/man/nvmf_hostnqn_generate.2
index 4b147a0..f3a23f5 100644
--- a/doc/man/nvmf_hostnqn_generate.2
+++ b/doc/man/nvmf_hostnqn_generate.2
@@ -1,4 +1,4 @@
-.TH "nvmf_hostnqn_generate" 9 "nvmf_hostnqn_generate" "June 2023" "libnvme API manual" LINUX
+.TH "nvmf_hostnqn_generate" 9 "nvmf_hostnqn_generate" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvmf_hostnqn_generate \- Generate a machine specific host nqn
.SH SYNOPSIS
diff --git a/doc/man/nvmf_log_discovery_lid_support.2 b/doc/man/nvmf_log_discovery_lid_support.2
index 241b93c..32eb30a 100644
--- a/doc/man/nvmf_log_discovery_lid_support.2
+++ b/doc/man/nvmf_log_discovery_lid_support.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvmf_log_discovery_lid_support" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvmf_log_discovery_lid_support" "December 2023" "API Manual" LINUX
.SH NAME
enum nvmf_log_discovery_lid_support \- Discovery log specific support
.SH SYNOPSIS
diff --git a/doc/man/nvmf_log_discovery_lsp.2 b/doc/man/nvmf_log_discovery_lsp.2
index 1d41732..9dff492 100644
--- a/doc/man/nvmf_log_discovery_lsp.2
+++ b/doc/man/nvmf_log_discovery_lsp.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvmf_log_discovery_lsp" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvmf_log_discovery_lsp" "December 2023" "API Manual" LINUX
.SH NAME
enum nvmf_log_discovery_lsp \- Discovery log specific field
.SH SYNOPSIS
diff --git a/doc/man/nvmf_prtype_str.2 b/doc/man/nvmf_prtype_str.2
index 6b0b758..1573057 100644
--- a/doc/man/nvmf_prtype_str.2
+++ b/doc/man/nvmf_prtype_str.2
@@ -1,4 +1,4 @@
-.TH "nvmf_prtype_str" 9 "nvmf_prtype_str" "June 2023" "libnvme API manual" LINUX
+.TH "nvmf_prtype_str" 9 "nvmf_prtype_str" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvmf_prtype_str \- Decode RDMA Provider type field
.SH SYNOPSIS
diff --git a/doc/man/nvmf_qptype_str.2 b/doc/man/nvmf_qptype_str.2
index 7435ddd..d1c0e88 100644
--- a/doc/man/nvmf_qptype_str.2
+++ b/doc/man/nvmf_qptype_str.2
@@ -1,4 +1,4 @@
-.TH "nvmf_qptype_str" 9 "nvmf_qptype_str" "June 2023" "libnvme API manual" LINUX
+.TH "nvmf_qptype_str" 9 "nvmf_qptype_str" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvmf_qptype_str \- Decode RDMA QP Service type field
.SH SYNOPSIS
diff --git a/doc/man/nvmf_rdma_cms.2 b/doc/man/nvmf_rdma_cms.2
index a2fb1d4..8775bea 100644
--- a/doc/man/nvmf_rdma_cms.2
+++ b/doc/man/nvmf_rdma_cms.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvmf_rdma_cms" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvmf_rdma_cms" "December 2023" "API Manual" LINUX
.SH NAME
enum nvmf_rdma_cms \- RDMA Connection Management Service Type codes for Discovery Log Page entry TSAS RDMA_CMS field
.SH SYNOPSIS
diff --git a/doc/man/nvmf_rdma_prtype.2 b/doc/man/nvmf_rdma_prtype.2
index f7a600d..22791c9 100644
--- a/doc/man/nvmf_rdma_prtype.2
+++ b/doc/man/nvmf_rdma_prtype.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvmf_rdma_prtype" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvmf_rdma_prtype" "December 2023" "API Manual" LINUX
.SH NAME
enum nvmf_rdma_prtype \- RDMA Provider Type codes for Discovery Log Page entry TSAS RDMA_PRTYPE field
.SH SYNOPSIS
diff --git a/doc/man/nvmf_rdma_qptype.2 b/doc/man/nvmf_rdma_qptype.2
index 6ee0c27..bbdd1b3 100644
--- a/doc/man/nvmf_rdma_qptype.2
+++ b/doc/man/nvmf_rdma_qptype.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvmf_rdma_qptype" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvmf_rdma_qptype" "December 2023" "API Manual" LINUX
.SH NAME
enum nvmf_rdma_qptype \- RDMA QP Service Type codes for Discovery Log Page entry TSAS RDMA_QPTYPE field
.SH SYNOPSIS
diff --git a/doc/man/nvmf_register_ctrl.2 b/doc/man/nvmf_register_ctrl.2
index 66a4da7..eb101cc 100644
--- a/doc/man/nvmf_register_ctrl.2
+++ b/doc/man/nvmf_register_ctrl.2
@@ -1,4 +1,4 @@
-.TH "nvmf_register_ctrl" 9 "nvmf_register_ctrl" "June 2023" "libnvme API manual" LINUX
+.TH "nvmf_register_ctrl" 9 "nvmf_register_ctrl" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvmf_register_ctrl \- Perform registration task with a DC
.SH SYNOPSIS
diff --git a/doc/man/nvmf_sectype_str.2 b/doc/man/nvmf_sectype_str.2
index c5f1bba..232f04c 100644
--- a/doc/man/nvmf_sectype_str.2
+++ b/doc/man/nvmf_sectype_str.2
@@ -1,4 +1,4 @@
-.TH "nvmf_sectype_str" 9 "nvmf_sectype_str" "June 2023" "libnvme API manual" LINUX
+.TH "nvmf_sectype_str" 9 "nvmf_sectype_str" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvmf_sectype_str \- Decode SECTYPE field
.SH SYNOPSIS
diff --git a/doc/man/nvmf_subtype_str.2 b/doc/man/nvmf_subtype_str.2
index fb874b8..b7cf8a4 100644
--- a/doc/man/nvmf_subtype_str.2
+++ b/doc/man/nvmf_subtype_str.2
@@ -1,4 +1,4 @@
-.TH "nvmf_subtype_str" 9 "nvmf_subtype_str" "June 2023" "libnvme API manual" LINUX
+.TH "nvmf_subtype_str" 9 "nvmf_subtype_str" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvmf_subtype_str \- Decode SUBTYPE field
.SH SYNOPSIS
diff --git a/doc/man/nvmf_tcp_sectype.2 b/doc/man/nvmf_tcp_sectype.2
index 89a98eb..dbdcdc4 100644
--- a/doc/man/nvmf_tcp_sectype.2
+++ b/doc/man/nvmf_tcp_sectype.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvmf_tcp_sectype" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvmf_tcp_sectype" "December 2023" "API Manual" LINUX
.SH NAME
enum nvmf_tcp_sectype \- Transport Specific Address Subtype Definition for NVMe/TCP Transport
.SH SYNOPSIS
diff --git a/doc/man/nvmf_treq.2 b/doc/man/nvmf_treq.2
index f91e7db..69a9952 100644
--- a/doc/man/nvmf_treq.2
+++ b/doc/man/nvmf_treq.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvmf_treq" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvmf_treq" "December 2023" "API Manual" LINUX
.SH NAME
enum nvmf_treq \- Transport Requirements codes for Discovery Log Page entry TREQ field
.SH SYNOPSIS
diff --git a/doc/man/nvmf_treq_str.2 b/doc/man/nvmf_treq_str.2
index 85f01bc..568c9e3 100644
--- a/doc/man/nvmf_treq_str.2
+++ b/doc/man/nvmf_treq_str.2
@@ -1,4 +1,4 @@
-.TH "nvmf_treq_str" 9 "nvmf_treq_str" "June 2023" "libnvme API manual" LINUX
+.TH "nvmf_treq_str" 9 "nvmf_treq_str" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvmf_treq_str \- Decode TREQ field
.SH SYNOPSIS
diff --git a/doc/man/nvmf_trtype.2 b/doc/man/nvmf_trtype.2
index ebdd63a..faa9f67 100644
--- a/doc/man/nvmf_trtype.2
+++ b/doc/man/nvmf_trtype.2
@@ -1,4 +1,4 @@
-.TH "libnvme" 9 "enum nvmf_trtype" "June 2023" "API Manual" LINUX
+.TH "libnvme" 9 "enum nvmf_trtype" "December 2023" "API Manual" LINUX
.SH NAME
enum nvmf_trtype \- Transport Type codes for Discovery Log Page entry TRTYPE field
.SH SYNOPSIS
diff --git a/doc/man/nvmf_trtype_str.2 b/doc/man/nvmf_trtype_str.2
index 2149982..afdf133 100644
--- a/doc/man/nvmf_trtype_str.2
+++ b/doc/man/nvmf_trtype_str.2
@@ -1,4 +1,4 @@
-.TH "nvmf_trtype_str" 9 "nvmf_trtype_str" "June 2023" "libnvme API manual" LINUX
+.TH "nvmf_trtype_str" 9 "nvmf_trtype_str" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvmf_trtype_str \- Decode TRTYPE field
.SH SYNOPSIS
diff --git a/doc/man/nvmf_update_config.2 b/doc/man/nvmf_update_config.2
index c57f505..da0d3e9 100644
--- a/doc/man/nvmf_update_config.2
+++ b/doc/man/nvmf_update_config.2
@@ -1,4 +1,4 @@
-.TH "nvmf_update_config" 9 "nvmf_update_config" "June 2023" "libnvme API manual" LINUX
+.TH "nvmf_update_config" 9 "nvmf_update_config" "December 2023" "libnvme API manual" LINUX
.SH NAME
nvmf_update_config \- Update fabrics configuration values
.SH SYNOPSIS
diff --git a/doc/rst/ioctl.rst b/doc/rst/ioctl.rst
index a2f3b86..4d8af34 100644
--- a/doc/rst/ioctl.rst
+++ b/doc/rst/ioctl.rst
@@ -1081,7 +1081,7 @@ The nvme command status if a response was received (see
:c:type:`enum nvme_status_field <nvme_status_field>`) or -1 with errno set otherwise.
-.. c:function:: int nvme_identify_secondary_ctrl_list (int fd, __u32 nsid, __u16 cntid, struct nvme_secondary_ctrl_list *sc_list)
+.. c:function:: int nvme_identify_secondary_ctrl_list (int fd, __u16 cntid, struct nvme_secondary_ctrl_list *sc_list)
Retrieves secondary controller list
@@ -1090,9 +1090,6 @@ The nvme command status if a response was received (see
``int fd``
File descriptor of nvme device
-``__u32 nsid``
- Namespace identifier
-
``__u16 cntid``
Return controllers starting at this identifier
@@ -2185,6 +2182,34 @@ The nvme command status if a response was received (see
:c:type:`enum nvme_status_field <nvme_status_field>`) or -1 with errno set otherwise
+.. c:function:: int nvme_get_log_phy_rx_eom (int fd, __u8 lsp, __u16 controller, __u32 len, struct nvme_phy_rx_eom_log *log)
+
+ Retrieve Physical Interface Receiver Eye Opening Measurement Log
+
+**Parameters**
+
+``int fd``
+ File descriptor of nvme device
+
+``__u8 lsp``
+ Log specific, controls action and measurement quality
+
+``__u16 controller``
+ Target controller ID
+
+``__u32 len``
+ The allocated size, minimum
+ struct nvme_phy_rx_eom_log
+
+``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
+:c:type:`enum nvme_status_field <nvme_status_field>`) or -1 with errno set otherwise
+
+
.. c:function:: int nvme_get_log_discovery (int fd, bool rae, __u32 offset, __u32 len, void *log)
Retrieve Discovery log page
@@ -2499,7 +2524,7 @@ The nvme command status if a response was received (see
:c:type:`enum nvme_status_field <nvme_status_field>`) or -1 with errno set otherwise.
-.. c:function:: int nvme_set_features_lba_range (int fd, __u32 nsid, __u32 nr_ranges, bool save, struct nvme_lba_range_type *data, __u32 *result)
+.. c:function:: int nvme_set_features_lba_range (int fd, __u32 nsid, __u8 nr_ranges, bool save, struct nvme_lba_range_type *data, __u32 *result)
Set LBA range feature
@@ -2511,7 +2536,7 @@ The nvme command status if a response was received (see
``__u32 nsid``
Namespace ID
-``__u32 nr_ranges``
+``__u8 nr_ranges``
Number of ranges in **data**
``bool save``
@@ -3063,6 +3088,39 @@ The nvme command status if a response was received (see
``__u32 *result``
The command completion result from CQE dword0
+**Description**
+
+
+Deprecated: doesn't support specifying a NSID.
+Use nvme_set_features_resv_mask2() instead.
+
+**Return**
+
+The nvme command status if a response was received (see
+:c:type:`enum nvme_status_field <nvme_status_field>`) or -1 with errno set otherwise.
+
+
+.. c:function:: int nvme_set_features_resv_mask2 (int fd, __u32 nsid, __u32 mask, bool save, __u32 *result)
+
+ Set reservation notification mask feature
+
+**Parameters**
+
+``int fd``
+ File descriptor of nvme device
+
+``__u32 nsid``
+ Namespace ID
+
+``__u32 mask``
+ Reservation Notification Mask Field
+
+``bool save``
+ Save value across power states
+
+``__u32 *result``
+ The command completion result from CQE dword0
+
**Return**
The nvme command status if a response was received (see
@@ -3087,6 +3145,39 @@ The nvme command status if a response was received (see
``__u32 *result``
The command completion result from CQE dword0
+**Description**
+
+
+Deprecated: doesn't support specifying a NSID.
+Use nvme_set_features_resv_persist2() instead.
+
+**Return**
+
+The nvme command status if a response was received (see
+:c:type:`enum nvme_status_field <nvme_status_field>`) or -1 with errno set otherwise.
+
+
+.. c:function:: int nvme_set_features_resv_persist2 (int fd, __u32 nsid, bool ptpl, bool save, __u32 *result)
+
+ Set persist through power loss feature
+
+**Parameters**
+
+``int fd``
+ File descriptor of nvme device
+
+``__u32 nsid``
+ Namespace ID
+
+``bool ptpl``
+ Persist Through Power Loss
+
+``bool save``
+ Save value across power states
+
+``__u32 *result``
+ The command completion result from CQE dword0
+
**Return**
The nvme command status if a response was received (see
@@ -3111,6 +3202,60 @@ The nvme command status if a response was received (see
``__u32 *result``
The command completion result from CQE dword0
+**Description**
+
+
+Deprecated: doesn't support specifying a NSID.
+Use nvme_set_features_write_protect2() instead.
+
+**Return**
+
+The nvme command status if a response was received (see
+:c:type:`enum nvme_status_field <nvme_status_field>`) or -1 with errno set otherwise.
+
+
+.. c:function:: int nvme_set_features_write_protect2 (int fd, __u32 nsid, enum nvme_feat_nswpcfg_state state, bool save, __u32 *result)
+
+ Set write protect feature
+
+**Parameters**
+
+``int fd``
+ File descriptor of nvme device
+
+``__u32 nsid``
+ Namespace ID
+
+``enum nvme_feat_nswpcfg_state state``
+ Write Protection State
+
+``bool save``
+ Save value across power states
+
+``__u32 *result``
+ The command completion result from CQE dword0
+
+**Return**
+
+The nvme command status if a response was received (see
+:c:type:`enum nvme_status_field <nvme_status_field>`) or -1 with errno set otherwise.
+
+
+.. c:function:: int nvme_set_features_iocs_profile (int fd, __u16 iocsi, bool save)
+
+ Set I/O command set profile feature
+
+**Parameters**
+
+``int fd``
+ File descriptor of nvme device
+
+``__u16 iocsi``
+ I/O Command Set Combination Index
+
+``bool save``
+ Save value across power states
+
**Return**
The nvme command status if a response was received (see
@@ -3246,6 +3391,39 @@ The nvme command status if a response was received (see
``__u32 *result``
The command completion result from CQE dword0
+**Description**
+
+
+Deprecated: doesn't support specifying a NSID.
+Use nvme_get_features_lba_range2() instead.
+
+**Return**
+
+The nvme command status if a response was received (see
+:c:type:`enum nvme_status_field <nvme_status_field>`) or -1 with errno set otherwise.
+
+
+.. c:function:: int nvme_get_features_lba_range2 (int fd, enum nvme_get_features_sel sel, __u32 nsid, struct nvme_lba_range_type *data, __u32 *result)
+
+ Get LBA range feature
+
+**Parameters**
+
+``int fd``
+ File descriptor of nvme device
+
+``enum nvme_get_features_sel sel``
+ Select which type of attribute to return, see :c:type:`enum nvme_get_features_sel <nvme_get_features_sel>`
+
+``__u32 nsid``
+ Namespace ID
+
+``struct nvme_lba_range_type *data``
+ Buffer to receive LBA Range Type data structure
+
+``__u32 *result``
+ The command completion result from CQE dword0
+
**Return**
The nvme command status if a response was received (see
@@ -3288,6 +3466,36 @@ The nvme command status if a response was received (see
``__u32 *result``
The command completion result from CQE dword0
+**Description**
+
+
+Deprecated: doesn't support specifying a NSID.
+Use nvme_get_features_err_recovery2() instead.
+
+**Return**
+
+The nvme command status if a response was received (see
+:c:type:`enum nvme_status_field <nvme_status_field>`) or -1 with errno set otherwise.
+
+
+.. c:function:: int nvme_get_features_err_recovery2 (int fd, enum nvme_get_features_sel sel, __u32 nsid, __u32 *result)
+
+ Get error recovery feature
+
+**Parameters**
+
+``int fd``
+ File descriptor of nvme device
+
+``enum nvme_get_features_sel sel``
+ Select which type of attribute to return, see :c:type:`enum nvme_get_features_sel <nvme_get_features_sel>`
+
+``__u32 nsid``
+ Namespace ID
+
+``__u32 *result``
+ The command completion result from CQE dword0
+
**Return**
The nvme command status if a response was received (see
@@ -3460,6 +3668,36 @@ The nvme command status if a response was received (see
``__u32 *result``
The command completion result from CQE dword0
+**Description**
+
+
+Deprecated: doesn't fetch the Host Memory Buffer Attributes data structure.
+Use nvme_get_features_host_mem_buf2() instead.
+
+**Return**
+
+The nvme command status if a response was received (see
+:c:type:`enum nvme_status_field <nvme_status_field>`) or -1 with errno set otherwise.
+
+
+.. c:function:: int nvme_get_features_host_mem_buf2 (int fd, enum nvme_get_features_sel sel, struct nvme_host_mem_buf_attrs *attrs, __u32 *result)
+
+ Get host memory buffer feature
+
+**Parameters**
+
+``int fd``
+ File descriptor of nvme device
+
+``enum nvme_get_features_sel sel``
+ Select which type of attribute to return, see :c:type:`enum nvme_get_features_sel <nvme_get_features_sel>`
+
+``struct nvme_host_mem_buf_attrs *attrs``
+ Buffer for returned Host Memory Buffer Attributes
+
+``__u32 *result``
+ The command completion result from CQE dword0
+
**Return**
The nvme command status if a response was received (see
@@ -3774,6 +4012,36 @@ The nvme command status if a response was received (see
``__u32 *result``
The command completion result from CQE dword0
+**Description**
+
+
+Deprecated: doesn't support specifying a NSID.
+Use nvme_get_features_resv_mask2() instead.
+
+**Return**
+
+The nvme command status if a response was received (see
+:c:type:`enum nvme_status_field <nvme_status_field>`) or -1 with errno set otherwise.
+
+
+.. c:function:: int nvme_get_features_resv_mask2 (int fd, enum nvme_get_features_sel sel, __u32 nsid, __u32 *result)
+
+ Get reservation mask feature
+
+**Parameters**
+
+``int fd``
+ File descriptor of nvme device
+
+``enum nvme_get_features_sel sel``
+ Select which type of attribute to return, see :c:type:`enum nvme_get_features_sel <nvme_get_features_sel>`
+
+``__u32 nsid``
+ Namespace ID
+
+``__u32 *result``
+ The command completion result from CQE dword0
+
**Return**
The nvme command status if a response was received (see
@@ -3795,6 +4063,36 @@ The nvme command status if a response was received (see
``__u32 *result``
The command completion result from CQE dword0
+**Description**
+
+
+Deprecated: doesn't support specifying a NSID.
+Use nvme_get_features_resv_persist2() instead.
+
+**Return**
+
+The nvme command status if a response was received (see
+:c:type:`enum nvme_status_field <nvme_status_field>`) or -1 with errno set otherwise.
+
+
+.. c:function:: int nvme_get_features_resv_persist2 (int fd, enum nvme_get_features_sel sel, __u32 nsid, __u32 *result)
+
+ Get reservation persist feature
+
+**Parameters**
+
+``int fd``
+ File descriptor of nvme device
+
+``enum nvme_get_features_sel sel``
+ Select which type of attribute to return, see :c:type:`enum nvme_get_features_sel <nvme_get_features_sel>`
+
+``__u32 nsid``
+ Namespace ID
+
+``__u32 *result``
+ The command completion result from CQE dword0
+
**Return**
The nvme command status if a response was received (see
@@ -4903,3 +5201,27 @@ The nvme command status if a response was received (see
:c:type:`enum nvme_status_field <nvme_status_field>`) or -1 with errno set otherwise.
+.. c:function:: void nvme_set_debug (bool debug)
+
+ Set NVMe command debugging output
+
+**Parameters**
+
+``bool debug``
+ true to enable or false to disable
+
+
+.. c:function:: bool nvme_get_debug (void)
+
+ Get NVMe command debugging output
+
+**Parameters**
+
+``void``
+ no arguments
+
+**Return**
+
+false if disabled or true if enabled.
+
+
diff --git a/doc/rst/linux.rst b/doc/rst/linux.rst
index b437499..819ee68 100644
--- a/doc/rst/linux.rst
+++ b/doc/rst/linux.rst
@@ -53,6 +53,68 @@ The nvme command status if a response was received (see
Data Area 4
+.. c:function:: int nvme_get_telemetry_max (int fd, enum nvme_telemetry_da *da, size_t *max_data_tx)
+
+ Get telemetry limits
+
+**Parameters**
+
+``int fd``
+ File descriptor of nvme device
+
+``enum nvme_telemetry_da *da``
+ On success return max supported data area
+
+``size_t *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
+:c:type:`enum nvme_status_field <nvme_status_field>`) or -1 with errno set otherwise.
+
+
+.. c:function:: int nvme_get_telemetry_log (int fd, bool create, bool ctrl, bool rae, size_t max_data_tx, enum nvme_telemetry_da da, struct nvme_telemetry_log **log, size_t *size)
+
+ Get specified telemetry log
+
+**Parameters**
+
+``int fd``
+ File descriptor of nvme device
+
+``bool create``
+ Generate new host initated telemetry capture
+
+``bool ctrl``
+ Get controller Initiated log
+
+``bool rae``
+ Retain asynchronous events
+
+``size_t max_data_tx``
+ Set the max data transfer size to be used retrieving telemetry.
+
+``enum nvme_telemetry_da da``
+ Log page data area, valid values: :c:type:`enum nvme_telemetry_da <nvme_telemetry_da>`.
+
+``struct nvme_telemetry_log **log``
+ On success, set to the value of the allocated and retrieved log.
+
+``size_t *size``
+ Ptr to the telemetry log size, so it can be returned
+
+**Description**
+
+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
+:c:type:`enum nvme_status_field <nvme_status_field>`) or -1 with errno set otherwise.
+
+
.. c:function:: int nvme_get_ctrl_telemetry (int fd, bool rae, struct nvme_telemetry_log **log, enum nvme_telemetry_da da, size_t *size)
Get controller telemetry log
@@ -439,3 +501,80 @@ The key serial number if the key could be inserted into
the keyring or 0 with errno otherwise.
+.. c:function:: 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)
+
+ Derive and insert TLS key
+
+**Parameters**
+
+``const char *keyring``
+ Keyring to use
+
+``const char *key_type``
+ Type of the resulting key
+
+``const char *hostnqn``
+ Host NVMe Qualified Name
+
+``const char *subsysnqn``
+ Subsystem NVMe Qualified Name
+
+``int version``
+ Key version to use
+
+``int hmac``
+ HMAC algorithm
+
+``unsigned char *configured_key``
+ Configured key data to derive the key from
+
+``int key_len``
+ Length of **configured_key**
+
+**Description**
+
+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.
+
+
+.. c:function:: char * nvme_generate_tls_key_identity (const char *hostnqn, const char *subsysnqn, int version, int hmac, unsigned char *configured_key, int key_len)
+
+ Generate the TLS key identity
+
+**Parameters**
+
+``const char *hostnqn``
+ Host NVMe Qualified Name
+
+``const char *subsysnqn``
+ Subsystem NVMe Qualified Name
+
+``int version``
+ Key version to use
+
+``int hmac``
+ HMAC algorithm
+
+``unsigned char *configured_key``
+ Configured key data to derive the key from
+
+``int key_len``
+ Length of **configured_key**
+
+**Description**
+
+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.
+
+
diff --git a/doc/rst/log.rst b/doc/rst/log.rst
index 45b4689..67911a5 100644
--- a/doc/rst/log.rst
+++ b/doc/rst/log.rst
@@ -28,3 +28,22 @@ logging functions
Sets the default logging variables for the library.
+.. c:function:: void nvme_set_root (nvme_root_t r)
+
+ Set nvme_root_t context
+
+**Parameters**
+
+``nvme_root_t r``
+ nvme_root_t context
+
+**Description**
+
+In order to be able to log from code paths where no root object is passed in
+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 global root object.
+
+
diff --git a/doc/rst/mi.rst b/doc/rst/mi.rst
index ba0f29a..2aa7438 100644
--- a/doc/rst/mi.rst
+++ b/doc/rst/mi.rst
@@ -1923,7 +1923,7 @@ See: :c:type:`struct nvme_primary_ctrl_cap <nvme_primary_ctrl_cap>`
0 on success, non-zero on failure
-.. c:function:: int nvme_mi_admin_identify_secondary_ctrl_list (nvme_mi_ctrl_t ctrl, __u32 nsid, __u16 cntid, struct nvme_secondary_ctrl_list *list)
+.. c:function:: int nvme_mi_admin_identify_secondary_ctrl_list (nvme_mi_ctrl_t ctrl, __u16 cntid, struct nvme_secondary_ctrl_list *list)
Perform an Admin identify for a secondary controller list.
@@ -1932,9 +1932,6 @@ See: :c:type:`struct nvme_primary_ctrl_cap <nvme_primary_ctrl_cap>`
``nvme_mi_ctrl_t ctrl``
Controller to process identify command
-``__u32 nsid``
- Namespace ID to specify list start
-
``__u16 cntid``
Controller ID to specify list start
@@ -2622,6 +2619,34 @@ The nvme command status if a response was received (see
:c:type:`enum nvme_status_field <nvme_status_field>`) or -1 with errno set otherwise.
+.. c:function:: 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)
+
+ Retrieve Physical Interface Receiver Eye Opening Measurement Log
+
+**Parameters**
+
+``nvme_mi_ctrl_t ctrl``
+ Controller to query
+
+``__u8 lsp``
+ Log specific, controls action and measurement quality
+
+``__u16 controller``
+ Target controller ID
+
+``__u32 len``
+ The allocated size, minimum
+ struct nvme_phy_rx_eom_log
+
+``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
+:c:type:`enum nvme_status_field <nvme_status_field>`) or -1 with errno set otherwise
+
+
.. c:function:: int nvme_mi_admin_get_log_discovery (nvme_mi_ctrl_t ctrl, bool rae, __u32 offset, __u32 len, void *log)
Retrieve Discovery log page
diff --git a/doc/rst/tree.rst b/doc/rst/tree.rst
index f964ec6..b73ffae 100644
--- a/doc/rst/tree.rst
+++ b/doc/rst/tree.rst
@@ -53,6 +53,22 @@ Sets the managing application string for **r**.
Returns the managing application string for **r** or NULL if not set.
+.. c:function:: void nvme_root_release_fds (nvme_root_t r)
+
+ Close all opened file descriptors in the tree
+
+**Parameters**
+
+``nvme_root_t r``
+ :c:type:`nvme_root_t` object
+
+**Description**
+
+Controller and Namespace objects cache the file descriptors
+of opened nvme devices. This API can be used to close and
+clear all cached fds in the tree.
+
+
.. c:function:: void nvme_free_tree (nvme_root_t r)
Free root object
@@ -469,6 +485,86 @@ will start at **p** instead of the first controller.
Controller instance
+.. c:function:: nvme_ctrl_t nvme_ctrl_find (nvme_subsystem_t s, const char *transport, const char *traddr, const char *trsvcid, const char *subsysnqn, const char *host_traddr, const char *host_iface)
+
+ Locate an existing controller
+
+**Parameters**
+
+``nvme_subsystem_t s``
+ :c:type:`nvme_subsystem_t` object
+
+``const char *transport``
+ Transport name
+
+``const char *traddr``
+ Transport address
+
+``const char *trsvcid``
+ Transport service identifier
+
+``const char *subsysnqn``
+ Subsystem NQN
+
+``const char *host_traddr``
+ Host transport address
+
+``const char *host_iface``
+ Host interface name
+
+**Description**
+
+Lookup a controller in **s** based on **transport**, **traddr**, **trsvcid**,
+**subsysnqn**, **host_traddr**, and **host_iface**. **transport** must be specified,
+other fields may be required depending on the transport. Parameters set
+to NULL will be ignored.
+
+Unlike nvme_lookup_ctrl(), this function does not create a new object if
+an existing controller cannot be found.
+
+**Return**
+
+Controller instance on success, NULL otherwise.
+
+
+.. c:function:: bool nvme_ctrl_config_match (struct nvme_ctrl *c, const char *transport, const char *traddr, const char *trsvcid, const char *subsysnqn, const char *host_traddr, const char *host_iface)
+
+ Check if ctrl **c** matches config params
+
+**Parameters**
+
+``struct nvme_ctrl *c``
+ An existing controller instance
+
+``const char *transport``
+ Transport name
+
+``const char *traddr``
+ Transport address
+
+``const char *trsvcid``
+ Transport service identifier
+
+``const char *subsysnqn``
+ Subsystem NQN
+
+``const char *host_traddr``
+ Host transport address
+
+``const char *host_iface``
+ Host interface name
+
+**Description**
+
+Check that controller **c** matches parameters: **transport**, **traddr**,
+**trsvcid**, **subsysnqn**, **host_traddr**, and **host_iface**. Parameters set
+to NULL will be ignored.
+
+**Return**
+
+true if there's a match, false otherwise.
+
+
.. c:function:: 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)
Allocate an unconnected NVMe controller
@@ -776,11 +872,30 @@ Next :c:type:`nvme_ns_t` object of an **s** iterator
``nvme_ns_t n``
Namespace instance
+**Description**
+
+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 ns object is deleted or
+nvme_ns_release_fd() is called.
+
**Return**
File descriptor associated with **n** or -1
+.. c:function:: void nvme_ns_release_fd (nvme_ns_t n)
+
+ Close fd and clear fd from ns object
+
+**Parameters**
+
+``nvme_ns_t n``
+ Namespace instance
+
+
.. c:function:: int nvme_ns_get_nsid (nvme_ns_t n)
NSID of a namespace
@@ -1302,11 +1417,30 @@ Parent namespace if present
``nvme_ctrl_t c``
Controller instance
+**Description**
+
+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.
+
**Return**
File descriptor associated with **c** or -1
+.. c:function:: void nvme_ctrl_release_fd (nvme_ctrl_t c)
+
+ Close fd and clear fd from controller object
+
+**Parameters**
+
+``nvme_ctrl_t c``
+ Controller instance
+
+
.. c:function:: const char * nvme_ctrl_get_name (nvme_ctrl_t c)
sysfs name of a controller
@@ -1350,6 +1484,26 @@ NVMe-over-Fabrics address string of **c** or empty string
of no address is present.
+.. c:function:: char * nvme_ctrl_get_src_addr (nvme_ctrl_t c, char *src_addr, size_t src_addr_len)
+
+ Extract src_addr from the c->address string
+
+**Parameters**
+
+``nvme_ctrl_t c``
+ Controller instance
+
+``char *src_addr``
+ Where to copy the src_addr. Size must be at least INET6_ADDRSTRLEN.
+
+``size_t src_addr_len``
+ Length of the buffer **src_addr**.
+
+**Return**
+
+Pointer to **src_addr** on success. NULL on failure to extract the src_addr.
+
+
.. c:function:: const char * nvme_ctrl_get_phy_slot (nvme_ctrl_t c)
PCI physical slot number of a controller
@@ -1395,7 +1549,7 @@ Model string of **c**
.. c:function:: const char * nvme_ctrl_get_state (nvme_ctrl_t c)
- Running state of an controller
+ Running state of a controller
**Parameters**
@@ -1962,6 +2116,20 @@ Managing application string or NULL if not set.
Sets the managing application string for **s**.
+.. c:function:: const char * nvme_subsystem_get_iopolicy (nvme_subsystem_t s)
+
+ Return the IO policy of subsytem
+
+**Parameters**
+
+``nvme_subsystem_t s``
+ nvme_subsystem_t object
+
+**Return**
+
+IO policy used by current subsystem
+
+
.. c:function:: int nvme_scan_topology (nvme_root_t r, nvme_scan_filter_t f, void *f_args)
Scan NVMe topology and apply filter
@@ -2015,6 +2183,22 @@ Host NQN of **h**
Host ID of **h**
+.. c:function:: void nvme_host_release_fds (struct nvme_host *h)
+
+ Close all opened file descriptors under host
+
+**Parameters**
+
+``struct nvme_host *h``
+ nvme_host_t object
+
+**Description**
+
+Controller and Namespace objects cache the file descriptors
+of opened nvme devices. This API can be used to close and
+clear all cached fds under this host.
+
+
.. c:function:: void nvme_free_host (nvme_host_t h)
Free nvme_host_t object
@@ -2220,6 +2404,22 @@ String with the contents of **attr** or ``NULL`` in case of an empty value
nvme_ns_t of the namespace with id **nsid** in subsystem **s**
+.. c:function:: void nvme_subsystem_release_fds (struct nvme_subsystem *s)
+
+ Close all opened fds under subsystem
+
+**Parameters**
+
+``struct nvme_subsystem *s``
+ nvme_subsystem_t object
+
+**Description**
+
+Controller and Namespace objects cache the file descriptors
+of opened nvme devices. This API can be used to close and
+clear all cached fds under this subsystem.
+
+
.. c:function:: char * nvme_get_path_attr (nvme_path_t p, const char *attr)
Read path sysfs attribute
diff --git a/doc/rst/types.rst b/doc/rst/types.rst
index 3c9725a..0ed38cf 100644
--- a/doc/rst/types.rst
+++ b/doc/rst/types.rst
@@ -607,7 +607,8 @@ power scale value
__le32 mnan;
__u8 maxdna[16];
__le32 maxcna;
- __u8 rsvd564[204];
+ __le32 oaqd;
+ __u8 rsvd568[200];
char subnqn[NVME_NQN_LENGTH];
__u8 rsvd1024[768];
__le32 ioccsz;
@@ -976,7 +977,12 @@ power scale value
maximum number of namespaces that are allowed to be attached to
this I/O controller.
-``rsvd564``
+``oaqd``
+ Optimal Aggregated Queue Depth indicates the recommended maximum
+ total number of outstanding I/O commands across all I/O queues
+ on the controller for optimal operation.
+
+``rsvd568``
Reserved
``subnqn``
@@ -1612,6 +1618,18 @@ power scale value
If set, then the controller supports
the copy command.
+``NVME_CTRL_ONCS_COPY_SINGLE_ATOMICITY``
+ If set, then the write portion of a
+ Copy command is performed as a single
+ write command to which the same
+ atomicity requirements that apply to
+ a write command apply.
+
+``NVME_CTRL_ONCS_ALL_FAST_COPY``
+ If set, then all copy operations for
+ the Copy command are fast copy
+ operations.
+
@@ -1886,8 +1904,7 @@ power scale value
__u8 nguid[16];
__u8 eui64[8];
struct nvme_lbaf lbaf[64];
- __le64 lbstm;
- __u8 vs[3704];
+ __u8 vs[3712];
};
**Members**
@@ -2070,9 +2087,6 @@ power scale value
``lbaf``
LBA Format, see :c:type:`struct nvme_lbaf <nvme_lbaf>`.
-``lbstm``
- Logical Block Storage Tag Mask for end-to-end protection
-
``vs``
Vendor Specific
@@ -4196,11 +4210,13 @@ bytes, in size. This log captures the controller’s internal state.
struct nvme_endurance_group_log {
__u8 critical_warning;
- __u8 rsvd1[2];
+ __u8 endurance_group_features;
+ __u8 rsvd2;
__u8 avl_spare;
__u8 avl_spare_threshold;
__u8 percent_used;
- __u8 rsvd6[26];
+ __le16 domain_identifier;
+ __u8 rsvd8[24];
__u8 endurance_estimate[16];
__u8 data_units_read[16];
__u8 data_units_written[16];
@@ -4209,7 +4225,9 @@ bytes, in size. This log captures the controller’s internal state.
__u8 host_write_cmds[16];
__u8 media_data_integrity_err[16];
__u8 num_err_info_log_entries[16];
- __u8 rsvd160[352];
+ __u8 total_end_grp_cap[16];
+ __u8 unalloc_end_grp_cap[16];
+ __u8 rsvd192[320];
};
**Members**
@@ -4217,7 +4235,10 @@ bytes, in size. This log captures the controller’s internal state.
``critical_warning``
Critical Warning
-``rsvd1``
+``endurance_group_features``
+ Endurance Group Features
+
+``rsvd2``
Reserved
``avl_spare``
@@ -4229,7 +4250,10 @@ bytes, in size. This log captures the controller’s internal state.
``percent_used``
Percentage Used
-``rsvd6``
+``domain_identifier``
+ Domain Identifier
+
+``rsvd8``
Reserved
``endurance_estimate``
@@ -4256,7 +4280,13 @@ bytes, in size. This log captures the controller’s internal state.
``num_err_info_log_entries``
Number of Error Information Log Entries
-``rsvd160``
+``total_end_grp_cap``
+ Total Endurance Group Capacity
+
+``unalloc_end_grp_cap``
+ Unallocated Endurance Group Capacity
+
+``rsvd192``
Reserved
@@ -5503,6 +5533,213 @@ bytes, in size. This log captures the controller’s internal state.
+.. c:struct:: nvme_eom_lane_desc
+
+ EOM Lane Descriptor
+
+**Definition**
+
+::
+
+ struct nvme_eom_lane_desc {
+ __u8 rsvd0;
+ __u8 mstatus;
+ __u8 lane;
+ __u8 eye;
+ __le16 top;
+ __le16 bottom;
+ __le16 left;
+ __le16 right;
+ __le16 nrows;
+ __le16 ncols;
+ __le16 edlen;
+ __u8 rsvd18[14];
+ __u8 eye_desc[];
+ };
+
+**Members**
+
+``rsvd0``
+ Reserved
+
+``mstatus``
+ Measurement Status
+
+``lane``
+ Lane number
+
+``eye``
+ Eye number
+
+``top``
+ Absolute number of rows from center to top edge of eye
+
+``bottom``
+ Absolute number of rows from center to bottom edge of eye
+
+``left``
+ Absolute number of rows from center to left edge of eye
+
+``right``
+ Absolute number of rows from center to right edge of eye
+
+``nrows``
+ Number of Rows
+
+``ncols``
+ Number of Columns
+
+``edlen``
+ Eye Data Length
+
+``rsvd18``
+ Reserved
+
+``eye_desc``
+ Printable Eye, Eye Data, and any Padding
+
+
+
+
+
+.. c:struct:: nvme_phy_rx_eom_log
+
+ Physical Interface Receiver Eye Opening Measurement Log
+
+**Definition**
+
+::
+
+ struct nvme_phy_rx_eom_log {
+ __u8 lid;
+ __u8 eomip;
+ __le16 hsize;
+ __le32 rsize;
+ __u8 eomdgn;
+ __u8 lr;
+ __u8 odp;
+ __u8 lanes;
+ __u8 epl;
+ __u8 lspfc;
+ __u8 li;
+ __u8 rsvd15[3];
+ __le16 lsic;
+ __le32 dsize;
+ __le16 nd;
+ __le16 maxtb;
+ __le16 maxlr;
+ __le16 etgood;
+ __le16 etbetter;
+ __le16 etbest;
+ __u8 rsvd36[28];
+ struct nvme_eom_lane_desc descs[];
+ };
+
+**Members**
+
+``lid``
+ Log Identifier
+
+``eomip``
+ EOM In Progress
+
+``hsize``
+ Header Size
+
+``rsize``
+ Result Size
+
+``eomdgn``
+ EOM Data Generation Number
+
+``lr``
+ Log Revision
+
+``odp``
+ Optional Data Present
+
+``lanes``
+ Number of lanes configured for this port
+
+``epl``
+ Eyes Per Lane
+
+``lspfc``
+ Log Specific Parameter Field Copy
+
+``li``
+ Link Information
+
+``rsvd15``
+ Reserved
+
+``lsic``
+ Log Specific Identifier Copy
+
+``dsize``
+ Descriptor Size
+
+``nd``
+ Number of Descriptors
+
+``maxtb``
+ Maximum Top Bottom
+
+``maxlr``
+ Maximum Left Right
+
+``etgood``
+ Estimated Time for Good Quality
+
+``etbetter``
+ Estimated Time for Better Quality
+
+``etbest``
+ Estimated Time for Best Quality
+
+``rsvd36``
+ Reserved
+
+``descs``
+ EOM Lane Descriptors
+
+
+
+
+
+.. c:enum:: nvme_eom_optional_data
+
+ EOM Optional Data Present Fields
+
+**Constants**
+
+``NVME_EOM_EYE_DATA_PRESENT``
+ Eye Data Present
+
+``NVME_EOM_PRINTABLE_EYE_PRESENT``
+ Printable Eye Present
+
+
+
+
+.. c:enum:: nvme_phy_rx_eom_progress
+
+ EOM In Progress Values
+
+**Constants**
+
+``NVME_PHY_RX_EOM_NOT_STARTED``
+ EOM Not Started
+
+``NVME_PHY_RX_EOM_IN_PROGRESS``
+ EOM In Progress
+
+``NVME_PHY_RX_EOM_COMPLETED``
+ EOM Completed
+
+
+
+
.. c:struct:: nvme_media_unit_stat_desc
Media Unit Status Descriptor
@@ -7232,7 +7469,11 @@ bytes, in size. This log captures the controller’s internal state.
struct nvme_feat_host_behavior {
__u8 acre;
- __u8 rsvd1[511];
+ __u8 etdas;
+ __u8 lbafee;
+ __u8 rsvd3;
+ __u16 cdfe;
+ __u8 rsvd6[506];
};
**Members**
@@ -7240,7 +7481,19 @@ bytes, in size. This log captures the controller’s internal state.
``acre``
Advanced Command Retry Enable
-``rsvd1``
+``etdas``
+ Extended Telemetry Data Area 4 Supported
+
+``lbafee``
+ LBA Format Extension Enable
+
+``rsvd3``
+ Reserved
+
+``cdfe``
+ Copy Descriptor Formats Enable
+
+``rsvd6``
Reserved
@@ -7380,6 +7633,130 @@ bytes, in size. This log captures the controller’s internal state.
+.. c:enum:: nvme_copy_range_sopt
+
+ NVMe Copy Range Source Options
+
+**Constants**
+
+``NVME_COPY_SOPT_FCO``
+ NVMe Copy Source Option Fast Copy Only
+
+
+
+
+.. c:struct:: nvme_copy_range_f2
+
+ Copy - Source Range Entries Descriptor Format 2h
+
+**Definition**
+
+::
+
+ struct nvme_copy_range_f2 {
+ __le32 snsid;
+ __u8 rsvd4[4];
+ __le64 slba;
+ __le16 nlb;
+ __u8 rsvd18[4];
+ __le16 sopt;
+ __le32 eilbrt;
+ __le16 elbat;
+ __le16 elbatm;
+ };
+
+**Members**
+
+``snsid``
+ Source Namespace Identifier
+
+``rsvd4``
+ Reserved
+
+``slba``
+ Starting LBA
+
+``nlb``
+ Number of Logical Blocks
+
+``rsvd18``
+ Reserved
+
+``sopt``
+ Source Options
+
+``eilbrt``
+ Expected Initial Logical Block Reference Tag /
+ Expected Logical Block Storage Tag
+
+``elbat``
+ Expected Logical Block Application Tag
+
+``elbatm``
+ Expected Logical Block Application Tag Mask
+
+
+
+
+
+.. c:struct:: nvme_copy_range_f3
+
+ Copy - Source Range Entries Descriptor Format 3h
+
+**Definition**
+
+::
+
+ struct nvme_copy_range_f3 {
+ __le32 snsid;
+ __u8 rsvd4[4];
+ __le64 slba;
+ __le16 nlb;
+ __u8 rsvd18[4];
+ __le16 sopt;
+ __u8 rsvd24[2];
+ __u8 elbt[10];
+ __le16 elbat;
+ __le16 elbatm;
+ };
+
+**Members**
+
+``snsid``
+ Source Namespace Identifier
+
+``rsvd4``
+ Reserved
+
+``slba``
+ Starting LBA
+
+``nlb``
+ Number of Logical Blocks
+
+``rsvd18``
+ Reserved
+
+``sopt``
+ Source Options
+
+``rsvd24``
+ Reserved
+
+``elbt``
+ Expected Initial Logical Block Reference Tag /
+ Expected Logical Block Storage Tag
+
+``elbat``
+ Expected Logical Block Application Tag
+
+``elbatm``
+ Expected Logical Block Application Tag Mask
+
+
+
+
+
.. c:struct:: nvme_registered_ctrl
Registered Controller Data Structure
@@ -9933,6 +10310,29 @@ entries are of a variable lengths (TEL), TEL is always a multiple of
``NVME_SC_CMD_SIZE_LIMIT_EXCEEDED``
Command Size Limit Exceeded
+``NVME_SC_INCOMPATIBLE_NS``
+ Incompatible Namespace or Format: At
+ least one source namespace and the
+ destination namespace have incompatible
+ formats.
+
+``NVME_SC_FAST_COPY_NOT_POSSIBLE``
+ Fast Copy Not Possible: The Fast Copy
+ Only (FCO) bit was set to ‘1’ in a Source
+ Range entry and the controller was not
+ able to use fast copy operations to copy
+ the specified data.
+
+``NVME_SC_OVERLAPPING_IO_RANGE``
+ Overlapping I/O Range: A source logical
+ block range overlaps the destination
+ logical block range.
+
+``NVME_SC_INSUFFICIENT_RESOURCES``
+ Insufficient Resources: A resource
+ shortage prevented the controller from
+ performing the requested copy.
+
``NVME_SC_CONNECT_FORMAT``
Incompatible Format: The NVM subsystem
does not support the record format
@@ -10508,6 +10908,9 @@ true if **status** is of the specified type and value
``NVME_LOG_LID_BOOT_PARTITION``
Boot Partition
+``NVME_LOG_LID_PHY_RX_EOM``
+ Physical Interface Receiver Eye Opening Measurement
+
``NVME_LOG_LID_FDP_CONFIGS``
FDP Configurations
@@ -11219,6 +11622,42 @@ true if **status** is of the specified type and value
+.. c:enum:: nvme_log_phy_rx_eom_action
+
+ Physical Interface Receiver Eye Opening Measurement Action
+
+**Constants**
+
+``NVME_LOG_PHY_RX_EOM_READ``
+ Read Log Data
+
+``NVME_LOG_PHY_RX_EOM_START_READ``
+ Start Measurement and Read Log Data
+
+``NVME_LOG_PHY_RX_EOM_ABORT_CLEAR``
+ Abort Measurement and Clear Log Data
+
+
+
+
+.. c:enum:: nvme_log_phy_rx_eom_quality
+
+ Physical Interface Receiver Eye Opening Measurement Quality
+
+**Constants**
+
+``NVME_LOG_PHY_RX_EOM_GOOD``
+ <= Better Quality
+
+``NVME_LOG_PHY_RX_EOM_BETTER``
+ <= Best Quality, >= Good Quality
+
+``NVME_LOG_PHY_RX_EOM_BEST``
+ >= Better Quality
+
+
+
+
.. c:enum:: nvme_pevent_log_action
Persistent Event Log - Action
diff --git a/doc/rst/util.rst b/doc/rst/util.rst
index 6f7974e..f45452e 100644
--- a/doc/rst/util.rst
+++ b/doc/rst/util.rst
@@ -233,6 +233,74 @@ otherwise.
Number of descriptors to construct
+.. c:function:: void nvme_init_copy_range_f2 (struct nvme_copy_range_f2 *copy, __u32 *snsids, __u16 *nlbs, __u64 *slbas, __u16 *sopts, __u32 *eilbrts, __u32 *elbatms, __u32 *elbats, __u16 nr)
+
+ Constructs a copy range f2 structure
+
+**Parameters**
+
+``struct nvme_copy_range_f2 *copy``
+ Copy range array
+
+``__u32 *snsids``
+ Source namespace identifier
+
+``__u16 *nlbs``
+ Number of logical blocks
+
+``__u64 *slbas``
+ Starting LBA
+
+``__u16 *sopts``
+ Source options
+
+``__u32 *eilbrts``
+ Expected initial logical block reference tag
+
+``__u32 *elbatms``
+ Expected logical block application tag mask
+
+``__u32 *elbats``
+ Expected logical block application tag
+
+``__u16 nr``
+ Number of descriptors to construct
+
+
+.. c:function:: void nvme_init_copy_range_f3 (struct nvme_copy_range_f3 *copy, __u32 *snsids, __u16 *nlbs, __u64 *slbas, __u16 *sopts, __u64 *eilbrts, __u32 *elbatms, __u32 *elbats, __u16 nr)
+
+ Constructs a copy range f3 structure
+
+**Parameters**
+
+``struct nvme_copy_range_f3 *copy``
+ Copy range array
+
+``__u32 *snsids``
+ Source namespace identifier
+
+``__u16 *nlbs``
+ Number of logical blocks
+
+``__u64 *slbas``
+ Starting LBA
+
+``__u16 *sopts``
+ Source options
+
+``__u64 *eilbrts``
+ Expected initial logical block reference tag
+
+``__u32 *elbatms``
+ Expected logical block application tag mask
+
+``__u32 *elbats``
+ Expected logical block application tag
+
+``__u16 nr``
+ Number of descriptors to construct
+
+
.. c:function:: int nvme_get_feature_length (int fid, __u32 cdw11, __u32 *len)
Retreive the command payload length for a specific feature identifier
@@ -598,3 +666,52 @@ Returns error code if generating of random number fails.
true if addr1 == addr2. false otherwise.
+.. c:function:: const char * nvme_iface_matching_addr (const struct ifaddrs *iface_list, const char *addr)
+
+ Get interface matching **addr**
+
+**Parameters**
+
+``const struct ifaddrs *iface_list``
+ Interface list returned by getifaddrs()
+
+``const char *addr``
+ Address to match
+
+**Description**
+
+Parse the interface list pointed to by **iface_list** looking
+for the interface that has **addr** as one of its assigned
+addresses.
+
+**Return**
+
+The name of the interface that owns **addr** or NULL.
+
+
+.. c:function:: bool nvme_iface_primary_addr_matches (const struct ifaddrs *iface_list, const char *iface, const char *addr)
+
+ Check that interface's primary address matches
+
+**Parameters**
+
+``const struct ifaddrs *iface_list``
+ Interface list returned by getifaddrs()
+
+``const char *iface``
+ Interface to match
+
+``const char *addr``
+ Address to match
+
+**Description**
+
+Parse the interface list pointed to by **iface_list** and looking for
+interface **iface**. The get its primary address and check if it matches
+**addr**.
+
+**Return**
+
+true if a match is found, false otherwise.
+
+
diff --git a/internal/meson.build b/internal/meson.build
index fde4cca..744f83e 100644
--- a/internal/meson.build
+++ b/internal/meson.build
@@ -19,3 +19,12 @@ internal_incdir = include_directories('.')
config_dep = declare_dependency(
include_directories : internal_incdir,
sources: config_h)
+
+config_h_path = meson.current_build_dir() / 'config.h'
+
+add_project_arguments(
+ [
+ '-include', config_h_path,
+ ],
+ language : 'c',
+)
diff --git a/libnvme/meson.build b/libnvme/meson.build
index 12a601e..b5b99fc 100644
--- a/libnvme/meson.build
+++ b/libnvme/meson.build
@@ -67,16 +67,16 @@ if build_python_bindings
test_env.append('PYTHONMALLOC', 'malloc')
# Test section
- test('[Python] import libnvme', python3, args: ['-c', 'from libnvme import nvme'], env: test_env, depends: pynvme_clib)
+ test('python-import-libnvme', python3, args: ['-c', 'from libnvme import nvme'], env: test_env, depends: pynvme_clib)
py_tests = [
- [ 'create ctrl object', [ files('tests/create-ctrl-obj.py'), ] ],
- [ 'SIGSEGV during gc', [ files('tests/gc.py'), ] ],
- [ 'Read NBFT file', [ files('tests/test-nbft.py'), '--filename', join_paths(meson.current_source_dir(), 'tests', 'NBFT') ] ],
+ [ 'create-ctrl-object', [ files('tests/create-ctrl-obj.py'), ] ],
+ [ 'sigsegv-during-gc', [ files('tests/gc.py'), ] ],
+ [ 'read-nbft-file', [ files('tests/test-nbft.py'), '--filename', join_paths(meson.current_source_dir(), 'tests', 'NBFT') ] ],
]
foreach test: py_tests
description = test[0]
args = test[1]
- test('[Python] ' + description, python3, args: args, env: test_env, depends: pynvme_clib)
+ test('python-' + description, python3, args: args, env: test_env, depends: pynvme_clib)
endforeach
endif
diff --git a/meson.build b/meson.build
index 77415eb..3030ee5 100644
--- a/meson.build
+++ b/meson.build
@@ -8,7 +8,7 @@
project(
'libnvme', ['c'],
meson_version: '>= 0.50.0',
- version: '1.5',
+ version: '1.7.1',
license: 'LGPL-2.1-or-later',
default_options: [
'c_std=gnu99',
@@ -20,8 +20,14 @@ project(
]
)
-maj_min = meson.project_version().split('-rc')[0]
-library_version = maj_min + '.0'
+vstr = meson.project_version().split('-rc')[0]
+vid = vstr.split('.')
+library_version = '.'.join(vid[0], vid[1])
+if vid.length() == 3
+ library_version = '.'.join(library_version, vid[2])
+else
+ library_version = library_version + '.0'
+endif
################################################################################
cc = meson.get_compiler('c')
@@ -230,6 +236,16 @@ conf.set(
),
description: 'Is network address and service translation available'
)
+conf.set(
+ 'HAVE_GLIBC_IOCTL',
+ cc.compiles(
+ '''#include <sys/ioctl.h>
+ int ioctl(int fd, unsigned long request, ...);
+ ''',
+ name: 'ioctl has glibc-style prototype'
+ ),
+ description: 'Is ioctl the glibc interface (rather than POSIX)'
+)
if cc.has_function_attribute('fallthrough')
conf.set('fallthrough', '__attribute__((__fallthrough__))')
@@ -253,7 +269,6 @@ add_project_arguments(
[
'-fomit-frame-pointer',
'-D_GNU_SOURCE',
- '-include', 'internal/config.h',
],
language : 'c',
)
@@ -264,7 +279,9 @@ subdir('internal')
subdir('ccan')
subdir('src')
subdir('libnvme')
-subdir('test')
+if get_option('tests')
+ subdir('test')
+endif
subdir('examples')
subdir('doc')
diff --git a/meson_options.txt b/meson_options.txt
index a1ed79f..251ae11 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -6,6 +6,7 @@ option('rstdir', type : 'string', value : '', description : 'directory for ReST
option('docs', type : 'combo', choices : ['false', 'html', 'man', 'rst', 'all'], description : 'install documentation')
option('docs-build', type : 'boolean', value : false, description : 'build documentation')
+option('tests', type : 'boolean', value : true, description : 'build tests')
option('python', type : 'feature', value: 'auto', description : 'Generate libnvme python bindings')
option('openssl', type : 'feature', value: 'auto', description : 'OpenSSL support')
diff --git a/scripts/build.sh b/scripts/build.sh
index 82d271b..5a615ae 100755
--- a/scripts/build.sh
+++ b/scripts/build.sh
@@ -1,4 +1,5 @@
#!/bin/bash
+set -e
usage() {
echo "Usage: build.sh [-b [release|debug]] "
@@ -19,6 +20,7 @@ usage() {
echo " fallback download all dependencies"
echo " and build them as shared libaries"
echo " cross use cross toolchain to build"
+ echo " coverage build coverage report"
echo ""
echo "configs with muon:"
echo " [default] minimal static build"
@@ -57,6 +59,9 @@ CONFIG=${1:-"default"}
cd "$(git rev-parse --show-toplevel)" || exit 1
BUILDDIR="$(pwd)/.build-ci"
+TOOLDIR="$(pwd)/.build-tools"
+
+fn_exists() { declare -F "$1" > /dev/null; }
config_meson_default() {
CC="${CC}" "${MESON}" setup \
@@ -95,6 +100,16 @@ config_meson_cross() {
"${BUILDDIR}"
}
+config_meson_coverage() {
+ CC="${CC}" "${MESON}" setup \
+ --werror \
+ --buildtype="${BUILDTYPE}" \
+ --wrap-mode=nofallback \
+ -Dlibdbus=enabled \
+ -Db_coverage=true \
+ "${BUILDDIR}"
+}
+
build_meson() {
"${MESON}" compile \
-C "${BUILDDIR}"
@@ -105,46 +120,60 @@ test_meson() {
-C "${BUILDDIR}"
}
+test_meson_coverage() {
+ "${MESON}" test \
+ -C "${BUILDDIR}"
+ ninja -C "${BUILDDIR}" coverage --verbose
+}
+
tools_build_samurai() {
- mkdir -p "${BUILDDIR}"/build-tools
- git clone --depth 1 https://github.com/michaelforney/samurai.git \
- "${BUILDDIR}/build-tools/samurai"
- pushd "${BUILDDIR}/build-tools/samurai" || exit 1
+ if [ ! -d "${TOOLDIR}"/samurai ]; then
+ git clone --depth 1 https://github.com/michaelforney/samurai.git \
+ "${TOOLDIR}/samurai"
+ fi
- CC="${CC}" make
- SAMU="${BUILDDIR}/build-tools/samurai/samu"
+ if [[ -f "${TOOLDIR}/samurai/samu" ]]; then
+ return
+ fi
+ pushd "${TOOLDIR}/samurai" || exit 1
+ CC="${CC}" make
popd || exit 1
}
tools_build_muon() {
- mkdir -p "${BUILDDIR}"/build-tools
- git clone --depth 1 https://git.sr.ht/~lattis/muon \
- "${BUILDDIR}/build-tools/muon"
- pushd "${BUILDDIR}/build-tools/muon" || exit 1
+ if [ ! -d "${TOOLDIR}/muon" ]; then
+ git clone --depth 1 https://git.sr.ht/~lattis/muon \
+ "${TOOLDIR}/muon"
+ fi
+
+ if [[ -f "${TOOLDIR}/build-muon/muon" ]]; then
+ return
+ fi
- CC="${CC}" ninja="${SAMU}" ./bootstrap.sh stage1
+ pushd "${TOOLDIR}/muon" || exit 1
+
+ CC="${CC}" CFLAGS="${CFLAGS} -std=c99" ninja="${SAMU}" \
+ ./bootstrap.sh stage1
CC="${CC}" ninja="${SAMU}" stage1/muon setup \
- -Dprefix="${BUILDDIR}/build-tools" \
- -Dlibcurl=enabled \
- -Dlibarchive=enabled \
- -Dlibpkgconf=enabled \
+ -Dprefix="${TOOLDIR}" \
-Ddocs=disabled \
-Dsamurai=disabled \
- "${BUILDDIR}/build-tools/.build-muon"
- "${SAMU}" -C "${BUILDDIR}/build-tools/.build-muon"
- MUON="${BUILDDIR}/build-tools/.build-muon/muon"
+ "${TOOLDIR}/build-muon"
+ "${SAMU}" -C "${TOOLDIR}/build-muon"
- # "${MUON}" -C "${BUILDDIR}/build-tools/.build-muon" test
+ # "${TOOLDIR}/build-muon/muon" \
+ # -C "${TOOLDIR}/build-muon" test
popd || exit 1
}
config_muon_default() {
- CC="${CC}" CFLAGS="${CFLAGS} -static" \
- ninja="${SAMU}" "${MUON}" setup \
+ CC="${CC}" CFLAGS="${CFLAGS}" ninja="${SAMU}" \
+ "${MUON}" setup \
-Ddefault_library=static \
+ -Dc_link_args="-static" \
-Djson-c=disabled \
-Dopenssl=disabled \
-Dkeyutils=disabled \
@@ -161,22 +190,25 @@ test_muon() {
ninja="${SAMU}" "${MUON}" -C "${BUILDDIR}" test
}
-rm -rf "${BUILDDIR}"
-
if [[ "${BUILDTOOL}" == "muon" ]]; then
- if ! which samu ; then
+ SAMU="$(which samu 2> /dev/null)" || true
+ if [[ -z "${SAMU}" ]]; then
tools_build_samurai
- else
- SAMU="$(which samu)"
+ SAMU="${TOOLDIR}/samurai/samu"
fi
- if ! which muon ; then
+ MUON="$(which muon 2> /dev/null)" || true
+ if [[ -z "${MUON}" ]]; then
tools_build_muon
- else
- MUON="$(which muon)"
+ MUON="${TOOLDIR}/build-muon/muon"
fi
fi
+echo "samu: ${SAMU}"
+echo "muon: ${MUON}"
+
+rm -rf "${BUILDDIR}"
+
config_"${BUILDTOOL}"_"${CONFIG}"
-build_"${BUILDTOOL}"
-test_"${BUILDTOOL}"
+fn_exists "build_${BUILDTOOL}_${CONFIG}" && "build_${BUILDTOOL}_${CONFIG}" || build_"${BUILDTOOL}"
+fn_exists "test_${BUILDTOOL}_${CONFIG}" && "test_${BUILDTOOL}_${CONFIG}" || test_"${BUILDTOOL}"
diff --git a/src/libnvme-mi.map b/src/libnvme-mi.map
index f1ce712..41e8110 100644
--- a/src/libnvme-mi.map
+++ b/src/libnvme-mi.map
@@ -49,7 +49,6 @@ LIBNVME_MI_1_1 {
nvme_mi_admin_security_send;
nvme_mi_admin_security_recv;
nvme_mi_endpoint_desc;
- nvme_mi_root_close;
nvme_mi_first_endpoint;
nvme_mi_next_endpoint;
nvme_mi_first_ctrl;
diff --git a/src/libnvme.map b/src/libnvme.map
index 82387d4..742f635 100644
--- a/src/libnvme.map
+++ b/src/libnvme.map
@@ -1,4 +1,37 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
+LIBNVME_1_7 {
+ global:
+ nvme_init_copy_range_f2;
+ nvme_init_copy_range_f3;
+ nvme_insert_tls_key_versioned;
+ nvme_generate_tls_key_identity;
+};
+
+LIBNVME_1_6 {
+ global:
+ nvme_ctrl_config_match;
+ nvme_ctrl_find;
+ nvme_ctrl_get_src_addr;
+ nvme_ctrl_release_fd;
+ nvme_get_debug;
+ nvme_get_features_err_recovery2;
+ nvme_get_features_host_mem_buf2;
+ nvme_get_features_iocs_profile;
+ nvme_get_features_lba_range2;
+ nvme_get_features_resv_mask2;
+ nvme_get_features_resv_persist2;
+ nvme_host_release_fds;
+ nvme_ns_release_fd;
+ nvme_root_release_fds;
+ nvme_set_debug;
+ nvme_set_features_iocs_profile;
+ nvme_set_features_resv_mask2;
+ nvme_set_features_resv_persist2;
+ nvme_set_features_write_protect2;
+ nvme_set_root;
+ nvme_subsystem_get_iopolicy;
+ nvme_subsystem_release_fds;
+};
LIBNVME_1_5 {
global:
@@ -25,8 +58,6 @@ LIBNVME_1_3 {
global:
nvme_ctrl_is_unique_discovery_ctrl;
nvme_ctrl_set_unique_discovery_ctrl;
- nvme_fdp_reclaim_unit_handle_status;
- nvme_fdp_reclaim_unit_handle_update;
nvme_io_mgmt_recv;
nvme_io_mgmt_send;
nvme_host_is_pdc_enabled;
@@ -55,19 +86,15 @@ LIBNVME_1_0 {
global:
nvme_admin_passthru64;
nvme_admin_passthru;
- nvme_attach_ns;
nvme_capacity_mgmt;
- nvme_compare;
nvme_copy;
nvme_create_root;
nvme_create_ctrl;
- nvme_ctrl_disconnect;
nvme_ctrl_first_ns;
nvme_ctrl_first_path;
nvme_ctrl_get_address;
nvme_ctrl_get_config;
nvme_ctrl_get_dhchap_key;
- nvme_ctrl_get_discovery_ctrl;
nvme_ctrl_get_fd;
nvme_ctrl_get_firmware;
nvme_ctrl_get_host_iface;
@@ -98,22 +125,14 @@ LIBNVME_1_0 {
nvme_dev_self_test;
nvme_dim_send;
nvme_directive_recv;
- nvme_directive_recv_identify_parameters;
- nvme_directive_recv_stream_allocate;
- nvme_directive_recv_stream_parameters;
- nvme_directive_recv_stream_status;
nvme_directive_send;
nvme_directive_send_id_endir;
- nvme_directive_send_stream_release_identifier;
- nvme_directive_send_stream_release_resource;
nvme_disconnect_ctrl;
nvme_dsm;
- nvme_dsm_range;
nvme_dump_config;
nvme_errno_to_string;
nvme_first_host;
nvme_first_subsystem;
- nvme_flush;
nvme_format_nvm;
nvme_free_ctrl;
nvme_free_host;
@@ -163,31 +182,7 @@ LIBNVME_1_0 {
nvme_get_host_telemetry;
nvme_get_lba_status;
nvme_get_log;
- nvme_get_log_ana;
- nvme_get_log_ana_groups;
- nvme_get_log_boot_partition;
- nvme_get_log_changed_ns_list;
- nvme_get_log_cmd_effects;
- nvme_get_log_create_telemetry_host;
- nvme_get_log_device_self_test;
- nvme_get_log_discovery;
- nvme_get_log_endurance_group;
- nvme_get_log_endurance_grp_evt;
- nvme_get_log_error;
- nvme_get_log_fid_supported_effects;
- nvme_get_log_fw_slot;
- nvme_get_log_lba_status;
nvme_get_log_page;
- nvme_get_log_persistent_event;
- nvme_get_log_predictable_lat_event;
- nvme_get_log_predictable_lat_nvmset;
- nvme_get_log_reservation;
- nvme_get_log_sanitize;
- nvme_get_log_smart;
- nvme_get_log_supported_log_pages;
- nvme_get_log_telemetry_ctrl;
- nvme_get_log_telemetry_host;
- nvme_get_log_zns_changed_zones;
nvme_get_logical_block_size;
nvme_get_new_host_telemetry;
nvme_get_ns_attr;
@@ -196,6 +191,7 @@ LIBNVME_1_0 {
nvme_get_property;
nvme_get_subsys_attr;
nvme_get_telemetry_log;
+ nvme_get_telemetry_max;
nvme_host_get_dhchap_key;
nvme_host_get_hostid;
nvme_host_get_hostnqn;
@@ -204,25 +200,6 @@ LIBNVME_1_0 {
nvme_host_set_dhchap_key;
nvme_host_set_hostsymname;
nvme_identify;
- nvme_identify_active_ns_list;
- nvme_identify_allocated_ns;
- nvme_identify_allocated_ns_list;
- nvme_identify_ctrl;
- nvme_identify_ctrl_list;
- nvme_identify_domain_list;
- nvme_identify_endurance_group_list;
- nvme_identify_independent_identify_ns;
- nvme_identify_ns_csi_user_data_format;
- nvme_identify_iocs_ns_csi_user_data_format;
- nvme_identify_iocs;
- nvme_identify_ns;
- nvme_identify_ns_descs;
- nvme_identify_ns_granularity;
- nvme_identify_nsid_ctrl_list;
- nvme_identify_nvmset_list;
- nvme_identify_primary_ctrl;
- nvme_identify_secondary_ctrl_list;
- nvme_identify_uuid;
nvme_init_copy_range;
nvme_init_ctrl;
nvme_init_ctrl_list;
@@ -243,10 +220,7 @@ LIBNVME_1_0 {
nvme_next_host;
nvme_next_subsystem;
nvme_ns_attach;
- nvme_ns_attach_ctrls;
nvme_ns_compare;
- nvme_ns_detach_ctrls;
- nvme_ns_dettach_ctrls;
nvme_ns_flush;
nvme_ns_get_csi;
nvme_ns_get_ctrl;
@@ -259,7 +233,6 @@ LIBNVME_1_0 {
nvme_ns_get_lba_util;
nvme_ns_get_meta_size;
nvme_ns_get_model;
- nvme_ns_get_model;
nvme_ns_get_name;
nvme_ns_get_nguid;
nvme_ns_get_nsid;
@@ -269,16 +242,12 @@ LIBNVME_1_0 {
nvme_ns_get_uuid;
nvme_ns_identify;
nvme_ns_mgmt;
- nvme_ns_mgmt_create;
- nvme_ns_mgmt_delete;
- nvme_ns_open;
nvme_ns_read;
nvme_ns_rescan;
nvme_ns_verify;
nvme_ns_write;
nvme_ns_write_uncorrectable;
nvme_ns_write_zeros;
- nvme_nvm_identify_ctrl;
nvme_open;
nvme_path_get_ana_state;
nvme_path_get_ctrl;
@@ -286,7 +255,6 @@ LIBNVME_1_0 {
nvme_path_get_ns;
nvme_path_get_sysfs_dir;
nvme_paths_filter;
- nvme_read;
nvme_read_config;
nvme_refresh_topology;
nvme_rescan_ctrl;
@@ -294,7 +262,6 @@ LIBNVME_1_0 {
nvme_resv_register;
nvme_resv_release;
nvme_resv_report;
- nvme_sanitize;
nvme_sanitize_nvm;
nvme_scan;
nvme_scan_ctrl;
@@ -306,9 +273,7 @@ LIBNVME_1_0 {
nvme_scan_subsystem_namespaces;
nvme_scan_subsystems;
nvme_security_receive;
- nvme_security_receive;
nvme_security_send;
- nvme_set_feature;
nvme_set_features;
nvme_set_features_arbitration;
nvme_set_features_async_event;
@@ -337,11 +302,8 @@ LIBNVME_1_0 {
nvme_set_features_write_atomic;
nvme_set_features_write_protect;
nvme_set_property;
- nvme_setup_ctrl_list;
- nvme_setup_id_ns;
nvme_status_to_errno;
nvme_status_to_string;
- nvme_status_type;
nvme_submit_admin_passthru64;
nvme_submit_admin_passthru;
nvme_submit_io_passthru64;
@@ -360,18 +322,10 @@ LIBNVME_1_0 {
nvme_subsystem_reset;
nvme_unlink_ctrl;
nvme_update_config;
- nvme_verify;
nvme_virtual_mgmt;
- nvme_write;
- nvme_write_uncorrectable;
- nvme_write_zeros;
nvme_zns_append;
- nvme_zns_identify_ctrl;
- nvme_zns_identify_ns;
- nvme_zns_identify_ns;
nvme_zns_mgmt_recv;
nvme_zns_mgmt_send;
- nvme_zns_report_zones;
nvmf_add_ctrl;
nvmf_adrfam_str;
nvmf_cms_str;
diff --git a/src/meson.build b/src/meson.build
index e8b667c..811f0f8 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -6,7 +6,6 @@
# Authors: Martin Belanger <Martin.Belanger@dell.com>
#
sources = [
- 'nvme/cleanup.c',
'nvme/nbft.c',
'nvme/fabrics.c',
'nvme/filters.c',
@@ -15,10 +14,10 @@ sources = [
'nvme/log.c',
'nvme/tree.c',
'nvme/util.c',
+ 'nvme/base64.c'
]
mi_sources = [
- 'nvme/cleanup.c',
'nvme/log.c',
'nvme/mi.c',
'nvme/mi-mctp.c',
diff --git a/src/nvme/base64.c b/src/nvme/base64.c
new file mode 100644
index 0000000..5fae829
--- /dev/null
+++ b/src/nvme/base64.c
@@ -0,0 +1,94 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * base64.c - RFC4648-compliant base64 encoding
+ *
+ * Copyright (c) 2020 SUSE LLC
+ *
+ * Author: Hannes Reinecke <hare@suse.de>
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+
+static const char base64_table[65] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+/**
+ * base64_encode() - base64-encode some bytes
+ * @src: the bytes to encode
+ * @srclen: number of bytes to encode
+ * @dst: (output) the base64-encoded string. Not NUL-terminated.
+ *
+ * Encodes the input string using characters from the set [A-Za-z0-9+,].
+ * The encoded string is roughly 4/3 times the size of the input string.
+ *
+ * Return: length of the encoded string
+ */
+int base64_encode(const unsigned char *src, int srclen, char *dst)
+{
+ int i, bits = 0;
+ u_int32_t ac = 0;
+ char *cp = dst;
+
+ for (i = 0; i < srclen; i++) {
+ ac = (ac << 8) | src[i];
+ bits += 8;
+ do {
+ bits -= 6;
+ *cp++ = base64_table[(ac >> bits) & 0x3f];
+ } while (bits >= 6);
+ }
+ if (bits) {
+ *cp++ = base64_table[(ac << (6 - bits)) & 0x3f];
+ bits -= 6;
+ }
+ while (bits < 0) {
+ *cp++ = '=';
+ bits += 2;
+ }
+
+ return cp - dst;
+}
+
+/**
+ * base64_decode() - base64-decode some bytes
+ * @src: the base64-encoded string to decode
+ * @len: number of bytes to decode
+ * @dst: (output) the decoded bytes.
+ *
+ * Decodes the base64-encoded bytes @src according to RFC 4648.
+ *
+ * Return: number of decoded bytes
+ */
+int base64_decode(const char *src, int srclen, unsigned char *dst)
+{
+ u_int32_t ac = 0;
+ int i, bits = 0;
+ unsigned char *bp = dst;
+
+ for (i = 0; i < srclen; i++) {
+ const char *p = strchr(base64_table, src[i]);
+
+ if (src[i] == '=') {
+ ac = (ac << 6);
+ bits += 6;
+ if (bits >= 8)
+ bits -= 8;
+ continue;
+ }
+ if (!p || !src[i])
+ return -EINVAL;
+ ac = (ac << 6) | (p - base64_table);
+ bits += 6;
+ if (bits >= 8) {
+ bits -= 8;
+ *bp++ = (unsigned char)(ac >> bits);
+ }
+ }
+ if (ac && ((1 << bits) - 1))
+ return -EAGAIN;
+
+ return bp - dst;
+}
diff --git a/src/nvme/base64.h b/src/nvme/base64.h
new file mode 100644
index 0000000..c0f62e2
--- /dev/null
+++ b/src/nvme/base64.h
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#ifndef _BASE64_H
+#define _BASE64_H
+
+int base64_encode(const unsigned char *src, int len, char *dst);
+int base64_decode(const char *src, int len, unsigned char *dst);
+
+#endif /* _BASE64_H */
diff --git a/src/nvme/cleanup.c b/src/nvme/cleanup.c
deleted file mode 100644
index e652e33..0000000
--- a/src/nvme/cleanup.c
+++ /dev/null
@@ -1,5 +0,0 @@
-// SPDX-License-Identifier: LGPL-2.1-or-later
-#include <stdlib.h>
-#include "cleanup.h"
-
-DEFINE_CLEANUP_FUNC(cleanup_charp, char *, free);
diff --git a/src/nvme/cleanup.h b/src/nvme/cleanup.h
index b7e1533..4327600 100644
--- a/src/nvme/cleanup.h
+++ b/src/nvme/cleanup.h
@@ -2,6 +2,11 @@
#ifndef __CLEANUP_H
#define __CLEANUP_H
+#include <dirent.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
#define __cleanup__(fn) __attribute__((cleanup(fn)))
#define DECLARE_CLEANUP_FUNC(name, type) \
@@ -14,6 +19,23 @@ DECLARE_CLEANUP_FUNC(name, type) \
free_fn(*__p); \
}
-DECLARE_CLEANUP_FUNC(cleanup_charp, char *);
+static inline void freep(void *p)
+{
+ free(*(void **)p);
+}
+#define _cleanup_free_ __cleanup__(freep)
+
+static inline DEFINE_CLEANUP_FUNC(cleanup_file, FILE *, fclose)
+#define _cleanup_file_ __cleanup__(cleanup_file)
+
+static inline DEFINE_CLEANUP_FUNC(cleanup_dir, DIR *, closedir)
+#define _cleanup_dir_ __cleanup__(cleanup_dir)
+
+static inline void cleanup_fd(int *fd)
+{
+ if (*fd >= 0)
+ close(*fd);
+}
+#define _cleanup_fd_ __cleanup__(cleanup_fd)
#endif
diff --git a/src/nvme/fabrics.c b/src/nvme/fabrics.c
index f0a06e8..4e042d8 100644
--- a/src/nvme/fabrics.c
+++ b/src/nvme/fabrics.c
@@ -32,6 +32,7 @@
#include <ccan/array_size/array_size.h>
#include <ccan/str/str.h>
+#include "cleanup.h"
#include "fabrics.h"
#include "linux.h"
#include "ioctl.h"
@@ -47,7 +48,7 @@
const char *nvmf_dev = "/dev/nvme-fabrics";
/**
- * strchomp() - Strip trailing white space
+ * strchomp() - Strip trailing spaces
* @str: String to strip
* @max: Maximum length of string
*/
@@ -55,11 +56,8 @@ static void strchomp(char *str, int max)
{
int i;
- for (i = max - 1; i >= 0; i--) {
- if (str[i] != '\0' && str[i] != ' ')
- return;
- else
- str[i] = '\0';
+ for (i = max - 1; i >= 0 && str[i] == ' '; i--) {
+ str[i] = '\0';
}
}
@@ -357,10 +355,16 @@ static int __add_argument(char **argstr, const char *tok, const char *arg)
return 0;
}
+static int __nvmf_supported_options(nvme_root_t r);
+#define nvmf_check_option(r, tok) \
+({ \
+ !__nvmf_supported_options(r) && (r)->options->tok; \
+})
+
#define add_bool_argument(o, argstr, tok, arg) \
({ \
int ret; \
- if (r->options->tok) { \
+ if (nvmf_check_option(r, tok)) { \
ret = __add_bool_argument(argstr, \
stringify(tok), \
arg); \
@@ -376,7 +380,7 @@ static int __add_argument(char **argstr, const char *tok, const char *arg)
#define add_int_argument(o, argstr, tok, arg, allow_zero) \
({ \
int ret; \
- if (r->options->tok) { \
+ if (nvmf_check_option(r, tok)) { \
ret = __add_int_argument(argstr, \
stringify(tok), \
arg, \
@@ -393,7 +397,7 @@ static int __add_argument(char **argstr, const char *tok, const char *arg)
#define add_int_or_minus_one_argument(o, argstr, tok, arg) \
({ \
int ret; \
- if (r->options->tok) { \
+ if (nvmf_check_option(r, tok)) { \
ret = __add_int_or_minus_one_argument(argstr, \
stringify(tok), \
arg); \
@@ -409,7 +413,7 @@ static int __add_argument(char **argstr, const char *tok, const char *arg)
#define add_argument(r, argstr, tok, arg) \
({ \
int ret; \
- if (r->options->tok) { \
+ if (nvmf_check_option(r, tok)) { \
ret = __add_argument(argstr, \
stringify(tok), \
arg); \
@@ -442,7 +446,6 @@ static int inet4_pton(const char *src, uint16_t port,
static int inet6_pton(nvme_root_t r, const char *src, uint16_t port,
struct sockaddr_storage *addr)
{
- int ret = -EINVAL;
struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr;
const char *scope = NULL;
char *p;
@@ -450,7 +453,7 @@ static int inet6_pton(nvme_root_t r, const char *src, uint16_t port,
if (strlen(src) > INET6_ADDRSTRLEN)
return -EINVAL;
- char *tmp = strdup(src);
+ _cleanup_free_ char *tmp = strdup(src);
if (!tmp) {
nvme_msg(r, LOG_ERR, "cannot copy: %s\n", src);
return -ENOMEM;
@@ -463,24 +466,20 @@ static int inet6_pton(nvme_root_t r, const char *src, uint16_t port,
}
if (inet_pton(AF_INET6, tmp, &addr6->sin6_addr) != 1)
- goto free_tmp;
+ return -EINVAL;
if (IN6_IS_ADDR_LINKLOCAL(&addr6->sin6_addr) && scope) {
addr6->sin6_scope_id = if_nametoindex(scope);
if (addr6->sin6_scope_id == 0) {
nvme_msg(r, LOG_ERR,
"can't find iface index for: %s (%m)\n", scope);
- goto free_tmp;
+ return -EINVAL;
}
}
addr6->sin6_family = AF_INET6;
addr6->sin6_port = htons(port);
- ret = 0;
-
-free_tmp:
- free(tmp);
- return ret;
+ return 0;
}
/**
@@ -655,7 +654,7 @@ static int build_options(nvme_host_t h, nvme_ctrl_t c, char **argstr)
static int __nvmf_supported_options(nvme_root_t r)
{
char buf[0x1000], *options, *p, *v;
- int fd, ret;
+ _cleanup_fd_ int fd = -1;
ssize_t len;
if (r->options)
@@ -684,14 +683,12 @@ static int __nvmf_supported_options(nvme_root_t r)
"Cannot read %s, using default options\n",
nvmf_dev);
*r->options = default_supported_options;
- ret = 0;
- goto out_close;
+ return 0;
}
nvme_msg(r, LOG_ERR, "Failed to read from %s: %s\n",
nvmf_dev, strerror(errno));
- ret = -ENVME_CONNECT_READ;
- goto out_close;
+ return -ENVME_CONNECT_READ;
}
buf[len] = '\0';
@@ -738,16 +735,13 @@ static int __nvmf_supported_options(nvme_root_t r)
parse_option(r, v, trsvcid);
}
nvme_msg(r, LOG_DEBUG, "\n");
- ret = 0;
-
-out_close:
- close(fd);
- return ret;
+ return 0;
}
static int __nvmf_add_ctrl(nvme_root_t r, const char *argstr)
{
- int ret, fd, len = strlen(argstr);
+ _cleanup_fd_ int fd;
+ int ret, len = strlen(argstr);
char buf[0x1000], *options, *p;
fd = open(nvmf_dev, O_RDWR);
@@ -765,31 +759,22 @@ static int __nvmf_add_ctrl(nvme_root_t r, const char *argstr)
nvmf_dev, strerror(errno));
switch (errno) {
case EALREADY:
- ret = -ENVME_CONNECT_ALREADY;
- break;
+ return -ENVME_CONNECT_ALREADY;
case EINVAL:
- ret = -ENVME_CONNECT_INVAL;
- break;
+ return -ENVME_CONNECT_INVAL;
case EADDRINUSE:
- ret = -ENVME_CONNECT_ADDRINUSE;
- break;
+ return -ENVME_CONNECT_ADDRINUSE;
case ENODEV:
- ret = -ENVME_CONNECT_NODEV;
- break;
+ return -ENVME_CONNECT_NODEV;
case EOPNOTSUPP:
- ret = -ENVME_CONNECT_OPNOTSUPP;
- break;
+ return -ENVME_CONNECT_OPNOTSUPP;
case ECONNREFUSED:
- ret = -ENVME_CONNECT_CONNREFUSED;
- break;
+ return -ENVME_CONNECT_CONNREFUSED;
case EADDRNOTAVAIL:
- ret = -ENVME_CONNECT_ADDRNOTAVAIL;
- break;
+ return -ENVME_CONNECT_ADDRNOTAVAIL;
default:
- ret = -ENVME_CONNECT_WRITE;
- break;
+ return -ENVME_CONNECT_WRITE;
}
- goto out_close;
}
memset(buf, 0x0, sizeof(buf));
@@ -797,8 +782,7 @@ static int __nvmf_add_ctrl(nvme_root_t r, const char *argstr)
if (len < 0) {
nvme_msg(r, LOG_ERR, "Failed to read from %s: %s\n",
nvmf_dev, strerror(errno));
- ret = -ENVME_CONNECT_READ;
- goto out_close;
+ return -ENVME_CONNECT_READ;
}
nvme_msg(r, LOG_DEBUG, "connect ctrl, response '%.*s'\n",
(int)strcspn(buf, "\n"), buf);
@@ -808,14 +792,33 @@ static int __nvmf_add_ctrl(nvme_root_t r, const char *argstr)
if (!*p)
continue;
if (sscanf(p, "instance=%d", &ret) == 1)
- goto out_close;
+ return ret;
}
nvme_msg(r, LOG_ERR, "Failed to parse ctrl info for \"%s\"\n", argstr);
- ret = -ENVME_CONNECT_PARSE;
-out_close:
- close(fd);
- return ret;
+ return -ENVME_CONNECT_PARSE;
+}
+
+static const char *lookup_context(nvme_root_t r, nvme_ctrl_t c)
+{
+
+ nvme_host_t h;
+ nvme_subsystem_t s;
+
+ nvme_for_each_host(r, h) {
+ nvme_for_each_subsystem(h, s) {
+ if (__nvme_lookup_ctrl(s, nvme_ctrl_get_transport(c),
+ nvme_ctrl_get_traddr(c),
+ NULL,
+ NULL,
+ nvme_ctrl_get_trsvcid(c),
+ NULL,
+ NULL))
+ return nvme_subsystem_get_application(s);
+ }
+ }
+
+ return NULL;
}
int nvmf_add_ctrl(nvme_host_t h, nvme_ctrl_t c,
@@ -823,7 +826,7 @@ int nvmf_add_ctrl(nvme_host_t h, nvme_ctrl_t c,
{
nvme_subsystem_t s;
const char *root_app, *app;
- char *argstr;
+ _cleanup_free_ char *argstr = NULL;
int ret;
/* highest prio have configs from command line */
@@ -839,6 +842,7 @@ int nvmf_add_ctrl(nvme_host_t h, nvme_ctrl_t c,
nvme_ctrl_get_host_traddr(c),
nvme_ctrl_get_host_iface(c),
nvme_ctrl_get_trsvcid(c),
+ NULL,
NULL);
if (fc) {
const char *key;
@@ -862,24 +866,9 @@ int nvmf_add_ctrl(nvme_host_t h, nvme_ctrl_t c,
root_app = nvme_root_get_application(h->r);
if (root_app) {
app = nvme_subsystem_get_application(s);
- if (!app && nvme_ctrl_is_discovery_ctrl(c)) {
- nvme_subsystem_t s;
- nvme_ctrl_t fc;
-
- nvme_for_each_subsystem(h, s) {
- fc = __nvme_lookup_ctrl(s, nvme_ctrl_get_transport(c),
- nvme_ctrl_get_traddr(c),
- NULL,
- NULL,
- nvme_ctrl_get_trsvcid(c),
- NULL);
-
- if (fc) {
- app = nvme_subsystem_get_application(s);
- break;
- }
- }
- }
+ if (!app && nvme_ctrl_is_discovery_ctrl(c))
+ app = lookup_context(h->r, c);
+
/*
* configuration is managed by an application,
* refuse to act on subsystems which either have
@@ -907,15 +896,11 @@ int nvmf_add_ctrl(nvme_host_t h, nvme_ctrl_t c,
free(traddr);
}
- ret = __nvmf_supported_options(h->r);
- if (ret)
- return ret;
ret = build_options(h, c, &argstr);
if (ret)
return ret;
ret = __nvmf_add_ctrl(h->r, argstr);
- free(argstr);
if (ret < 0) {
errno = -ret;
return -1;
@@ -1020,12 +1005,12 @@ nvme_ctrl_t nvmf_connect_disc_entry(nvme_host_t h,
return NULL;
}
- if (e->treq & NVMF_TREQ_DISABLE_SQFLOW)
+ if (e->treq & NVMF_TREQ_DISABLE_SQFLOW &&
+ nvmf_check_option(h->r, disable_sqflow))
c->cfg.disable_sqflow = true;
if (e->trtype == NVMF_TRTYPE_TCP &&
- (e->treq & NVMF_TREQ_REQUIRED ||
- e->treq & NVMF_TREQ_NOT_REQUIRED))
+ e->tsas.tcp.sectype != NVMF_TCP_SECTYPE_NONE)
c->cfg.tls = true;
ret = nvmf_add_ctrl(h, c, cfg);
@@ -1046,45 +1031,55 @@ nvme_ctrl_t nvmf_connect_disc_entry(nvme_host_t h,
return NULL;
}
-static struct nvmf_discovery_log *nvme_discovery_log(nvme_ctrl_t c,
- struct nvme_get_log_args *args,
- int max_retries)
+/*
+ * Most of nvmf_discovery_log is reserved, so only fetch the initial bytes.
+ * 8 bytes for GENCTR, 8 for NUMREC, and 2 for RECFMT.
+ * Since only multiples of 4 bytes are allowed, round 18 up to 20.
+ */
+#define DISCOVERY_HEADER_LEN 20
+
+static struct nvmf_discovery_log *nvme_discovery_log(
+ const struct nvme_get_discovery_args *args)
{
- nvme_root_t r = c->s && c->s->h ? c->s->h->r : NULL;
- struct nvmf_discovery_log *log = NULL;
- int ret, retries = 0;
- const char *name = nvme_ctrl_get_name(c);
+ nvme_root_t r = root_from_ctrl(args->c);
+ struct nvmf_discovery_log *log;
+ int retries = 0;
+ const char *name = nvme_ctrl_get_name(args->c);
uint64_t genctr, numrec;
- unsigned int size;
- int fd = nvme_ctrl_get_fd(c);
-
- args->fd = fd;
+ 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,
+ };
- do {
- size = sizeof(struct nvmf_discovery_log);
+ log = __nvme_alloc(sizeof(*log));
+ if (!log) {
+ nvme_msg(r, LOG_ERR,
+ "could not allocate memory for discovery log header\n");
+ errno = ENOMEM;
+ return NULL;
+ }
- free(log);
- log = calloc(1, size);
- if (!log) {
- nvme_msg(r, LOG_ERR,
- "could not allocate memory for discovery log header\n");
- errno = ENOMEM;
- return NULL;
- }
+ nvme_msg(r, 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,
+ "%s: discover try %d/%d failed, error %d\n",
+ name, retries, args->max_retries, errno);
+ goto out_free_log;
+ }
- nvme_msg(r, LOG_DEBUG, "%s: get header (try %d/%d)\n",
- name, retries, max_retries);
- args->rae = true;
- args->lpo = 0;
- args->len = size;
- args->log = log;
- ret = nvme_get_log_page(fd, NVME_LOG_PAGE_PDU_SIZE, args);
- if (ret) {
- nvme_msg(r, LOG_INFO,
- "%s: discover try %d/%d failed, error %d\n",
- name, retries, max_retries, errno);
- goto out_free_log;
- }
+ do {
+ size_t entries_size;
numrec = le64_to_cpu(log->numrec);
genctr = le64_to_cpu(log->genctr);
@@ -1092,11 +1087,9 @@ static struct nvmf_discovery_log *nvme_discovery_log(nvme_ctrl_t c,
if (numrec == 0)
break;
- size = sizeof(struct nvmf_discovery_log) +
- sizeof(struct nvmf_disc_log_entry) * numrec;
-
free(log);
- log = calloc(1, size);
+ entries_size = sizeof(*log->entries) * numrec;
+ log = __nvme_alloc(sizeof(*log) + entries_size);
if (!log) {
nvme_msg(r, LOG_ERR,
"could not alloc memory for discovery log page\n");
@@ -1105,19 +1098,16 @@ static struct nvmf_discovery_log *nvme_discovery_log(nvme_ctrl_t c,
}
nvme_msg(r, LOG_DEBUG,
- "%s: get %" PRIu64
- " records (length %d genctr %" PRIu64 ")\n",
- name, numrec, size, genctr);
-
- args->rae = true;
- args->lpo = sizeof(struct nvmf_discovery_log);
- args->len = size - sizeof(struct nvmf_discovery_log);
- args->log = log->entries;
- ret = nvme_get_log_page(fd, NVME_LOG_PAGE_PDU_SIZE, args);
- if (ret) {
+ "%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,
"%s: discover try %d/%d failed, error %d\n",
- name, retries, max_retries, errno);
+ name, retries, args->max_retries, errno);
goto out_free_log;
}
@@ -1127,19 +1117,17 @@ static struct nvmf_discovery_log *nvme_discovery_log(nvme_ctrl_t c,
*/
nvme_msg(r, LOG_DEBUG, "%s: get header again\n", name);
- args->rae = false;
- args->lpo = 0;
- args->len = sizeof(struct nvmf_discovery_log);
- args->log = log;
- ret = nvme_get_log_page(fd, NVME_LOG_PAGE_PDU_SIZE, args);
- if (ret) {
+ 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,
"%s: discover try %d/%d failed, error %d\n",
- name, retries, max_retries, errno);
+ name, retries, args->max_retries, errno);
goto out_free_log;
}
} while (genctr != le64_to_cpu(log->genctr) &&
- ++retries < max_retries);
+ ++retries < args->max_retries);
if (genctr != le64_to_cpu(log->genctr)) {
nvme_msg(r, LOG_INFO, "%s: discover genctr mismatch\n", name);
@@ -1159,87 +1147,31 @@ out_free_log:
return NULL;
}
-static void sanitize_discovery_log_entry(struct nvmf_disc_log_entry *e)
+static void sanitize_discovery_log_entry(struct nvmf_disc_log_entry *e)
{
- switch (e->trtype) {
- case NVMF_TRTYPE_RDMA:
- case NVMF_TRTYPE_TCP:
- switch (e->adrfam) {
- case NVMF_ADDR_FAMILY_IP4:
- case NVMF_ADDR_FAMILY_IP6:
- strchomp(e->traddr, NVMF_TRADDR_SIZE);
- strchomp(e->trsvcid, NVMF_TRSVCID_SIZE);
- break;
- }
- break;
- case NVMF_TRTYPE_FC:
- switch (e->adrfam) {
- case NVMF_ADDR_FAMILY_FC:
- strchomp(e->traddr, NVMF_TRADDR_SIZE);
- break;
- }
- break;
- case NVMF_TRTYPE_LOOP:
- strchomp(e->traddr, NVMF_TRADDR_SIZE);
- break;
- }
+ strchomp(e->trsvcid, sizeof(e->trsvcid));
+ strchomp(e->traddr, sizeof(e->traddr));
}
int nvmf_get_discovery_log(nvme_ctrl_t c, struct nvmf_discovery_log **logp,
int max_retries)
{
- struct nvmf_discovery_log *log;
-
- struct nvme_get_log_args args = {
- .args_size = sizeof(args),
- .fd = nvme_ctrl_get_fd(c),
- .nsid = NVME_NSID_NONE,
- .lsp = NVMF_LOG_DISC_LSP_NONE,
- .lsi = NVME_LOG_LSI_NONE,
- .uuidx = NVME_UUID_NONE,
+ struct nvme_get_discovery_args args = {
+ .c = c,
+ .max_retries = max_retries,
.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
- .result = NULL,
- .lid = NVME_LOG_LID_DISCOVER,
- .log = NULL,
- .len = 0,
- .csi = NVME_CSI_NVM,
- .rae = false,
- .ot = false,
+ .lsp = NVMF_LOG_DISC_LSP_NONE,
};
- log = nvme_discovery_log(c, &args, max_retries);
- if (!log)
- return -1;
-
- for (int i = 0; i < le64_to_cpu(log->numrec); i++)
- sanitize_discovery_log_entry(&log->entries[i]);
-
- *logp = log;
- return 0;
+ *logp = nvmf_get_discovery_wargs(&args);
+ return *logp ? 0 : -1;
}
struct nvmf_discovery_log *nvmf_get_discovery_wargs(struct nvme_get_discovery_args *args)
{
struct nvmf_discovery_log *log;
- struct nvme_get_log_args _args = {
- .args_size = sizeof(_args),
- .fd = nvme_ctrl_get_fd(args->c),
- .nsid = NVME_NSID_NONE,
- .lsp = args->lsp,
- .lsi = NVME_LOG_LSI_NONE,
- .uuidx = NVME_UUID_NONE,
- .timeout = args->timeout,
- .result = args->result,
- .lid = NVME_LOG_LID_DISCOVER,
- .log = NULL,
- .len = 0,
- .csi = NVME_CSI_NVM,
- .rae = false,
- .ot = false,
- };
-
- log = nvme_discovery_log(args->c, &_args, args->max_retries);
+ log = nvme_discovery_log(args);
if (!log)
return NULL;
@@ -1254,7 +1186,7 @@ struct nvmf_discovery_log *nvmf_get_discovery_wargs(struct nvme_get_discovery_ar
static int uuid_from_device_tree(char *system_uuid)
{
ssize_t len;
- int f;
+ _cleanup_fd_ int f;
f = open(PATH_UUID_IBM, O_RDONLY);
if (f < 0)
@@ -1262,7 +1194,6 @@ static int uuid_from_device_tree(char *system_uuid)
memset(system_uuid, 0, NVME_UUID_LEN_STRING);
len = read(f, system_uuid, NVME_UUID_LEN_STRING - 1);
- close(f);
if (len < 0)
return -ENXIO;
@@ -1299,7 +1230,7 @@ static bool is_dmi_uuid_valid(const char *buf, size_t len)
static int uuid_from_dmi_entries(char *system_uuid)
{
int f;
- DIR *d;
+ _cleanup_dir_ DIR *d;
struct dirent *de;
char buf[512] = {0};
@@ -1350,7 +1281,6 @@ static int uuid_from_dmi_entries(char *system_uuid)
(uint8_t)buf[8 + 14], (uint8_t)buf[8 + 15]);
break;
}
- closedir(d);
return strlen(system_uuid) ? 0 : -ENXIO;
}
@@ -1364,10 +1294,9 @@ static int uuid_from_dmi_entries(char *system_uuid)
*/
static int uuid_from_product_uuid(char *system_uuid)
{
- FILE *stream;
+ _cleanup_file_ FILE *stream;
ssize_t nread;
- int ret;
- char *line = NULL;
+ _cleanup_free_ char *line = NULL;
size_t len = 0;
stream = fopen(PATH_DMI_PROD_UUID, "re");
@@ -1376,10 +1305,8 @@ static int uuid_from_product_uuid(char *system_uuid)
system_uuid[0] = '\0';
nread = getline(&line, &len, stream);
- if (nread != NVME_UUID_LEN_STRING) {
- ret = -ENXIO;
- goto out;
- }
+ if (nread != NVME_UUID_LEN_STRING)
+ return -ENXIO;
/* The kernel is handling the byte swapping according DMTF
* SMBIOS 3.0 Section 7.2.1 System UUID */
@@ -1387,13 +1314,7 @@ static int uuid_from_product_uuid(char *system_uuid)
memcpy(system_uuid, line, NVME_UUID_LEN_STRING - 1);
system_uuid[NVME_UUID_LEN_STRING - 1] = '\0';
- ret = 0;
-
-out:
- free(line);
- fclose(stream);
-
- return ret;
+ return 0;
}
/**
@@ -1443,7 +1364,8 @@ char *nvmf_hostnqn_generate()
static char *nvmf_read_file(const char *f, int len)
{
char buf[len];
- int ret, fd;
+ _cleanup_fd_ int fd;
+ int ret;
fd = open(f, O_RDONLY);
if (fd < 0)
@@ -1451,7 +1373,6 @@ static char *nvmf_read_file(const char *f, int len)
memset(buf, 0, len);
ret = read(fd, buf, len - 1);
- close (fd);
if (ret < 0 || !strlen(buf))
return NULL;
@@ -1575,7 +1496,7 @@ static int nvmf_dim(nvme_ctrl_t c, enum nvmf_dim_tas tas, __u8 trtype,
__u32 *result)
{
nvme_root_t r = c->s && c->s->h ? c->s->h->r : NULL;
- struct nvmf_dim_data *dim;
+ _cleanup_free_ struct nvmf_dim_data *dim = NULL;
struct nvmf_ext_die *die;
__u32 tdl;
__u32 tel;
@@ -1662,11 +1583,7 @@ static int nvmf_dim(nvme_ctrl_t c, enum nvmf_dim_tas tas, __u8 trtype,
args.data_len = tdl;
args.data = dim;
- ret = nvme_dim_send(&args);
-
- free(dim);
-
- return ret;
+ return nvme_dim_send(&args);
}
/**
@@ -1720,25 +1637,31 @@ static const char *dctype_str[] = {
*/
static int nvme_fetch_cntrltype_dctype_from_id(nvme_ctrl_t c)
{
- struct nvme_id_ctrl id = { 0 };
+ _cleanup_free_ struct nvme_id_ctrl *id;
int ret;
- ret = nvme_ctrl_identify(c, &id);
+ id = __nvme_alloc(sizeof(*id));
+ if (!id) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ ret = nvme_ctrl_identify(c, id);
if (ret)
return ret;
if (!c->cntrltype) {
- if (id.cntrltype > NVME_CTRL_CNTRLTYPE_ADMIN || !cntrltype_str[id.cntrltype])
+ if (id->cntrltype > NVME_CTRL_CNTRLTYPE_ADMIN || !cntrltype_str[id->cntrltype])
c->cntrltype = strdup("reserved");
else
- c->cntrltype = strdup(cntrltype_str[id.cntrltype]);
+ c->cntrltype = strdup(cntrltype_str[id->cntrltype]);
}
- if (!c->dctype) {
- if (id.dctype > NVME_CTRL_DCTYPE_CDC || !dctype_str[id.dctype])
+ if (!c->dctype) {
+ if (id->dctype > NVME_CTRL_DCTYPE_CDC || !dctype_str[id->dctype])
c->dctype = strdup("reserved");
else
- c->dctype = strdup(dctype_str[id.dctype]);
+ c->dctype = strdup(dctype_str[id->dctype]);
}
return 0;
}
diff --git a/src/nvme/ioctl.c b/src/nvme/ioctl.c
index b9710b3..9090b7e 100644
--- a/src/nvme/ioctl.c
+++ b/src/nvme/ioctl.c
@@ -13,9 +13,11 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <inttypes.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
+#include <sys/time.h>
#include <ccan/build_assert/build_assert.h>
#include <ccan/endian/endian.h>
@@ -23,6 +25,8 @@
#include "ioctl.h"
#include "util.h"
+static bool nvme_debug;
+
static int nvme_verify_chr(int fd)
{
static struct stat nvme_stat;
@@ -86,13 +90,62 @@ static int nvme_submit_passthru64(int fd, unsigned long ioctl_cmd,
return err;
}
+static void nvme_show_command(struct nvme_passthru_cmd *cmd, int err, struct timeval start,
+ struct timeval end)
+{
+ printf("opcode : %02x\n", cmd->opcode);
+ printf("flags : %02x\n", cmd->flags);
+ printf("rsvd1 : %04x\n", cmd->rsvd1);
+ printf("nsid : %08x\n", cmd->nsid);
+ printf("cdw2 : %08x\n", cmd->cdw2);
+ printf("cdw3 : %08x\n", cmd->cdw3);
+ printf("data_len : %08x\n", cmd->data_len);
+ printf("metadata_len : %08x\n", cmd->metadata_len);
+ printf("addr : %"PRIx64"\n", (uint64_t)(uintptr_t)cmd->addr);
+ printf("metadata : %"PRIx64"\n", (uint64_t)(uintptr_t)cmd->metadata);
+ printf("cdw10 : %08x\n", cmd->cdw10);
+ printf("cdw11 : %08x\n", cmd->cdw11);
+ printf("cdw12 : %08x\n", cmd->cdw12);
+ printf("cdw13 : %08x\n", cmd->cdw13);
+ printf("cdw14 : %08x\n", cmd->cdw14);
+ printf("cdw15 : %08x\n", cmd->cdw15);
+ printf("timeout_ms : %08x\n", cmd->timeout_ms);
+ printf("result : %08x\n", cmd->result);
+ printf("err : %d\n", err);
+ printf("latency : %lu us\n",
+ (end.tv_sec - start.tv_sec) * 1000000 + (end.tv_usec - start.tv_usec));
+}
+
+void nvme_set_debug(bool debug)
+{
+ nvme_debug = debug;
+}
+
+bool nvme_get_debug(void)
+{
+ return nvme_debug;
+}
+
static int nvme_submit_passthru(int fd, unsigned long ioctl_cmd,
struct nvme_passthru_cmd *cmd, __u32 *result)
{
- int err = ioctl(fd, ioctl_cmd, cmd);
+ struct timeval start;
+ struct timeval end;
+ int err;
+
+ if (nvme_get_debug())
+ gettimeofday(&start, NULL);
+
+ err = ioctl(fd, ioctl_cmd, cmd);
+
+ if (nvme_get_debug()) {
+ gettimeofday(&end, NULL);
+ nvme_show_command(cmd, err, start, end);
+ }
if (err >= 0 && result)
*result = cmd->result;
+
return err;
}
@@ -532,16 +585,18 @@ 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_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, __u32 nr_ranges, bool save,
+int nvme_set_features_lba_range(int fd, __u32 nsid, __u8 nr_ranges, bool save,
struct nvme_lba_range_type *data, __u32 *result)
{
- return -1;
+ 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,
@@ -562,8 +617,8 @@ int nvme_set_features_err_recovery(int fd, __u32 nsid, __u16 tler, bool dulbe,
__u32 value = NVME_SET(tler, FEAT_ERROR_RECOVERY_TLER) |
NVME_SET(!!dulbe, FEAT_ERROR_RECOVERY_DULBE);
- return __nvme_set_features(fd, NVME_FEAT_FID_ERR_RECOVERY, value, save,
- result);
+ 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)
@@ -577,8 +632,8 @@ int nvme_set_features_volatile_wc(int fd, bool wce, bool save, __u32 *result)
int nvme_set_features_irq_coalesce(int fd, __u8 thr, __u8 time, bool save,
__u32 *result)
{
- __u32 value = NVME_SET(thr, FEAT_IRQC_TIME) |
- NVME_SET(time, FEAT_IRQC_THR);
+ __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);
@@ -612,19 +667,31 @@ int nvme_set_features_async_event(int fd, __u32 events,
int nvme_set_features_auto_pst(int fd, bool apste, bool save,
struct nvme_feat_auto_pst *apst, __u32 *result)
{
- __u32 value = NVME_SET(!!apste, FEAT_APST_APSTE);
+ struct nvme_set_features_args args = {
+ .args_size = sizeof(args),
+ .fd = fd,
+ .fid = NVME_FEAT_FID_AUTO_PST,
+ .nsid = NVME_NSID_NONE,
+ .cdw11 = NVME_SET(!!apste, FEAT_APST_APSTE),
+ .save = save,
+ .uuidx = NVME_UUID_NONE,
+ .data = apst,
+ .data_len = sizeof(*apst),
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = result,
+ };
- return __nvme_set_features(fd, NVME_FEAT_FID_AUTO_PST, value, save,
- result);
+ return nvme_set_features(&args);
}
int nvme_set_features_timestamp(int fd, bool save, __u64 timestamp)
{
__le64 t = cpu_to_le64(timestamp);
- struct nvme_timestamp ts;
+ struct nvme_timestamp ts = {};
struct nvme_set_features_args args = {
.args_size = sizeof(args),
.fd = fd,
+ .fid = NVME_FEAT_FID_TIMESTAMP,
.nsid = NVME_NSID_NONE,
.cdw11 = 0,
.cdw12 = 0,
@@ -694,8 +761,8 @@ int nvme_set_features_plm_config(int fd, bool plm, __u16 nvmsetid, bool save,
.save = save,
.uuidx = NVME_UUID_NONE,
.cdw15 = 0,
- .data_len = 0,
- .data = NULL,
+ .data_len = sizeof(*data),
+ .data = data,
.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
.result = result,
};
@@ -746,7 +813,7 @@ int nvme_set_features_host_behavior(int fd, bool save,
.nsid = NVME_NSID_NONE,
.cdw11 = 0,
.cdw12 = 0,
- .save = save,
+ .save = false,
.uuidx = NVME_UUID_NONE,
.cdw15 = 0,
.data_len = sizeof(*data),
@@ -780,7 +847,7 @@ int nvme_set_features_sw_progress(int fd, __u8 pbslc, bool save,
result);
}
-int nvme_set_features_host_id(int fd, bool save, bool exhid, __u8 *hostid)
+int nvme_set_features_host_id(int fd, bool exhid, bool save, __u8 *hostid)
{
__u32 len = exhid ? 16 : 8;
__u32 value = !!exhid;
@@ -809,20 +876,42 @@ int nvme_set_features_resv_mask(int fd, __u32 mask, bool save, __u32 *result)
result);
}
+int nvme_set_features_resv_mask2(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, bool ptpl, bool save, __u32 *result)
{
return __nvme_set_features(fd, NVME_FEAT_FID_RESV_PERSIST, !!ptpl, save,
result);
}
+int nvme_set_features_resv_persist2(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, enum nvme_feat_nswpcfg_state state,
bool save, __u32 *result)
{
return __nvme_set_features(fd, NVME_FEAT_FID_WRITE_PROTECT, state,
- save, result);
+ false, result);
+}
+
+int nvme_set_features_write_protect2(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, __u8 iocsi, bool save)
+int nvme_set_features_iocs_profile(int fd, __u16 iocsi, bool save)
{
__u32 value = NVME_SET(iocsi, FEAT_IOCSP_IOCSCI);
@@ -898,8 +987,28 @@ int nvme_get_features_lba_range(int fd, enum nvme_get_features_sel sel,
.sel = sel,
.cdw11 = 0,
.uuidx = NVME_UUID_NONE,
- .data_len = 0,
- .data = NULL,
+ .data_len = sizeof(*data),
+ .data = data,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = result,
+ };
+
+ return nvme_get_features(&args);
+}
+
+int nvme_get_features_lba_range2(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,
};
@@ -920,6 +1029,24 @@ int nvme_get_features_err_recovery(int fd, enum nvme_get_features_sel sel,
result);
}
+int nvme_get_features_err_recovery2(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)
{
@@ -945,7 +1072,7 @@ int nvme_get_features_irq_config(int fd, enum nvme_get_features_sel sel,
struct nvme_get_features_args args = {
.args_size = sizeof(args),
.fd = fd,
- .fid = NVME_FEAT_FID_LBA_RANGE,
+ .fid = NVME_FEAT_FID_IRQ_CONFIG,
.nsid = NVME_NSID_NONE,
.sel = sel,
.cdw11 = iv,
@@ -978,13 +1105,13 @@ int nvme_get_features_auto_pst(int fd, enum nvme_get_features_sel sel,
struct nvme_get_features_args args = {
.args_size = sizeof(args),
.fd = fd,
- .fid = NVME_FEAT_FID_LBA_RANGE,
+ .fid = NVME_FEAT_FID_AUTO_PST,
.nsid = NVME_NSID_NONE,
.sel = sel,
.cdw11 = 0,
.uuidx = NVME_UUID_NONE,
- .data_len = 0,
- .data = NULL,
+ .data_len = sizeof(*apst),
+ .data = apst,
.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
.result = result,
};
@@ -998,6 +1125,26 @@ int nvme_get_features_host_mem_buf(int fd, enum nvme_get_features_sel sel,
return __nvme_get_features(fd, NVME_FEAT_FID_HOST_MEM_BUF, sel, result);
}
+int nvme_get_features_host_mem_buf2(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)
{
@@ -1050,8 +1197,8 @@ int nvme_get_features_plm_config(int fd, enum nvme_get_features_sel sel,
.sel = sel,
.cdw11 = nvmsetid,
.uuidx = NVME_UUID_NONE,
- .data_len = 0,
- .data = NULL,
+ .data_len = sizeof(*data),
+ .data = data,
.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
.result = result,
};
@@ -1098,8 +1245,8 @@ int nvme_get_features_host_behavior(int fd, enum nvme_get_features_sel sel,
.sel = sel,
.cdw11 = 0,
.uuidx = NVME_UUID_NONE,
- .data_len = 0,
- .data = NULL,
+ .data_len = sizeof(*data),
+ .data = data,
.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
.result = result,
};
@@ -1122,7 +1269,7 @@ int nvme_get_features_endurance_event_cfg(int fd, enum nvme_get_features_sel sel
.fid = NVME_FEAT_FID_ENDURANCE_EVT_CFG,
.nsid = NVME_NSID_NONE,
.sel = sel,
- .cdw11 = 0,
+ .cdw11 = endgid,
.uuidx = NVME_UUID_NONE,
.data_len = 0,
.data = NULL,
@@ -1165,12 +1312,46 @@ int nvme_get_features_resv_mask(int fd, enum nvme_get_features_sel sel,
return __nvme_get_features(fd, NVME_FEAT_FID_RESV_MASK, sel, result);
}
+int nvme_get_features_resv_mask2(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 *result)
{
return __nvme_get_features(fd, NVME_FEAT_FID_RESV_PERSIST, sel, result);
}
+int nvme_get_features_resv_persist2(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)
@@ -1387,6 +1568,7 @@ int nvme_get_lba_status(struct nvme_get_lba_status_args *args)
.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,
@@ -1655,33 +1837,35 @@ static int nvme_set_var_size_tags(__u32 *cmd_dw2, __u32 *cmd_dw3, __u32 *cmd_dw1
__u8 pif, __u8 sts, __u64 reftag, __u64 storage_tag)
{
__u32 cdw2 = 0, cdw3 = 0, cdw14;
+ beint64_t be_reftag = cpu_to_be64(reftag);
+ beint64_t be_storage_tag = cpu_to_be64(storage_tag);
switch (pif) {
/* 16b Protection Information */
case 0:
- cdw14 = reftag & 0xffffffff;
- cdw14 |= ((storage_tag << (32 - sts)) & 0xffffffff);
+ cdw14 = be_reftag & 0xffffffff;
+ cdw14 |= ((be_storage_tag << (32 - sts)) & 0xffffffff);
break;
/* 32b Protection Information */
case 1:
- cdw14 = reftag & 0xffffffff;
- cdw3 = reftag >> 32;
- cdw14 |= ((storage_tag << (80 - sts)) & 0xffff0000);
+ cdw14 = be_reftag & 0xffffffff;
+ cdw3 = be_reftag >> 32;
+ cdw14 |= ((be_storage_tag << (80 - sts)) & 0xffff0000);
if (sts >= 48)
- cdw3 |= ((storage_tag >> (sts - 48)) & 0xffffffff);
+ cdw3 |= ((be_storage_tag >> (sts - 48)) & 0xffffffff);
else
- cdw3 |= ((storage_tag << (48 - sts)) & 0xffffffff);
- cdw2 = (storage_tag >> (sts - 16)) & 0xffff;
+ cdw3 |= ((be_storage_tag << (48 - sts)) & 0xffffffff);
+ cdw2 = (be_storage_tag >> (sts - 16)) & 0xffff;
break;
/* 64b Protection Information */
case 2:
- cdw14 = reftag & 0xffffffff;
- cdw3 = (reftag >> 32) & 0xffff;
- cdw14 |= ((storage_tag << (48 - sts)) & 0xffffffff);
+ cdw14 = be_reftag & 0xffffffff;
+ cdw3 = (be_reftag >> 32) & 0xffff;
+ cdw14 |= ((be_storage_tag << (48 - sts)) & 0xffffffff);
if (sts >= 16)
- cdw3 |= ((storage_tag >> (sts - 16)) & 0xffff);
+ cdw3 |= ((be_storage_tag >> (sts - 16)) & 0xffff);
else
- cdw3 |= ((storage_tag << (16 - sts)) & 0xffff);
+ cdw3 |= ((be_storage_tag << (16 - sts)) & 0xffff);
break;
default:
perror("Unsupported Protection Information Format");
@@ -1793,6 +1977,10 @@ int nvme_copy(struct nvme_copy_args *args)
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);
diff --git a/src/nvme/ioctl.h b/src/nvme/ioctl.h
index 4d843bc..4a0698f 100644
--- a/src/nvme/ioctl.h
+++ b/src/nvme/ioctl.h
@@ -748,7 +748,6 @@ static inline int nvme_identify_primary_ctrl(int fd, __u16 cntid,
/**
* nvme_identify_secondary_ctrl_list() - Retrieves secondary controller list
* @fd: File descriptor of nvme device
- * @nsid: Namespace identifier
* @cntid: Return controllers starting at this identifier
* @sc_list: User space destination address to transfer the data
*
@@ -763,7 +762,7 @@ static inline int nvme_identify_primary_ctrl(int fd, __u16 cntid,
* 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_identify_secondary_ctrl_list(int fd, __u32 nsid,
+static inline int nvme_identify_secondary_ctrl_list(int fd,
__u16 cntid, struct nvme_secondary_ctrl_list *sc_list)
{
struct nvme_identify_args args = {
@@ -774,7 +773,7 @@ static inline int nvme_identify_secondary_ctrl_list(int fd, __u32 nsid,
.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
.cns = NVME_IDENTIFY_CNS_SECONDARY_CTRL_LIST,
.csi = NVME_CSI_NVM,
- .nsid = nsid,
+ .nsid = NVME_NSID_NONE,
.cntid = cntid,
.cns_specific_id = NVME_CNSSPECID_NONE,
.uuidx = NVME_UUID_NONE,
@@ -981,21 +980,8 @@ static inline int nvme_identify_allocated_ns_list_csi(int fd, __u32 nsid,
static inline int nvme_identify_independent_identify_ns(int fd, __u32 nsid,
struct nvme_id_independent_id_ns *ns)
{
- struct nvme_identify_args args = {
- .result = NULL,
- .data = ns,
- .args_size = sizeof(args),
- .fd = fd,
- .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
- .cns = NVME_IDENTIFY_CNS_CSI_INDEPENDENT_ID_NS,
- .csi = NVME_CSI_NVM,
- .nsid = nsid,
- .cntid = NVME_CNTLID_NONE,
- .cns_specific_id = NVME_CNSSPECID_NONE,
- .uuidx = NVME_UUID_NONE,
- };
-
- return nvme_identify(&args);
+ return nvme_identify_cns_nsid(
+ fd, NVME_IDENTIFY_CNS_CSI_INDEPENDENT_ID_NS, nsid, ns);
}
/**
@@ -1194,20 +1180,8 @@ static inline int nvme_identify_iocs(int fd, __u16 cntlid,
static inline int nvme_zns_identify_ns(int fd, __u32 nsid,
struct nvme_zns_id_ns *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 = NVME_CSI_ZNS,
- .nsid = nsid,
- .cntid = NVME_CNTLID_NONE,
- .cns_specific_id = NVME_CNSSPECID_NONE,
- };
-
- return nvme_identify(&args);
+ return nvme_identify_ns_csi(
+ fd, nsid, NVME_UUID_NONE, NVME_CSI_ZNS, data);
}
/**
@@ -1946,7 +1920,7 @@ static inline int nvme_get_log_boot_partition(int fd, bool rae,
.nsid = NVME_NSID_NONE,
.csi = NVME_CSI_NVM,
.lsi = NVME_LOG_LSI_NONE,
- .lsp = NVME_LOG_LSP_NONE,
+ .lsp = lsp,
.uuidx = NVME_UUID_NONE,
.rae = rae,
.ot = false,
@@ -1955,6 +1929,41 @@ static inline int nvme_get_log_boot_partition(int fd, bool rae,
}
/**
+ * nvme_get_log_phy_rx_eom() - Retrieve Physical Interface Receiver Eye Opening Measurement Log
+ * @fd: File descriptor of nvme device
+ * @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_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);
+}
+
+/**
* nvme_get_log_discovery() - Retrieve Discovery log page
* @fd: File descriptor of nvme device
* @rae: Retain asynchronous events
@@ -2266,7 +2275,7 @@ int nvme_set_features_power_mgmt(int fd, __u8 ps, __u8 wh, bool save,
* 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_lba_range(int fd, __u32 nsid, __u32 nr_ranges, bool save,
+int nvme_set_features_lba_range(int fd, __u32 nsid, __u8 nr_ranges, bool save,
struct nvme_lba_range_type *data, __u32 *result);
/**
@@ -2542,7 +2551,25 @@ int nvme_set_features_host_id(int fd, bool exhid, bool save, __u8 *hostid);
/**
* nvme_set_features_resv_mask() - Set reservation notification mask feature
+ *
+ * Deprecated: doesn't support specifying a NSID.
+ * Use nvme_set_features_resv_mask2() instead.
+ *
+ * @fd: File descriptor of nvme device
+ * @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.
+ */
+int nvme_set_features_resv_mask(int fd, __u32 mask, bool save, __u32 *result)
+ __attribute__((deprecated));
+
+/**
+ * nvme_set_features_resv_mask2() - Set reservation notification mask feature
* @fd: File descriptor of nvme device
+ * @nsid: Namespace ID
* @mask: Reservation Notification Mask Field
* @save: Save value across power states
* @result: The command completion result from CQE dword0
@@ -2550,11 +2577,30 @@ int nvme_set_features_host_id(int fd, bool exhid, bool save, __u8 *hostid);
* 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_resv_mask(int fd, __u32 mask, bool save, __u32 *result);
+int nvme_set_features_resv_mask2(int fd, __u32 nsid, __u32 mask, bool save,
+ __u32 *result);
/**
* nvme_set_features_resv_persist() - Set persist through power loss feature
+ *
+ * Deprecated: doesn't support specifying a NSID.
+ * Use nvme_set_features_resv_persist2() instead.
+ *
+ * @fd: File descriptor of nvme device
+ * @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.
+ */
+int nvme_set_features_resv_persist(int fd, bool ptpl, bool save, __u32 *result)
+ __attribute__((deprecated));
+
+/**
+ * nvme_set_features_resv_persist2() - Set persist through power loss feature
* @fd: File descriptor of nvme device
+ * @nsid: Namespace ID
* @ptpl: Persist Through Power Loss
* @save: Save value across power states
* @result: The command completion result from CQE dword0
@@ -2562,10 +2608,15 @@ int nvme_set_features_resv_mask(int fd, __u32 mask, bool save, __u32 *result);
* 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_resv_persist(int fd, bool ptpl, bool save, __u32 *result);
+int nvme_set_features_resv_persist2(int fd, __u32 nsid, bool ptpl, bool save,
+ __u32 *result);
/**
* nvme_set_features_write_protect() - Set write protect feature
+ *
+ * Deprecated: doesn't support specifying a NSID.
+ * Use nvme_set_features_write_protect2() instead.
+ *
* @fd: File descriptor of nvme device
* @state: Write Protection State
* @save: Save value across power states
@@ -2575,7 +2626,34 @@ int nvme_set_features_resv_persist(int fd, bool ptpl, bool save, __u32 *result);
* &enum nvme_status_field) or -1 with errno set otherwise.
*/
int nvme_set_features_write_protect(int fd, enum nvme_feat_nswpcfg_state state,
- bool save, __u32 *result);
+ bool save, __u32 *result)
+ __attribute__((deprecated));
+
+/**
+ * nvme_set_features_write_protect2() - Set write protect feature
+ * @fd: File descriptor of nvme device
+ * @nsid: Namespace ID
+ * @state: Write Protection State
+ * @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.
+ */
+int nvme_set_features_write_protect2(int fd, __u32 nsid,
+ enum nvme_feat_nswpcfg_state state,
+ bool save, __u32 *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
+ *
+ * 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_iocs_profile(int fd, __u16 iocsi, bool save);
/**
* nvme_get_features() - Retrieve a feature attribute
@@ -2660,6 +2738,10 @@ int nvme_get_features_power_mgmt(int fd, enum nvme_get_features_sel sel,
/**
* nvme_get_features_lba_range() - Get LBA range feature
+ *
+ * Deprecated: doesn't support specifying a NSID.
+ * Use nvme_get_features_lba_range2() instead.
+ *
* @fd: File descriptor of nvme device
* @sel: Select which type of attribute to return, see &enum nvme_get_features_sel
* @data: User address of feature data, if applicable
@@ -2670,7 +2752,22 @@ int nvme_get_features_power_mgmt(int fd, enum nvme_get_features_sel sel,
*/
int nvme_get_features_lba_range(int fd, enum nvme_get_features_sel sel,
struct nvme_lba_range_type *data,
- __u32 *result);
+ __u32 *result) __attribute__((deprecated));
+
+/**
+ * nvme_get_features_lba_range2() - Get LBA range feature
+ * @fd: File descriptor of nvme device
+ * @sel: Select which type of attribute to return, see &enum nvme_get_features_sel
+ * @nsid: Namespace ID
+ * @data: 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.
+ */
+int nvme_get_features_lba_range2(int fd, enum nvme_get_features_sel sel,
+ __u32 nsid, struct nvme_lba_range_type *data,
+ __u32 *result);
/**
* nvme_get_features_temp_thresh() - Get temperature threshold feature
@@ -2686,6 +2783,10 @@ int nvme_get_features_temp_thresh(int fd, enum nvme_get_features_sel sel,
/**
* nvme_get_features_err_recovery() - Get error recovery feature
+ *
+ * Deprecated: doesn't support specifying a NSID.
+ * Use nvme_get_features_err_recovery2() instead.
+ *
* @fd: File descriptor of nvme device
* @sel: Select which type of attribute to return, see &enum nvme_get_features_sel
* @result: The command completion result from CQE dword0
@@ -2694,7 +2795,20 @@ int nvme_get_features_temp_thresh(int fd, enum nvme_get_features_sel sel,
* &enum nvme_status_field) or -1 with errno set otherwise.
*/
int nvme_get_features_err_recovery(int fd, enum nvme_get_features_sel sel,
- __u32 *result);
+ __u32 *result) __attribute__((deprecated));
+
+/**
+ * nvme_get_features_err_recovery2() - Get error recovery feature
+ * @fd: File descriptor of nvme device
+ * @sel: Select which type of attribute to return, see &enum nvme_get_features_sel
+ * @nsid: Namespace 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.
+ */
+int nvme_get_features_err_recovery2(int fd, enum nvme_get_features_sel sel,
+ __u32 nsid, __u32 *result);
/**
* nvme_get_features_volatile_wc() - Get volatile write cache feature
@@ -2784,6 +2898,10 @@ int nvme_get_features_auto_pst(int fd, enum nvme_get_features_sel sel,
/**
* nvme_get_features_host_mem_buf() - Get host memory buffer feature
+ *
+ * Deprecated: doesn't fetch the Host Memory Buffer Attributes data structure.
+ * Use nvme_get_features_host_mem_buf2() instead.
+ *
* @fd: File descriptor of nvme device
* @sel: Select which type of attribute to return, see &enum nvme_get_features_sel
* @result: The command completion result from CQE dword0
@@ -2792,7 +2910,21 @@ int nvme_get_features_auto_pst(int fd, enum nvme_get_features_sel sel,
* &enum nvme_status_field) or -1 with errno set otherwise.
*/
int nvme_get_features_host_mem_buf(int fd, enum nvme_get_features_sel sel,
- __u32 *result);
+ __u32 *result) __attribute__((deprecated));
+
+/**
+ * nvme_get_features_host_mem_buf2() - 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
+ * @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.
+ */
+int nvme_get_features_host_mem_buf2(int fd, enum nvme_get_features_sel sel,
+ struct nvme_host_mem_buf_attrs *attrs,
+ __u32 *result);
/**
* nvme_get_features_timestamp() - Get timestamp feature
@@ -2957,6 +3089,10 @@ int nvme_get_features_host_id(int fd, enum nvme_get_features_sel sel,
/**
* nvme_get_features_resv_mask() - Get reservation mask feature
+ *
+ * Deprecated: doesn't support specifying a NSID.
+ * Use nvme_get_features_resv_mask2() instead.
+ *
* @fd: File descriptor of nvme device
* @sel: Select which type of attribute to return, see &enum nvme_get_features_sel
* @result: The command completion result from CQE dword0
@@ -2965,10 +3101,27 @@ int nvme_get_features_host_id(int fd, enum nvme_get_features_sel sel,
* &enum nvme_status_field) or -1 with errno set otherwise.
*/
int nvme_get_features_resv_mask(int fd, enum nvme_get_features_sel sel,
- __u32 *result);
+ __u32 *result) __attribute__((deprecated));
+
+/**
+ * nvme_get_features_resv_mask2() - Get reservation mask feature
+ * @fd: File descriptor of nvme device
+ * @sel: Select which type of attribute to return, see &enum nvme_get_features_sel
+ * @nsid: Namespace 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.
+ */
+int nvme_get_features_resv_mask2(int fd, enum nvme_get_features_sel sel,
+ __u32 nsid, __u32 *result);
/**
* nvme_get_features_resv_persist() - Get reservation persist feature
+ *
+ * Deprecated: doesn't support specifying a NSID.
+ * Use nvme_get_features_resv_persist2() instead.
+ *
* @fd: File descriptor of nvme device
* @sel: Select which type of attribute to return, see &enum nvme_get_features_sel
* @result: The command completion result from CQE dword0
@@ -2977,7 +3130,20 @@ int nvme_get_features_resv_mask(int fd, enum nvme_get_features_sel sel,
* &enum nvme_status_field) or -1 with errno set otherwise.
*/
int nvme_get_features_resv_persist(int fd, enum nvme_get_features_sel sel,
- __u32 *result);
+ __u32 *result) __attribute__((deprecated));
+
+/**
+ * nvme_get_features_resv_persist2() - Get reservation persist feature
+ * @fd: File descriptor of nvme device
+ * @sel: Select which type of attribute to return, see &enum nvme_get_features_sel
+ * @nsid: Namespace 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.
+ */
+int nvme_get_features_resv_persist2(int fd, enum nvme_get_features_sel sel,
+ __u32 nsid, __u32 *result);
/**
* nvme_get_features_write_protect() - Get write protect feature
@@ -3881,4 +4047,16 @@ int nvme_zns_append(struct nvme_zns_append_args *args);
*/
int nvme_dim_send(struct nvme_dim_args *args);
+/**
+ * nvme_set_debug - Set NVMe command debugging output
+ * @debug: true to enable or false to disable
+ */
+void nvme_set_debug(bool debug);
+
+/**
+ * nvme_get_debug - Get NVMe command debugging output
+ *
+ * Return: false if disabled or true if enabled.
+ */
+bool nvme_get_debug(void);
#endif /* _LIBNVME_IOCTL_H */
diff --git a/src/nvme/json.c b/src/nvme/json.c
index 7a5a69e..4d0f987 100644
--- a/src/nvme/json.c
+++ b/src/nvme/json.c
@@ -14,6 +14,7 @@
#include <json.h>
+#include "cleanup.h"
#include "fabrics.h"
#include "log.h"
#include "private.h"
@@ -189,31 +190,34 @@ static void json_parse_host(nvme_root_t r, struct json_object *host_obj)
}
}
+static DEFINE_CLEANUP_FUNC(cleanup_tokener, json_tokener *, json_tokener_free)
+#define _cleanup_tokener_ __cleanup__(cleanup_tokener)
+
static struct json_object *parse_json(nvme_root_t r, int fd)
{
char buf[JSON_FILE_BUF_SIZE];
- struct json_object *obj = NULL;
+ struct json_object *obj;
char *str = NULL;
- json_tokener *tok = NULL;
+ _cleanup_tokener_ json_tokener *tok = NULL;
int ret;
- void *ptr = NULL;
+ _cleanup_free_ void *ptr = NULL;
int len = 0;
while ((ret = read(fd, buf, JSON_FILE_BUF_SIZE)) > 0) {
str = realloc(ptr, len + ret);
if (!str)
- goto out;
+ return NULL;
memcpy(&str[len], buf, ret);
len += ret;
ptr = str;
}
if (ret < 0 || !len)
- goto out;
+ return NULL;
tok = json_tokener_new_ex(JSON_TOKENER_DEFAULT_DEPTH);
if (!tok)
- goto out;
+ return NULL;
/* Enforce correctly formatted JSON */
tok->flags = JSON_TOKENER_STRICT;
@@ -222,10 +226,6 @@ static struct json_object *parse_json(nvme_root_t r, int fd)
if (!obj)
nvme_msg(r, LOG_DEBUG, "JSON parsing failed: %s\n",
json_util_get_last_err());
-out:
- if (tok)
- json_tokener_free(tok);
- free(ptr);
return obj;
}
@@ -335,21 +335,21 @@ static void json_update_port(struct json_object *ctrl_array, nvme_ctrl_t c)
* Store the keyring description in the JSON config file.
*/
if (cfg->keyring) {
- char *desc = nvme_describe_key_serial(cfg->keyring);
+ _cleanup_free_ char *desc =
+ nvme_describe_key_serial(cfg->keyring);
if (desc) {
json_object_object_add(port_obj, "keyring",
json_object_new_string(desc));
- free(desc);
}
}
if (cfg->tls_key) {
- char *desc = nvme_describe_key_serial(cfg->tls_key);
+ _cleanup_free_ char *desc =
+ nvme_describe_key_serial(cfg->tls_key);
if (desc) {
json_object_object_add(port_obj, "tls_key",
json_object_new_string(desc));
- free(desc);
}
}
diff --git a/src/nvme/linux.c b/src/nvme/linux.c
index c6eedc2..163086e 100644
--- a/src/nvme/linux.c
+++ b/src/nvme/linux.c
@@ -35,15 +35,17 @@
#include <ccan/endian/endian.h>
+#include "cleanup.h"
#include "linux.h"
#include "tree.h"
#include "log.h"
#include "private.h"
+#include "base64.h"
static int __nvme_open(const char *name)
{
- char *path;
- int fd, ret;
+ _cleanup_free_ char *path = NULL;
+ int ret;
ret = asprintf(&path, "%s/%s", "/dev", name);
if (ret < 0) {
@@ -51,9 +53,7 @@ static int __nvme_open(const char *name)
return -1;
}
- fd = open(path, O_RDONLY);
- free(path);
- return fd;
+ return open(path, O_RDONLY);
}
int nvme_open(const char *name)
@@ -122,17 +122,51 @@ int nvme_fw_download_seq(int fd, __u32 size, __u32 xfer, __u32 offset,
return err;
}
-static int nvme_get_telemetry_log(int fd, bool create, bool ctrl, bool rae,
- struct nvme_telemetry_log **buf, enum nvme_telemetry_da da,
- size_t *size)
+int nvme_get_telemetry_max(int fd, enum nvme_telemetry_da *da, size_t *data_tx)
+{
+ _cleanup_free_ struct nvme_id_ctrl *id_ctrl;
+ int err;
+
+ id_ctrl = __nvme_alloc(sizeof(*id_ctrl));
+ if (!id_ctrl) {
+ errno = ENOMEM;
+ return -1;
+ }
+ err = nvme_identify_ctrl(fd, id_ctrl);
+ if (err)
+ return err;
+
+ if (data_tx) {
+ *data_tx = id_ctrl->mdts;
+ if (id_ctrl->mdts) {
+ /* assuming CAP.MPSMIN is zero minimum Memory Page Size is at least
+ * 4096 bytes
+ */
+ *data_tx = (1 << id_ctrl->mdts) * 4096;
+ }
+ }
+ if (da) {
+ if (id_ctrl->lpa & 0x8)
+ *da = NVME_TELEMETRY_DA_3;
+ if (id_ctrl->lpa & 0x40)
+ *da = NVME_TELEMETRY_DA_4;
+
+ }
+ return err;
+}
+
+int nvme_get_telemetry_log(int fd, bool create, bool ctrl, bool rae, size_t max_data_tx,
+ enum nvme_telemetry_da da, struct nvme_telemetry_log **buf,
+ size_t *size)
{
static const __u32 xfer = NVME_LOG_TELEM_BLOCK_SIZE;
struct nvme_telemetry_log *telem;
enum nvme_cmd_get_log_lid lid;
- struct nvme_id_ctrl id_ctrl;
- void *log, *tmp;
+ _cleanup_free_ void *log;
+ void *tmp;
int err;
+ size_t dalb;
struct nvme_get_log_args args = {
.args_size = sizeof(args),
.fd = fd,
@@ -167,89 +201,101 @@ static int nvme_get_telemetry_log(int fd, bool create, bool ctrl, bool rae,
}
if (err)
- goto free;
+ return err;
telem = log;
if (ctrl && !telem->ctrlavail) {
*buf = log;
+ log = NULL;
*size = xfer;
return 0;
}
switch (da) {
case NVME_TELEMETRY_DA_1:
+ dalb = le16_to_cpu(telem->dalb1);
+ break;
case NVME_TELEMETRY_DA_2:
+ dalb = le16_to_cpu(telem->dalb2);
+ break;
case NVME_TELEMETRY_DA_3:
/* dalb3 >= dalb2 >= dalb1 */
- *size = (le16_to_cpu(telem->dalb3) + 1) * xfer;
+ dalb = le16_to_cpu(telem->dalb3);
break;
case NVME_TELEMETRY_DA_4:
- err = nvme_identify_ctrl(fd, &id_ctrl);
- if (err) {
- perror("identify-ctrl");
- errno = EINVAL;
- goto free;
- }
-
- if (id_ctrl.lpa & 0x40) {
- *size = (le32_to_cpu(telem->dalb4) + 1) * xfer;
- } else {
- fprintf(stderr, "Data area 4 unsupported, bit 6 of Log Page Attributes not set\n");
- errno = EINVAL;
- err = -1;
- goto free;
- }
+ dalb = le32_to_cpu(telem->dalb4);
break;
default:
- fprintf(stderr, "Invalid data area parameter - %d\n", da);
errno = EINVAL;
- err = -1;
- goto free;
+ return -1;
}
+ if (dalb == 0) {
+ errno = ENOENT;
+ return -1;
+ }
+
+ *size = (dalb + 1) * xfer;
tmp = realloc(log, *size);
if (!tmp) {
errno = ENOMEM;
- err = -1;
- goto free;
+ return -1;
}
log = tmp;
args.lid = lid;
args.log = log;
args.len = *size;
- err = nvme_get_log_page(fd, 4096, &args);
- if (!err) {
- *buf = log;
- return 0;
+ err = nvme_get_log_page(fd, max_data_tx, &args);
+ if (err)
+ return err;
+
+ *buf = log;
+ log = NULL;
+ return 0;
+}
+
+
+static int nvme_check_get_telemetry_log(int fd, 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);
+
+ if (err)
+ return err;
+ if (da > max_da) {
+ errno = ENOENT;
+ return -1;
}
-free:
- free(log);
- return err;
+ return nvme_get_telemetry_log(fd, create, ctrl, rae, 4096, da, log, size);
}
+
int nvme_get_ctrl_telemetry(int fd, bool rae, struct nvme_telemetry_log **log,
enum nvme_telemetry_da da, size_t *size)
{
- return nvme_get_telemetry_log(fd, false, true, rae, log, da, size);
+ return nvme_check_get_telemetry_log(fd, false, true, rae, log, da, size);
}
int nvme_get_host_telemetry(int fd, struct nvme_telemetry_log **log,
enum nvme_telemetry_da da, size_t *size)
{
- return nvme_get_telemetry_log(fd, false, false, false, log, da, size);
+ return nvme_check_get_telemetry_log(fd, false, false, false, log, da, size);
}
int nvme_get_new_host_telemetry(int fd, struct nvme_telemetry_log **log,
enum nvme_telemetry_da da, size_t *size)
{
- return nvme_get_telemetry_log(fd, true, false, false, log, da, size);
+ return nvme_check_get_telemetry_log(fd, true, false, false, log, da, size);
}
int nvme_get_lba_status_log(int fd, bool rae, struct nvme_lba_status_log **log)
{
- __u32 size = sizeof(struct nvme_lba_status_log);
- void *buf, *tmp;
+ __u32 size;
+ _cleanup_free_ struct nvme_lba_status_log *buf;
+ void *tmp;
int err;
struct nvme_get_log_args args = {
.args_size = sizeof(args),
@@ -265,38 +311,42 @@ int nvme_get_lba_status_log(int fd, bool rae, struct nvme_lba_status_log **log)
.ot = false,
};
- buf = malloc(size);
+ buf = malloc(sizeof(*buf));
if (!buf)
return -1;
- *log = buf;
- err = nvme_get_log_lba_status(fd, true, 0, size, buf);
- if (err)
- goto free;
+ err = nvme_get_log_lba_status(fd, true, 0, sizeof(*buf), buf);
+ if (err) {
+ *log = NULL;
+ return err;
+ }
- size = le32_to_cpu((*log)->lslplen);
- if (!size)
+ size = le32_to_cpu(buf->lslplen);
+ if (!size) {
+ *log = buf;
+ buf = NULL;
return 0;
+ }
tmp = realloc(buf, size);
if (!tmp) {
- err = -1;
- goto free;
+ *log = NULL;
+ return -1;
}
buf = tmp;
- *log = buf;
args.lid = NVME_LOG_LID_LBA_STATUS;
args.log = buf;
args.len = size;
err = nvme_get_log_page(fd, 4096, &args);
- if (!err)
- return 0;
+ if (err) {
+ *log = NULL;
+ return err;
+ }
-free:
- *log = NULL;
- free(buf);
- return err;
+ *log = buf;
+ buf = NULL;
+ return 0;
}
static int nvme_ns_attachment(int fd, __u32 nsid, __u16 num_ctrls,
@@ -335,38 +385,48 @@ int nvme_namespace_detach_ctrls(int fd, __u32 nsid, __u16 num_ctrls,
int nvme_get_ana_log_len(int fd, size_t *analen)
{
- struct nvme_id_ctrl ctrl;
+ _cleanup_free_ struct nvme_id_ctrl *ctrl;
int ret;
- ret = nvme_identify_ctrl(fd, &ctrl);
+ ctrl = __nvme_alloc(sizeof(*ctrl));
+ if (!ctrl) {
+ errno = ENOMEM;
+ return -1;
+ }
+ ret = nvme_identify_ctrl(fd, ctrl);
if (ret)
return ret;
*analen = sizeof(struct nvme_ana_log) +
- le32_to_cpu(ctrl.nanagrpid) * sizeof(struct nvme_ana_group_desc) +
- le32_to_cpu(ctrl.mnan) * sizeof(__le32);
+ le32_to_cpu(ctrl->nanagrpid) * sizeof(struct nvme_ana_group_desc) +
+ le32_to_cpu(ctrl->mnan) * sizeof(__le32);
return 0;
}
int nvme_get_logical_block_size(int fd, __u32 nsid, int *blksize)
{
- struct nvme_id_ns ns;
+ _cleanup_free_ struct nvme_id_ns *ns;
__u8 flbas;
int ret;
- ret = nvme_identify_ns(fd, nsid, &ns);
+ ns = __nvme_alloc(sizeof(*ns));
+ if (!ns) {
+ errno = ENOMEM;
+ return -1;
+ }
+ ret = nvme_identify_ns(fd, nsid, ns);
if (ret)
return ret;
- nvme_id_ns_flbas_to_lbaf_inuse(ns.flbas, &flbas);
- *blksize = 1 << ns.lbaf[flbas].ds;
+ nvme_id_ns_flbas_to_lbaf_inuse(ns->flbas, &flbas);
+ *blksize = 1 << ns->lbaf[flbas].ds;
return 0;
}
static int __nvme_set_attr(const char *path, const char *value)
{
- int ret, fd;
+ _cleanup_fd_ int fd;
fd = open(path, O_WRONLY);
if (fd < 0) {
@@ -376,23 +436,19 @@ static int __nvme_set_attr(const char *path, const char *value)
#endif
return -1;
}
- ret = write(fd, value, strlen(value));
- close(fd);
- return ret;
+ return write(fd, value, strlen(value));
}
int nvme_set_attr(const char *dir, const char *attr, const char *value)
{
- char *path;
+ _cleanup_free_ char *path = NULL;
int ret;
ret = asprintf(&path, "%s/%s", dir, attr);
if (ret < 0)
return -1;
- ret = __nvme_set_attr(path, value);
- free(path);
- return ret;
+ return __nvme_set_attr(path, value);
}
static char *__nvme_get_attr(const char *path)
@@ -426,7 +482,7 @@ static char *__nvme_get_attr(const char *path)
char *nvme_get_attr(const char *dir, const char *attr)
{
- char *path, *value;
+ _cleanup_free_ char *path = NULL;
int ret;
ret = asprintf(&path, "%s/%s", dir, attr);
@@ -435,9 +491,7 @@ char *nvme_get_attr(const char *dir, const char *attr)
return NULL;
}
- value = __nvme_get_attr(path);
- free(path);
- return value;
+ return __nvme_get_attr(path);
}
char *nvme_get_subsys_attr(nvme_subsystem_t s, const char *attr)
@@ -476,21 +530,80 @@ int nvme_gen_dhchap_key(char *hostnqn, enum nvme_hmac_alg hmac,
return 0;
}
-static int derive_nvme_keys(const char *hostnqn, const char *identity,
- int hmac, unsigned char *configured,
- unsigned char *psk, int key_len)
+static int derive_retained_key(int hmac, const char *hostnqn,
+ unsigned char *generated,
+ unsigned char *retained,
+ size_t key_len)
+{
+ nvme_msg(NULL, LOG_ERR, "NVMe TLS is not supported; "
+ "recompile with OpenSSL support.\n");
+ errno = ENOTSUP;
+ return -1;
+}
+
+static int gen_tls_identity(const char *hostnqn, const char *subsysnqn,
+ int version, int hmac, char *identity,
+ unsigned char *retained, size_t key_len)
{
- errno = EOPNOTSUPP;
+ if (version != 0) {
+ nvme_msg(NULL, LOG_ERR, "NVMe TLS 2.0 is not supported; "
+ "recompile with OpenSSL support.\n");
+ errno = ENOTSUP;
+ return -1;
+ }
+ sprintf(identity, "NVMe0R%02d %s %s",
+ hmac, hostnqn, subsysnqn);
+ return strlen(identity);
+}
+
+static int derive_tls_key(int hmac, const char *identity,
+ unsigned char *retained,
+ unsigned char *psk, size_t key_len)
+{
+ nvme_msg(NULL, LOG_ERR, "NVMe TLS is not supported; "
+ "recompile with OpenSSL support.\n");
+ errno = ENOTSUP;
return -1;
}
#else /* CONFIG_OPENSSL */
-static int derive_retained_key(const EVP_MD *md, const char *hostnqn,
+static const EVP_MD *select_hmac(int hmac, size_t *key_len)
+{
+ const EVP_MD *md = NULL;
+
+ switch (hmac) {
+ case NVME_HMAC_ALG_SHA2_256:
+ md = EVP_sha256();
+ *key_len = 32;
+ break;
+ case NVME_HMAC_ALG_SHA2_384:
+ md = EVP_sha384();
+ *key_len = 48;
+ break;
+ default:
+ break;
+ }
+ return md;
+}
+
+static DEFINE_CLEANUP_FUNC(
+ cleanup_evp_pkey_ctx, EVP_PKEY_CTX *, EVP_PKEY_CTX_free)
+#define _cleanup_evp_pkey_ctx_ __cleanup__(cleanup_evp_pkey_ctx)
+
+static int derive_retained_key(int hmac, const char *hostnqn,
unsigned char *generated,
unsigned char *retained,
size_t key_len)
{
- EVP_PKEY_CTX *ctx;
- int ret;
+ const EVP_MD *md;
+ _cleanup_evp_pkey_ctx_ EVP_PKEY_CTX *ctx = NULL;
+ uint16_t length = key_len & 0xFFFF;
+ size_t hmac_len;
+
+ md = select_hmac(hmac, &hmac_len);
+ if (!md || hmac_len > key_len) {
+ errno = EINVAL;
+ return -1;
+ }
ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL);
if (!ctx) {
@@ -499,42 +612,60 @@ static int derive_retained_key(const EVP_MD *md, const char *hostnqn,
}
if (EVP_PKEY_derive_init(ctx) <= 0) {
- ret = -ENOMEM;
- goto out_free_ctx;
- }
- ret = -ENOKEY;
- if (EVP_PKEY_CTX_set_hkdf_md(ctx, md) <= 0)
- goto out_free_ctx;
- if (EVP_PKEY_CTX_set1_hkdf_key(ctx, generated, key_len) <= 0)
- goto out_free_ctx;
+ 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, generated, key_len) <= 0) {
+ errno = ENOKEY;
+ return -1;
+ }
if (EVP_PKEY_CTX_add1_hkdf_info(ctx,
- (const unsigned char *)"tls13 ", 6) <= 0)
- goto out_free_ctx;
+ (const unsigned char *)&length, 2) <= 0) {
+ errno = ENOKEY;
+ return -1;
+ }
if (EVP_PKEY_CTX_add1_hkdf_info(ctx,
- (const unsigned char *)"HostNQN", 7) <= 0)
- goto out_free_ctx;
+ (const unsigned char *)"tls13 ", 6) <= 0) {
+ errno = ENOKEY;
+ return -1;
+ }
if (EVP_PKEY_CTX_add1_hkdf_info(ctx,
- (const unsigned char *)hostnqn, strlen(hostnqn)) <= 0)
- goto out_free_ctx;
-
- if (EVP_PKEY_derive(ctx, retained, &key_len) > 0)
- ret = key_len;
+ (const unsigned char *)"HostNQN", 7) <= 0) {
+ errno = ENOKEY;
+ return -1;
+ }
+ if (EVP_PKEY_CTX_add1_hkdf_info(ctx,
+ (const unsigned char *)hostnqn, strlen(hostnqn)) <= 0) {
+ errno = ENOKEY;
+ return -1;
+ }
-out_free_ctx:
- if (ret < 0) {
- errno = -ret;
- ret = -1;
+ if (EVP_PKEY_derive(ctx, retained, &key_len) <= 0) {
+ errno = ENOKEY;
+ return -1;
}
- EVP_PKEY_CTX_free(ctx);
- return ret;
+
+ return key_len;
}
-static int derive_tls_key(const EVP_MD *md, const char *identity,
+static int derive_tls_key(int hmac, const char *identity,
unsigned char *retained,
unsigned char *psk, size_t key_len)
{
- EVP_PKEY_CTX *ctx;
- int ret;
+ const EVP_MD *md;
+ _cleanup_evp_pkey_ctx_ EVP_PKEY_CTX *ctx = NULL;
+ size_t hmac_len;
+ uint16_t length = key_len & 0xFFFF;
+
+ md = select_hmac(hmac, &hmac_len);
+ if (!md || hmac_len > key_len) {
+ errno = EINVAL;
+ return -1;
+ }
ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL);
if (!ctx) {
@@ -543,85 +674,59 @@ static int derive_tls_key(const EVP_MD *md, const char *identity,
}
if (EVP_PKEY_derive_init(ctx) <= 0) {
- ret = -ENOMEM;
- goto out_free_ctx;
- }
- ret = -ENOKEY;
- if (EVP_PKEY_CTX_set_hkdf_md(ctx, md) <= 0)
- goto out_free_ctx;
- if (EVP_PKEY_CTX_set1_hkdf_key(ctx, retained, key_len) <= 0)
- goto out_free_ctx;
- if (EVP_PKEY_CTX_add1_hkdf_info(ctx,
- (const unsigned char *)"tls13 ", 6) <= 0)
- goto out_free_ctx;
+ 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 *)"nvme-tls-psk", 12) <= 0)
- goto out_free_ctx;
+ (const unsigned char *)&length, 2) <= 0) {
+ errno = ENOKEY;
+ return -1;
+ }
if (EVP_PKEY_CTX_add1_hkdf_info(ctx,
- (const unsigned char *)identity,
- strlen(identity)) <= 0)
- goto out_free_ctx;
-
- if (EVP_PKEY_derive(ctx, psk, &key_len) > 0)
- ret = key_len;
-
-out_free_ctx:
- EVP_PKEY_CTX_free(ctx);
- if (ret < 0) {
- errno = -ret;
- ret = -1;
+ (const unsigned char *)"tls13 ", 6) <= 0) {
+ errno = ENOKEY;
+ return -1;
}
-
- return ret;
-}
-
-static int derive_nvme_keys(const char *hostnqn, const char *identity,
- int hmac, unsigned char *configured,
- unsigned char *psk, int key_len)
-{
- const EVP_MD *md;
- unsigned char *retained;
- int ret = -1;
-
- if (!hostnqn || !identity) {
- errno = EINVAL;
+ if (EVP_PKEY_CTX_add1_hkdf_info(ctx,
+ (const unsigned char *)"nvme-tls-psk", 12) <= 0) {
+ errno = ENOKEY;
return -1;
}
-
- switch (hmac) {
- case 1:
- md = EVP_sha256();
- break;
- case 2:
- md = EVP_sha384();
- break;
- default:
- errno = EINVAL;
+ if (EVP_PKEY_CTX_add1_hkdf_info(ctx,
+ (const unsigned char *)identity,
+ strlen(identity)) <= 0) {
+ errno = ENOKEY;
return -1;
}
- retained = malloc(key_len);
- if (!retained) {
- errno = ENOMEM;
+ if (EVP_PKEY_derive(ctx, psk, &key_len) <= 0) {
+ errno = ENOKEY;
return -1;
}
- ret = derive_retained_key(md, hostnqn, configured, retained, key_len);
- if (ret > 0)
- ret = derive_tls_key(md, identity, retained, psk, key_len);
- free(retained);
- return ret;
+
+ return key_len;
}
#endif /* CONFIG_OPENSSL */
#ifdef CONFIG_OPENSSL_1
+static DEFINE_CLEANUP_FUNC(cleanup_hmac_ctx, HMAC_CTX *, HMAC_CTX_free)
+#define _cleanup_hmac_ctx_ __cleanup__(cleanup_hmac_ctx)
+
int nvme_gen_dhchap_key(char *hostnqn, enum nvme_hmac_alg hmac,
unsigned int key_len, unsigned char *secret,
unsigned char *key)
{
const char hmac_seed[] = "NVMe-over-Fabrics";
- HMAC_CTX *hmac_ctx;
+ _cleanup_hmac_ctx_ HMAC_CTX *hmac_ctx;
const EVP_MD *md;
- int err = -1;
ENGINE_load_builtin_engines();
ENGINE_register_all_complete();
@@ -629,14 +734,13 @@ int nvme_gen_dhchap_key(char *hostnqn, enum nvme_hmac_alg hmac,
hmac_ctx = HMAC_CTX_new();
if (!hmac_ctx) {
errno = ENOMEM;
- return err;
+ return -1;
}
switch (hmac) {
case NVME_HMAC_ALG_NONE:
memcpy(key, secret, key_len);
- err = 0;
- goto out;
+ return 0;
case NVME_HMAC_ALG_SHA2_256:
md = EVP_sha256();
break;
@@ -648,82 +752,164 @@ int nvme_gen_dhchap_key(char *hostnqn, enum nvme_hmac_alg hmac,
break;
default:
errno = EINVAL;
- goto out;
+ return -1;
}
if (!md) {
errno = EINVAL;
- goto out;
+ return -1;
}
if (!HMAC_Init_ex(hmac_ctx, secret, key_len, md, NULL)) {
errno = ENOMEM;
- goto out;
+ return -1;
}
if (!HMAC_Update(hmac_ctx, (unsigned char *)hostnqn,
strlen(hostnqn))) {
errno = ENOKEY;
- goto out;
+ return -1;
}
if (!HMAC_Update(hmac_ctx, (unsigned char *)hmac_seed,
strlen(hmac_seed))) {
errno = ENOKEY;
- goto out;
+ return -1;
}
if (!HMAC_Final(hmac_ctx, key, &key_len)) {
errno = ENOKEY;
- goto out;
+ return -1;
}
- err = 0;
+ return 0;
+}
-out:
- HMAC_CTX_free(hmac_ctx);
- return err;
+static int gen_tls_identity(const char *hostnqn, const char *subsysnqn,
+ int version, int hmac, char *identity,
+ unsigned char *retained, size_t key_len)
+{
+ static const char hmac_seed[] = "NVMe-over-Fabrics";
+ size_t hmac_len;
+ const EVP_MD *md = select_hmac(hmac, &hmac_len);
+ _cleanup_hmac_ctx_ HMAC_CTX *hmac_ctx = NULL;
+ _cleanup_free_ unsigned char *psk_ctx = NULL;
+ _cleanup_free_ char *enc_ctx = NULL;
+ size_t len;
+
+ if (version == 0) {
+ sprintf(identity, "NVMe%01dR%02d %s %s",
+ version, hmac, hostnqn, subsysnqn);
+ return strlen(identity);
+ }
+ if (version > 1) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ hmac_ctx = HMAC_CTX_new();
+ if (!hmac_ctx) {
+ errno = ENOMEM;
+ return -1;
+ }
+ if (!md) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ psk_ctx = malloc(key_len);
+ if (!psk_ctx) {
+ errno = ENOMEM;
+ return -1;
+ }
+ if (!HMAC_Init_ex(hmac_ctx, retained, key_len, md, NULL)) {
+ errno = ENOMEM;
+ return -1;
+ }
+ if (!HMAC_Update(hmac_ctx, (unsigned char *)hostnqn,
+ strlen(hostnqn))) {
+ errno = ENOKEY;
+ return -1;
+ }
+ if (!HMAC_Update(hmac_ctx, (unsigned char *)" ", 1)) {
+ errno = ENOKEY;
+ return -1;
+ }
+ if (!HMAC_Update(hmac_ctx, (unsigned char *)subsysnqn,
+ strlen(subsysnqn))) {
+ errno = ENOKEY;
+ return -1;
+ }
+ if (!HMAC_Update(hmac_ctx, (unsigned char *)" ", 1)) {
+ errno = ENOKEY;
+ return -1;
+ }
+ if (!HMAC_Update(hmac_ctx, (unsigned char *)hmac_seed,
+ strlen(hmac_seed))) {
+ errno = ENOKEY;
+ return -1;
+ }
+ if (!HMAC_Final(hmac_ctx, psk_ctx, (unsigned int *)&key_len)) {
+ errno = ENOKEY;
+ return -1;
+ }
+ enc_ctx = malloc(key_len * 2);
+ memset(enc_ctx, 0, key_len * 2);
+ len = base64_encode(psk_ctx, key_len, enc_ctx);
+ if (len < 0) {
+ errno = ENOKEY;
+ return len;
+ }
+ sprintf(identity, "NVMe%01dR%02d %s %s %s",
+ version, hmac, hostnqn, subsysnqn, enc_ctx);
+ return strlen(identity);
}
#endif /* !CONFIG_OPENSSL_1 */
#ifdef CONFIG_OPENSSL_3
+static DEFINE_CLEANUP_FUNC(
+ cleanup_ossl_lib_ctx, OSSL_LIB_CTX *, OSSL_LIB_CTX_free)
+#define _cleanup_ossl_lib_ctx_ __cleanup__(cleanup_ossl_lib_ctx)
+static DEFINE_CLEANUP_FUNC(cleanup_evp_mac_ctx, EVP_MAC_CTX *, EVP_MAC_CTX_free)
+#define _cleanup_evp_mac_ctx_ __cleanup__(cleanup_evp_mac_ctx)
+static DEFINE_CLEANUP_FUNC(cleanup_evp_mac, EVP_MAC *, EVP_MAC_free)
+#define _cleanup_evp_mac_ __cleanup__(cleanup_evp_mac)
+
int nvme_gen_dhchap_key(char *hostnqn, enum nvme_hmac_alg hmac,
unsigned int key_len, unsigned char *secret,
unsigned char *key)
{
const char hmac_seed[] = "NVMe-over-Fabrics";
OSSL_PARAM params[2], *p = params;
- OSSL_LIB_CTX *lib_ctx;
- EVP_MAC_CTX *mac_ctx = NULL;
- EVP_MAC *mac = NULL;
+ _cleanup_ossl_lib_ctx_ OSSL_LIB_CTX *lib_ctx;
+ _cleanup_evp_mac_ctx_ EVP_MAC_CTX *mac_ctx = NULL;
+ _cleanup_evp_mac_ EVP_MAC *mac = NULL;
char *progq = NULL;
char *digest;
size_t len;
- int err = -1;
lib_ctx = OSSL_LIB_CTX_new();
if (!lib_ctx) {
errno = ENOMEM;
- return err;
+ return -1;
}
mac = EVP_MAC_fetch(lib_ctx, OSSL_MAC_NAME_HMAC, progq);
if (!mac) {
errno = ENOMEM;
- goto out;
+ return -1;
}
mac_ctx = EVP_MAC_CTX_new(mac);
if (!mac_ctx) {
errno = ENOMEM;
- goto out;
+ return -1;
}
switch (hmac) {
case NVME_HMAC_ALG_NONE:
memcpy(key, secret, key_len);
- err = 0;
- goto out;
+ return 0;
case NVME_HMAC_ALG_SHA2_256:
digest = OSSL_DIGEST_NAME_SHA2_256;
break;
@@ -735,7 +921,7 @@ int nvme_gen_dhchap_key(char *hostnqn, enum nvme_hmac_alg hmac,
break;
default:
errno = EINVAL;
- goto out;
+ return -1;
}
*p++ = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_DIGEST,
digest,
@@ -744,42 +930,224 @@ int nvme_gen_dhchap_key(char *hostnqn, enum nvme_hmac_alg hmac,
if (!EVP_MAC_init(mac_ctx, secret, key_len, params)) {
errno = ENOKEY;
- goto out;
+ return -1;
}
if (!EVP_MAC_update(mac_ctx, (unsigned char *)hostnqn,
strlen(hostnqn))) {
errno = ENOKEY;
- goto out;
+ return -1;
}
if (!EVP_MAC_update(mac_ctx, (unsigned char *)hmac_seed,
strlen(hmac_seed))) {
errno = ENOKEY;
- goto out;
+ return -1;
}
if (!EVP_MAC_final(mac_ctx, key, &len, key_len)) {
errno = ENOKEY;
- goto out;
+ return -1;
}
if (len != key_len) {
errno = EMSGSIZE;
- goto out;
+ return -1;
}
- err = 0;
+ return 0;
+}
-out:
- EVP_MAC_CTX_free(mac_ctx);
- EVP_MAC_free(mac);
- OSSL_LIB_CTX_free(lib_ctx);
+static int gen_tls_identity(const char *hostnqn, const char *subsysnqn,
+ int version, int hmac, char *identity,
+ unsigned char *retained, size_t key_len)
+{
+ static const char hmac_seed[] = "NVMe-over-Fabrics";
+ size_t hmac_len;
+ OSSL_PARAM params[2], *p = params;
+ _cleanup_ossl_lib_ctx_ OSSL_LIB_CTX *lib_ctx = NULL;
+ _cleanup_evp_mac_ctx_ EVP_MAC_CTX *mac_ctx = NULL;
+ _cleanup_evp_mac_ EVP_MAC *mac = NULL;
+ char *progq = NULL;
+ char *digest = NULL;
+ _cleanup_free_ unsigned char *psk_ctx = NULL;
+ _cleanup_free_ char *enc_ctx = NULL;
+ size_t len;
- return err;
+ if (version == 0) {
+ sprintf(identity, "NVMe%01dR%02d %s %s",
+ version, hmac, hostnqn, subsysnqn);
+ return strlen(identity);
+ }
+ if (version > 1) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ lib_ctx = OSSL_LIB_CTX_new();
+ if (!lib_ctx) {
+ errno = ENOMEM;
+ return -1;
+ }
+ mac = EVP_MAC_fetch(lib_ctx, OSSL_MAC_NAME_HMAC, progq);
+ if (!mac) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ mac_ctx = EVP_MAC_CTX_new(mac);
+ if (!mac_ctx) {
+ errno = ENOMEM;
+ return -1;
+ }
+ switch (hmac) {
+ case NVME_HMAC_ALG_SHA2_256:
+ digest = OSSL_DIGEST_NAME_SHA2_256;
+ break;
+ case NVME_HMAC_ALG_SHA2_384:
+ digest = OSSL_DIGEST_NAME_SHA2_384;
+ break;
+ default:
+ errno = EINVAL;
+ break;
+ }
+ if (!digest)
+ return -1;
+ *p++ = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_DIGEST,
+ digest, 0);
+ *p = OSSL_PARAM_construct_end();
+
+ psk_ctx = malloc(key_len);
+ if (!psk_ctx) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ 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;
+ }
+ 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;
+ }
+ 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;
+ }
+ enc_ctx = malloc(hmac_len * 2);
+ memset(enc_ctx, 0, hmac_len * 2);
+ len = base64_encode(psk_ctx, hmac_len, enc_ctx);
+ if (len < 0) {
+ errno = ENOKEY;
+ return len;
+ }
+ sprintf(identity, "NVMe%01dR%02d %s %s %s",
+ version, hmac, hostnqn, subsysnqn, enc_ctx);
+ return strlen(identity);
}
#endif /* !CONFIG_OPENSSL_3 */
+static int derive_nvme_keys(const char *hostnqn, const char *subsysnqn,
+ char *identity, int version,
+ int hmac, unsigned char *configured,
+ unsigned char *psk, int key_len)
+{
+ _cleanup_free_ unsigned char *retained = NULL;
+ int ret = -1;
+
+ if (!hostnqn || !subsysnqn || !identity || !psk) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ retained = malloc(key_len);
+ if (!retained) {
+ errno = ENOMEM;
+ return -1;
+ }
+ ret = derive_retained_key(hmac, hostnqn, configured, retained, key_len);
+ if (ret < 0)
+ return ret;
+ ret = gen_tls_identity(hostnqn, subsysnqn, version, hmac,
+ identity, retained, key_len);
+ if (ret < 0)
+ return ret;
+ return derive_tls_key(hmac, identity, retained, psk, key_len);
+}
+
+static size_t nvme_identity_len(int hmac, int version, const char *hostnqn,
+ const char *subsysnqn)
+{
+ size_t len;
+
+ len = strlen(hostnqn) + strlen(subsysnqn) + 12;
+ if (version == 1) {
+ len += 66;
+ if (hmac == NVME_HMAC_ALG_SHA2_384)
+ len += 32;
+ } else if (version > 1) {
+ errno = EINVAL;
+ return -1;
+ }
+ return len;
+}
+
+char *nvme_generate_tls_key_identity(const char *hostnqn, const char *subsysnqn,
+ int version, int hmac,
+ unsigned char *configured_key, int key_len)
+{
+ char *identity;
+ size_t identity_len;
+ _cleanup_free_ unsigned char *psk = NULL;
+ int ret = -1;
+
+ identity_len = nvme_identity_len(hmac, version, hostnqn, subsysnqn);
+ if (identity_len < 0)
+ return NULL;
+
+ identity = malloc(identity_len);
+ if (!identity)
+ return NULL;
+
+ psk = malloc(key_len);
+ if (!psk)
+ goto out_free_identity;
+
+ 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;
+}
+
#ifdef CONFIG_KEYUTILS
long nvme_lookup_keyring(const char *keyring)
{
@@ -820,37 +1188,41 @@ int nvme_set_keyring(long key_id)
return 0;
}
-long 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)
+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)
{
- key_serial_t keyring_id, key = 0;
- char *identity;
- unsigned char *psk;
+ key_serial_t keyring_id, key;
+ _cleanup_free_ char *identity = NULL;
+ size_t identity_len;
+ _cleanup_free_ unsigned char *psk = NULL;
int ret = -1;
keyring_id = nvme_lookup_keyring(keyring);
if (keyring_id == 0)
return -1;
- identity = malloc(strlen(hostnqn) + strlen(subsysnqn) + 12);
+ identity_len = nvme_identity_len(hmac, version, hostnqn, subsysnqn);
+ if (identity_len < 0)
+ return -1;
+
+ identity = malloc(identity_len);
if (!identity) {
errno = ENOMEM;
return -1;
}
- sprintf(identity, "NVMe0R%02d %s %s", hmac, hostnqn, subsysnqn);
-
psk = malloc(key_len);
if (!psk) {
errno = ENOMEM;
- goto out_free_identity;
+ return 0;
}
memset(psk, 0, key_len);
- ret = derive_nvme_keys(hostnqn, identity, hmac,
+ ret = derive_nvme_keys(hostnqn, subsysnqn, identity, version, hmac,
configured_key, psk, key_len);
if (ret != key_len)
- goto out_free_psk;
+ return 0;
key = keyctl_search(keyring_id, key_type, identity, 0);
if (key > 0) {
@@ -862,10 +1234,6 @@ long nvme_insert_tls_key(const char *keyring, const char *key_type,
if (key < 0)
key = 0;
}
-out_free_psk:
- free(psk);
-out_free_identity:
- free(identity);
return key;
}
@@ -902,10 +1270,23 @@ int nvme_set_keyring(long key_id)
return -1;
}
+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)
+{
+ nvme_msg(NULL, LOG_ERR, "key operations not supported; "
+ "recompile with keyutils support.\n");
+ errno = ENOTSUP;
+ return -1;
+}
+#endif
+
long 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)
{
- return derive_nvme_keys(NULL, NULL, 0, NULL, NULL, 0);
+ return nvme_insert_tls_key_versioned(keyring, key_type,
+ hostnqn, subsysnqn, 0, hmac,
+ configured_key, key_len);
}
-#endif
diff --git a/src/nvme/linux.h b/src/nvme/linux.h
index 37ba9d4..11ee76e 100644
--- a/src/nvme/linux.h
+++ b/src/nvme/linux.h
@@ -49,6 +49,37 @@ enum nvme_telemetry_da {
};
/**
+ * nvme_get_telemetry_max() - Get telemetry limits
+ * @fd: File descriptor of nvme device
+ * @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.
+ */
+int nvme_get_telemetry_max(int fd, enum nvme_telemetry_da *da, size_t *max_data_tx);
+
+/**
+ * nvme_get_telemetry_log() - Get specified telemetry log
+ * @fd: File descriptor of nvme device
+ * @create: Generate new host initated telemetry capture
+ * @ctrl: Get controller Initiated log
+ * @rae: Retain asynchronous events
+ * @max_data_tx: Set the max data transfer size to be used retrieving telemetry.
+ * @da: Log page data area, valid values: &enum nvme_telemetry_da.
+ * @log: On success, set to the value of the allocated and retrieved log.
+ * @size: Ptr to the telemetry log size, so it can be returned
+ *
+ * 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.
+ */
+int nvme_get_telemetry_log(int fd, 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
* @rae: Retain asynchronous events
@@ -262,4 +293,46 @@ long 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);
+/**
+ * nvme_insert_tls_key_versioned() - Derive and insert TLS key
+ * @keyring: Keyring to use
+ * @key_type: Type of the resulting key
+ * @hostnqn: Host NVMe Qualified Name
+ * @subsysnqn: Subsystem NVMe Qualified Name
+ * @version: Key version to use
+ * @hmac: HMAC algorithm
+ * @configured_key: Configured key data to derive the key from
+ * @key_len: Length of @configured_key
+ *
+ * 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.
+ */
+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);
+
+/**
+ * nvme_generate_tls_key_identity() - Generate the TLS key identity
+ * @hostnqn: Host NVMe Qualified Name
+ * @subsysnqn: Subsystem NVMe Qualified Name
+ * @version: Key version to use
+ * @hmac: HMAC algorithm
+ * @configured_key: Configured key data to derive the key from
+ * @key_len: Length of @configured_key
+ *
+ * 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.
+ */
+char *nvme_generate_tls_key_identity(const char *hostnqn, const char *subsysnqn,
+ int version, int hmac,
+ unsigned char *configured_key, int key_len);
+
#endif /* _LIBNVME_LINUX_H */
diff --git a/src/nvme/log.c b/src/nvme/log.c
index e4697df..2ffca3e 100644
--- a/src/nvme/log.c
+++ b/src/nvme/log.c
@@ -26,11 +26,13 @@
#define LOG_CLOCK CLOCK_MONOTONIC
#endif
+static nvme_root_t root;
+
void __attribute__((format(printf, 4, 5)))
__nvme_msg(nvme_root_t r, int lvl,
const char *func, const char *format, ...)
{
- FILE *fp = r ? r->fp : stderr;
+ FILE *fp = stderr;
va_list ap;
char pidbuf[16];
char timebuf[32];
@@ -44,10 +46,16 @@ __nvme_msg(nvme_root_t r, int lvl,
"[%s] <%s>%s ",
"[%s] <%s> %s: ",
};
- char *header __cleanup__(cleanup_charp) = NULL;
- char *message __cleanup__(cleanup_charp) = NULL;
+ _cleanup_free_ char *header = NULL;
+ _cleanup_free_ char *message = NULL;
int idx = 0;
+ if (!r)
+ r = root;
+
+ if (r)
+ fp = r->fp;
+
if (r && lvl > r->log_level)
return;
@@ -90,3 +98,8 @@ void nvme_init_logging(nvme_root_t r, int lvl, bool log_pid, bool log_tstamp)
r->log_pid = log_pid;
r->log_timestamp = log_tstamp;
}
+
+void nvme_set_root(nvme_root_t r)
+{
+ root = r;
+}
diff --git a/src/nvme/log.h b/src/nvme/log.h
index 1cf797a..7c345f6 100644
--- a/src/nvme/log.h
+++ b/src/nvme/log.h
@@ -35,4 +35,17 @@
*/
void nvme_init_logging(nvme_root_t r, int lvl, bool log_pid, bool log_tstamp);
+/**
+ * nvme_set_root() - Set nvme_root_t context
+ * @r: nvme_root_t context
+ *
+ * In order to be able to log from code paths where no root object is passed in
+ * 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 global root object.
+ */
+void nvme_set_root(nvme_root_t r);
+
#endif /* _LOG_H */
diff --git a/src/nvme/mi-mctp.c b/src/nvme/mi-mctp.c
index 0c5972a..86c4c29 100644
--- a/src/nvme/mi-mctp.c
+++ b/src/nvme/mi-mctp.c
@@ -82,6 +82,8 @@ struct nvme_mi_transport_mctp {
int net;
__u8 eid;
int sd;
+ void *resp_buf;
+ size_t resp_buf_size;
};
static int ioctl_tag(int sd, unsigned long req, struct mctp_ioc_tag_ctl *ctl)
@@ -175,60 +177,40 @@ struct nvme_mi_msg_resp_mpr {
/* Check if this response was a More Processing Required response; if so,
* populate the worst-case expected processing time, given in milliseconds.
+ *
+ * buf is the incoming message data, including type byte, but excluding
+ * the MIC which has been extracted into the mic argument already.
*/
-static bool nvme_mi_mctp_resp_is_mpr(struct nvme_mi_resp *resp, size_t len,
+static bool nvme_mi_mctp_resp_is_mpr(void *buf, size_t len,
__le32 mic, unsigned int *mpr_time)
{
- struct nvme_mi_admin_resp_hdr *admin_msg;
struct nvme_mi_msg_resp_mpr *msg;
- size_t clen;
__u32 crc;
- /* We need at least the minimal header plus checksum */
- if (len < sizeof(*msg) + sizeof(mic))
+ /* We need at least the minimal header */
+ if (len < sizeof(*msg))
return false;
- msg = (struct nvme_mi_msg_resp_mpr *)resp->hdr;
+ msg = (struct nvme_mi_msg_resp_mpr *)buf;
if (msg->status != NVME_MI_RESP_MPR)
return false;
- /* Find and verify the MIC from the response, which may not be laid out
- * in resp as we expect. We have to preserve resp->hdr_len and
- * resp->data_len, as we will need them for the eventual reply message.
- * Because of that, we can't use verify_resp_mic here.
- *
- * If the packet was at the expected response size, then mic will
- * be set already; if not, find it within the header/data buffers.
- */
-
/* Devices may send a MPR response as a full-sized Admin response,
* rather than the minimal MI-only header. Allow this, but only if the
* type indicates admin, and the allocated response header is the
* correct size for an Admin response.
*/
- if (((msg->hdr.nmp >> 3) & 0xf) == NVME_MI_MT_ADMIN &&
- len == sizeof(*admin_msg) + sizeof(mic) &&
- resp->hdr_len == sizeof(*admin_msg)) {
- if (resp->data_len)
- mic = *(__le32 *)resp->data;
- } else if (len == sizeof(*msg) + sizeof(mic)) {
- if (resp->hdr_len > sizeof(*msg))
- mic = *(__le32 *)(msg + 1);
- else if (resp->data_len)
- mic = *(__le32 *)(resp->data);
- } else {
- return false;
- }
-
- /* Since our response is just a header, we're guaranteed to have
- * all data in resp->hdr. The response may be shorter than the expected
- * header though, so clamp to len.
+ if (!(len == sizeof(*msg) ||
+ ((msg->hdr.nmp >> 3 & 0x0f) == NVME_MI_MT_ADMIN &&
+ len == sizeof(struct nvme_mi_admin_resp_hdr))))
+ return false;
+
+ /* Verify the MIC from the response. We're dealing with linear
+ * header data here, and need to preserve the resp pointer & size
+ * values, so can't use verify_resp_mic here.
*/
- len -= sizeof(mic);
- clen = len < resp->hdr_len ? len : resp->hdr_len;
-
- crc = ~nvme_mi_crc32_update(0xffffffff, resp->hdr, clen);
+ crc = ~nvme_mi_crc32_update(0xffffffff, buf, len);
if (le32_to_cpu(mic) != crc)
return false;
@@ -242,14 +224,14 @@ static int nvme_mi_mctp_submit(struct nvme_mi_ep *ep,
struct nvme_mi_req *req,
struct nvme_mi_resp *resp)
{
+ ssize_t len, resp_len, resp_hdr_len, resp_data_len;
struct nvme_mi_transport_mctp *mctp;
- struct iovec req_iov[3], resp_iov[3];
+ struct iovec req_iov[3], resp_iov[1];
struct msghdr req_msg, resp_msg;
int i, rc, errno_save, timeout;
struct sockaddr_mctp addr;
struct pollfd pollfds[1];
unsigned int mpr_time;
- ssize_t len;
__le32 mic;
__u8 tag;
@@ -306,20 +288,30 @@ static int nvme_mi_mctp_submit(struct nvme_mi_ep *ep,
goto out;
}
- resp_iov[0].iov_base = ((__u8 *)resp->hdr) + 1;
- resp_iov[0].iov_len = resp->hdr_len - 1;
-
- resp_iov[1].iov_base = ((__u8 *)resp->data);
- resp_iov[1].iov_len = resp->data_len;
+ resp_len = resp->hdr_len + resp->data_len + sizeof(mic);
+ if (resp_len > mctp->resp_buf_size) {
+ void *tmp = realloc(mctp->resp_buf, resp_len);
+ if (!tmp) {
+ errno_save = errno;
+ nvme_msg(ep->root, LOG_ERR,
+ "Failure allocating response buffer: %m\n");
+ errno = errno_save;
+ rc = -1;
+ goto out;
+ }
+ mctp->resp_buf = tmp;
+ mctp->resp_buf_size = resp_len;
+ }
- resp_iov[2].iov_base = &mic;
- resp_iov[2].iov_len = sizeof(mic);
+ /* offset by one: the MCTP message type is excluded from the buffer */
+ resp_iov[0].iov_base = mctp->resp_buf + 1;
+ resp_iov[0].iov_len = resp_len - 1;
memset(&resp_msg, 0, sizeof(resp_msg));
resp_msg.msg_name = &addr;
resp_msg.msg_namelen = sizeof(addr);
resp_msg.msg_iov = resp_iov;
- resp_msg.msg_iovlen = 3;
+ resp_msg.msg_iovlen = 1;
pollfds[0].fd = mctp->sd;
pollfds[0].events = POLLIN;
@@ -333,13 +325,14 @@ retry:
nvme_msg(ep->root, LOG_ERR,
"Failed polling on MCTP socket: %m");
errno = errno_save;
- return -1;
+ goto out;
}
if (rc == 0) {
nvme_msg(ep->root, LOG_DEBUG, "Timeout on MCTP socket");
errno = ETIMEDOUT;
- return -1;
+ rc = -1;
+ goto out;
}
rc = -1;
@@ -361,7 +354,7 @@ retry:
}
/* Re-add the type byte, so we can work on aligned lengths from here */
- resp->hdr->type = MCTP_TYPE_NVME | MCTP_TYPE_MIC;
+ ((uint8_t *)mctp->resp_buf)[0] = MCTP_TYPE_NVME | MCTP_TYPE_MIC;
len += 1;
/* The smallest response data is 8 bytes: generic 4-byte message header
@@ -375,21 +368,21 @@ retry:
goto out;
}
- /* We can't have header/payload data that isn't a multiple of 4 bytes */
- if (len & 0x3) {
- nvme_msg(ep->root, LOG_WARNING,
- "Response message has unaligned length (%zd)!\n",
- len);
- errno = EPROTO;
- goto out;
- }
+ /* Start unpacking the linear resp buffer into the split header + data
+ * + MIC. We check for a MPR response before fully unpacking, as we'll
+ * need to preserve the resp layout if we need to retry the receive.
+ */
+
+ /* MIC is always at the tail */
+ memcpy(&mic, mctp->resp_buf + len - sizeof(mic), sizeof(mic));
+ len -= 4;
/* Check for a More Processing Required response. This is a slight
* layering violation, as we're pre-checking the MIC and inspecting
* header fields. However, we need to do this in the transport in order
* to keep the tag allocated and retry the recvmsg
*/
- if (nvme_mi_mctp_resp_is_mpr(resp, len, mic, &mpr_time)) {
+ if (nvme_mi_mctp_resp_is_mpr(mctp->resp_buf, len, mic, &mpr_time)) {
nvme_msg(ep->root, LOG_DEBUG,
"Received More Processing Required, waiting for response\n");
@@ -406,30 +399,20 @@ retry:
goto retry;
}
- /* If we have a shorter than expected response, we need to find the
- * MIC and the correct split between header & data. We know that the
- * split is 4-byte aligned, so the MIC will be entirely within one
- * of the iovecs.
- */
- if (len == resp->hdr_len + resp->data_len + sizeof(mic)) {
- /* Common case: expected data length. Header, data and MIC
- * are already laid-out correctly. Nothing to do. */
-
- } else if (len < resp->hdr_len + sizeof(mic)) {
- /* Response is smaller than the expected header. MIC is
- * somewhere in the header buf */
- resp->hdr_len = len - sizeof(mic);
- resp->data_len = 0;
- memcpy(&mic, ((uint8_t *)resp->hdr) + resp->hdr_len,
- sizeof(mic));
-
- } else {
- /* We have a full header, but data is truncated - possibly
- * zero bytes. MIC is somewhere in the data buf */
- resp->data_len = len - resp->hdr_len - sizeof(mic);
- memcpy(&mic, ((uint8_t *)resp->data) + resp->data_len,
- sizeof(mic));
- }
+ /* we expect resp->hdr_len bytes, but we may have less */
+ resp_hdr_len = resp->hdr_len;
+ if (resp_hdr_len > len)
+ resp_hdr_len = len;
+ memcpy(resp->hdr, mctp->resp_buf, resp_hdr_len);
+ resp->hdr_len = resp_hdr_len;
+ len -= resp_hdr_len;
+
+ /* any remaining bytes are the data payload */
+ resp_data_len = resp->data_len;
+ if (resp_data_len > len)
+ resp_data_len = len;
+ memcpy(resp->data, mctp->resp_buf + resp_hdr_len, resp_data_len);
+ resp->data_len = resp_data_len;
resp->mic = le32_to_cpu(mic);
@@ -450,6 +433,7 @@ static void nvme_mi_mctp_close(struct nvme_mi_ep *ep)
mctp = ep->transport_data;
close(mctp->sd);
+ free(mctp->resp_buf);
free(ep->transport_data);
}
@@ -488,15 +472,29 @@ nvme_mi_ep_t nvme_mi_open_mctp(nvme_root_t root, unsigned int netid, __u8 eid)
return NULL;
mctp = malloc(sizeof(*mctp));
- if (!mctp)
- goto err_free_ep;
+ if (!mctp) {
+ errno_save = errno;
+ goto err_close_ep;
+ }
+
+ memset(mctp, 0, sizeof(*mctp));
+ mctp->sd = -1;
+
+ mctp->resp_buf_size = 4096;
+ mctp->resp_buf = malloc(mctp->resp_buf_size);
+ if (!mctp->resp_buf) {
+ errno_save = errno;
+ goto err_free_mctp;
+ }
mctp->net = netid;
mctp->eid = eid;
mctp->sd = ops.socket(AF_MCTP, SOCK_DGRAM, 0);
- if (mctp->sd < 0)
- goto err_free_ep;
+ if (mctp->sd < 0) {
+ errno_save = errno;
+ goto err_free_rspbuf;
+ }
ep->transport = &nvme_mi_transport_mctp;
ep->transport_data = mctp;
@@ -512,10 +510,14 @@ nvme_mi_ep_t nvme_mi_open_mctp(nvme_root_t root, unsigned int netid, __u8 eid)
return ep;
-err_free_ep:
- errno_save = errno;
- nvme_mi_close(ep);
+err_free_rspbuf:
+ free(mctp->resp_buf);
+err_free_mctp:
free(mctp);
+err_close_ep:
+ /* the ep->transport is not set yet, so this will not call back
+ * into nvme_mi_mctp_close() */
+ nvme_mi_close(ep);
errno = errno_save;
return NULL;
}
diff --git a/src/nvme/mi.c b/src/nvme/mi.c
index 3799f35..82ed88a 100644
--- a/src/nvme/mi.c
+++ b/src/nvme/mi.c
@@ -413,11 +413,6 @@ int nvme_mi_submit(nvme_mi_ep_t ep, struct nvme_mi_req *req,
return -1;
}
- if (resp->data_len & 0x3) {
- errno = EINVAL;
- return -1;
- }
-
if (ep->transport->mic_enabled)
nvme_mi_calc_req_mic(req);
@@ -580,8 +575,10 @@ int nvme_mi_admin_xfer(nvme_mi_ctrl_t ctrl,
return -1;
}
- /* must be aligned */
- if (resp_data_offset & 0x3) {
+ /* 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;
}
@@ -1051,7 +1048,7 @@ int nvme_mi_admin_set_features(nvme_mi_ctrl_t ctrl,
nvme_admin_set_features);
req_hdr.cdw1 = cpu_to_le32(args->nsid);
- req_hdr.cdw10 = cpu_to_le32((args->save ? 1 : 0) << 31 |
+ 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);
@@ -1223,7 +1220,7 @@ int nvme_mi_admin_fw_commit(nvme_mi_ctrl_t ctrl,
nvme_mi_admin_init_req(&req, &req_hdr, ctrl->id,
nvme_admin_fw_commit);
- req_hdr.cdw10 = cpu_to_le32(((args->bpid & 0x1) << 31) |
+ req_hdr.cdw10 = cpu_to_le32(((__u32)(args->bpid & 0x1) << 31) |
((args->action & 0x7) << 3) |
((args->slot & 0x7) << 0));
diff --git a/src/nvme/mi.h b/src/nvme/mi.h
index 211cb29..bd26627 100644
--- a/src/nvme/mi.h
+++ b/src/nvme/mi.h
@@ -1395,7 +1395,6 @@ static inline int nvme_mi_admin_identify_primary_ctrl(nvme_mi_ctrl_t ctrl,
* nvme_mi_admin_identify_secondary_ctrl_list() - Perform an Admin identify for
* a secondary controller list.
* @ctrl: Controller to process identify command
- * @nsid: Namespace ID to specify list start
* @cntid: Controller ID to specify list start
* @list: List data to populate
*
@@ -1412,7 +1411,6 @@ static inline int nvme_mi_admin_identify_primary_ctrl(nvme_mi_ctrl_t ctrl,
* See: &struct nvme_secondary_ctrl_list
*/
static inline int nvme_mi_admin_identify_secondary_ctrl_list(nvme_mi_ctrl_t ctrl,
- __u32 nsid,
__u16 cntid,
struct nvme_secondary_ctrl_list *list)
{
@@ -1422,7 +1420,7 @@ static inline int nvme_mi_admin_identify_secondary_ctrl_list(nvme_mi_ctrl_t ctrl
.args_size = sizeof(args),
.cns = NVME_IDENTIFY_CNS_SECONDARY_CTRL_LIST,
.csi = NVME_CSI_NVM,
- .nsid = nsid,
+ .nsid = NVME_NSID_NONE,
.cntid = cntid,
.cns_specific_id = NVME_CNSSPECID_NONE,
.uuidx = NVME_UUID_NONE,
@@ -2109,6 +2107,41 @@ static inline int nvme_mi_admin_get_log_boot_partition(nvme_mi_ctrl_t ctrl,
}
/**
+ * 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_discovery() - Retrieve Discovery log page
* @ctrl: Controller to query
* @rae: Retain asynchronous events
diff --git a/src/nvme/nbft.c b/src/nvme/nbft.c
index a1e17cd..2c87088 100644
--- a/src/nvme/nbft.c
+++ b/src/nvme/nbft.c
@@ -33,17 +33,15 @@ static __u8 csum(const __u8 *buffer, ssize_t length)
static void format_ip_addr(char *buf, size_t buflen, __u8 *addr)
{
- struct in6_addr *addr_ipv6;
+ struct in6_addr addr_ipv6;
- addr_ipv6 = (struct in6_addr *)addr;
- if (addr_ipv6->s6_addr32[0] == 0 &&
- addr_ipv6->s6_addr32[1] == 0 &&
- ntohl(addr_ipv6->s6_addr32[2]) == 0xffff)
+ memcpy(&addr_ipv6, addr, sizeof(addr_ipv6));
+ if (IN6_IS_ADDR_V4MAPPED(&addr_ipv6))
/* ipv4 */
- inet_ntop(AF_INET, &(addr_ipv6->s6_addr32[3]), buf, buflen);
+ inet_ntop(AF_INET, &addr_ipv6.s6_addr32[3], buf, buflen);
else
/* ipv6 */
- inet_ntop(AF_INET6, addr_ipv6, buf, buflen);
+ inet_ntop(AF_INET6, &addr_ipv6, buf, buflen);
}
static bool in_heap(struct nbft_header *header, struct nbft_heap_obj obj)
@@ -199,15 +197,15 @@ static int read_ssns(struct nbft_info *nbft,
verify(raw_ssns->structure_id == NBFT_DESC_SSNS,
"invalid ID in SSNS descriptor");
+ /* verify transport type */
+ verify(raw_ssns->trtype == NBFT_TRTYPE_TCP,
+ "invalid transport type in SSNS descriptor");
+
ssns = calloc(1, sizeof(*ssns));
if (!ssns)
return -ENOMEM;
ssns->index = le16_to_cpu(raw_ssns->index);
-
- /* transport type */
- verify(raw_ssns->trtype == NBFT_TRTYPE_TCP,
- "invalid transport type in SSNS descriptor");
strncpy(ssns->transport, trtype_to_string(raw_ssns->trtype), sizeof(ssns->transport));
/* transport specific flags */
@@ -413,26 +411,29 @@ static int read_discovery(struct nbft_info *nbft,
struct nbft_discovery *raw_discovery,
struct nbft_info_discovery **d)
{
- struct nbft_info_discovery *discovery;
+ struct nbft_info_discovery *discovery = NULL;
struct nbft_header *header = (struct nbft_header *)nbft->raw_nbft;
+ int r = -EINVAL;
if (!(raw_discovery->flags & NBFT_DISCOVERY_VALID))
- return -EINVAL;
+ goto error;
verify(raw_discovery->structure_id == NBFT_DESC_DISCOVERY,
"invalid ID in discovery descriptor");
discovery = calloc(1, sizeof(struct nbft_info_discovery));
- if (!discovery)
- return -ENOMEM;
+ if (!discovery) {
+ r = -ENOMEM;
+ goto error;
+ }
discovery->index = raw_discovery->index;
if (get_heap_obj(raw_discovery, discovery_ctrl_addr_obj, 1, &discovery->uri))
- return -EINVAL;
+ goto error;
if (get_heap_obj(raw_discovery, discovery_ctrl_nqn_obj, 1, &discovery->nqn))
- return -EINVAL;
+ goto error;
discovery->hfi = hfi_from_index(nbft, raw_discovery->hfi_index);
if (raw_discovery->hfi_index && !discovery->hfi)
@@ -447,7 +448,12 @@ static int read_discovery(struct nbft_info *nbft,
nbft->filename, discovery->index);
*d = discovery;
- return 0;
+ r = 0;
+
+error:
+ if (r)
+ free(discovery);
+ return r;
}
static int read_security(struct nbft_info *nbft,
diff --git a/src/nvme/private.h b/src/nvme/private.h
index 809b3bb..ee9d738 100644
--- a/src/nvme/private.h
+++ b/src/nvme/private.h
@@ -106,6 +106,7 @@ struct nvme_subsystem {
char *firmware;
char *subsystype;
char *application;
+ char *iopolicy;
};
struct nvme_host {
@@ -179,7 +180,9 @@ int json_dump_tree(nvme_root_t r);
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,
- nvme_ctrl_t p);
+ const char *subsysnqn, nvme_ctrl_t p);
+
+void *__nvme_alloc(size_t len);
#if (LOG_FUNCNAME == 1)
#define __nvme_log_func __func__
@@ -197,6 +200,11 @@ __nvme_msg(nvme_root_t r, int lvl, const char *func, const char *format, ...);
format, ##__VA_ARGS__); \
} while (0)
+#define root_from_ctrl(c) ((c)->s && (c)->s->h ? (c)->s->h->r : NULL)
+#define root_from_ns(n) ((n)->s && (n)->s->h ? (n)->s->h->r : \
+ (n)->c && (n)->c->s && (n)->c->s->h ? (n)->c->s->h->r : \
+ NULL)
+
/* mi internal headers */
/* internal transport API */
diff --git a/src/nvme/tree.c b/src/nvme/tree.c
index a2ac069..07a3c53 100644
--- a/src/nvme/tree.c
+++ b/src/nvme/tree.c
@@ -15,6 +15,7 @@
#include <fcntl.h>
#include <libgen.h>
#include <unistd.h>
+#include <ifaddrs.h>
#include <sys/types.h>
#include <sys/stat.h>
@@ -24,6 +25,7 @@
#include <ccan/endian/endian.h>
#include <ccan/list/list.h>
+#include "cleanup.h"
#include "ioctl.h"
#include "linux.h"
#include "filters.h"
@@ -34,6 +36,31 @@
#include "log.h"
#include "private.h"
+/**
+ * struct candidate_args - Used to look for a controller matching these parameters
+ * @transport: Transport type: loop, fc, rdma, tcp
+ * @traddr: Transport address (destination address)
+ * @trsvcid: Transport service ID
+ * @subsysnqn: Subsystem NQN
+ * @host_traddr: Host transport address (source address)
+ * @host_iface: Host interface for connection (tcp only)
+ * @iface_list: Interface list (tcp only)
+ * @addreq: Address comparison function (for traddr, host-traddr)
+ * @well_known_nqn: Set to "true" when @subsysnqn is the well-known NQN
+ */
+struct candidate_args {
+ const char *transport;
+ const char *traddr;
+ const char *trsvcid;
+ const char *subsysnqn;
+ const char *host_traddr;
+ const char *host_iface;
+ struct ifaddrs *iface_list;
+ bool (*addreq)(const char *, const char *);
+ bool well_known_nqn;
+};
+typedef bool (*ctrl_match_t)(struct nvme_ctrl *c, struct candidate_args *candidate);
+
const char *nvme_slots_sysfs_dir = "/sys/bus/pci/slots";
static struct nvme_host *default_host;
@@ -78,17 +105,24 @@ static bool streqcase0(const char *s1, const char *s2)
return !strcasecmp(s1, s2);
}
-static inline void nvme_free_dirents(struct dirent **d, int i)
+struct dirents {
+ struct dirent **ents;
+ int num;
+};
+
+static void cleanup_dirents(struct dirents *ents)
{
- while (i-- > 0)
- free(d[i]);
- free(d);
+ while (ents->num > 0)
+ free(ents->ents[--ents->num]);
+ free(ents->ents);
}
+#define _cleanup_dirents_ __cleanup__(cleanup_dirents)
+
nvme_host_t nvme_default_host(nvme_root_t r)
{
struct nvme_host *h;
- char *hostnqn, *hostid;
+ _cleanup_free_ char *hostnqn, *hostid;
hostnqn = nvmf_hostnqn_from_file();
if (!hostnqn)
@@ -100,61 +134,55 @@ nvme_host_t nvme_default_host(nvme_root_t r)
nvme_host_set_hostsymname(h, NULL);
default_host = h;
- free(hostnqn);
- if (hostid)
- free(hostid);
return h;
}
int nvme_scan_topology(struct nvme_root *r, nvme_scan_filter_t f, void *f_args)
{
- struct dirent **subsys, **ctrls;
- int i, num_subsys, num_ctrls, ret;
+ _cleanup_dirents_ struct dirents subsys = {}, ctrls = {};
+ int i, ret;
if (!r)
return 0;
- num_ctrls = nvme_scan_ctrls(&ctrls);
- if (num_ctrls < 0) {
+ ctrls.num = nvme_scan_ctrls(&ctrls.ents);
+ if (ctrls.num < 0) {
nvme_msg(r, LOG_DEBUG, "failed to scan ctrls: %s\n",
strerror(errno));
- return num_ctrls;
+ return ctrls.num;
}
- for (i = 0; i < num_ctrls; i++) {
- nvme_ctrl_t c = nvme_scan_ctrl(r, ctrls[i]->d_name);
+ for (i = 0; i < ctrls.num; i++) {
+ nvme_ctrl_t c = nvme_scan_ctrl(r, ctrls.ents[i]->d_name);
if (!c) {
nvme_msg(r, LOG_DEBUG, "failed to scan ctrl %s: %s\n",
- ctrls[i]->d_name, strerror(errno));
+ ctrls.ents[i]->d_name, strerror(errno));
continue;
}
if ((f) && !f(NULL, c, NULL, f_args)) {
nvme_msg(r, LOG_DEBUG, "filter out controller %s\n",
- ctrls[i]->d_name);
+ ctrls.ents[i]->d_name);
nvme_free_ctrl(c);
}
}
- nvme_free_dirents(ctrls, i);
-
- num_subsys = nvme_scan_subsystems(&subsys);
- if (num_subsys < 0) {
+ subsys.num = nvme_scan_subsystems(&subsys.ents);
+ if (subsys.num < 0) {
nvme_msg(r, LOG_DEBUG, "failed to scan subsystems: %s\n",
strerror(errno));
- return num_subsys;
+ return subsys.num;
}
- for (i = 0; i < num_subsys; i++) {
- ret = nvme_scan_subsystem(r, subsys[i]->d_name, f, f_args);
+ for (i = 0; i < subsys.num; i++) {
+ ret = nvme_scan_subsystem(
+ r, subsys.ents[i]->d_name, f, f_args);
if (ret < 0) {
nvme_msg(r, LOG_DEBUG,
"failed to scan subsystem %s: %s\n",
- subsys[i]->d_name, strerror(errno));
+ subsys.ents[i]->d_name, strerror(errno));
}
}
- nvme_free_dirents(subsys, i);
-
return 0;
}
@@ -172,6 +200,7 @@ nvme_root_t nvme_create_root(FILE *fp, int log_level)
r->fp = fp;
list_head_init(&r->hosts);
list_head_init(&r->endpoints);
+ nvme_set_root(r);
return r;
}
@@ -234,8 +263,10 @@ const char *nvme_root_get_application(nvme_root_t r)
void nvme_root_set_application(nvme_root_t r, const char *a)
{
- if (r->application)
+ if (r->application) {
free(r->application);
+ r->application = NULL;
+ }
if (a)
r->application = strdup(a);
}
@@ -338,9 +369,18 @@ void nvme_free_tree(nvme_root_t r)
free(r->config_file);
if (r->application)
free(r->application);
+ nvme_set_root(NULL);
free(r);
}
+void nvme_root_release_fds(nvme_root_t r)
+{
+ struct nvme_host *h, *_h;
+
+ nvme_for_each_host_safe(r, h, _h)
+ nvme_host_release_fds(h);
+}
+
const char *nvme_subsystem_get_nqn(nvme_subsystem_t s)
{
return s->subsysnqn;
@@ -368,12 +408,19 @@ const char *nvme_subsystem_get_application(nvme_subsystem_t s)
void nvme_subsystem_set_application(nvme_subsystem_t s, const char *a)
{
- if (s->application)
+ if (s->application) {
free(s->application);
+ s->application = NULL;
+ }
if (a)
s->application = strdup(a);
}
+const char *nvme_subsystem_get_iopolicy(nvme_subsystem_t s)
+{
+ return s->iopolicy;
+}
+
nvme_ctrl_t nvme_subsystem_first_ctrl(nvme_subsystem_t s)
{
return list_top(&s->ctrls, struct nvme_ctrl, entry);
@@ -412,7 +459,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);
- close(n->fd);
+ nvme_ns_release_fd(n);
free(n->generic_name);
free(n->name);
free(n->sysfs_dir);
@@ -451,9 +498,23 @@ static void __nvme_free_subsystem(struct nvme_subsystem *s)
free(s->subsystype);
if (s->application)
free(s->application);
+ if (s->iopolicy)
+ free(s->iopolicy);
free(s);
}
+void nvme_subsystem_release_fds(struct nvme_subsystem *s)
+{
+ struct nvme_ctrl *c, *_c;
+ struct nvme_ns *n, *_n;
+
+ nvme_subsystem_for_each_ctrl_safe(s, c, _c)
+ nvme_ctrl_release_fd(c);
+
+ nvme_subsystem_for_each_ns_safe(s, n, _n)
+ nvme_ns_release_fd(n);
+}
+
/*
* Stub for SWIG
*/
@@ -524,6 +585,14 @@ static void __nvme_free_host(struct nvme_host *h)
free(h);
}
+void nvme_host_release_fds(struct nvme_host *h)
+{
+ struct nvme_subsystem *s, *_s;
+
+ nvme_for_each_subsystem_safe(h, s, _s)
+ nvme_subsystem_release_fds(s);
+}
+
/* Stub for SWIG */
void nvme_free_host(struct nvme_host *h)
{
@@ -563,27 +632,26 @@ struct nvme_host *nvme_lookup_host(nvme_root_t r, const char *hostnqn,
static int nvme_subsystem_scan_namespaces(nvme_root_t r, nvme_subsystem_t s,
nvme_scan_filter_t f, void *f_args)
{
- struct dirent **namespaces;
- int i, num_ns, ret;
+ _cleanup_dirents_ struct dirents namespaces = {};
+ int i, ret;
- num_ns = nvme_scan_subsystem_namespaces(s, &namespaces);
- if (num_ns < 0) {
+ namespaces.num = nvme_scan_subsystem_namespaces(s, &namespaces.ents);
+ if (namespaces.num < 0) {
nvme_msg(r, LOG_DEBUG,
"failed to scan namespaces for subsys %s: %s\n",
s->subsysnqn, strerror(errno));
- return num_ns;
+ return namespaces.num;
}
- for (i = 0; i < num_ns; i++) {
+ for (i = 0; i < namespaces.num; i++) {
ret = nvme_subsystem_scan_namespace(r, s,
- namespaces[i]->d_name, f, f_args);
+ namespaces.ents[i]->d_name, f, f_args);
if (ret < 0)
nvme_msg(r, LOG_DEBUG,
"failed to scan namespace %s: %s\n",
- namespaces[i]->d_name, strerror(errno));
+ namespaces.ents[i]->d_name, strerror(errno));
}
- nvme_free_dirents(namespaces, i);
return 0;
}
@@ -610,15 +678,28 @@ static int nvme_init_subsystem(nvme_subsystem_t s, const char *name)
s->sysfs_dir = (char *)path;
if (s->h->r->application)
s->application = strdup(s->h->r->application);
+ s->iopolicy = nvme_get_attr(path, "iopolicy");
return 0;
}
+static bool __nvme_scan_subsystem(struct nvme_root *r, nvme_subsystem_t s,
+ nvme_scan_filter_t f, void *f_args)
+{
+ if (f && !f(s, NULL, NULL, f_args)) {
+ nvme_msg(r, LOG_DEBUG, "filter out subsystem %s\n", s->name);
+ __nvme_free_subsystem(s);
+ return false;
+ }
+ nvme_subsystem_scan_namespaces(r, s, f, f_args);
+ return true;
+}
+
static int nvme_scan_subsystem(struct nvme_root *r, const char *name,
nvme_scan_filter_t f, void *f_args)
{
struct nvme_subsystem *s = NULL, *_s;
- char *path, *subsysnqn;
+ _cleanup_free_ char *path = NULL, *subsysnqn = NULL;
nvme_host_t h = NULL;
int ret;
@@ -628,7 +709,6 @@ static int nvme_scan_subsystem(struct nvme_root *r, const char *name,
return ret;
subsysnqn = nvme_get_attr(path, "subsysnqn");
- free(path);
if (!subsysnqn) {
errno = ENODEV;
return -1;
@@ -644,6 +724,10 @@ static int nvme_scan_subsystem(struct nvme_root *r, const char *name,
continue;
if (strcmp(_s->name, name))
continue;
+ if (!__nvme_scan_subsystem(r, _s, f, f_args)) {
+ errno = EINVAL;
+ return -1;
+ }
s = _s;
}
}
@@ -659,26 +743,18 @@ static int nvme_scan_subsystem(struct nvme_root *r, const char *name,
s = nvme_alloc_subsystem(h, name, subsysnqn);
if (!s) {
errno = ENOMEM;
+ return -1;
+ }
+ if (!__nvme_scan_subsystem(r, s, f, f_args)) {
+ errno = EINVAL;
+ return -1;
}
} else if (strcmp(s->subsysnqn, subsysnqn)) {
- nvme_msg(r, LOG_WARNING, "NQN mismatch for subsystem '%s'\n",
+ nvme_msg(r, LOG_DEBUG, "NQN mismatch for subsystem '%s'\n",
name);
- s = NULL;
- free(subsysnqn);
errno = EINVAL;
return -1;
}
- free(subsysnqn);
- if (!s)
- return -1;
-
- if (f && !f(s, NULL, NULL, f_args)) {
- nvme_msg(r, LOG_DEBUG, "filter out subsystem %s\n", name);
- __nvme_free_subsystem(s);
- return 0;
- }
-
- nvme_subsystem_scan_namespaces(r, s, f, f_args);
return 0;
}
@@ -740,7 +816,7 @@ static void nvme_subsystem_set_path_ns(nvme_subsystem_t s, nvme_path_t p)
static int nvme_ctrl_scan_path(nvme_root_t r, struct nvme_ctrl *c, char *name)
{
struct nvme_path *p;
- char *path, *grpid;
+ _cleanup_free_ char *path = NULL, *grpid = NULL;
int ret;
nvme_msg(r, LOG_DEBUG, "scan controller %s path %s\n",
@@ -758,12 +834,13 @@ static int nvme_ctrl_scan_path(nvme_root_t r, struct nvme_ctrl *c, char *name)
p = calloc(1, sizeof(*p));
if (!p) {
errno = ENOMEM;
- goto free_path;
+ return -1;
}
p->c = c;
p->name = strdup(name);
p->sysfs_dir = path;
+ path = NULL;
p->ana_state = nvme_get_path_attr(p, "ana_state");
if (!p->ana_state)
p->ana_state = strdup("optimized");
@@ -771,7 +848,6 @@ static int nvme_ctrl_scan_path(nvme_root_t r, struct nvme_ctrl *c, char *name)
grpid = nvme_get_path_attr(p, "ana_grpid");
if (grpid) {
sscanf(grpid, "%d", &p->grpid);
- free(grpid);
}
list_node_init(&p->nentry);
@@ -779,26 +855,29 @@ static int nvme_ctrl_scan_path(nvme_root_t r, struct nvme_ctrl *c, char *name)
list_node_init(&p->entry);
list_add(&c->paths, &p->entry);
return 0;
-
-free_path:
- free(path);
- return -1;
}
int nvme_ctrl_get_fd(nvme_ctrl_t c)
{
- nvme_root_t r = c->s && c->s->h ? c->s->h->r : NULL;
-
if (c->fd < 0) {
c->fd = nvme_open(c->name);
if (c->fd < 0)
- nvme_msg(r, LOG_ERR,
+ nvme_msg(root_from_ctrl(c), LOG_ERR,
"Failed to open ctrl %s, errno %d\n",
c->name, errno);
}
return c->fd;
}
+void nvme_ctrl_release_fd(nvme_ctrl_t c)
+{
+ if (c->fd < 0)
+ return;
+
+ close(c->fd);
+ c->fd = -1;
+}
+
nvme_subsystem_t nvme_ctrl_get_subsystem(nvme_ctrl_t c)
{
return c->s;
@@ -824,6 +903,32 @@ const char *nvme_ctrl_get_address(nvme_ctrl_t c)
return c->address ? c->address : "";
}
+char *nvme_ctrl_get_src_addr(nvme_ctrl_t c, char *src_addr, size_t src_addr_len)
+{
+ size_t l;
+ char *p;
+
+ if (!c->address)
+ return NULL;
+
+ p = strstr(c->address, "src_addr=");
+ if (!p)
+ return NULL;
+
+ p += strlen("src_addr=");
+ l = strcspn(p, ",%"); /* % to eliminate IPv6 scope (if present) */
+ if (l >= src_addr_len) {
+ nvme_msg(root_from_ctrl(c), LOG_ERR,
+ "Buffer for src_addr is too small (%zu must be > %zu)\n",
+ src_addr_len, l);
+ return NULL;
+ }
+
+ strncpy(src_addr, p, l);
+ src_addr[l] = '\0';
+ return src_addr;
+}
+
const char *nvme_ctrl_get_phy_slot(nvme_ctrl_t c)
{
return c->phy_slot ? c->phy_slot : "";
@@ -998,10 +1103,7 @@ nvme_path_t nvme_ctrl_next_path(nvme_ctrl_t c, nvme_path_t p)
do { if (a) { free(a); (a) = NULL; } } while (0)
void nvme_deconfigure_ctrl(nvme_ctrl_t c)
{
- if (c->fd >= 0) {
- close(c->fd);
- c->fd = -1;
- }
+ nvme_ctrl_release_fd(c);
FREE_CTRL_ATTR(c->name);
FREE_CTRL_ATTR(c->sysfs_dir);
FREE_CTRL_ATTR(c->firmware);
@@ -1140,40 +1242,391 @@ struct nvme_ctrl *nvme_create_ctrl(nvme_root_t r,
return c;
}
+/**
+ * _tcp_ctrl_match_host_traddr_no_src_addr() - Match host_traddr w/o src_addr
+ * @c: An existing controller instance
+ * @candidate: Candidate ctrl we're trying to match with @c.
+ *
+ * On kernels prior to 6.1 (i.e. src_addr is not available), try to match
+ * a candidate controller's host_traddr to that of an existing controller.
+ *
+ * This function takes an optimistic approach. In doubt, it will declare a
+ * match and return true.
+ *
+ * Return: true if @c->host_traddr matches @candidate->host_traddr. false otherwise.
+ */
+static bool _tcp_ctrl_match_host_traddr_no_src_addr(struct nvme_ctrl *c, struct candidate_args *candidate)
+{
+ if (c->cfg.host_traddr)
+ return candidate->addreq(candidate->host_traddr, c->cfg.host_traddr);
+
+ /* If c->cfg.host_traddr is NULL, then the controller (c)
+ * uses the interface's primary address as the source
+ * address. If c->cfg.host_iface is defined we can
+ * determine the primary address associated with that
+ * interface and compare that to the candidate->host_traddr.
+ */
+ if (c->cfg.host_iface)
+ return nvme_iface_primary_addr_matches(candidate->iface_list,
+ c->cfg.host_iface,
+ candidate->host_traddr);
+
+ /* If both c->cfg.host_traddr and c->cfg.host_iface are
+ * NULL, we don't have enough information to make a
+ * 100% positive match. Regardless, let's be optimistic
+ * and assume that we have a match.
+ */
+ nvme_msg(root_from_ctrl(c), LOG_DEBUG,
+ "Not enough data, but assume %s matches candidate's host_traddr: %s\n",
+ nvme_ctrl_get_name(c), candidate->host_traddr);
+
+ return true;
+}
+
+/**
+ * _tcp_ctrl_match_host_iface_no_src_addr() - Match host_iface w/o src_addr
+ * @c: An existing controller instance
+ * @candidate: Candidate ctrl we're trying to match with @c.
+ *
+ * On kernels prior to 6.1 (i.e. src_addr is not available), try to match
+ * a candidate controller's host_iface to that of an existing controller.
+ *
+ * This function takes an optimistic approach. In doubt, it will declare a
+ * match and return true.
+ *
+ * Return: true if @c->host_iface matches @candidate->host_iface. false otherwise.
+ */
+static bool _tcp_ctrl_match_host_iface_no_src_addr(struct nvme_ctrl *c, struct candidate_args *candidate)
+{
+ if (c->cfg.host_iface)
+ return streq0(candidate->host_iface, c->cfg.host_iface);
+
+ /* If c->cfg.host_traddr is not NULL we can infer the controller's (c)
+ * interface from it and compare it to the candidate->host_iface.
+ */
+ if (c->cfg.host_traddr) {
+ const char *c_host_iface;
+
+ c_host_iface = nvme_iface_matching_addr(candidate->iface_list, c->cfg.host_traddr);
+ return streq0(candidate->host_iface, c_host_iface);
+ }
+
+ /* If both c->cfg.host_traddr and c->cfg.host_iface are
+ * NULL, we don't have enough information to make a
+ * 100% positive match. Regardless, let's be optimistic
+ * and assume that we have a match.
+ */
+ nvme_msg(root_from_ctrl(c), LOG_DEBUG,
+ "Not enough data, but assume %s matches candidate's host_iface: %s\n",
+ nvme_ctrl_get_name(c), candidate->host_iface);
+
+ return true;
+}
+
+/**
+ * _tcp_opt_params_match_no_src_addr() - Match optional host_traddr/host_iface w/o src_addr
+ * @c: An existing controller instance
+ * @candidate: Candidate ctrl we're trying to match with @c.
+ *
+ * Before kernel 6.1, the src_addr was not reported by the kernel which makes
+ * it hard to match a candidate's host_traddr and host_iface to an existing
+ * controller if that controller was created without specifying the
+ * host_traddr and/or host_iface. This function tries its best in the absense
+ * of a src_addr to match @c to @candidate. This may not be 100% accurate.
+ * Only the src_addr can provide 100% accuracy.
+ *
+ * This function takes an optimistic approach. In doubt, it will declare a
+ * match and return true.
+ *
+ * Return: true if @c matches @candidate. false otherwise.
+ */
+static bool _tcp_opt_params_match_no_src_addr(struct nvme_ctrl *c, struct candidate_args *candidate)
+{
+ /* Check host_traddr only if candidate is interested */
+ if (candidate->host_traddr) {
+ if (!_tcp_ctrl_match_host_traddr_no_src_addr(c, candidate))
+ return false;
+ }
+
+ /* Check host_iface only if candidate is interested */
+ if (candidate->host_iface) {
+ if (!_tcp_ctrl_match_host_iface_no_src_addr(c, candidate))
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * _tcp_opt_params_match() - Match optional host_traddr/host_iface
+ * @c: An existing controller instance
+ * @candidate: Candidate ctrl we're trying to match with @c.
+ *
+ * The host_traddr and host_iface are optional for TCP. When they are not
+ * specified, the kernel looks up the destination IP address (traddr) in the
+ * routing table to determine the best interface for the connection. The
+ * kernel then retrieves the primary IP address assigned to that interface
+ * and uses that as the connection’s source address.
+ *
+ * An interface’s primary address is the default source address used for
+ * all connections made on that interface unless host-traddr is used to
+ * override the default. Kernel-selected interfaces and/or source addresses
+ * are hidden from user-space applications unless the kernel makes that
+ * information available through the "src_addr" attribute in the
+ * sysfs (kernel 6.1 or later).
+ *
+ * Sometimes, an application may force the interface by specifying the
+ * "host-iface" or may force a different source address (instead of the
+ * primary address) by providing the "host-traddr".
+ *
+ * If the candidate specifies the host_traddr and/or host_iface but they
+ * do not match the existing controller's host_traddr and/or host_iface
+ * (they could be NULL), we may still be able to find a match by taking
+ * the existing controller's src_addr into consideration since that
+ * parameter identifies the actual source address of the connection and
+ * therefore can be used to infer the interface of the connection. However,
+ * the src_addr can only be read from the nvme device's sysfs "address"
+ * attribute starting with kernel 6.1 (or kernels that backported the
+ * src_addr patch).
+ *
+ * For legacy kernels that do not provide the src_addr we must use a
+ * different algorithm to match the host_traddr and host_iface, but
+ * it's not 100% accurate.
+ *
+ * Return: true if @c matches @candidate. false otherwise.
+ */
+static bool _tcp_opt_params_match(struct nvme_ctrl *c, struct candidate_args *candidate)
+{
+ char *src_addr, buffer[INET6_ADDRSTRLEN];
+
+ /* Check if src_addr is available (kernel 6.1 or later) */
+ src_addr = nvme_ctrl_get_src_addr(c, buffer, sizeof(buffer));
+ if (!src_addr)
+ return _tcp_opt_params_match_no_src_addr(c, candidate);
+
+ /* Check host_traddr only if candidate is interested */
+ if (candidate->host_traddr &&
+ !candidate->addreq(candidate->host_traddr, src_addr))
+ return false;
+
+ /* Check host_iface only if candidate is interested */
+ if (candidate->host_iface &&
+ !streq0(candidate->host_iface,
+ nvme_iface_matching_addr(candidate->iface_list, src_addr)))
+ return false;
+
+ return true;
+}
+
+/**
+ * _tcp_match_ctrl() - Check if controller matches candidate (TCP only)
+ * @c: An existing controller instance
+ * @candidate: Candidate ctrl we're trying to match with @c.
+ *
+ * We want to determine if an existing controller can be re-used
+ * for the candidate controller we're trying to instantiate.
+ *
+ * For TCP, we do not have a match if the candidate's transport, traddr,
+ * trsvcid are not identical to those of the the existing controller.
+ * These 3 parameters are mandatory for a match.
+ *
+ * The host_traddr and host_iface are optional. When the candidate does
+ * not specify them (both NULL), we can ignore them. Otherwise, we must
+ * employ advanced investigation techniques to determine if there's a match.
+ *
+ * Return: true if a match is found, false otherwise.
+ */
+static bool _tcp_match_ctrl(struct nvme_ctrl *c, struct candidate_args *candidate)
+{
+ if (!streq0(c->transport, candidate->transport))
+ return false;
+
+ if (!streq0(c->trsvcid, candidate->trsvcid))
+ return false;
+
+ if (!candidate->addreq(c->traddr, candidate->traddr))
+ return false;
+
+ if (candidate->well_known_nqn && !nvme_ctrl_is_discovery_ctrl(c))
+ return false;
+
+ if (candidate->subsysnqn && !streq0(c->subsysnqn, candidate->subsysnqn))
+ return false;
+
+ /* Check host_traddr / host_iface only if candidate is interested */
+ if ((candidate->host_iface || candidate->host_traddr) &&
+ !_tcp_opt_params_match(c, candidate))
+ return false;
+
+ return true;
+}
+
+/**
+ * _match_ctrl() - Check if controller matches candidate (non TCP transport)
+ * @c: An existing controller instance
+ * @candidate: Candidate ctrl we're trying to match with @c.
+ *
+ * We want to determine if an existing controller can be re-used
+ * for the candidate controller we're trying to instantiate. This function
+ * is used for all transports except TCP.
+ *
+ * Return: true if a match is found, false otherwise.
+ */
+static bool _match_ctrl(struct nvme_ctrl *c, struct candidate_args *candidate)
+{
+ if (!streq0(c->transport, candidate->transport))
+ return false;
+
+ if (candidate->traddr && c->traddr &&
+ !candidate->addreq(c->traddr, candidate->traddr))
+ return false;
+
+ if (candidate->host_traddr && c->cfg.host_traddr &&
+ !candidate->addreq(c->cfg.host_traddr, candidate->host_traddr))
+ return false;
+
+ if (candidate->host_iface && c->cfg.host_iface &&
+ !streq0(c->cfg.host_iface, candidate->host_iface))
+ return false;
+
+ if (candidate->trsvcid && c->trsvcid &&
+ !streq0(c->trsvcid, candidate->trsvcid))
+ return false;
+
+ if (candidate->well_known_nqn && !nvme_ctrl_is_discovery_ctrl(c))
+ return false;
+
+ if (candidate->subsysnqn && !streq0(c->subsysnqn, candidate->subsysnqn))
+ return false;
+
+ return true;
+}
+/**
+ * _candidate_init() - Init candidate and get the matching function
+ *
+ * @candidate: Candidate struct to initialize
+ * @transport: Transport name
+ * @traddr: Transport address
+ * @trsvcid: Transport service identifier
+ * @subsysnqn: Subsystem NQN
+ * @host_traddr: Host transport address
+ * @host_iface: Host interface name
+ * @host_iface: Host interface name
+ *
+ * The function _candidate_free() must be called to release resources once
+ * the candidate object is not longer required.
+ *
+ * Return: The matching function to use when comparing an existing
+ * controller to the candidate controller.
+ */
+static ctrl_match_t _candidate_init(struct candidate_args *candidate,
+ const char *transport,
+ const char *traddr,
+ const char *trsvcid,
+ const char *subsysnqn,
+ const char *host_traddr,
+ const char *host_iface)
+{
+ memset(candidate, 0, sizeof(*candidate));
+
+ candidate->traddr = traddr;
+ candidate->trsvcid = trsvcid;
+ candidate->transport = transport;
+ candidate->subsysnqn = subsysnqn;
+ candidate->host_iface = host_iface;
+ candidate->host_traddr = host_traddr;
+
+ if (streq0(subsysnqn, NVME_DISC_SUBSYS_NAME)) {
+ /* Since TP8013, the NQN of discovery controllers can be the
+ * well-known NQN (i.e. nqn.2014-08.org.nvmexpress.discovery) or
+ * a unique NQN. A DC created using the well-known NQN may later
+ * display a unique NQN when looked up in the sysfs. Therefore,
+ * ignore (i.e. set to NULL) the well-known NQN when looking for
+ * a match.
+ */
+ candidate->subsysnqn = NULL;
+ candidate->well_known_nqn = true;
+ }
+
+ if (streq0(transport, "tcp")) {
+ /* For TCP we may need to access the interface map.
+ * Let's retrieve and cache the map.
+ */
+ if (getifaddrs(&candidate->iface_list) == -1)
+ candidate->iface_list = NULL;
+
+ candidate->addreq = nvme_ipaddrs_eq;
+ return _tcp_match_ctrl;
+ }
+
+ if (streq0(transport, "rdma")) {
+ candidate->addreq = nvme_ipaddrs_eq;
+ return _match_ctrl;
+ }
+
+ /* All other transport types */
+ candidate->addreq = streqcase0;
+ return _match_ctrl;
+}
+
+/**
+ * _candidate_free() - Release resources allocated by _candidate_init()
+ *
+ * @candidate: data to free.
+ */
+static void _candidate_free(struct candidate_args *candidate)
+{
+ freeifaddrs(candidate->iface_list); /* This is NULL-safe */
+}
+
+#define _cleanup_candidate_ __cleanup__(_candidate_free)
+
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,
- nvme_ctrl_t p)
-
+ const char *subsysnqn, nvme_ctrl_t p)
{
- struct nvme_ctrl *c;
- bool (*addreq)(const char *, const char *);
+ struct nvme_ctrl *c, *matching_c = NULL;
+ _cleanup_candidate_ struct candidate_args candidate;
+ ctrl_match_t ctrl_match;
- if (!strcmp(transport, "tcp") || !strcmp(transport, "rdma"))
- addreq = nvme_ipaddrs_eq; /* IP address compare for TCP/RDMA */
- else
- addreq = streqcase0; /* Case-insensitive for FC (n/a for loop) */
+ /* Init candidate and get the matching function to use */
+ ctrl_match = _candidate_init(&candidate, transport, traddr, trsvcid,
+ subsysnqn, host_traddr, host_iface);
c = p ? nvme_subsystem_next_ctrl(s, p) : nvme_subsystem_first_ctrl(s);
for (; c != NULL; c = nvme_subsystem_next_ctrl(s, c)) {
- if (!streq0(c->transport, transport))
- continue;
- if (traddr && c->traddr &&
- !addreq(c->traddr, traddr))
- continue;
- if (host_traddr && c->cfg.host_traddr &&
- !addreq(c->cfg.host_traddr, host_traddr))
- continue;
- if (host_iface && c->cfg.host_iface &&
- !streq0(c->cfg.host_iface, host_iface))
- continue;
- if (trsvcid && c->trsvcid &&
- !streq0(c->trsvcid, trsvcid))
- continue;
- return c;
+ if (ctrl_match(c, &candidate)) {
+ matching_c = c;
+ break;
+ }
}
- return NULL;
+ return matching_c;
+}
+
+bool nvme_ctrl_config_match(struct nvme_ctrl *c, const char *transport,
+ const char *traddr, const char *trsvcid,
+ const char *subsysnqn, const char *host_traddr,
+ const char *host_iface)
+{
+ ctrl_match_t ctrl_match;
+ _cleanup_candidate_ struct candidate_args candidate;
+
+ /* Init candidate and get the matching function to use */
+ ctrl_match = _candidate_init(&candidate, transport, traddr, trsvcid,
+ subsysnqn, host_traddr, host_iface);
+
+ return ctrl_match(c, &candidate);
+}
+
+nvme_ctrl_t nvme_ctrl_find(nvme_subsystem_t s, const char *transport,
+ const char *traddr, const char *trsvcid,
+ const char *subsysnqn, const char *host_traddr,
+ const char *host_iface)
+{
+ return __nvme_lookup_ctrl(s, transport, traddr, host_traddr, host_iface,
+ trsvcid, subsysnqn, NULL/*p*/);
}
nvme_ctrl_t nvme_lookup_ctrl(nvme_subsystem_t s, const char *transport,
@@ -1188,7 +1641,7 @@ nvme_ctrl_t nvme_lookup_ctrl(nvme_subsystem_t s, const char *transport,
return NULL;
c = __nvme_lookup_ctrl(s, transport, traddr, host_traddr,
- host_iface, trsvcid, p);
+ host_iface, trsvcid, NULL, p);
if (c)
return c;
@@ -1205,73 +1658,63 @@ nvme_ctrl_t nvme_lookup_ctrl(nvme_subsystem_t s, const char *transport,
static int nvme_ctrl_scan_paths(nvme_root_t r, struct nvme_ctrl *c)
{
- struct dirent **paths;
- int i, ret;
+ _cleanup_dirents_ struct dirents paths = {};
+ int i;
- ret = nvme_scan_ctrl_namespace_paths(c, &paths);
- if (ret < 0)
- return ret;
+ paths.num = nvme_scan_ctrl_namespace_paths(c, &paths.ents);
+ if (paths.num < 0)
+ return paths.num;
- for (i = 0; i < ret; i++)
- nvme_ctrl_scan_path(r, c, paths[i]->d_name);
+ for (i = 0; i < paths.num; i++)
+ nvme_ctrl_scan_path(r, c, paths.ents[i]->d_name);
- nvme_free_dirents(paths, i);
return 0;
}
static int nvme_ctrl_scan_namespaces(nvme_root_t r, struct nvme_ctrl *c)
{
- struct dirent **namespaces;
- int i, ret;
+ _cleanup_dirents_ struct dirents namespaces = {};
+ int i;
- ret = nvme_scan_ctrl_namespaces(c, &namespaces);
- for (i = 0; i < ret; i++)
- nvme_ctrl_scan_namespace(r, c, namespaces[i]->d_name);
+ namespaces.num = nvme_scan_ctrl_namespaces(c, &namespaces.ents);
+ for (i = 0; i < namespaces.num; i++)
+ nvme_ctrl_scan_namespace(r, c, namespaces.ents[i]->d_name);
- nvme_free_dirents(namespaces, i);
return 0;
}
static char *nvme_ctrl_lookup_subsystem_name(nvme_root_t r,
const char *ctrl_name)
{
- struct dirent **subsys;
- char *subsys_name = NULL;
- int ret, i;
+ _cleanup_dirents_ struct dirents subsys = {};
+ int i;
- ret = nvme_scan_subsystems(&subsys);
- if (ret < 0)
+ subsys.num = nvme_scan_subsystems(&subsys.ents);
+ if (subsys.num < 0)
return NULL;
- for (i = 0; i < ret; i++) {
+ for (i = 0; i < subsys.num; i++) {
struct stat st;
- char *path;
+ _cleanup_free_ char *path = NULL;
if (asprintf(&path, "%s/%s/%s", nvme_subsys_sysfs_dir,
- subsys[i]->d_name, ctrl_name) < 0) {
+ subsys.ents[i]->d_name, ctrl_name) < 0) {
errno = ENOMEM;
return NULL;
}
nvme_msg(r, LOG_DEBUG, "lookup subsystem %s\n", path);
if (stat(path, &st) < 0) {
- free(path);
continue;
}
- subsys_name = strdup(subsys[i]->d_name);
- free(path);
- break;
+ return strdup(subsys.ents[i]->d_name);
}
- nvme_free_dirents(subsys, ret);
- return subsys_name;
+ return NULL;
}
static char *nvme_ctrl_lookup_phy_slot(nvme_root_t r, const char *address)
{
- char *target_addr;
- char *addr;
- char *path;
- int found = 0;
+ _cleanup_free_ char *target_addr = NULL;
int ret;
- DIR *slots_dir;
+ _cleanup_dir_ DIR *slots_dir = NULL;
struct dirent *entry;
if (!address)
@@ -1289,25 +1732,20 @@ static char *nvme_ctrl_lookup_phy_slot(nvme_root_t r, const char *address)
if (entry->d_type == DT_DIR &&
strncmp(entry->d_name, ".", 1) != 0 &&
strncmp(entry->d_name, "..", 2) != 0) {
- ret = asprintf(&path, "/sys/bus/pci/slots/%s", entry->d_name);
+ _cleanup_free_ char *path = NULL;
+ _cleanup_free_ char *addr = NULL;
+
+ ret = asprintf(&path, "%s/%s",
+ nvme_slots_sysfs_dir, entry->d_name);
if (ret < 0) {
errno = ENOMEM;
return NULL;
}
addr = nvme_get_attr(path, "address");
- if (strcmp(addr, target_addr) == 0) {
- found = 1;
- free(path);
- free(addr);
- break;
- }
- free(path);
- free(addr);
+ if (strcmp(addr, target_addr) == 0)
+ return strdup(entry->d_name);
}
}
- free(target_addr);
- if (found)
- return strdup(entry->d_name);
return NULL;
}
@@ -1361,8 +1799,9 @@ static int nvme_configure_ctrl(nvme_root_t r, nvme_ctrl_t c, const char *path,
int nvme_init_ctrl(nvme_host_t h, nvme_ctrl_t c, int instance)
{
nvme_subsystem_t s;
- char *subsys_name = NULL;
- char *path, *name;
+ _cleanup_free_ char *subsys_name = NULL;
+ char *path;
+ _cleanup_free_ char *name = NULL;
int ret;
ret = asprintf(&name, "nvme%d", instance);
@@ -1373,20 +1812,19 @@ int nvme_init_ctrl(nvme_host_t h, nvme_ctrl_t c, int instance)
ret = asprintf(&path, "%s/nvme%d", nvme_ctrl_sysfs_dir, instance);
if (ret < 0) {
errno = ENOMEM;
- goto out_free_name;
+ return ret;
}
ret = nvme_configure_ctrl(h->r, c, path, name);
if (ret < 0) {
free(path);
- goto out_free_name;
+ return ret;
}
c->address = nvme_get_attr(path, "address");
if (!c->address && strcmp(c->transport, "loop")) {
errno = ENVME_CONNECT_INVAL_TR;
- ret = -1;
- goto out_free_name;
+ return -1;
}
subsys_name = nvme_ctrl_lookup_subsystem_name(h->r, name);
@@ -1395,23 +1833,17 @@ int nvme_init_ctrl(nvme_host_t h, nvme_ctrl_t c, int instance)
"Failed to lookup subsystem name for %s\n",
c->name);
errno = ENVME_CONNECT_LOOKUP_SUBSYS_NAME;
- ret = -1;
- goto out_free_name;
+ return -1;
}
s = nvme_lookup_subsystem(h, subsys_name, c->subsysnqn);
if (!s) {
errno = ENVME_CONNECT_LOOKUP_SUBSYS;
- ret = -1;
- goto out_free_subsys;
+ return -1;
}
if (s->subsystype && !strcmp(s->subsystype, "discovery"))
c->discovery_ctrl = true;
c->s = s;
list_add(&s->ctrls, &c->entry);
-out_free_subsys:
- free(subsys_name);
- out_free_name:
- free(name);
return ret;
}
@@ -1419,8 +1851,10 @@ static nvme_ctrl_t nvme_ctrl_alloc(nvme_root_t r, nvme_subsystem_t s,
const char *path, const char *name)
{
nvme_ctrl_t c, p;
- char *addr = NULL, *address = NULL, *a, *e;
- char *transport, *traddr = NULL, *trsvcid = NULL;
+ _cleanup_free_ char *addr = NULL, *address = NULL;
+ char *a, *e;
+ _cleanup_free_ char *transport;
+ char *traddr = NULL, *trsvcid = NULL;
char *host_traddr = NULL, *host_iface = NULL;
int ret;
@@ -1432,7 +1866,8 @@ static nvme_ctrl_t nvme_ctrl_alloc(nvme_root_t r, nvme_subsystem_t s,
/* Parse 'address' string into components */
addr = nvme_get_attr(path, "address");
if (!addr) {
- char *rpath = NULL, *p = NULL, *_a = NULL;
+ _cleanup_free_ char *rpath = NULL;
+ char *p = NULL, *_a = NULL;
/* loop transport might not have an address */
if (!strcmp(transport, "loop"))
@@ -1440,14 +1875,12 @@ static nvme_ctrl_t nvme_ctrl_alloc(nvme_root_t r, nvme_subsystem_t s,
/* Older kernel don't support pcie transport addresses */
if (strcmp(transport, "pcie")) {
- free(transport);
errno = ENXIO;
return NULL;
}
/* Figure out the PCI address from the attribute path */
rpath = realpath(path, NULL);
if (!rpath) {
- free(transport);
errno = ENOMEM;
return NULL;
}
@@ -1462,7 +1895,6 @@ static nvme_ctrl_t nvme_ctrl_alloc(nvme_root_t r, nvme_subsystem_t s,
}
if (p)
addr = strdup(p);
- free(rpath);
} else if (!strcmp(transport, "pcie")) {
/* The 'address' string is the transport address */
traddr = addr;
@@ -1500,16 +1932,13 @@ skip_address:
} while (c);
if (!c)
c = p;
- free(transport);
- if (address)
- free(address);
if (!c && !p) {
nvme_msg(r, LOG_ERR, "failed to lookup ctrl\n");
errno = ENODEV;
- free(addr);
return NULL;
}
c->address = addr;
+ addr = NULL;
if (s->subsystype && !strcmp(s->subsystype, "discovery"))
c->discovery_ctrl = true;
ret = nvme_configure_ctrl(r, c, path, name);
@@ -1521,8 +1950,9 @@ nvme_ctrl_t nvme_scan_ctrl(nvme_root_t r, const char *name)
nvme_host_t h;
nvme_subsystem_t s;
nvme_ctrl_t c;
- char *path;
- char *hostnqn, *hostid, *subsysnqn, *subsysname;
+ _cleanup_free_ char *path = NULL;
+ _cleanup_free_ char *hostnqn = NULL, *hostid = NULL;
+ _cleanup_free_ char *subsysnqn = NULL, *subsysname = NULL;
int ret;
nvme_msg(r, LOG_DEBUG, "scan controller %s\n", name);
@@ -1535,10 +1965,6 @@ nvme_ctrl_t nvme_scan_ctrl(nvme_root_t r, const char *name)
hostnqn = nvme_get_attr(path, "hostnqn");
hostid = nvme_get_attr(path, "hostid");
h = nvme_lookup_host(r, hostnqn, hostid);
- if (hostnqn)
- free(hostnqn);
- if (hostid)
- free(hostid);
if (h) {
if (h->dhchap_key)
free(h->dhchap_key);
@@ -1551,7 +1977,6 @@ nvme_ctrl_t nvme_scan_ctrl(nvme_root_t r, const char *name)
if (!h) {
h = nvme_default_host(r);
if (!h) {
- free(path);
errno = ENOMEM;
return NULL;
}
@@ -1559,7 +1984,6 @@ nvme_ctrl_t nvme_scan_ctrl(nvme_root_t r, const char *name)
subsysnqn = nvme_get_attr(path, "subsysnqn");
if (!subsysnqn) {
- free(path);
errno = ENXIO;
return NULL;
}
@@ -1568,27 +1992,21 @@ nvme_ctrl_t nvme_scan_ctrl(nvme_root_t r, const char *name)
nvme_msg(r, LOG_ERR,
"failed to lookup subsystem for controller %s\n",
name);
- free(subsysnqn);
- free(path);
errno = ENXIO;
return NULL;
}
s = nvme_lookup_subsystem(h, subsysname, subsysnqn);
- free(subsysnqn);
- free(subsysname);
if (!s) {
- free(path);
errno = ENOMEM;
return NULL;
}
c = nvme_ctrl_alloc(r, s, path, name);
- if (!c) {
- free(path);
+ if (!c)
return NULL;
- }
+ path = NULL;
nvme_ctrl_scan_namespaces(r, c);
nvme_ctrl_scan_paths(r, c);
return c;
@@ -1622,9 +2040,26 @@ static int nvme_bytes_to_lba(nvme_ns_t n, off_t offset, size_t count,
int nvme_ns_get_fd(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);
+ }
+
return n->fd;
}
+void nvme_ns_release_fd(nvme_ns_t n)
+{
+ if (n->fd < 0)
+ return;
+
+ close(n->fd);
+ n->fd = -1;
+}
+
nvme_subsystem_t nvme_ns_get_subsystem(nvme_ns_t n)
{
return n->s;
@@ -1887,57 +2322,164 @@ int nvme_ns_flush(nvme_ns_t n)
return nvme_flush(nvme_ns_get_fd(n), nvme_ns_get_nsid(n));
}
-static void nvme_ns_parse_descriptors(struct nvme_ns *n,
- struct nvme_ns_id_desc *descs)
+static int nvme_strtou64(const char *str, void *res)
{
- void *d = descs;
- int i, len;
+ char *endptr;
+ __u64 v;
- for (i = 0; i < NVME_IDENTIFY_DATA_SIZE; i += len) {
- struct nvme_ns_id_desc *desc = d + i;
+ errno = 0;
+ v = strtoull(str, &endptr, 0);
- if (!desc->nidl)
- break;
- len = desc->nidl + sizeof(*desc);
+ if (errno != 0)
+ return -errno;
- switch (desc->nidt) {
- case NVME_NIDT_EUI64:
- memcpy(n->eui64, desc->nid, sizeof(n->eui64));
- break;
- case NVME_NIDT_NGUID:
- memcpy(n->nguid, desc->nid, sizeof(n->nguid));
- break;
- case NVME_NIDT_UUID:
- memcpy(n->uuid, desc->nid, sizeof(n->uuid));
- break;
- case NVME_NIDT_CSI:
- memcpy(&n->csi, desc->nid, sizeof(n->csi));
- break;
+ if (endptr == str) {
+ /* no digits found */
+ return -EINVAL;
+ }
+
+ *(__u64 *)res = v;
+ return 0;
+}
+
+static int nvme_strtou32(const char *str, void *res)
+{
+ char *endptr;
+ __u32 v;
+
+ errno = 0;
+ v = strtol(str, &endptr, 0);
+
+ if (errno != 0)
+ return -errno;
+
+ if (endptr == str) {
+ /* no digits found */
+ return -EINVAL;
+ }
+
+ *(__u32 *)res = v;
+ return 0;
+}
+
+static int nvme_strtoi(const char *str, void *res)
+{
+ char *endptr;
+ int v;
+
+ errno = 0;
+ v = strtol(str, &endptr, 0);
+
+ if (errno != 0)
+ return -errno;
+
+ if (endptr == str) {
+ /* no digits found */
+ return -EINVAL;
+ }
+
+ *(int *)res = v;
+ return 0;
+}
+
+static int nvme_strtoeuid(const char *str, void *res)
+{
+ memcpy(res, str, 8);
+ return 0;
+}
+
+static int nvme_strtouuid(const char *str, void *res)
+{
+ memcpy(res, str, NVME_UUID_LEN);
+ return 0;
+}
+
+struct sysfs_attr_table {
+ void *var;
+ int (*parse)(const char *str, void *res);
+ bool mandatory;
+ const char *name;
+};
+
+#define GETSHIFT(x) (__builtin_ffsll(x) - 1)
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+
+static int parse_attrs(const char *path, struct sysfs_attr_table *tbl, int size)
+{
+ char *str;
+ int ret, i;
+
+ for (i = 0; i < size; i++) {
+ struct sysfs_attr_table *e = &tbl[i];
+
+ str = nvme_get_attr(path, e->name);
+ if (!str) {
+ if (!e->mandatory)
+ continue;
+ return -ENOENT;
}
+ ret = e->parse(str, e->var);
+ free(str);
+ if (ret)
+ return ret;
}
+
+ return 0;
}
-static int nvme_ns_init(struct nvme_ns *n)
+static int nvme_ns_init(const char *path, struct nvme_ns *ns)
{
- struct nvme_id_ns ns = { };
- uint8_t buffer[NVME_IDENTIFY_DATA_SIZE] = { };
- struct nvme_ns_id_desc *descs = (void *)buffer;
- uint8_t flbas;
+ _cleanup_free_ char *attr = NULL;
+ struct stat sb;
int ret;
- ret = nvme_ns_identify(n, &ns);
+ struct sysfs_attr_table base[] = {
+ { &ns->nsid, nvme_strtou32, true, "nsid" },
+ { &ns->lba_count, nvme_strtou64, true, "size" },
+ { &ns->lba_size, nvme_strtou64, true, "queue/physical_block_size" },
+ { ns->eui64, nvme_strtoeuid, false, "eui" },
+ { ns->nguid, nvme_strtouuid, false, "nguid" },
+ { ns->uuid, nvme_strtouuid, false, "uuid" }
+ };
+
+ ret = parse_attrs(path, base, ARRAY_SIZE(base));
if (ret)
return ret;
- nvme_id_ns_flbas_to_lbaf_inuse(ns.flbas, &flbas);
- n->lba_shift = ns.lbaf[flbas].ds;
- n->lba_size = 1 << n->lba_shift;
- n->lba_count = le64_to_cpu(ns.nsze);
- n->lba_util = le64_to_cpu(ns.nuse);
- n->meta_size = le16_to_cpu(ns.lbaf[flbas].ms);
+ ns->lba_shift = GETSHIFT(ns->lba_size);
+
+ if (asprintf(&attr, "%s/csi", path) < 0)
+ return -errno;
+ ret = stat(attr, &sb);
+ if (ret == 0) {
+ /* only available on kernels >= 6.8 */
+ struct sysfs_attr_table ext[] = {
+ { &ns->csi, nvme_strtoi, true, "csi" },
+ { &ns->lba_util, nvme_strtou64, true, "nuse" },
+ { &ns->meta_size, nvme_strtoi, true, "metadata_bytes"},
+
+ };
- if (!nvme_ns_identify_descs(n, descs))
- nvme_ns_parse_descriptors(n, descs);
+ ret = parse_attrs(path, ext, ARRAY_SIZE(ext));
+ if (ret)
+ return ret;
+ } else {
+ struct nvme_id_ns *id;
+ uint8_t flbas;
+
+ id = __nvme_alloc(sizeof(*ns));
+ if (!id)
+ return -ENOMEM;
+
+ ret = nvme_ns_identify(ns, id);
+ if (ret)
+ return ret;
+
+ nvme_id_ns_flbas_to_lbaf_inuse(id->flbas, &flbas);
+ ns->lba_count = le64_to_cpu(id->nsze);
+ ns->lba_util = le64_to_cpu(id->nuse);
+ ns->meta_size = le16_to_cpu(id->lbaf[flbas].ms);
+ }
return 0;
}
@@ -1956,7 +2498,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 *name)
+static nvme_ns_t nvme_ns_open(const char *sys_path, const char *name)
{
struct nvme_ns *n;
@@ -1966,26 +2508,20 @@ static nvme_ns_t nvme_ns_open(const char *name)
return NULL;
}
+ n->fd = -1;
n->name = strdup(name);
- n->fd = nvme_open(n->name);
- if (n->fd < 0)
- goto free_ns;
nvme_ns_set_generic_name(n, name);
- if (nvme_get_nsid(n->fd, &n->nsid) < 0)
- goto close_fd;
-
- if (nvme_ns_init(n) != 0)
- goto close_fd;
+ if (nvme_ns_init(sys_path, n) != 0)
+ goto free_ns;
list_head_init(&n->paths);
list_node_init(&n->entry);
+ nvme_ns_release_fd(n); /* Do not leak fds */
return n;
-close_fd:
- close(n->fd);
free_ns:
free(n->generic_name);
free(n->name);
@@ -2020,9 +2556,9 @@ static char *nvme_ns_generic_to_blkdev(const char *generic)
static struct nvme_ns *__nvme_scan_namespace(const char *sysfs_dir, const char *name)
{
struct nvme_ns *n;
- char *path;
+ _cleanup_free_ char *path = NULL;
int ret;
- char *blkdev;
+ _cleanup_free_ char *blkdev = NULL;
blkdev = nvme_ns_generic_to_blkdev(name);
if (!blkdev) {
@@ -2033,23 +2569,17 @@ static struct nvme_ns *__nvme_scan_namespace(const char *sysfs_dir, const char *
ret = asprintf(&path, "%s/%s", sysfs_dir, blkdev);
if (ret < 0) {
errno = ENOMEM;
- goto free_blkdev;
+ return NULL;
}
- n = nvme_ns_open(blkdev);
+ n = nvme_ns_open(path, blkdev);
if (!n)
- goto free_path;
+ return NULL;
n->sysfs_dir = path;
+ path = NULL;
- free(blkdev);
return n;
-
-free_path:
- free(path);
-free_blkdev:
- free(blkdev);
- return NULL;
}
nvme_ns_t nvme_scan_namespace(const char *name)
diff --git a/src/nvme/tree.h b/src/nvme/tree.h
index bcf3636..a30e8eb 100644
--- a/src/nvme/tree.h
+++ b/src/nvme/tree.h
@@ -15,6 +15,7 @@
#include <stddef.h>
#include <sys/types.h>
+#include <netinet/in.h>
#include "ioctl.h"
#include "util.h"
@@ -62,6 +63,17 @@ void nvme_root_set_application(nvme_root_t r, const char *a);
const char *nvme_root_get_application(nvme_root_t r);
/**
+ * nvme_root_release_fds - Close all opened file descriptors in the tree
+ * @r: &nvme_root_t object
+ *
+ * Controller and Namespace objects cache the file descriptors
+ * of opened nvme devices. This API can be used to close and
+ * clear all cached fds in the tree.
+ *
+ */
+void nvme_root_release_fds(nvme_root_t r);
+
+/**
* nvme_free_tree() - Free root object
* @r: &nvme_root_t object
*
@@ -295,6 +307,51 @@ nvme_ctrl_t nvme_lookup_ctrl(nvme_subsystem_t s, const char *transport,
const char *host_iface, const char *trsvcid,
nvme_ctrl_t p);
+/**
+ * nvme_ctrl_find() - Locate an existing controller
+ * @s: &nvme_subsystem_t object
+ * @transport: Transport name
+ * @traddr: Transport address
+ * @trsvcid: Transport service identifier
+ * @subsysnqn: Subsystem NQN
+ * @host_traddr: Host transport address
+ * @host_iface: Host interface name
+ *
+ * Lookup a controller in @s based on @transport, @traddr, @trsvcid,
+ * @subsysnqn, @host_traddr, and @host_iface. @transport must be specified,
+ * other fields may be required depending on the transport. Parameters set
+ * to NULL will be ignored.
+ *
+ * Unlike nvme_lookup_ctrl(), this function does not create a new object if
+ * an existing controller cannot be found.
+ *
+ * Return: Controller instance on success, NULL otherwise.
+ */
+nvme_ctrl_t nvme_ctrl_find(nvme_subsystem_t s, const char *transport,
+ const char *traddr, const char *trsvcid,
+ const char *subsysnqn, const char *host_traddr,
+ const char *host_iface);
+
+/**
+ * nvme_ctrl_config_match() - Check if ctrl @c matches config params
+ * @c: An existing controller instance
+ * @transport: Transport name
+ * @traddr: Transport address
+ * @trsvcid: Transport service identifier
+ * @subsysnqn: Subsystem NQN
+ * @host_traddr: Host transport address
+ * @host_iface: Host interface name
+ *
+ * Check that controller @c matches parameters: @transport, @traddr,
+ * @trsvcid, @subsysnqn, @host_traddr, and @host_iface. Parameters set
+ * to NULL will be ignored.
+ *
+ * Return: true if there's a match, false otherwise.
+ */
+bool nvme_ctrl_config_match(struct nvme_ctrl *c, const char *transport,
+ const char *traddr, const char *trsvcid,
+ const char *subsysnqn, const char *host_traddr,
+ const char *host_iface);
/**
* nvme_create_ctrl() - Allocate an unconnected NVMe controller
@@ -484,11 +541,25 @@ nvme_ns_t nvme_subsystem_next_ns(nvme_subsystem_t s, nvme_ns_t n);
* nvme_ns_get_fd() - Get associated file descriptor
* @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
+ * remain cached until the ns object is deleted or
+ * nvme_ns_release_fd() is called.
+ *
* Return: File descriptor associated with @n or -1
*/
int nvme_ns_get_fd(nvme_ns_t n);
/**
+ * nvme_ns_release_fd() - Close fd and clear fd from ns object
+ * @n: Namespace instance
+ *
+ */
+void nvme_ns_release_fd(nvme_ns_t n);
+
+/**
* nvme_ns_get_nsid() - NSID of a namespace
* @n: Namespace instance
*
@@ -772,11 +843,25 @@ nvme_ns_t nvme_path_get_ns(nvme_path_t p);
* nvme_ctrl_get_fd() - Get associated file descriptor
* @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.
+ *
* Return: File descriptor associated with @c or -1
*/
int nvme_ctrl_get_fd(nvme_ctrl_t c);
/**
+ * nvme_ctrl_release_fd() - Close fd and clear fd from controller object
+ * @c: Controller instance
+ *
+ */
+void nvme_ctrl_release_fd(nvme_ctrl_t c);
+
+/**
* nvme_ctrl_get_name() - sysfs name of a controller
* @c: Controller instance
*
@@ -802,6 +887,16 @@ const char *nvme_ctrl_get_sysfs_dir(nvme_ctrl_t c);
const char *nvme_ctrl_get_address(nvme_ctrl_t c);
/**
+ * nvme_ctrl_get_src_addr() - Extract src_addr from the c->address string
+ * @c: Controller instance
+ * @src_addr: Where to copy the src_addr. Size must be at least INET6_ADDRSTRLEN.
+ * @src_addr_len: Length of the buffer @src_addr.
+ *
+ * Return: Pointer to @src_addr on success. NULL on failure to extract the src_addr.
+ */
+char *nvme_ctrl_get_src_addr(nvme_ctrl_t c, char *src_addr, size_t src_addr_len);
+
+/**
* nvme_ctrl_get_phy_slot() - PCI physical slot number of a controller
* @c: Controller instance
*
@@ -827,7 +922,7 @@ const char *nvme_ctrl_get_firmware(nvme_ctrl_t c);
const char *nvme_ctrl_get_model(nvme_ctrl_t c);
/**
- * nvme_ctrl_get_state() - Running state of an controller
+ * nvme_ctrl_get_state() - Running state of a controller
* @c: Controller instance
*
* Return: String indicating the running state of @c
@@ -1148,6 +1243,14 @@ const char *nvme_subsystem_get_application(nvme_subsystem_t s);
void nvme_subsystem_set_application(nvme_subsystem_t s, const char *a);
/**
+ * nvme_subsystem_get_iopolicy() - Return the IO policy of subsytem
+ * @s: nvme_subsystem_t object
+ *
+ * Return: IO policy used by current subsystem
+ */
+const char *nvme_subsystem_get_iopolicy(nvme_subsystem_t s);
+
+/**
* nvme_scan_topology() - Scan NVMe topology and apply filter
* @r: nvme_root_t object
* @f: filter to apply
@@ -1177,6 +1280,16 @@ const char *nvme_host_get_hostnqn(nvme_host_t h);
const char *nvme_host_get_hostid(nvme_host_t h);
/**
+ * nvme_host_release_fds() - Close all opened file descriptors under host
+ * @h: nvme_host_t object
+ *
+ * Controller and Namespace objects cache the file descriptors
+ * of opened nvme devices. This API can be used to close and
+ * clear all cached fds under this host.
+ */
+void nvme_host_release_fds(struct nvme_host *h);
+
+/**
* nvme_free_host() - Free nvme_host_t object
* @h: nvme_host_t object
*/
@@ -1293,6 +1406,18 @@ nvme_ns_t nvme_subsystem_lookup_namespace(struct nvme_subsystem *s,
__u32 nsid);
/**
+ * nvme_subsystem_release_fds() - Close all opened fds under subsystem
+ * @s: nvme_subsystem_t object
+ *
+ * Controller and Namespace objects cache the file descriptors
+ * of opened nvme devices. This API can be used to close and
+ * clear all cached fds under this subsystem.
+ *
+ */
+void nvme_subsystem_release_fds(struct nvme_subsystem *s);
+
+
+/**
* nvme_get_path_attr() - Read path sysfs attribute
* @p: nvme_path_t object
* @attr: sysfs attribute name
diff --git a/src/nvme/types.h b/src/nvme/types.h
index 3bf2237..29ac050 100644
--- a/src/nvme/types.h
+++ b/src/nvme/types.h
@@ -43,7 +43,7 @@
* Returns: The 'name' field from 'value'
*/
#define NVME_SET(value, name) \
- (((value) & NVME_##name##_MASK) << NVME_##name##_SHIFT)
+ (((__u32)(value) & NVME_##name##_MASK) << NVME_##name##_SHIFT)
/**
* enum nvme_constants - A place to stash various constant nvme values
@@ -611,6 +611,19 @@ static const __u64 NVME_PMRMSC_CBA_MASK = 0xfffffffffffffull;
#define NVME_PMRMSC_CMSE(pmrmsc) NVME_GET(pmrmsc, PMRMSC_CMSE)
#define NVME_PMRMSC_CBA(pmrmsc) NVME_GET(pmrmsc, PMRMSC_CBA)
+enum nvme_flbas {
+ NVME_FLBAS_LOWER_SHIFT = 0,
+ NVME_FLBAS_META_EXT_SHIFT = 4,
+ NVME_FLBAS_HIGHER_SHIFT = 5,
+ NVME_FLBAS_LOWER_MASK = 0xf,
+ NVME_FLBAS_META_EXT_MASK = 0x1,
+ NVME_FLBAS_HIGHER_MASK = 0x3,
+};
+
+#define NVME_FLBAS_LOWER(flbas) NVME_GET(flbas, FLBAS_LOWER)
+#define NVME_FLBAS_META_EXT(flbas) NVME_GET(flbas, FLBAS_META_EXT)
+#define NVME_FLBAS_HIGHER(flbas) NVME_GET(flbas, FLBAS_HIGHER)
+
/**
* enum nvme_psd_flags - Possible flag values in nvme power state descriptor
* @NVME_PSD_FLAGS_MXPS: Indicates the scale for the Maximum Power
@@ -930,7 +943,10 @@ struct nvme_id_psd {
* @maxcna: Maximum I/O Controller Namespace Attachments indicates the
* maximum number of namespaces that are allowed to be attached to
* this I/O controller.
- * @rsvd564: Reserved
+ * @oaqd: Optimal Aggregated Queue Depth indicates the recommended maximum
+ * total number of outstanding I/O commands across all I/O queues
+ * on the controller for optimal operation.
+ * @rsvd568: Reserved
* @subnqn: NVM Subsystem NVMe Qualified Name, UTF-8 null terminated string
* @rsvd1024: Reserved
* @ioccsz: I/O Queue Command Capsule Supported Size, defines the maximum
@@ -1035,7 +1051,8 @@ struct nvme_id_ctrl {
__le32 mnan;
__u8 maxdna[16];
__le32 maxcna;
- __u8 rsvd564[204];
+ __le32 oaqd;
+ __u8 rsvd568[200];
char subnqn[NVME_NQN_LENGTH];
__u8 rsvd1024[768];
@@ -1489,6 +1506,14 @@ enum nvme_id_ctrl_cqes {
* the Verify command.
* @NVME_CTRL_ONCS_COPY: If set, then the controller supports
* the copy command.
+ * @NVME_CTRL_ONCS_COPY_SINGLE_ATOMICITY: If set, then the write portion of a
+ * Copy command is performed as a single
+ * write command to which the same
+ * atomicity requirements that apply to
+ * a write command apply.
+ * @NVME_CTRL_ONCS_ALL_FAST_COPY: If set, then all copy operations for
+ * the Copy command are fast copy
+ * operations.
*/
enum nvme_id_ctrl_oncs {
NVME_CTRL_ONCS_COMPARE = 1 << 0,
@@ -1500,6 +1525,8 @@ enum nvme_id_ctrl_oncs {
NVME_CTRL_ONCS_TIMESTAMP = 1 << 6,
NVME_CTRL_ONCS_VERIFY = 1 << 7,
NVME_CTRL_ONCS_COPY = 1 << 8,
+ NVME_CTRL_ONCS_COPY_SINGLE_ATOMICITY = 1 << 9,
+ NVME_CTRL_ONCS_ALL_FAST_COPY = 1 << 10,
};
/**
@@ -1772,7 +1799,6 @@ enum nvme_lbaf_rp {
* remains fixed throughout the life of the namespace and is
* preserved across namespace and controller operations
* @lbaf: LBA Format, see &struct nvme_lbaf.
- * @lbstm: Logical Block Storage Tag Mask for end-to-end protection
* @vs: Vendor Specific
*/
struct nvme_id_ns {
@@ -1816,8 +1842,7 @@ struct nvme_id_ns {
__u8 nguid[16];
__u8 eui64[8];
struct nvme_lbaf lbaf[64];
- __le64 lbstm;
- __u8 vs[3704];
+ __u8 vs[3712];
};
/**
@@ -3075,11 +3100,13 @@ struct nvme_telemetry_log {
/**
* struct nvme_endurance_group_log - Endurance Group Information Log
* @critical_warning: Critical Warning
- * @rsvd1: Reserved
+ * @endurance_group_features: Endurance Group Features
+ * @rsvd2: Reserved
* @avl_spare: Available Spare
* @avl_spare_threshold: Available Spare Threshold
* @percent_used: Percentage Used
- * @rsvd6: Reserved
+ * @domain_identifier: Domain Identifier
+ * @rsvd8: Reserved
* @endurance_estimate: Endurance Estimate
* @data_units_read: Data Units Read
* @data_units_written: Data Units Written
@@ -3088,15 +3115,19 @@ struct nvme_telemetry_log {
* @host_write_cmds: Host Write Commands
* @media_data_integrity_err: Media and Data Integrity Errors
* @num_err_info_log_entries: Number of Error Information Log Entries
- * @rsvd160: Reserved
+ * @total_end_grp_cap: Total Endurance Group Capacity
+ * @unalloc_end_grp_cap: Unallocated Endurance Group Capacity
+ * @rsvd192: Reserved
*/
struct nvme_endurance_group_log {
__u8 critical_warning;
- __u8 rsvd1[2];
+ __u8 endurance_group_features;
+ __u8 rsvd2;
__u8 avl_spare;
__u8 avl_spare_threshold;
__u8 percent_used;
- __u8 rsvd6[26];
+ __le16 domain_identifier;
+ __u8 rsvd8[24];
__u8 endurance_estimate[16];
__u8 data_units_read[16];
__u8 data_units_written[16];
@@ -3105,7 +3136,9 @@ struct nvme_endurance_group_log {
__u8 host_write_cmds[16];
__u8 media_data_integrity_err[16];
__u8 num_err_info_log_entries[16];
- __u8 rsvd160[352];
+ __u8 total_end_grp_cap[16];
+ __u8 unalloc_end_grp_cap[16];
+ __u8 rsvd192[320];
};
/**
@@ -3710,6 +3743,110 @@ struct nvme_boot_partition {
};
/**
+ * struct nvme_eom_lane_desc - EOM Lane Descriptor
+ * @rsvd0: Reserved
+ * @mstatus: Measurement Status
+ * @lane: Lane number
+ * @eye: Eye number
+ * @top: Absolute number of rows from center to top edge of eye
+ * @bottom: Absolute number of rows from center to bottom edge of eye
+ * @left: Absolute number of rows from center to left edge of eye
+ * @right: Absolute number of rows from center to right edge of eye
+ * @nrows: Number of Rows
+ * @ncols: Number of Columns
+ * @edlen: Eye Data Length
+ * @rsvd18: Reserved
+ * @eye_desc: Printable Eye, Eye Data, and any Padding
+ */
+struct nvme_eom_lane_desc {
+ __u8 rsvd0;
+ __u8 mstatus;
+ __u8 lane;
+ __u8 eye;
+ __le16 top;
+ __le16 bottom;
+ __le16 left;
+ __le16 right;
+ __le16 nrows;
+ __le16 ncols;
+ __le16 edlen;
+ __u8 rsvd18[14];
+ __u8 eye_desc[];
+};
+
+/**
+ * struct nvme_phy_rx_eom_log - Physical Interface Receiver Eye Opening Measurement Log
+ * @lid: Log Identifier
+ * @eomip: EOM In Progress
+ * @hsize: Header Size
+ * @rsize: Result Size
+ * @eomdgn: EOM Data Generation Number
+ * @lr: Log Revision
+ * @odp: Optional Data Present
+ * @lanes: Number of lanes configured for this port
+ * @epl: Eyes Per Lane
+ * @lspfc: Log Specific Parameter Field Copy
+ * @li: Link Information
+ * @rsvd15: Reserved
+ * @lsic: Log Specific Identifier Copy
+ * @dsize: Descriptor Size
+ * @nd: Number of Descriptors
+ * @maxtb: Maximum Top Bottom
+ * @maxlr: Maximum Left Right
+ * @etgood: Estimated Time for Good Quality
+ * @etbetter: Estimated Time for Better Quality
+ * @etbest: Estimated Time for Best Quality
+ * @rsvd36: Reserved
+ * @descs: EOM Lane Descriptors
+ */
+struct nvme_phy_rx_eom_log {
+ __u8 lid;
+ __u8 eomip;
+ __le16 hsize;
+ __le32 rsize;
+ __u8 eomdgn;
+ __u8 lr;
+ __u8 odp;
+ __u8 lanes;
+ __u8 epl;
+ __u8 lspfc;
+ __u8 li;
+ __u8 rsvd15[3];
+ __le16 lsic;
+ __le32 dsize;
+ __le16 nd;
+ __le16 maxtb;
+ __le16 maxlr;
+ __le16 etgood;
+ __le16 etbetter;
+ __le16 etbest;
+ __u8 rsvd36[28];
+ struct nvme_eom_lane_desc descs[];
+};
+
+/**
+ * enum nvme_eom_optional_data - EOM Optional Data Present Fields
+ * @NVME_EOM_EYE_DATA_PRESENT: Eye Data Present
+ * @NVME_EOM_PRINTABLE_EYE_PRESENT: Printable Eye Present
+ */
+enum nvme_eom_optional_data {
+ NVME_EOM_EYE_DATA_PRESENT = 1,
+ NVME_EOM_PRINTABLE_EYE_PRESENT = 1 << 1,
+};
+
+/**
+ * enum nvme_phy_rx_eom_progress - EOM In Progress Values
+ * @NVME_PHY_RX_EOM_NOT_STARTED: EOM Not Started
+ * @NVME_PHY_RX_EOM_IN_PROGRESS: EOM In Progress
+ * @NVME_PHY_RX_EOM_COMPLETED: EOM Completed
+ */
+enum nvme_phy_rx_eom_progress {
+ NVME_PHY_RX_EOM_NOT_STARTED = 0,
+ NVME_PHY_RX_EOM_IN_PROGRESS = 1,
+ NVME_PHY_RX_EOM_COMPLETED = 2,
+};
+
+/**
* struct nvme_media_unit_stat_desc - Media Unit Status Descriptor
* @muid: Media Unit Identifier
* @domainid: Domain Identifier
@@ -4604,11 +4741,19 @@ struct nvme_plm_config {
/**
* struct nvme_feat_host_behavior - Host Behavior Support - Data Structure
* @acre: Advanced Command Retry Enable
- * @rsvd1: Reserved
+ * @etdas: Extended Telemetry Data Area 4 Supported
+ * @lbafee: LBA Format Extension Enable
+ * @rsvd3: Reserved
+ * @cdfe: Copy Descriptor Formats Enable
+ * @rsvd6: Reserved
*/
struct nvme_feat_host_behavior {
__u8 acre;
- __u8 rsvd1[511];
+ __u8 etdas;
+ __u8 lbafee;
+ __u8 rsvd3;
+ __u16 cdfe;
+ __u8 rsvd6[506];
};
/**
@@ -4674,6 +4819,66 @@ struct nvme_copy_range_f1 {
};
/**
+ * enum nvme_copy_range_sopt - NVMe Copy Range Source Options
+ * @NVME_COPY_SOPT_FCO: NVMe Copy Source Option Fast Copy Only
+ */
+enum nvme_copy_range_sopt {
+ NVME_COPY_SOPT_FCO = 1 << 15,
+};
+
+/**
+ * struct nvme_copy_range_f2 - Copy - Source Range Entries Descriptor Format 2h
+ * @snsid: Source Namespace Identifier
+ * @rsvd4: Reserved
+ * @slba: Starting LBA
+ * @nlb: Number of Logical Blocks
+ * @rsvd18: Reserved
+ * @sopt: Source Options
+ * @eilbrt: Expected Initial Logical Block Reference Tag /
+ * Expected Logical Block Storage Tag
+ * @elbatm: Expected Logical Block Application Tag Mask
+ * @elbat: Expected Logical Block Application Tag
+ */
+struct nvme_copy_range_f2 {
+ __le32 snsid;
+ __u8 rsvd4[4];
+ __le64 slba;
+ __le16 nlb;
+ __u8 rsvd18[4];
+ __le16 sopt;
+ __le32 eilbrt;
+ __le16 elbat;
+ __le16 elbatm;
+};
+
+/**
+ * struct nvme_copy_range_f3 - Copy - Source Range Entries Descriptor Format 3h
+ * @snsid: Source Namespace Identifier
+ * @rsvd4: Reserved
+ * @slba: Starting LBA
+ * @nlb: Number of Logical Blocks
+ * @rsvd18: Reserved
+ * @sopt: Source Options
+ * @rsvd24: Reserved
+ * @elbt: Expected Initial Logical Block Reference Tag /
+ * Expected Logical Block Storage Tag
+ * @elbatm: Expected Logical Block Application Tag Mask
+ * @elbat: Expected Logical Block Application Tag
+ */
+struct nvme_copy_range_f3 {
+ __le32 snsid;
+ __u8 rsvd4[4];
+ __le64 slba;
+ __le16 nlb;
+ __u8 rsvd18[4];
+ __le16 sopt;
+ __u8 rsvd24[2];
+ __u8 elbt[10];
+ __le16 elbat;
+ __le16 elbatm;
+};
+
+/**
* struct nvme_registered_ctrl - Registered Controller Data Structure
* @cntlid: Controller ID
* @rcsts: Reservation Status
@@ -6125,6 +6330,21 @@ struct nvme_mi_vpd_hdr {
* @NVME_SC_INVALID_PI: Invalid Protection Information
* @NVME_SC_READ_ONLY: Attempted Write to Read Only Range
* @NVME_SC_CMD_SIZE_LIMIT_EXCEEDED: Command Size Limit Exceeded
+ * @NVME_SC_INCOMPATIBLE_NS: Incompatible Namespace or Format: At
+ * least one source namespace and the
+ * destination namespace have incompatible
+ * formats.
+ * @NVME_SC_FAST_COPY_NOT_POSSIBLE: Fast Copy Not Possible: The Fast Copy
+ * Only (FCO) bit was set to ‘1’ in a Source
+ * Range entry and the controller was not
+ * able to use fast copy operations to copy
+ * the specified data.
+ * @NVME_SC_OVERLAPPING_IO_RANGE: Overlapping I/O Range: A source logical
+ * block range overlaps the destination
+ * logical block range.
+ * @NVME_SC_INSUFFICIENT_RESOURCES: Insufficient Resources: A resource
+ * shortage prevented the controller from
+ * performing the requested copy.
* @NVME_SC_CONNECT_FORMAT: Incompatible Format: The NVM subsystem
* does not support the record format
* specified by the host.
@@ -6370,6 +6590,10 @@ enum nvme_status_field {
NVME_SC_INVALID_PI = 0x81,
NVME_SC_READ_ONLY = 0x82,
NVME_SC_CMD_SIZE_LIMIT_EXCEEDED = 0x83,
+ NVME_SC_INCOMPATIBLE_NS = 0x85,
+ NVME_SC_FAST_COPY_NOT_POSSIBLE = 0x86,
+ NVME_SC_OVERLAPPING_IO_RANGE = 0x87,
+ NVME_SC_INSUFFICIENT_RESOURCES = 0x89,
/*
* I/O Command Set Specific - Fabrics commands:
@@ -6501,7 +6725,7 @@ static inline __u32 nvme_status_get_type(int status)
*/
static inline __u32 nvme_status_get_value(int status)
{
- return status & ~(NVME_STATUS_TYPE_MASK << NVME_STATUS_TYPE_SHIFT);
+ return status & ~NVME_SET(NVME_STATUS_TYPE_MASK, STATUS_TYPE);
}
/**
@@ -6688,6 +6912,7 @@ enum nvme_identify_cns {
* @NVME_LOG_LID_FID_SUPPORTED_EFFECTS: Feature Identifiers Supported and Effects
* @NVME_LOG_LID_MI_CMD_SUPPORTED_EFFECTS: NVMe-MI Commands Supported and Effects
* @NVME_LOG_LID_BOOT_PARTITION: Boot Partition
+ * @NVME_LOG_LID_PHY_RX_EOM: Physical Interface Receiver Eye Opening Measurement
* @NVME_LOG_LID_FDP_CONFIGS: FDP Configurations
* @NVME_LOG_LID_FDP_RUH_USAGE: Reclaim Unit Handle Usage
* @NVME_LOG_LID_FDP_STATS: FDP Statistics
@@ -6719,6 +6944,7 @@ enum nvme_cmd_get_log_lid {
NVME_LOG_LID_FID_SUPPORTED_EFFECTS = 0x12,
NVME_LOG_LID_MI_CMD_SUPPORTED_EFFECTS = 0x13,
NVME_LOG_LID_BOOT_PARTITION = 0x15,
+ NVME_LOG_LID_PHY_RX_EOM = 0x19,
NVME_LOG_LID_FDP_CONFIGS = 0x20,
NVME_LOG_LID_FDP_RUH_USAGE = 0x21,
NVME_LOG_LID_FDP_STATS = 0x22,
@@ -7012,7 +7238,7 @@ enum nvme_feat {
NVME_FEAT_WP_WPS_SHIFT = 0,
NVME_FEAT_WP_WPS_MASK = 0x7,
NVME_FEAT_IOCSP_IOCSCI_SHIFT = 0,
- NVME_FEAT_IOCSP_IOCSCI_MASK = 0xff,
+ NVME_FEAT_IOCSP_IOCSCI_MASK = 0x1ff,
NVME_FEAT_FDP_ENABLED_SHIFT = 0,
NVME_FEAT_FDP_ENABLED_MASK = 0x1,
NVME_FEAT_FDP_INDEX_SHIFT = 8,
@@ -7273,6 +7499,30 @@ enum nvme_log_ana_lsp {
};
/**
+ * enum nvme_log_phy_rx_eom_action - Physical Interface Receiver Eye Opening Measurement Action
+ * @NVME_LOG_PHY_RX_EOM_READ: Read Log Data
+ * @NVME_LOG_PHY_RX_EOM_START_READ: Start Measurement and Read Log Data
+ * @NVME_LOG_PHY_RX_EOM_ABORT_CLEAR: Abort Measurement and Clear Log Data
+ */
+enum nvme_log_phy_rx_eom_action {
+ NVME_LOG_PHY_RX_EOM_READ = 0,
+ NVME_LOG_PHY_RX_EOM_START_READ = 1,
+ NVME_LOG_PHY_RX_EOM_ABORT_CLEAR = 2,
+};
+
+/**
+ * enum nvme_log_phy_rx_eom_quality - Physical Interface Receiver Eye Opening Measurement Quality
+ * @NVME_LOG_PHY_RX_EOM_GOOD: <= Better Quality
+ * @NVME_LOG_PHY_RX_EOM_BETTER: <= Best Quality, >= Good Quality
+ * @NVME_LOG_PHY_RX_EOM_BEST: >= Better Quality
+ */
+enum nvme_log_phy_rx_eom_quality {
+ NVME_LOG_PHY_RX_EOM_GOOD = 0,
+ NVME_LOG_PHY_RX_EOM_BETTER = 1,
+ NVME_LOG_PHY_RX_EOM_BEST = 2,
+};
+
+/**
* enum nvme_pevent_log_action - Persistent Event Log - Action
* @NVME_PEVENT_LOG_READ: Read Log Data
* @NVME_PEVENT_LOG_EST_CTX_AND_READ: Establish Context and Read Log Data
diff --git a/src/nvme/util.c b/src/nvme/util.c
index 143cc31..45512ff 100644
--- a/src/nvme/util.c
+++ b/src/nvme/util.c
@@ -7,6 +7,7 @@
* Chaitanya Kulkarni <chaitanya.kulkarni@wdc.com>
*/
+#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
@@ -22,6 +23,7 @@
#include <ccan/endian/endian.h>
+#include "cleanup.h"
#include "private.h"
#include "util.h"
#include "log.h"
@@ -290,6 +292,10 @@ static const char * const nvm_status[] = {
[NVME_SC_INVALID_PI] = "Invalid Protection Information: The command's Protection Information Field settings are invalid for the namespace's Protection Information format",
[NVME_SC_READ_ONLY] = "Attempted Write to Read Only Range: The LBA range specified contains read-only blocks",
[NVME_SC_CMD_SIZE_LIMIT_EXCEEDED] = "Command Size Limit Exceeded",
+ [NVME_SC_INCOMPATIBLE_NS] = "Incompatible Namespace or Format",
+ [NVME_SC_FAST_COPY_NOT_POSSIBLE] = "Fast Copy Not Possible",
+ [NVME_SC_OVERLAPPING_IO_RANGE] = "Overlapping I/O Range",
+ [NVME_SC_INSUFFICIENT_RESOURCES] = "Insufficient Resources",
[NVME_SC_ZNS_INVALID_OP_REQUEST] = "Invalid Zone Operation Request: The operation requested is invalid",
[NVME_SC_ZNS_ZRWA_RESOURCES_UNAVAILABLE] = "ZRWA Resources Unavailable: No ZRWAs are available",
[NVME_SC_ZNS_BOUNDARY_ERROR] = "Zoned Boundary Error: Invalid Zone Boundary crossing",
@@ -385,6 +391,16 @@ const char *nvme_status_to_string(int status, bool fabrics)
return s;
}
+static inline void nvme_init_copy_range_elbt(__u8 *elbt, __u64 eilbrt)
+{
+ int i;
+
+ for (i = 0; i < 8; i++)
+ elbt[9 - i] = (eilbrt >> (8 * i)) & 0xff;
+ elbt[1] = 0;
+ elbt[0] = 0;
+}
+
void nvme_init_copy_range(struct nvme_copy_range *copy, __u16 *nlbs,
__u64 *slbas, __u32 *eilbrts, __u32 *elbatms,
__u32 *elbats, __u16 nr)
@@ -404,18 +420,51 @@ void nvme_init_copy_range_f1(struct nvme_copy_range_f1 *copy, __u16 *nlbs,
__u64 *slbas, __u64 *eilbrts, __u32 *elbatms,
__u32 *elbats, __u16 nr)
{
- int i, j;
+ int i;
+
+ for (i = 0; i < nr; i++) {
+ copy[i].nlb = cpu_to_le16(nlbs[i]);
+ copy[i].slba = cpu_to_le64(slbas[i]);
+ copy[i].elbatm = cpu_to_le16(elbatms[i]);
+ copy[i].elbat = cpu_to_le16(elbats[i]);
+ nvme_init_copy_range_elbt(copy[i].elbt, eilbrts[i]);
+ }
+}
+
+void nvme_init_copy_range_f2(struct nvme_copy_range_f2 *copy, __u32 *snsids,
+ __u16 *nlbs, __u64 *slbas, __u16 *sopts,
+ __u32 *eilbrts, __u32 *elbatms, __u32 *elbats,
+ __u16 nr)
+{
+ int i;
for (i = 0; i < nr; i++) {
+ copy[i].snsid = cpu_to_le32(snsids[i]);
copy[i].nlb = cpu_to_le16(nlbs[i]);
copy[i].slba = cpu_to_le64(slbas[i]);
+ copy[i].sopt = cpu_to_le16(sopts[i]);
+ copy[i].eilbrt = cpu_to_le32(eilbrts[i]);
copy[i].elbatm = cpu_to_le16(elbatms[i]);
copy[i].elbat = cpu_to_le16(elbats[i]);
- for (j = 0; j < 8; j++)
- copy[i].elbt[9 - j] = (eilbrts[i] >> (8 * j)) & 0xff;
- copy[i].elbt[1] = 0;
- copy[i].elbt[0] = 0;
- }
+ }
+}
+
+void nvme_init_copy_range_f3(struct nvme_copy_range_f3 *copy, __u32 *snsids,
+ __u16 *nlbs, __u64 *slbas, __u16 *sopts,
+ __u64 *eilbrts, __u32 *elbatms, __u32 *elbats,
+ __u16 nr)
+{
+ int i;
+
+ for (i = 0; i < nr; i++) {
+ copy[i].snsid = cpu_to_le32(snsids[i]);
+ copy[i].nlb = cpu_to_le16(nlbs[i]);
+ copy[i].slba = cpu_to_le64(slbas[i]);
+ copy[i].sopt = cpu_to_le16(sopts[i]);
+ copy[i].elbatm = cpu_to_le16(elbatms[i]);
+ copy[i].elbat = cpu_to_le16(elbats[i]);
+ nvme_init_copy_range_elbt(copy[i].elbt, eilbrts[i]);
+ }
}
void nvme_init_dsm_range(struct nvme_dsm_range *dsm, __u32 *ctx_attrs,
@@ -708,7 +757,7 @@ char *kv_keymatch(const char *kv, const char *key)
static size_t read_file(const char * fname, char *buffer, size_t *bufsz)
{
char *p;
- FILE *file;
+ _cleanup_file_ FILE *file;
size_t len;
file = fopen(fname, "re");
@@ -716,7 +765,6 @@ static size_t read_file(const char * fname, char *buffer, size_t *bufsz)
return 0;
p = fgets(buffer, *bufsz, file);
- fclose(file);
if (!p)
return 0;
@@ -758,7 +806,7 @@ size_t get_entity_name(char *buffer, size_t bufsz)
size_t get_entity_version(char *buffer, size_t bufsz)
{
- FILE *file;
+ _cleanup_file_ FILE *file;
size_t num_bytes = 0;
/* /proc/sys/kernel/ostype typically contains the string "Linux" */
@@ -808,7 +856,6 @@ size_t get_entity_version(char *buffer, size_t bufsz)
if (s)
ver_id_len = copy_value(ver_id, sizeof(ver_id), s);
}
- fclose(file);
if (name_len) {
/* Append a space */
@@ -881,14 +928,13 @@ int nvme_uuid_from_string(const char *str, unsigned char uuid[NVME_UUID_LEN])
int nvme_uuid_random(unsigned char uuid[NVME_UUID_LEN])
{
- int f;
+ _cleanup_fd_ int f;
ssize_t n;
f = open("/dev/urandom", O_RDONLY);
if (f < 0)
return -errno;
n = read(f, uuid, NVME_UUID_LEN);
- close(f);
if (n < 0)
return -errno;
else if (n != NVME_UUID_LEN)
@@ -906,6 +952,46 @@ int nvme_uuid_random(unsigned char uuid[NVME_UUID_LEN])
}
#ifdef HAVE_NETDB
+static bool _nvme_ipaddrs_eq(struct sockaddr *addr1, struct sockaddr *addr2)
+{
+ struct sockaddr_in *sockaddr_v4;
+ struct sockaddr_in6 *sockaddr_v6;
+
+ if (addr1->sa_family == AF_INET && addr2->sa_family == AF_INET) {
+ struct sockaddr_in *sockaddr1 = (struct sockaddr_in *)addr1;
+ struct sockaddr_in *sockaddr2 = (struct sockaddr_in *)addr2;
+ return sockaddr1->sin_addr.s_addr == sockaddr2->sin_addr.s_addr;
+ }
+
+ if (addr1->sa_family == AF_INET6 && addr2->sa_family == AF_INET6) {
+ struct sockaddr_in6 *sockaddr1 = (struct sockaddr_in6 *)addr1;
+ struct sockaddr_in6 *sockaddr2 = (struct sockaddr_in6 *)addr2;
+ return !memcmp(&sockaddr1->sin6_addr, &sockaddr2->sin6_addr, sizeof(struct in6_addr));
+ }
+
+ switch (addr1->sa_family) {
+ case AF_INET:
+ sockaddr_v6 = (struct sockaddr_in6 *)addr2;
+ if (IN6_IS_ADDR_V4MAPPED(&sockaddr_v6->sin6_addr)) {
+ sockaddr_v4 = (struct sockaddr_in *)addr1;
+ return sockaddr_v4->sin_addr.s_addr == sockaddr_v6->sin6_addr.s6_addr32[3];
+ }
+ break;
+
+ case AF_INET6:
+ sockaddr_v6 = (struct sockaddr_in6 *)addr1;
+ if (IN6_IS_ADDR_V4MAPPED(&sockaddr_v6->sin6_addr)) {
+ sockaddr_v4 = (struct sockaddr_in *)addr2;
+ return sockaddr_v4->sin_addr.s_addr == sockaddr_v6->sin6_addr.s6_addr32[3];
+ }
+ break;
+
+ default: ;
+ }
+
+ return false;
+}
+
bool nvme_ipaddrs_eq(const char *addr1, const char *addr2)
{
bool result = false;
@@ -924,37 +1010,7 @@ bool nvme_ipaddrs_eq(const char *addr1, const char *addr2)
if (getaddrinfo(addr2, 0, &hint2, &info2) || !info2)
goto ipaddrs_eq_fail;
- if (info1->ai_family == AF_INET && info2->ai_family == AF_INET) {
- struct sockaddr_in *sockaddr1 = (struct sockaddr_in *)(info1->ai_addr);
- struct sockaddr_in *sockaddr2 = (struct sockaddr_in *)(info2->ai_addr);
- result = sockaddr1->sin_addr.s_addr == sockaddr2->sin_addr.s_addr;
- } else if (info1->ai_family == AF_INET6 && info2->ai_family == AF_INET6) {
- struct sockaddr_in6 *sockaddr1 = (struct sockaddr_in6 *)(info1->ai_addr);
- struct sockaddr_in6 *sockaddr2 = (struct sockaddr_in6 *)(info2->ai_addr);
- result = !memcmp(&sockaddr1->sin6_addr, &sockaddr2->sin6_addr, sizeof(struct in6_addr));
- } else {
- struct sockaddr_in *sockaddr_v4;
- struct sockaddr_in6 *sockaddr_v6;
- switch (info1->ai_family) {
- case AF_INET:
- sockaddr_v6 = (struct sockaddr_in6 *)(info2->ai_addr);
- if (IN6_IS_ADDR_V4MAPPED(&sockaddr_v6->sin6_addr)) {
- sockaddr_v4 = (struct sockaddr_in *)(info1->ai_addr);
- result = sockaddr_v4->sin_addr.s_addr == sockaddr_v6->sin6_addr.s6_addr32[3];
- }
- break;
-
- case AF_INET6:
- sockaddr_v6 = (struct sockaddr_in6 *)(info1->ai_addr);
- if (IN6_IS_ADDR_V4MAPPED(&sockaddr_v6->sin6_addr)) {
- sockaddr_v4 = (struct sockaddr_in *)(info2->ai_addr);
- result = sockaddr_v4->sin_addr.s_addr == sockaddr_v6->sin6_addr.s6_addr32[3];
- }
- break;
-
- default: ;
- }
- }
+ result = _nvme_ipaddrs_eq(info1->ai_addr, info2->ai_addr);
ipaddrs_eq_fail:
if (info1)
@@ -972,3 +1028,91 @@ bool nvme_ipaddrs_eq(const char *addr1, const char *addr2)
return false;
}
#endif /* HAVE_NETDB */
+
+#ifdef HAVE_NETDB
+const char *nvme_iface_matching_addr(const struct ifaddrs *iface_list, const char *addr)
+{
+ const struct ifaddrs *iface_it;
+ struct addrinfo *info = NULL, hint = { .ai_flags = AI_NUMERICHOST, .ai_family = AF_UNSPEC };
+ const char *iface_name = NULL;
+
+ if (!iface_list || !addr || getaddrinfo(addr, 0, &hint, &info) || !info)
+ return NULL;
+
+ /* Walk through the linked list */
+ for (iface_it = iface_list; iface_it != NULL; iface_it = iface_it->ifa_next) {
+ struct sockaddr *ifaddr = iface_it->ifa_addr;
+
+ if (ifaddr && (ifaddr->sa_family == AF_INET || ifaddr->sa_family == AF_INET6) &&
+ _nvme_ipaddrs_eq(info->ai_addr, ifaddr)) {
+ iface_name = iface_it->ifa_name;
+ break;
+ }
+ }
+
+ freeaddrinfo(info);
+
+ return iface_name;
+}
+
+bool nvme_iface_primary_addr_matches(const struct ifaddrs *iface_list, const char *iface, const char *addr)
+{
+ const struct ifaddrs *iface_it;
+ struct addrinfo *info = NULL, hint = { .ai_flags = AI_NUMERICHOST, .ai_family = AF_UNSPEC };
+ bool match_found = false;
+
+ if (!iface_list || !addr || getaddrinfo(addr, 0, &hint, &info) || !info)
+ return false;
+
+ /* Walk through the linked list */
+ for (iface_it = iface_list; iface_it != NULL; iface_it = iface_it->ifa_next) {
+ if (strcmp(iface, iface_it->ifa_name))
+ continue; /* Not the interface we're looking for*/
+
+ /* The interface list is ordered in a way that the primary
+ * address is listed first. As soon as the parsed address
+ * matches the family of the address we're looking for, we
+ * have found the primary address for that family.
+ */
+ if (iface_it->ifa_addr && (iface_it->ifa_addr->sa_family == info->ai_addr->sa_family)) {
+ match_found = _nvme_ipaddrs_eq(info->ai_addr, iface_it->ifa_addr);
+ break;
+ }
+ }
+
+ freeaddrinfo(info);
+
+ return match_found;
+}
+
+#else /* HAVE_NETDB */
+
+const char *nvme_iface_matching_addr(const struct ifaddrs *iface_list, const char *addr)
+{
+ nvme_msg(NULL, LOG_ERR, "no support for interface lookup; "
+ "recompile with libnss support.\n");
+
+ return NULL;
+}
+
+bool nvme_iface_primary_addr_matches(const struct ifaddrs *iface_list, const char *iface, const char *addr)
+{
+ nvme_msg(NULL, LOG_ERR, "no support for interface lookup; "
+ "recompile with libnss support.\n");
+
+ return false;
+}
+
+#endif /* HAVE_NETDB */
+
+void *__nvme_alloc(size_t len)
+{
+ size_t _len = round_up(len, 0x1000);
+ void *p;
+
+ if (posix_memalign((void *)&p, getpagesize(), _len))
+ return NULL;
+
+ memset(p, 0, _len);
+ return p;
+}
diff --git a/src/nvme/util.h b/src/nvme/util.h
index 9d6faf3..16d5b9c 100644
--- a/src/nvme/util.h
+++ b/src/nvme/util.h
@@ -9,6 +9,8 @@
#ifndef _LIBNVME_UTIL_H
#define _LIBNVME_UTIL_H
+#include <ifaddrs.h>
+
#include "types.h"
/**
@@ -149,6 +151,40 @@ void nvme_init_copy_range_f1(struct nvme_copy_range_f1 *copy, __u16 *nlbs,
__u32 *elbats, __u16 nr);
/**
+ * nvme_init_copy_range_f2() - Constructs a copy range f2 structure
+ * @copy: Copy range array
+ * @snsids: Source namespace identifier
+ * @nlbs: Number of logical blocks
+ * @slbas: Starting LBA
+ * @sopts: Source options
+ * @eilbrts: Expected initial logical block reference tag
+ * @elbatms: Expected logical block application tag mask
+ * @elbats: Expected logical block application tag
+ * @nr: Number of descriptors to construct
+ */
+void nvme_init_copy_range_f2(struct nvme_copy_range_f2 *copy, __u32 *snsids,
+ __u16 *nlbs, __u64 *slbas, __u16 *sopts,
+ __u32 *eilbrts, __u32 *elbatms, __u32 *elbats,
+ __u16 nr);
+
+/**
+ * nvme_init_copy_range_f3() - Constructs a copy range f3 structure
+ * @copy: Copy range array
+ * @snsids: Source namespace identifier
+ * @nlbs: Number of logical blocks
+ * @slbas: Starting LBA
+ * @sopts: Source options
+ * @eilbrts: Expected initial logical block reference tag
+ * @elbatms: Expected logical block application tag mask
+ * @elbats: Expected logical block application tag
+ * @nr: Number of descriptors to construct
+ */
+void nvme_init_copy_range_f3(struct nvme_copy_range_f3 *copy, __u32 *snsids,
+ __u16 *nlbs, __u64 *slbas, __u16 *sopts,
+ __u64 *eilbrts, __u32 *elbatms, __u32 *elbats,
+ __u16 nr);
+
+/**
* nvme_get_feature_length() - Retreive the command payload length for a
* specific feature identifier
* @fid: Feature identifier, see &enum nvme_features_id.
@@ -447,8 +483,8 @@ static inline void nvme_feature_decode_namespace_write_protect(__u32 value,
static inline void nvme_id_ns_flbas_to_lbaf_inuse(__u8 flbas, __u8 *lbaf_inuse)
{
- *lbaf_inuse = (((flbas & NVME_NS_FLBAS_HIGHER_MASK) >> 1) |
- (flbas & NVME_NS_FLBAS_LOWER_MASK));
+ *lbaf_inuse = ((NVME_FLBAS_HIGHER(flbas) >> 1) |
+ NVME_FLBAS_LOWER(flbas));
}
struct nvme_root;
@@ -639,4 +675,31 @@ int nvme_uuid_random(unsigned char uuid[NVME_UUID_LEN]);
*/
bool nvme_ipaddrs_eq(const char *addr1, const char *addr2);
+/**
+ * nvme_iface_matching_addr - Get interface matching @addr
+ * @iface_list: Interface list returned by getifaddrs()
+ * @addr: Address to match
+ *
+ * Parse the interface list pointed to by @iface_list looking
+ * for the interface that has @addr as one of its assigned
+ * addresses.
+ *
+ * Return: The name of the interface that owns @addr or NULL.
+ */
+const char *nvme_iface_matching_addr(const struct ifaddrs *iface_list, const char *addr);
+
+/**
+ * nvme_iface_primary_addr_matches - Check that interface's primary address matches
+ * @iface_list: Interface list returned by getifaddrs()
+ * @iface: Interface to match
+ * @addr: Address to match
+ *
+ * Parse the interface list pointed to by @iface_list and looking for
+ * interface @iface. The get its primary address and check if it matches
+ * @addr.
+ *
+ * Return: true if a match is found, false otherwise.
+ */
+bool nvme_iface_primary_addr_matches(const struct ifaddrs *iface_list, const char *iface, const char *addr);
+
#endif /* _LIBNVME_UTIL_H */
diff --git a/subprojects/json-c.wrap b/subprojects/json-c.wrap
index ce9ff51..569f78e 100644
--- a/subprojects/json-c.wrap
+++ b/subprojects/json-c.wrap
@@ -1,12 +1,13 @@
[wrap-file]
-directory = json-c-0.16
-source_url = https://s3.amazonaws.com/json-c_releases/releases/json-c-0.16.tar.gz
-source_filename = json-c-0.16.tar.gz
-source_hash = 8e45ac8f96ec7791eaf3bb7ee50e9c2100bbbc87b8d0f1d030c5ba8a0288d96b
-patch_filename = json-c_0.16-3_patch.zip
-patch_url = https://wrapdb.mesonbuild.com/v2/json-c_0.16-3/get_patch
-patch_hash = 6e712826ba1e6e1b6d21c6157a764984fedc6b594c9f92443498b972b6377a94
-wrapdb_version = 0.16-3
+directory = json-c-0.17
+source_url = https://s3.amazonaws.com/json-c_releases/releases/json-c-0.17.tar.gz
+source_filename = json-c-0.17.tar.gz
+source_hash = 7550914d58fb63b2c3546f3ccfbe11f1c094147bd31a69dcd23714d7956159e6
+patch_filename = json-c_0.17-2_patch.zip
+patch_url = https://wrapdb.mesonbuild.com/v2/json-c_0.17-2/get_patch
+patch_hash = c1a9a7e2ea6bed89a59e13a5684be25899a5a510963154c4450c5a492b8f3984
+source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/json-c_0.17-2/json-c-0.17.tar.gz
+wrapdb_version = 0.17-2
[provide]
json-c = json_c_dep
diff --git a/subprojects/openssl.wrap b/subprojects/openssl.wrap
index 1354406..b69462f 100644
--- a/subprojects/openssl.wrap
+++ b/subprojects/openssl.wrap
@@ -1,13 +1,13 @@
[wrap-file]
-directory = openssl-3.0.7
-source_url = https://www.openssl.org/source/openssl-3.0.7.tar.gz
-source_filename = openssl-3.0.7.tar.gz
-source_hash = 83049d042a260e696f62406ac5c08bf706fd84383f945cf21bd61e9ed95c396e
-patch_filename = openssl_3.0.7-2_patch.zip
-patch_url = https://wrapdb.mesonbuild.com/v2/openssl_3.0.7-2/get_patch
-patch_hash = dcc5d21bb602a5ca43bbaf14de858955f748b2abb2c0102ba193bd3964ac13a4
-source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/openssl_3.0.7-2/openssl-3.0.7.tar.gz
-wrapdb_version = 3.0.7-2
+directory = openssl-3.0.8
+source_url = https://www.openssl.org/source/openssl-3.0.8.tar.gz
+source_filename = openssl-3.0.8.tar.gz
+source_hash = 6c13d2bf38fdf31eac3ce2a347073673f5d63263398f1f69d0df4a41253e4b3e
+patch_filename = openssl_3.0.8-2_patch.zip
+patch_url = https://wrapdb.mesonbuild.com/v2/openssl_3.0.8-2/get_patch
+patch_hash = e84b5fe469e681e3318184157a0c7c43d4cbacd078bb88f506e31569f8f75072
+source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/openssl_3.0.8-2/openssl-3.0.8.tar.gz
+wrapdb_version = 3.0.8-2
[provide]
libcrypto = libcrypto_dep
diff --git a/test/ioctl/discovery.c b/test/ioctl/discovery.c
new file mode 100644
index 0000000..f5f6f51
--- /dev/null
+++ b/test/ioctl/discovery.c
@@ -0,0 +1,428 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+
+#include <libnvme.h>
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ccan/array_size/array_size.h>
+#include <ccan/endian/endian.h>
+
+#include "../../src/nvme/private.h"
+#include "mock.h"
+#include "util.h"
+
+#define TEST_FD 0xFD
+#define HEADER_LEN 20
+
+static void arbitrary_ascii_string(size_t max_len, char *str, char *log_str)
+{
+ size_t len;
+ size_t i;
+
+ len = arbitrary_range(max_len + 1);
+ for (i = 0; i < len; i++) {
+ /*
+ * ASCII strings shall contain only code values 20h through 7Eh.
+ * Exclude 20h (space) because it ends the string.
+ */
+ str[i] = log_str[i] = arbitrary_range(0x7E - 0x20) + 0x20 + 1;
+ }
+ for (i = len; i < max_len; i++) {
+ str[i] = '\0';
+ log_str[i] = ' ';
+ }
+}
+
+static void arbitrary_entry(struct nvmf_disc_log_entry *entry,
+ struct nvmf_disc_log_entry *log_entry)
+{
+ arbitrary(entry, sizeof(*entry));
+ memcpy(log_entry, entry, sizeof(*entry));
+ arbitrary_ascii_string(
+ sizeof(entry->trsvcid), entry->trsvcid, log_entry->trsvcid);
+ arbitrary_ascii_string(
+ sizeof(entry->traddr), entry->traddr, log_entry->traddr);
+}
+
+static void arbitrary_entries(size_t len,
+ struct nvmf_disc_log_entry *entries,
+ struct nvmf_disc_log_entry *log_entries)
+{
+ size_t i;
+
+ for (i = 0; i < len; i++)
+ arbitrary_entry(&entries[i], &log_entries[i]);
+}
+
+static void test_no_entries(nvme_ctrl_t c)
+{
+ struct nvmf_discovery_log header = {};
+ /* No entries to fetch after fetching the header */
+ struct mock_cmd mock_admin_cmds[] = {
+ {
+ .opcode = nvme_admin_get_log_page,
+ .data_len = HEADER_LEN,
+ .cdw10 = (HEADER_LEN / 4 - 1) << 16 /* NUMDL */
+ | NVME_LOG_LID_DISCOVER, /* LID */
+ .out_data = &header,
+ },
+ };
+ 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");
+ end_mock_cmds();
+ cmp(log, &header, sizeof(header), "incorrect header");
+ free(log);
+}
+
+static void test_four_entries(nvme_ctrl_t c)
+{
+ size_t num_entries = 4;
+ struct nvmf_disc_log_entry entries[num_entries];
+ struct nvmf_disc_log_entry log_entries[num_entries];
+ struct nvmf_discovery_log header = {.numrec = cpu_to_le64(num_entries)};
+ /*
+ * All 4 entries should be fetched at once
+ * followed by the header again (to ensure genctr hasn't changed)
+ */
+ struct mock_cmd mock_admin_cmds[] = {
+ {
+ .opcode = nvme_admin_get_log_page,
+ .data_len = HEADER_LEN,
+ .cdw10 = (HEADER_LEN / 4 - 1) << 16 /* NUMDL */
+ | NVME_LOG_LID_DISCOVER, /* LID */
+ .out_data = &header,
+ },
+ {
+ .opcode = nvme_admin_get_log_page,
+ .data_len = sizeof(entries),
+ .cdw10 = (sizeof(entries) / 4 - 1) << 16 /* NUMDL */
+ | NVME_LOG_LID_DISCOVER, /* LID */
+ .cdw12 = sizeof(header), /* LPOL */
+ .out_data = log_entries,
+ },
+ {
+ .opcode = nvme_admin_get_log_page,
+ .data_len = HEADER_LEN,
+ .cdw10 = (HEADER_LEN / 4 - 1) << 16 /* NUMDL */
+ | NVME_LOG_LID_DISCOVER, /* LID */
+ .out_data = &header,
+ },
+ };
+ struct nvmf_discovery_log *log = NULL;
+
+ 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");
+ end_mock_cmds();
+ cmp(log, &header, sizeof(header), "incorrect header");
+ cmp(log->entries, entries, sizeof(entries), "incorrect entries");
+ free(log);
+}
+
+static void test_five_entries(nvme_ctrl_t c)
+{
+ size_t num_entries = 5;
+ struct nvmf_disc_log_entry entries[num_entries];
+ struct nvmf_disc_log_entry log_entries[num_entries];
+ size_t first_entries = 4;
+ size_t first_data_len = first_entries * sizeof(*entries);
+ size_t second_entries = num_entries - first_entries;
+ size_t second_data_len = second_entries * sizeof(*entries);
+ struct nvmf_discovery_log header = {.numrec = cpu_to_le64(num_entries)};
+ /*
+ * The first 4 entries (4 KB) are fetched together,
+ * followed by last entry separately.
+ * Finally, the header is fetched again to check genctr.
+ */
+ struct mock_cmd mock_admin_cmds[] = {
+ {
+ .opcode = nvme_admin_get_log_page,
+ .data_len = HEADER_LEN,
+ .cdw10 = (HEADER_LEN / 4 - 1) << 16 /* NUMDL */
+ | NVME_LOG_LID_DISCOVER, /* LID */
+ .out_data = &header,
+ },
+ {
+ .opcode = nvme_admin_get_log_page,
+ .data_len = first_data_len,
+ .cdw10 = (first_data_len / 4 - 1) << 16 /* NUMDL */
+ | 1 << 15 /* RAE */
+ | NVME_LOG_LID_DISCOVER, /* LID */
+ .cdw12 = sizeof(header), /* LPOL */
+ .out_data = log_entries,
+ },
+ {
+ .opcode = nvme_admin_get_log_page,
+ .data_len = second_data_len,
+ .cdw10 = (second_data_len / 4 - 1) << 16 /* NUMDL */
+ | NVME_LOG_LID_DISCOVER, /* LID */
+ .cdw12 = sizeof(header) + first_data_len, /* LPOL */
+ .out_data = log_entries + first_entries,
+ },
+ {
+ .opcode = nvme_admin_get_log_page,
+ .data_len = HEADER_LEN,
+ .cdw10 = (HEADER_LEN / 4 - 1) << 16 /* NUMDL */
+ | NVME_LOG_LID_DISCOVER, /* LID */
+ .out_data = &header,
+ },
+ };
+ struct nvmf_discovery_log *log = NULL;
+
+ 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");
+ end_mock_cmds();
+ cmp(log, &header, sizeof(header), "incorrect header");
+ cmp(log->entries, entries, sizeof(entries), "incorrect entries");
+ free(log);
+}
+
+static void test_genctr_change(nvme_ctrl_t c)
+{
+ struct nvmf_disc_log_entry entries1[1];
+ struct nvmf_discovery_log header1 = {
+ .numrec = cpu_to_le64(ARRAY_SIZE(entries1)),
+ };
+ size_t num_entries2 = 2;
+ struct nvmf_disc_log_entry entries2[num_entries2];
+ struct nvmf_disc_log_entry log_entries2[num_entries2];
+ struct nvmf_discovery_log header2 = {
+ .genctr = cpu_to_le64(1),
+ .numrec = cpu_to_le64(num_entries2),
+ };
+ /*
+ * genctr changes after the entries are fetched the first time,
+ * so the log page entries are refetched
+ */
+ struct mock_cmd mock_admin_cmds[] = {
+ {
+ .opcode = nvme_admin_get_log_page,
+ .data_len = HEADER_LEN,
+ .cdw10 = (HEADER_LEN / 4 - 1) << 16 /* NUMDL */
+ | NVME_LOG_LID_DISCOVER, /* LID */
+ .out_data = &header1,
+ },
+ {
+ .opcode = nvme_admin_get_log_page,
+ .data_len = sizeof(entries1),
+ .cdw10 = (sizeof(entries1) / 4 - 1) << 16 /* NUMDL */
+ | NVME_LOG_LID_DISCOVER, /* NUMDL */
+ .cdw12 = sizeof(header1), /* LPOL */
+ .out_data = entries1,
+ },
+ {
+ .opcode = nvme_admin_get_log_page,
+ .data_len = HEADER_LEN,
+ .cdw10 = (HEADER_LEN / 4 - 1) << 16 /* NUMDL */
+ | NVME_LOG_LID_DISCOVER, /* LID */
+ .out_data = &header2,
+ },
+ {
+ .opcode = nvme_admin_get_log_page,
+ .data_len = sizeof(entries2),
+ .cdw10 = (sizeof(entries2) / 4 - 1) << 16 /* NUMDL */
+ | NVME_LOG_LID_DISCOVER, /* LID */
+ .cdw12 = sizeof(header2), /* LPOL */
+ .out_data = log_entries2,
+ },
+ {
+ .opcode = nvme_admin_get_log_page,
+ .data_len = HEADER_LEN,
+ .cdw10 = (HEADER_LEN / 4 - 1) << 16 /* NUMDL */
+ | NVME_LOG_LID_DISCOVER, /* LID */
+ .out_data = &header2,
+ },
+ };
+ struct nvmf_discovery_log *log = NULL;
+
+ 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");
+ end_mock_cmds();
+ cmp(log, &header2, sizeof(header2), "incorrect header");
+ cmp(log->entries, entries2, sizeof(entries2), "incorrect entries");
+ free(log);
+}
+
+static void test_max_retries(nvme_ctrl_t c)
+{
+ struct nvmf_disc_log_entry entry;
+ struct nvmf_discovery_log header1 = {.numrec = cpu_to_le64(1)};
+ struct nvmf_discovery_log header2 = {
+ .genctr = cpu_to_le64(1),
+ .numrec = cpu_to_le64(1),
+ };
+ struct nvmf_discovery_log header3 = {
+ .genctr = cpu_to_le64(2),
+ .numrec = cpu_to_le64(1),
+ };
+ /* genctr changes in both attempts, hitting the max retries (2) */
+ struct mock_cmd mock_admin_cmds[] = {
+ {
+ .opcode = nvme_admin_get_log_page,
+ .data_len = HEADER_LEN,
+ .cdw10 = (HEADER_LEN / 4 - 1) << 16 /* NUMDL */
+ | NVME_LOG_LID_DISCOVER, /* LID */
+ .out_data = &header1,
+ },
+ {
+ .opcode = nvme_admin_get_log_page,
+ .data_len = sizeof(entry),
+ .cdw10 = (sizeof(entry) / 4 - 1) << 16 /* NUMDL */
+ | NVME_LOG_LID_DISCOVER, /* LID */
+ .cdw12 = sizeof(header1), /* LPOL */
+ .out_data = &entry,
+ },
+ {
+ .opcode = nvme_admin_get_log_page,
+ .data_len = HEADER_LEN,
+ .cdw10 = (HEADER_LEN / 4 - 1) << 16 /* NUMDL */
+ | NVME_LOG_LID_DISCOVER, /* LID */
+ .out_data = &header2,
+ },
+ {
+ .opcode = nvme_admin_get_log_page,
+ .data_len = sizeof(entry),
+ .cdw10 = (sizeof(entry) / 4 - 1) << 16 /* NUMDL */
+ | NVME_LOG_LID_DISCOVER, /* LID */
+ .cdw12 = sizeof(header2), /* LPOL */
+ .out_data = &entry,
+ },
+ {
+ .opcode = nvme_admin_get_log_page,
+ .data_len = HEADER_LEN,
+ .cdw10 = (HEADER_LEN / 4 - 1) << 16 /* NUMDL */
+ | NVME_LOG_LID_DISCOVER, /* LID */
+ .out_data = &header3,
+ },
+ };
+ struct nvmf_discovery_log *log = NULL;
+
+ 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");
+ end_mock_cmds();
+ check(errno == EAGAIN, "discovery failed: %m");
+ check(!log, "unexpected log page returned");
+}
+
+static void test_header_error(nvme_ctrl_t c)
+{
+ /* Stop after an error in fetching the header the first time */
+ struct mock_cmd mock_admin_cmds[] = {
+ {
+ .opcode = nvme_admin_get_log_page,
+ .data_len = HEADER_LEN,
+ .cdw10 = (HEADER_LEN / 4 - 1) << 16 /* NUMDL */
+ | NVME_LOG_LID_DISCOVER, /* LID */
+ .err = NVME_SC_INVALID_OPCODE,
+ },
+ };
+ 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");
+ end_mock_cmds();
+ check(!log, "unexpected log page returned");
+}
+
+static void test_entries_error(nvme_ctrl_t c)
+{
+ struct nvmf_discovery_log header = {.numrec = cpu_to_le64(1)};
+ size_t entry_size = sizeof(struct nvmf_disc_log_entry);
+ /* Stop after an error in fetching the entries */
+ struct mock_cmd mock_admin_cmds[] = {
+ {
+ .opcode = nvme_admin_get_log_page,
+ .data_len = HEADER_LEN,
+ .cdw10 = (HEADER_LEN / 4 - 1) << 16 /* NUMDL */
+ | NVME_LOG_LID_DISCOVER, /* LID */
+ .out_data = &header,
+ },
+ {
+ .opcode = nvme_admin_get_log_page,
+ .data_len = entry_size,
+ .cdw10 = (entry_size / 4 - 1) << 16 /* NUMDL */
+ | NVME_LOG_LID_DISCOVER, /* LID */
+ .cdw12 = sizeof(header), /* LPOL */
+ .err = -EIO,
+ },
+ };
+ 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");
+ end_mock_cmds();
+ check(errno == EIO, "discovery failed: %m");
+ check(!log, "unexpected log page returned");
+}
+
+static void test_genctr_error(nvme_ctrl_t c)
+{
+ struct nvmf_disc_log_entry entry;
+ struct nvmf_discovery_log header = {.numrec = cpu_to_le64(1)};
+ /* Stop after an error in refetching the header */
+ struct mock_cmd mock_admin_cmds[] = {
+ {
+ .opcode = nvme_admin_get_log_page,
+ .data_len = HEADER_LEN,
+ .cdw10 = (HEADER_LEN / 4 - 1) << 16 /* NUMDL */
+ | NVME_LOG_LID_DISCOVER, /* LID */
+ .out_data = &header,
+ },
+ {
+ .opcode = nvme_admin_get_log_page,
+ .data_len = sizeof(entry),
+ .cdw10 = (sizeof(entry) / 4 - 1) << 16 /* NUMDL */
+ | NVME_LOG_LID_DISCOVER, /* LID */
+ .cdw12 = sizeof(header), /* LPOL */
+ .out_data = &entry,
+ },
+ {
+ .opcode = nvme_admin_get_log_page,
+ .data_len = HEADER_LEN,
+ .cdw10 = (HEADER_LEN / 4 - 1) << 16 /* NUMDL */
+ | NVME_LOG_LID_DISCOVER, /* LID */
+ .err = NVME_SC_INTERNAL,
+ },
+ };
+ struct nvmf_discovery_log *log = NULL;
+
+ 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");
+ 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};
+
+ printf("Running test %s...", test_name);
+ fflush(stdout);
+ check(asprintf(&c.name, "%s_ctrl", test_name) >= 0, "asprintf() failed");
+ test_fn(&c);
+ free(c.name);
+ puts(" OK");
+}
+
+#define RUN_TEST(name) run_test(#name, test_ ## name)
+
+int main(void)
+{
+ set_mock_fd(TEST_FD);
+ RUN_TEST(no_entries);
+ RUN_TEST(four_entries);
+ RUN_TEST(five_entries);
+ RUN_TEST(genctr_change);
+ RUN_TEST(max_retries);
+ RUN_TEST(header_error);
+ RUN_TEST(entries_error);
+ RUN_TEST(genctr_error);
+}
diff --git a/test/ioctl/features.c b/test/ioctl/features.c
new file mode 100644
index 0000000..7386497
--- /dev/null
+++ b/test/ioctl/features.c
@@ -0,0 +1,1604 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+
+#include <libnvme.h>
+
+#include <errno.h>
+#include <inttypes.h>
+
+#include "mock.h"
+#include "util.h"
+
+#define TEST_FD 0xFD
+#define TEST_TIMEOUT 1234
+#define TEST_NSID 0x89ABCDEF
+#define TEST_CDW11 0x11111111
+#define TEST_CDW12 0x12121212
+#define TEST_CDW13 0x13131313
+#define TEST_CDW15 0x15151515
+#define TEST_UUIDX 0b1001110
+#define TEST_FID 0xFE
+#define TEST_RESULT 0x12345678
+#define TEST_SEL NVME_GET_FEATURES_SEL_SAVED
+#define TEST_SC NVME_SC_INVALID_FIELD
+
+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,
+ .in_data = data,
+ .data_len = sizeof(data),
+ .cdw10 = (uint32_t)1 << 31 /* SAVE */
+ | TEST_FID,
+ .cdw11 = TEST_CDW11,
+ .cdw12 = TEST_CDW12,
+ .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);
+ end_mock_cmds();
+ check(err == 0, "set features returned error %d, errno %m", err);
+ check(result == TEST_RESULT,
+ "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT);
+}
+
+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,
+ .data_len = sizeof(data),
+ .cdw10 = TEST_SEL << 8 | TEST_FID,
+ .cdw11 = TEST_CDW11,
+ .cdw14 = TEST_UUIDX,
+ .timeout_ms = TEST_TIMEOUT,
+ .out_data = data,
+ .result = TEST_RESULT,
+ };
+ int err;
+
+ arbitrary(data, sizeof(data));
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_get_features(&args);
+ end_mock_cmds();
+ check(err == 0, "get features returned error %d, errno %m", err);
+ check(result == TEST_RESULT,
+ "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT);
+ cmp(get_data, data, sizeof(data), "incorrect data");
+}
+
+static void test_set_features_data(void)
+{
+ uint8_t data[128];
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_set_features,
+ .nsid = TEST_NSID,
+ .in_data = data,
+ .data_len = sizeof(data),
+ .cdw10 = TEST_FID,
+ .cdw11 = TEST_CDW11,
+ .result = TEST_RESULT,
+ };
+ uint32_t result = 0;
+ int err;
+
+ 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);
+ end_mock_cmds();
+ check(err == 0, "set features returned error %d, errno %m", err);
+ check(result == TEST_RESULT,
+ "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT);
+}
+
+static void test_get_features_data(void)
+{
+ uint8_t data[128], get_data[sizeof(data)] = {};
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_get_features,
+ .nsid = TEST_NSID,
+ .data_len = sizeof(data),
+ .cdw10 = NVME_GET_FEATURES_SEL_CURRENT << 8 | TEST_FID,
+ .out_data = data,
+ .result = TEST_RESULT,
+ };
+ uint32_t result = 0;
+ int err;
+
+ 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);
+ end_mock_cmds();
+ check(err == 0, "set features returned error %d, errno %m", err);
+ check(result == TEST_RESULT,
+ "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT);
+ cmp(get_data, data, sizeof(data), "incorrect data");
+}
+
+static void test_set_features_simple(void)
+{
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_set_features,
+ .nsid = TEST_NSID,
+ .cdw10 = (uint32_t)1 << 31 /* SAVE */
+ | TEST_FID,
+ .cdw11 = TEST_CDW11,
+ .result = TEST_RESULT,
+ };
+ uint32_t result = 0;
+ int err;
+
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_set_features_simple(
+ TEST_FD, TEST_FID, TEST_NSID, TEST_CDW11, true, &result);
+ end_mock_cmds();
+ check(err == 0, "set features returned error %d, errno %m", err);
+ check(result == TEST_RESULT,
+ "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT);
+}
+
+static void test_get_features_simple(void)
+{
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_get_features,
+ .nsid = TEST_NSID,
+ .cdw10 = NVME_GET_FEATURES_SEL_CURRENT << 8 | TEST_FID,
+ .result = TEST_RESULT,
+ };
+ uint32_t result = 0;
+ int err;
+
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_get_features_simple(TEST_FD, TEST_FID, TEST_NSID, &result);
+ end_mock_cmds();
+ check(err == 0, "set features returned error %d, errno %m", err);
+ check(result == TEST_RESULT,
+ "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT);
+}
+
+static void test_set_arbitration(void)
+{
+ uint8_t HPW = 0xAA, MPW = 0xBB, LPW = 0xCC, AB = 0b111;
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_set_features,
+ .cdw10 = NVME_FEAT_FID_ARBITRATION,
+ .cdw11 = (uint32_t)HPW << 24 | MPW << 16 | LPW << 8 | AB,
+ .result = TEST_RESULT,
+ };
+ uint32_t result = 0;
+ int err;
+
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_set_features_arbitration(
+ TEST_FD, AB, LPW, MPW, HPW, false, &result);
+ end_mock_cmds();
+ check(err == 0, "set features returned error %d, errno %m", err);
+ check(result == TEST_RESULT,
+ "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT);
+}
+
+static void test_get_arbitration(void)
+{
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_get_features,
+ .cdw10 = TEST_SEL << 8 | NVME_FEAT_FID_ARBITRATION,
+ .result = TEST_RESULT,
+ };
+ uint32_t result = 0;
+ int err;
+
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_get_features_arbitration(TEST_FD, TEST_SEL, &result);
+ end_mock_cmds();
+ check(err == 0, "get features returned error %d, errno %m", err);
+ check(result == TEST_RESULT,
+ "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT);
+}
+
+static void test_set_power_mgmt(void)
+{
+ uint8_t PS = 0b10101, WH = 0b101;
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_set_features,
+ .cdw10 = (uint32_t)1 << 31 /* SAVE */
+ | NVME_FEAT_FID_POWER_MGMT,
+ .cdw11 = WH << 5 | PS,
+ .result = TEST_RESULT,
+ };
+ uint32_t result = 0;
+ int err;
+
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_set_features_power_mgmt(TEST_FD, PS, WH, true, &result);
+ end_mock_cmds();
+ check(err == 0, "set features returned error %d, errno %m", err);
+ check(result == TEST_RESULT,
+ "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT);
+}
+
+static void test_get_power_mgmt(void)
+{
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_get_features,
+ .cdw10 = TEST_SEL << 8 | NVME_FEAT_FID_POWER_MGMT,
+ .result = TEST_RESULT,
+ };
+ uint32_t result = 0;
+ int err;
+
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_get_features_power_mgmt(TEST_FD, TEST_SEL, &result);
+ end_mock_cmds();
+ check(err == 0, "get features returned error %d, errno %m", err);
+ check(result == TEST_RESULT,
+ "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT);
+}
+
+static void test_set_lba_range(void)
+{
+ uint8_t NUM = 64;
+ struct nvme_lba_range_type range_types;
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_set_features,
+ .nsid = TEST_NSID,
+ .in_data = &range_types,
+ .data_len = sizeof(range_types),
+ .cdw10 = NVME_FEAT_FID_LBA_RANGE,
+ .cdw11 = NUM - 1,
+ .result = TEST_RESULT,
+ };
+ uint32_t result = 0;
+ int err;
+
+ 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);
+ end_mock_cmds();
+ check(err == 0, "set features returned error %d, errno %m", err);
+ check(result == TEST_RESULT,
+ "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT);
+}
+
+static void test_get_lba_range(void)
+{
+ struct nvme_lba_range_type range_types, get_range_types = {};
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_get_features,
+ .nsid = TEST_NSID,
+ .data_len = sizeof(range_types),
+ .cdw10 = TEST_SEL << 8 | NVME_FEAT_FID_LBA_RANGE,
+ .out_data = &range_types,
+ .result = TEST_RESULT,
+ };
+ uint32_t result = 0;
+ int err;
+
+ arbitrary(&range_types, sizeof(range_types));
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_get_features_lba_range2(
+ TEST_FD, TEST_SEL, TEST_NSID, &get_range_types, &result);
+ end_mock_cmds();
+ check(err == 0, "get features returned error %d, errno %m", err);
+ check(result == TEST_RESULT,
+ "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT);
+ cmp(&get_range_types, &range_types, sizeof(range_types),
+ "incorrect LBA range types");
+}
+
+static void test_set_temp_thresh(void)
+{
+ uint16_t TMPTH = 0xFEDC;
+ uint8_t TMPSEL = 0x8;
+ enum nvme_feat_tmpthresh_thsel THSEL =
+ NVME_FEATURE_TEMPTHRESH_THSEL_UNDER;
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_set_features,
+ .cdw10 = (uint32_t)1 << 31 /* SAVE */
+ | NVME_FEAT_FID_TEMP_THRESH,
+ .cdw11 = THSEL << 20 | TMPSEL << 16 | TMPTH,
+ .result = TEST_RESULT,
+ };
+ uint32_t result = 0;
+ int err;
+
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_set_features_temp_thresh(
+ TEST_FD, TMPTH, TMPSEL, THSEL, true, &result);
+ end_mock_cmds();
+ check(err == 0, "set features returned error %d, errno %m", err);
+ check(result == TEST_RESULT,
+ "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT);
+}
+
+static void test_get_temp_thresh(void)
+{
+ /*
+ * nvme_get_features_temp_thresh() doesn't support
+ * specifying TMPSEL and THSEL
+ */
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_get_features,
+ .cdw10 = TEST_SEL << 8 | NVME_FEAT_FID_TEMP_THRESH,
+ .cdw11 = NVME_FEATURE_TEMPTHRESH_THSEL_OVER << 20,
+ .result = TEST_RESULT,
+ };
+ uint32_t result = 0;
+ int err;
+
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_get_features_temp_thresh(TEST_FD, TEST_SEL, &result);
+ end_mock_cmds();
+ check(err == 0, "get features returned error %d, errno %m", err);
+ check(result == TEST_RESULT,
+ "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT);
+}
+
+static void test_set_err_recovery(void)
+{
+ uint16_t TLER = 0xCDEF;
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_set_features,
+ .nsid = TEST_NSID,
+ .cdw10 = NVME_FEAT_FID_ERR_RECOVERY,
+ .cdw11 = 1 << 16 /* DULBE */
+ | TLER,
+ .result = TEST_RESULT,
+ };
+ uint32_t result = 0;
+ int err;
+
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_set_features_err_recovery(
+ TEST_FD, TEST_NSID, TLER, true, false, &result);
+ end_mock_cmds();
+ check(err == 0, "set features returned error %d, errno %m", err);
+ check(result == TEST_RESULT,
+ "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT);
+}
+
+static void test_get_err_recovery(void)
+{
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_get_features,
+ .nsid = TEST_NSID,
+ .cdw10 = TEST_SEL << 8 | NVME_FEAT_FID_ERR_RECOVERY,
+ .result = TEST_RESULT,
+ };
+ uint32_t result = 0;
+ int err;
+
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_get_features_err_recovery2(
+ TEST_FD, TEST_SEL, TEST_NSID, &result);
+ end_mock_cmds();
+ check(err == 0, "get features returned error %d, errno %m", err);
+ check(result == TEST_RESULT,
+ "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT);
+}
+
+static void test_set_volatile_wc(void)
+{
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_set_features,
+ .cdw10 = (uint32_t)1 << 31 /* SAVE */
+ | NVME_FEAT_FID_VOLATILE_WC,
+ .cdw11 = 1 << 0, /* WCE */
+ .result = TEST_RESULT,
+ };
+ uint32_t result = 0;
+ int err;
+
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_set_features_volatile_wc(TEST_FD, true, true, &result);
+ end_mock_cmds();
+ check(err == 0, "set features returned error %d, errno %m", err);
+ check(result == TEST_RESULT,
+ "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT);
+}
+
+static void test_get_volatile_wc(void)
+{
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_get_features,
+ .cdw10 = TEST_SEL << 8
+ | NVME_FEAT_FID_VOLATILE_WC,
+ .result = TEST_RESULT,
+ };
+ uint32_t result = 0;
+ int err;
+
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_get_features_volatile_wc(TEST_FD, TEST_SEL, &result);
+ end_mock_cmds();
+ check(err == 0, "get features returned error %d, errno %m", err);
+ check(result == TEST_RESULT,
+ "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT);
+}
+
+static void test_get_num_queues(void)
+{
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_get_features,
+ .cdw10 = TEST_SEL << 8 | NVME_FEAT_FID_NUM_QUEUES,
+ .result = TEST_RESULT,
+ };
+ uint32_t result = 0;
+ int err;
+
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_get_features_num_queues(TEST_FD, TEST_SEL, &result);
+ end_mock_cmds();
+ check(err == 0, "get features returned error %d, errno %m", err);
+ check(result == TEST_RESULT,
+ "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT);
+}
+
+static void test_set_irq_coalesce(void)
+{
+ uint8_t THR = 0xAB, TIME = 0xCD;
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_set_features,
+ .cdw10 = NVME_FEAT_FID_IRQ_COALESCE,
+ .cdw11 = TIME << 8 | THR,
+ .result = TEST_RESULT,
+ };
+ uint32_t result = 0;
+ int err;
+
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_set_features_irq_coalesce(
+ TEST_FD, THR, TIME, false, &result);
+ end_mock_cmds();
+ check(err == 0, "set features returned error %d, errno %m", err);
+ check(result == TEST_RESULT,
+ "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT);
+}
+
+static void test_get_irq_coalesce(void)
+{
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_get_features,
+ .cdw10 = TEST_SEL << 8 | NVME_FEAT_FID_IRQ_COALESCE,
+ .result = TEST_RESULT,
+ };
+ uint32_t result = 0;
+ int err;
+
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_get_features_irq_coalesce(TEST_FD, TEST_SEL, &result);
+ end_mock_cmds();
+ check(err == 0, "get features returned error %d, errno %m", err);
+ check(result == TEST_RESULT,
+ "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT);
+}
+
+static void test_set_irq_config(void)
+{
+ uint16_t IV = 0x1234;
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_set_features,
+ .cdw10 = (uint32_t)1 << 31 /* SAVE */
+ | NVME_FEAT_FID_IRQ_CONFIG,
+ .cdw11 = 1 << 16 /* CD */
+ | IV,
+ .result = TEST_RESULT,
+ };
+ uint32_t result = 0;
+ int err;
+
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_set_features_irq_config(TEST_FD, IV, true, true, &result);
+ end_mock_cmds();
+ check(err == 0, "set features returned error %d, errno %m", err);
+ check(result == TEST_RESULT,
+ "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT);
+}
+
+static void test_get_irq_config(void)
+{
+ uint16_t IV = 0x5678;
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_get_features,
+ .cdw10 = TEST_SEL << 8 | NVME_FEAT_FID_IRQ_CONFIG,
+ .cdw11 = IV,
+ .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);
+ end_mock_cmds();
+ check(err == 0, "get features returned error %d, errno %m", err);
+ check(result == TEST_RESULT,
+ "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT);
+}
+
+static void test_set_write_atomic(void)
+{
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_set_features,
+ .cdw10 = NVME_FEAT_FID_WRITE_ATOMIC,
+ .cdw11 = 1 << 0, /* DN */
+ .result = TEST_RESULT,
+ };
+ uint32_t result = 0;
+ int err;
+
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_set_features_write_atomic(TEST_FD, true, false, &result);
+ end_mock_cmds();
+ check(err == 0, "set features returned error %d, errno %m", err);
+ check(result == TEST_RESULT,
+ "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT);
+}
+
+static void test_get_write_atomic(void)
+{
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_get_features,
+ .cdw10 = TEST_SEL << 8 | NVME_FEAT_FID_WRITE_ATOMIC,
+ .result = TEST_RESULT,
+ };
+ uint32_t result = 0;
+ int err;
+
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_get_features_write_atomic(TEST_FD, TEST_SEL, &result);
+ end_mock_cmds();
+ check(err == 0, "get features returned error %d, errno %m", err);
+ check(result == TEST_RESULT,
+ "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT);
+}
+
+static void test_set_async_event(void)
+{
+ uint32_t EVENTS = 0x87654321;
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_set_features,
+ .cdw10 = (uint32_t)1 << 31 /* SAVE */
+ | NVME_FEAT_FID_ASYNC_EVENT,
+ .cdw11 = EVENTS,
+ .result = TEST_RESULT,
+ };
+ uint32_t result = 0;
+ int err;
+
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_set_features_async_event(TEST_FD, EVENTS, true, &result);
+ end_mock_cmds();
+ check(err == 0, "set features returned error %d, errno %m", err);
+ check(result == TEST_RESULT,
+ "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT);
+}
+
+static void test_get_async_event(void)
+{
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_get_features,
+ .cdw10 = TEST_SEL << 8 | NVME_FEAT_FID_ASYNC_EVENT,
+ .result = TEST_RESULT,
+ };
+ uint32_t result = 0;
+ int err;
+
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_get_features_async_event(TEST_FD, TEST_SEL, &result);
+ end_mock_cmds();
+ check(err == 0, "get features returned error %d, errno %m", err);
+ check(result == TEST_RESULT,
+ "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT);
+}
+
+static void test_set_auto_pst(void)
+{
+ struct nvme_feat_auto_pst apst;
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_set_features,
+ .in_data = &apst,
+ .data_len = sizeof(apst),
+ .cdw10 = NVME_FEAT_FID_AUTO_PST,
+ .cdw11 = 1 << 0, /* APSTE */
+ .result = TEST_RESULT,
+ };
+ uint32_t result = 0;
+ int err;
+
+ arbitrary(&apst, sizeof(apst));
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_set_features_auto_pst(TEST_FD, true, false, &apst, &result);
+ end_mock_cmds();
+ check(err == 0, "set features returned error %d, errno %m", err);
+ check(result == TEST_RESULT,
+ "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT);
+}
+
+static void test_get_auto_pst(void)
+{
+ struct nvme_feat_auto_pst apst, get_apst = {};
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_get_features,
+ .data_len = sizeof(apst),
+ .cdw10 = TEST_SEL << 8 | NVME_FEAT_FID_AUTO_PST,
+ .out_data = &apst,
+ .result = TEST_RESULT,
+ };
+ uint32_t result = 0;
+ int err;
+
+ 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);
+ end_mock_cmds();
+ check(err == 0, "get features returned error %d, errno %m", err);
+ check(result == TEST_RESULT,
+ "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT);
+ cmp(&get_apst, &apst, sizeof(apst), "incorrect apst");
+}
+
+static void test_get_host_mem_buf(void)
+{
+ struct nvme_host_mem_buf_attrs attrs, get_attrs = {};
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_get_features,
+ .data_len = sizeof(attrs),
+ .cdw10 = TEST_SEL << 8 | NVME_FEAT_FID_HOST_MEM_BUF,
+ .out_data = &attrs,
+ .result = TEST_RESULT,
+ };
+ uint32_t result = 0;
+ int err;
+
+ arbitrary(&attrs, sizeof(attrs));
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_get_features_host_mem_buf2(
+ TEST_FD, TEST_SEL, &get_attrs, &result);
+ end_mock_cmds();
+ check(err == 0, "get features returned error %d, errno %m", err);
+ check(result == TEST_RESULT,
+ "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT);
+ cmp(&get_attrs, &attrs, sizeof(attrs), "incorrect attrs");
+}
+
+static void test_set_timestamp(void)
+{
+ struct nvme_timestamp ts = {.timestamp = {1, 2, 3, 4, 5, 6}};
+ uint64_t timestamp = ts.timestamp[0]
+ | (uint64_t) ts.timestamp[1] << 8
+ | (uint64_t) ts.timestamp[2] << 16
+ | (uint64_t) ts.timestamp[3] << 24
+ | (uint64_t) ts.timestamp[4] << 32
+ | (uint64_t) ts.timestamp[5] << 40;
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_set_features,
+ .in_data = &ts,
+ .data_len = sizeof(ts),
+ .cdw10 = (uint32_t)1 << 31 /* SAVE */
+ | NVME_FEAT_FID_TIMESTAMP,
+ };
+ int err;
+
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_set_features_timestamp(TEST_FD, true, timestamp);
+ end_mock_cmds();
+ check(err == 0, "set features returned error %d, errno %m", err);
+}
+
+static void test_get_timestamp(void)
+{
+ struct nvme_timestamp ts, get_ts = {};
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_get_features,
+ .data_len = sizeof(ts),
+ .cdw10 = TEST_SEL << 8 | NVME_FEAT_FID_TIMESTAMP,
+ .out_data = &ts,
+ };
+ int err;
+
+ arbitrary(&ts, sizeof(ts));
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_get_features_timestamp(TEST_FD, TEST_SEL, &get_ts);
+ end_mock_cmds();
+ check(err == 0, "get features returned error %d, errno %m", err);
+ cmp(&get_ts, &ts, sizeof(ts), "incorrect timestamp");
+}
+
+static void test_get_kato(void)
+{
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_get_features,
+ .cdw10 = TEST_SEL << 8 | NVME_FEAT_FID_KATO,
+ .result = TEST_RESULT,
+ };
+ uint32_t result = 0;
+ int err;
+
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_get_features_kato(TEST_FD, TEST_SEL, &result);
+ end_mock_cmds();
+ check(err == 0, "get features returned error %d, errno %m", err);
+ check(result == TEST_RESULT,
+ "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT);
+}
+
+static void test_set_hctm(void)
+{
+ uint16_t TMT2 = 0x4321, TMT1 = 0x8765;
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_set_features,
+ .cdw10 = NVME_FEAT_FID_HCTM,
+ .cdw11 = (uint32_t)TMT1 << 16 | TMT2,
+ .result = TEST_RESULT,
+ };
+ uint32_t result = 0;
+ int err;
+
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_set_features_hctm(TEST_FD, TMT2, TMT1, false, &result);
+ end_mock_cmds();
+ check(err == 0, "set features returned error %d, errno %m", err);
+ check(result == TEST_RESULT,
+ "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT);
+}
+
+static void test_get_hctm(void)
+{
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_get_features,
+ .cdw10 = TEST_SEL << 8 | NVME_FEAT_FID_HCTM,
+ .result = TEST_RESULT,
+ };
+ uint32_t result = 0;
+ int err;
+
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_get_features_hctm(TEST_FD, TEST_SEL, &result);
+ end_mock_cmds();
+ check(err == 0, "get features returned error %d, errno %m", err);
+ check(result == TEST_RESULT,
+ "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT);
+}
+
+static void test_set_nopsc(void)
+{
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_set_features,
+ .cdw10 = (uint32_t)1 << 31 /* SAVE */
+ | NVME_FEAT_FID_NOPSC,
+ .cdw11 = 1 << 0 /* NOPPME */,
+ .result = TEST_RESULT,
+ };
+ uint32_t result = 0;
+ int err;
+
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_set_features_nopsc(TEST_FD, true, true, &result);
+ end_mock_cmds();
+ check(err == 0, "set features returned error %d, errno %m", err);
+ check(result == TEST_RESULT,
+ "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT);
+}
+
+static void test_get_nopsc(void)
+{
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_get_features,
+ .cdw10 = TEST_SEL << 8 | NVME_FEAT_FID_NOPSC,
+ .result = TEST_RESULT,
+ };
+ uint32_t result = 0;
+ int err;
+
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_get_features_nopsc(TEST_FD, TEST_SEL, &result);
+ end_mock_cmds();
+ check(err == 0, "get features returned error %d, errno %m", err);
+ check(result == TEST_RESULT,
+ "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT);
+}
+
+static void test_set_rrl(void)
+{
+ uint8_t RRL = 0xA;
+ uint16_t NVMSETID = 0x1234;
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_set_features,
+ .cdw10 = NVME_FEAT_FID_RRL,
+ .cdw11 = NVMSETID,
+ .cdw12 = RRL,
+ .result = TEST_RESULT,
+ };
+ uint32_t result = 0;
+ int err;
+
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_set_features_rrl(TEST_FD, RRL, NVMSETID, false, &result);
+ end_mock_cmds();
+ check(err == 0, "set features returned error %d, errno %m", err);
+ check(result == TEST_RESULT,
+ "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT);
+}
+
+static void test_get_rrl(void)
+{
+ /* nvme_get_features_rrl() doesn't support specifying the NVMSETID */
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_get_features,
+ .cdw10 = TEST_SEL << 8 | NVME_FEAT_FID_RRL,
+ .result = TEST_RESULT,
+ };
+ uint32_t result = 0;
+ int err;
+
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_get_features_rrl(TEST_FD, TEST_SEL, &result);
+ end_mock_cmds();
+ check(err == 0, "get features returned error %d, errno %m", err);
+ check(result == TEST_RESULT,
+ "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT);
+}
+
+static void test_set_plm_config(void)
+{
+ uint16_t NVMSETID = 0xFEDC;
+ struct nvme_plm_config config;
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_set_features,
+ .in_data = &config,
+ .data_len = sizeof(config),
+ .cdw10 = (uint32_t)1 << 31 /* SAVE */
+ | NVME_FEAT_FID_PLM_CONFIG,
+ .cdw11 = NVMSETID,
+ .cdw12 = 1 << 0 /* Predictable Latency Enable */,
+ .result = TEST_RESULT,
+ };
+ uint32_t result = 0;
+ int err;
+
+ 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);
+ end_mock_cmds();
+ check(err == 0, "set features returned error %d, errno %m", err);
+ check(result == TEST_RESULT,
+ "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT);
+}
+
+static void test_get_plm_config(void)
+{
+ uint16_t NVMSETID = 0xABCD;
+ struct nvme_plm_config config, get_config = {};
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_get_features,
+ .data_len = sizeof(config),
+ .cdw10 = TEST_SEL << 8 | NVME_FEAT_FID_PLM_CONFIG,
+ .cdw11 = NVMSETID,
+ .out_data = &config,
+ .result = TEST_RESULT,
+ };
+ uint32_t result = 0;
+ int err;
+
+ 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);
+ end_mock_cmds();
+ check(err == 0, "get features returned error %d, errno %m", err);
+ check(result == TEST_RESULT,
+ "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT);
+ cmp(&get_config, &config, sizeof(config), "incorrect PLM config");
+}
+
+static void test_set_plm_window(void)
+{
+ enum nvme_feat_plm_window_select SEL = NVME_FEATURE_PLM_NDWIN;
+ uint16_t NVMSETID = 0x4321;
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_set_features,
+ .cdw10 = NVME_FEAT_FID_PLM_WINDOW,
+ .cdw11 = NVMSETID,
+ .cdw12 = SEL,
+ .result = TEST_RESULT,
+ };
+ uint32_t result = 0;
+ int err;
+
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_set_features_plm_window(
+ TEST_FD, SEL, NVMSETID, false, &result);
+ end_mock_cmds();
+ check(err == 0, "set features returned error %d, errno %m", err);
+ check(result == TEST_RESULT,
+ "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT);
+}
+
+static void test_get_plm_window(void)
+{
+ uint16_t NVMSETID = 0x8765;
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_get_features,
+ .cdw10 = TEST_SEL << 8 | NVME_FEAT_FID_PLM_WINDOW,
+ .cdw11 = NVMSETID,
+ .result = TEST_RESULT,
+ };
+ uint32_t result = 0;
+ int err;
+
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_get_features_plm_window(
+ TEST_FD, TEST_SEL, NVMSETID, &result);
+ end_mock_cmds();
+ check(err == 0, "get features returned error %d, errno %m", err);
+ check(result == TEST_RESULT,
+ "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT);
+}
+
+static void test_set_lba_sts_interval(void)
+{
+ uint16_t LSIRI = 0x1234, LSIPI = 0x5678;
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_set_features,
+ .cdw10 = (uint32_t)1 << 31 /* SAVE */
+ | NVME_FEAT_FID_LBA_STS_INTERVAL,
+ .cdw11 = LSIPI << 16 | LSIRI,
+ .result = TEST_RESULT,
+ };
+ uint32_t result = 0;
+ int err;
+
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_set_features_lba_sts_interval(
+ TEST_FD, LSIRI, LSIPI, true, &result);
+ end_mock_cmds();
+ check(err == 0, "set features returned error %d, errno %m", err);
+ check(result == TEST_RESULT,
+ "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT);
+}
+
+static void test_get_lba_sts_interval(void)
+{
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_get_features,
+ .cdw10 = TEST_SEL << 8 | NVME_FEAT_FID_LBA_STS_INTERVAL,
+ .result = TEST_RESULT,
+ };
+ uint32_t result = 0;
+ int err;
+
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_get_features_lba_sts_interval(TEST_FD, TEST_SEL, &result);
+ end_mock_cmds();
+ check(err == 0, "get features returned error %d, errno %m", err);
+ check(result == TEST_RESULT,
+ "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT);
+}
+
+static void test_set_host_behavior(void)
+{
+ /* nvme_set_features_host_behavior() ignores SAVE */
+ struct nvme_feat_host_behavior behavior;
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_set_features,
+ .in_data = &behavior,
+ .data_len = sizeof(behavior),
+ .cdw10 = NVME_FEAT_FID_HOST_BEHAVIOR,
+ };
+ int err;
+
+ arbitrary(&behavior, sizeof(behavior));
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_set_features_host_behavior(TEST_FD, true, &behavior);
+ end_mock_cmds();
+ check(err == 0, "set features returned error %d, errno %m", err);
+}
+
+static void test_get_host_behavior(void)
+{
+ struct nvme_feat_host_behavior behavior, get_behavior = {};
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_get_features,
+ .data_len = sizeof(behavior),
+ .cdw10 = TEST_SEL << 8 | NVME_FEAT_FID_HOST_BEHAVIOR,
+ .out_data = &behavior,
+ .result = TEST_RESULT,
+ };
+ uint32_t result = 0;
+ int err;
+
+ 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);
+ end_mock_cmds();
+ check(err == 0, "get features returned error %d, errno %m", err);
+ check(result == TEST_RESULT,
+ "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT);
+ cmp(&get_behavior, &behavior, sizeof(behavior), "incorrect behavior");
+}
+
+static void test_set_sanitize(void)
+{
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_set_features,
+ .cdw10 = NVME_FEAT_FID_SANITIZE,
+ .cdw11 = 1 << 0, /* NODRM */
+ .result = TEST_RESULT,
+ };
+ uint32_t result = 0;
+ int err;
+
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_set_features_sanitize(TEST_FD, true, false, &result);
+ end_mock_cmds();
+ check(err == 0, "set features returned error %d, errno %m", err);
+ check(result == TEST_RESULT,
+ "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT);
+}
+
+static void test_get_sanitize(void)
+{
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_get_features,
+ .cdw10 = TEST_SEL << 8 | NVME_FEAT_FID_SANITIZE,
+ .result = TEST_RESULT,
+ };
+ uint32_t result = 0;
+ int err;
+
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_get_features_sanitize(TEST_FD, TEST_SEL, &result);
+ end_mock_cmds();
+ check(err == 0, "get features returned error %d, errno %m", err);
+ check(result == TEST_RESULT,
+ "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT);
+}
+
+static void test_set_endurance_evt_cfg(void)
+{
+ uint16_t ENDGID = 0x9876;
+ uint8_t EGWARN = 0xCD;
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_set_features,
+ .cdw10 = (uint32_t)1 << 31 /* SAVE */
+ | NVME_FEAT_FID_ENDURANCE_EVT_CFG,
+ .cdw11 = EGWARN << 16 | ENDGID,
+ .result = TEST_RESULT,
+ };
+ uint32_t result = 0;
+ int err;
+
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_set_features_endurance_evt_cfg(
+ TEST_FD, ENDGID, EGWARN, true, &result);
+ end_mock_cmds();
+ check(err == 0, "set features returned error %d, errno %m", err);
+ check(result == TEST_RESULT,
+ "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT);
+}
+
+static void test_get_endurance_event_cfg(void)
+{
+ uint16_t ENDGID = 0x6789;
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_get_features,
+ .cdw10 = TEST_SEL << 8 | NVME_FEAT_FID_ENDURANCE_EVT_CFG,
+ .cdw11 = ENDGID,
+ .result = TEST_RESULT,
+ };
+ uint32_t result = 0;
+ int err;
+
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_get_features_endurance_event_cfg(
+ TEST_FD, TEST_SEL, ENDGID, &result);
+ end_mock_cmds();
+ check(err == 0, "get features returned error %d, errno %m", err);
+ check(result == TEST_RESULT,
+ "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT);
+}
+
+static void test_set_iocs_profile(void)
+{
+ uint16_t IOCSI = 0b101100111;
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_set_features,
+ .cdw10 = NVME_FEAT_FID_IOCS_PROFILE,
+ .cdw11 = IOCSI,
+ };
+ int err;
+
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_set_features_iocs_profile(TEST_FD, IOCSI, false);
+ end_mock_cmds();
+ check(err == 0, "set features returned error %d, errno %m", err);
+}
+
+static void test_get_iocs_profile(void)
+{
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_get_features,
+ .cdw10 = TEST_SEL << 8 | NVME_FEAT_FID_IOCS_PROFILE,
+ .result = TEST_RESULT,
+ };
+ uint32_t result = 0;
+ int err;
+
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_get_features_iocs_profile(TEST_FD, TEST_SEL, &result);
+ end_mock_cmds();
+ check(err == 0, "get features returned error %d, errno %m", err);
+ check(result == TEST_RESULT,
+ "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT);
+}
+
+static void test_set_sw_progress(void)
+{
+ uint8_t PBSLC = 0xBA;
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_set_features,
+ .cdw10 = (uint32_t)1 << 31 /* SAVE */
+ | NVME_FEAT_FID_SW_PROGRESS,
+ .cdw11 = PBSLC,
+ .result = TEST_RESULT,
+ };
+ uint32_t result = 0;
+ int err;
+
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_set_features_sw_progress(TEST_FD, PBSLC, true, &result);
+ end_mock_cmds();
+ check(err == 0, "set features returned error %d, errno %m", err);
+ check(result == TEST_RESULT,
+ "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT);
+}
+
+static void test_get_sw_progress(void)
+{
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_get_features,
+ .cdw10 = TEST_SEL << 8 | NVME_FEAT_FID_SW_PROGRESS,
+ .result = TEST_RESULT,
+ };
+ uint32_t result = 0;
+ int err;
+
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_get_features_sw_progress(TEST_FD, TEST_SEL, &result);
+ end_mock_cmds();
+ check(err == 0, "get features returned error %d, errno %m", err);
+ check(result == TEST_RESULT,
+ "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT);
+}
+
+static void test_set_host_id(void)
+{
+ uint8_t hostid[8];
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_set_features,
+ .in_data = hostid,
+ .data_len = sizeof(hostid),
+ .cdw10 = (uint32_t)1 << 31 /* SAVE */
+ | NVME_FEAT_FID_HOST_ID,
+ .result = TEST_RESULT,
+ };
+ int err;
+
+ arbitrary(hostid, sizeof(hostid));
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_set_features_host_id(TEST_FD, false, true, hostid);
+ end_mock_cmds();
+ check(err == 0, "set features returned error %d, errno %m", err);
+}
+
+static void test_set_host_id_extended(void)
+{
+ uint8_t hostid[16];
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_set_features,
+ .in_data = hostid,
+ .data_len = sizeof(hostid),
+ .cdw10 = NVME_FEAT_FID_HOST_ID,
+ .cdw11 = 1 << 0, /* EXHID */
+ .result = TEST_RESULT,
+ };
+ int err;
+
+ arbitrary(hostid, sizeof(hostid));
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_set_features_host_id(TEST_FD, true, false, hostid);
+ end_mock_cmds();
+ check(err == 0, "set features returned error %d, errno %m", err);
+}
+
+static void test_get_host_id(void)
+{
+ uint8_t hostid[8], get_hostid[sizeof(hostid)] = {};
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_get_features,
+ .data_len = sizeof(hostid),
+ .cdw10 = TEST_SEL << 8 | NVME_FEAT_FID_HOST_ID,
+ .out_data = hostid,
+ .result = TEST_RESULT,
+ };
+ int err;
+
+ 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);
+ end_mock_cmds();
+ check(err == 0, "get features returned error %d, errno %m", err);
+ cmp(get_hostid, hostid, sizeof(hostid), "incorrect host identifier");
+}
+
+static void test_get_host_id_extended(void)
+{
+ uint8_t hostid[16], get_hostid[sizeof(hostid)] = {};
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_get_features,
+ .data_len = sizeof(hostid),
+ .cdw10 = TEST_SEL << 8 | NVME_FEAT_FID_HOST_ID,
+ .cdw11 = 1 << 0, /* EXHID */
+ .out_data = hostid,
+ .result = TEST_RESULT,
+ };
+ int err;
+
+ 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);
+ end_mock_cmds();
+ check(err == 0, "get features returned error %d, errno %m", err);
+ cmp(get_hostid, hostid, sizeof(hostid), "incorrect host identifier");
+}
+
+static void test_set_resv_mask(void)
+{
+ uint32_t MASK = 0x23456789;
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_set_features,
+ .nsid = TEST_NSID,
+ .cdw10 = (uint32_t)1 << 31 /* SAVE */
+ | NVME_FEAT_FID_RESV_MASK,
+ .cdw11 = MASK,
+ .result = TEST_RESULT,
+ };
+ uint32_t result = 0;
+ int err;
+
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_set_features_resv_mask2(
+ TEST_FD, TEST_NSID, MASK, true, &result);
+ end_mock_cmds();
+ check(err == 0, "set features returned error %d, errno %m", err);
+ check(result == TEST_RESULT,
+ "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT);
+}
+
+static void test_get_resv_mask(void)
+{
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_get_features,
+ .nsid = TEST_NSID,
+ .cdw10 = TEST_SEL << 8 | NVME_FEAT_FID_RESV_MASK,
+ .result = TEST_RESULT,
+ };
+ uint32_t result = 0;
+ int err;
+
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_get_features_resv_mask2(
+ TEST_FD, TEST_SEL, TEST_NSID, &result);
+ end_mock_cmds();
+ check(err == 0, "get features returned error %d, errno %m", err);
+ check(result == TEST_RESULT,
+ "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT);
+}
+
+static void test_set_resv_persist(void)
+{
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_set_features,
+ .nsid = TEST_NSID,
+ .cdw10 = NVME_FEAT_FID_RESV_PERSIST,
+ .cdw11 = 1 << 0, /* PTPL */
+ .result = TEST_RESULT,
+ };
+ uint32_t result = 0;
+ int err;
+
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_set_features_resv_persist2(
+ TEST_FD, TEST_NSID, true, false, &result);
+ end_mock_cmds();
+ check(err == 0, "set features returned error %d, errno %m", err);
+ check(result == TEST_RESULT,
+ "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT);
+}
+
+static void test_get_resv_persist(void)
+{
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_get_features,
+ .nsid = TEST_NSID,
+ .cdw10 = TEST_SEL << 8 | NVME_FEAT_FID_RESV_PERSIST,
+ .result = TEST_RESULT,
+ };
+ uint32_t result = 0;
+ int err;
+
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_get_features_resv_persist2(
+ TEST_FD, TEST_SEL, TEST_NSID, &result);
+ end_mock_cmds();
+ check(err == 0, "get features returned error %d, errno %m", err);
+ check(result == TEST_RESULT,
+ "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT);
+}
+
+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;
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_set_features,
+ .nsid = TEST_NSID,
+ .cdw10 = NVME_FEAT_FID_WRITE_PROTECT,
+ .cdw11 = STATE,
+ .result = TEST_RESULT,
+ };
+ uint32_t result = 0;
+ int err;
+
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_set_features_write_protect2(
+ TEST_FD, TEST_NSID, STATE, true, &result);
+ end_mock_cmds();
+ check(err == 0, "set features returned error %d, errno %m", err);
+ check(result == TEST_RESULT,
+ "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT);
+}
+
+static void test_get_write_protect(void)
+{
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_get_features,
+ .nsid = TEST_NSID,
+ .cdw10 = TEST_SEL << 8 | NVME_FEAT_FID_WRITE_PROTECT,
+ .result = TEST_RESULT,
+ };
+ uint32_t result = 0;
+ int err;
+
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_get_features_write_protect(
+ TEST_FD, TEST_NSID, TEST_SEL, &result);
+ end_mock_cmds();
+ check(err == 0, "get features returned error %d, errno %m", err);
+ check(result == TEST_RESULT,
+ "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT);
+}
+
+/*
+ * All set_features functions tail-call nvme_set_features(),
+ * so testing errors in any of them will do
+ */
+
+static void test_set_status_code_error(void)
+{
+ uint32_t EVENTS = 0x12345678;
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_set_features,
+ .cdw10 = NVME_FEAT_FID_ASYNC_EVENT,
+ .cdw11 = EVENTS,
+ .result = TEST_RESULT,
+ .err = TEST_SC,
+ };
+ uint32_t result = 0;
+ int err;
+
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_set_features_async_event(TEST_FD, EVENTS, false, &result);
+ end_mock_cmds();
+ check(err == TEST_SC, "got error %d, expected %d", err, TEST_SC);
+ check(result == TEST_RESULT,
+ "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT);
+}
+
+static void test_set_kernel_error(void)
+{
+ uint32_t MASK = 0x87654321;
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_set_features,
+ .nsid = TEST_NSID,
+ .cdw10 = NVME_FEAT_FID_RESV_MASK,
+ .cdw11 = MASK,
+ .result = TEST_RESULT,
+ .err = -EIO,
+ };
+ uint32_t result = 0;
+ int err;
+
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_set_features_resv_mask2(
+ TEST_FD, TEST_NSID, MASK, false, &result);
+ end_mock_cmds();
+ check(err == -1, "got error %d, expected -1", err);
+ check(errno == EIO, "unexpected error %m");
+ check(!result, "result unexpectedly set to %" PRIu32, result);
+}
+
+/*
+ * All get_features functions tail-call nvme_get_features(),
+ * so testing errors in any of them will do
+ */
+
+static void test_get_status_code_error(void)
+{
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_get_features,
+ .cdw10 = TEST_SEL << 8 | NVME_FEAT_FID_KATO,
+ .result = TEST_RESULT,
+ .err = TEST_SC,
+ };
+ uint32_t result = 0;
+ int err;
+
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_get_features_kato(TEST_FD, TEST_SEL, &result);
+ end_mock_cmds();
+ check(err == TEST_SC, "got error %d, expected %d", err, TEST_SC);
+ check(result == TEST_RESULT,
+ "got result %" PRIu32 ", expected %" PRIu32, result, TEST_RESULT);
+}
+
+static void test_get_kernel_error(void)
+{
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_get_features,
+ .cdw10 = TEST_SEL << 8 | NVME_FEAT_FID_NUM_QUEUES,
+ .result = TEST_RESULT,
+ .err = -EBUSY,
+ };
+ uint32_t result = 0;
+ int err;
+
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_get_features_num_queues(TEST_FD, TEST_SEL, &result);
+ end_mock_cmds();
+ check(err == -1, "got error %d, expected -1", err);
+ check(errno == EBUSY, "unexpected error %m");
+ check(!result, "result unexpectedly set to %" PRIu32, result);
+}
+
+static void run_test(const char *test_name, void (*test_fn)(void))
+{
+ printf("Running test %s...", test_name);
+ fflush(stdout);
+ test_fn();
+ puts(" OK");
+}
+
+#define RUN_TEST(name) run_test(#name, test_ ## name)
+
+int main(void)
+{
+ set_mock_fd(TEST_FD);
+ RUN_TEST(set_features);
+ RUN_TEST(get_features);
+ RUN_TEST(set_features_data);
+ RUN_TEST(get_features_data);
+ RUN_TEST(set_features_simple);
+ RUN_TEST(get_features_simple);
+ RUN_TEST(set_arbitration);
+ RUN_TEST(get_arbitration);
+ RUN_TEST(set_power_mgmt);
+ RUN_TEST(get_power_mgmt);
+ RUN_TEST(set_lba_range);
+ RUN_TEST(get_lba_range);
+ RUN_TEST(set_temp_thresh);
+ RUN_TEST(get_temp_thresh);
+ RUN_TEST(set_err_recovery);
+ RUN_TEST(get_err_recovery);
+ RUN_TEST(set_volatile_wc);
+ RUN_TEST(get_volatile_wc);
+ RUN_TEST(get_num_queues);
+ RUN_TEST(set_irq_coalesce);
+ RUN_TEST(get_irq_coalesce);
+ RUN_TEST(set_irq_config);
+ RUN_TEST(get_irq_config);
+ RUN_TEST(set_write_atomic);
+ RUN_TEST(get_write_atomic);
+ RUN_TEST(set_async_event);
+ RUN_TEST(get_async_event);
+ RUN_TEST(set_auto_pst);
+ RUN_TEST(get_auto_pst);
+ RUN_TEST(get_host_mem_buf);
+ RUN_TEST(set_timestamp);
+ RUN_TEST(get_timestamp);
+ RUN_TEST(get_kato);
+ RUN_TEST(set_hctm);
+ RUN_TEST(get_hctm);
+ RUN_TEST(set_nopsc);
+ RUN_TEST(get_nopsc);
+ RUN_TEST(set_rrl);
+ RUN_TEST(get_rrl);
+ RUN_TEST(set_plm_config);
+ RUN_TEST(get_plm_config);
+ RUN_TEST(set_plm_window);
+ RUN_TEST(get_plm_window);
+ RUN_TEST(set_lba_sts_interval);
+ RUN_TEST(get_lba_sts_interval);
+ RUN_TEST(set_host_behavior);
+ RUN_TEST(get_host_behavior);
+ RUN_TEST(set_sanitize);
+ RUN_TEST(get_sanitize);
+ RUN_TEST(set_endurance_evt_cfg);
+ RUN_TEST(get_endurance_event_cfg);
+ RUN_TEST(set_iocs_profile);
+ RUN_TEST(get_iocs_profile);
+ RUN_TEST(set_sw_progress);
+ RUN_TEST(get_sw_progress);
+ RUN_TEST(set_host_id);
+ RUN_TEST(set_host_id_extended);
+ RUN_TEST(get_host_id);
+ RUN_TEST(get_host_id_extended);
+ RUN_TEST(set_resv_mask);
+ RUN_TEST(get_resv_mask);
+ RUN_TEST(set_resv_persist);
+ RUN_TEST(get_resv_persist);
+ RUN_TEST(set_write_protect);
+ RUN_TEST(get_write_protect);
+ RUN_TEST(set_status_code_error);
+ RUN_TEST(set_kernel_error);
+ RUN_TEST(get_status_code_error);
+ RUN_TEST(get_kernel_error);
+}
diff --git a/test/ioctl/identify.c b/test/ioctl/identify.c
new file mode 100644
index 0000000..ccde02b
--- /dev/null
+++ b/test/ioctl/identify.c
@@ -0,0 +1,572 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+
+#include <libnvme.h>
+
+#include <errno.h>
+#include <stdlib.h>
+
+#include "mock.h"
+#include "util.h"
+
+#define TEST_FD 0xFD
+#define TEST_NSID 0x12345678
+#define TEST_NVMSETID 0xABCD
+#define TEST_UUID 123
+#define TEST_CSI NVME_CSI_KV
+#define TEST_CNTID 0x4321
+#define TEST_DOMID 0xFEDC
+#define TEST_ENDGID 0x0123
+#define TEST_SC NVME_SC_INVALID_FIELD
+
+static void test_ns(void)
+{
+ struct nvme_id_ns expected_id, id = {};
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_identify,
+ .nsid = TEST_NSID,
+ .data_len = sizeof(expected_id),
+ .cdw10 = NVME_IDENTIFY_CNS_NS,
+ .out_data = &expected_id,
+ };
+ int err;
+
+ arbitrary(&expected_id, sizeof(expected_id));
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_identify_ns(TEST_FD, 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");
+}
+
+static void test_ctrl(void)
+{
+ struct nvme_id_ctrl expected_id, id = {};
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_identify,
+ .data_len = sizeof(expected_id),
+ .cdw10 = NVME_IDENTIFY_CNS_CTRL,
+ .out_data = &expected_id,
+ };
+ int err;
+
+ arbitrary(&expected_id, sizeof(expected_id));
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_identify_ctrl(TEST_FD, &id);
+ end_mock_cmds();
+ check(err == 0, "identify returned error %d, errno %m", err);
+ cmp(&id, &expected_id, sizeof(id), "incorrect identify data");
+}
+
+static void test_active_ns_list(void)
+{
+ struct nvme_ns_list expected_id, id = {};
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_identify,
+ .nsid = TEST_NSID,
+ .data_len = sizeof(expected_id),
+ .cdw10 = NVME_IDENTIFY_CNS_NS_ACTIVE_LIST,
+ .out_data = &expected_id,
+ };
+ int err;
+
+ 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);
+ end_mock_cmds();
+ check(err == 0, "identify returned error %d, errno %m", err);
+ cmp(&id, &expected_id, sizeof(id), "incorrect identify data");
+}
+
+static void test_ns_descs(void)
+{
+ uint8_t expected_id[NVME_IDENTIFY_DATA_SIZE];
+ struct nvme_ns_id_desc *id;
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_identify,
+ .nsid = TEST_NSID,
+ .data_len = sizeof(expected_id),
+ .cdw10 = NVME_IDENTIFY_CNS_NS_DESC_LIST,
+ .out_data = &expected_id,
+ };
+ int err;
+
+ arbitrary(expected_id, sizeof(expected_id));
+ 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);
+ end_mock_cmds();
+ check(err == 0, "identify returned error %d, errno %m", err);
+ cmp(id, expected_id, sizeof(expected_id), "incorrect identify data");
+ free(id);
+}
+
+static void test_nvmset_list(void)
+{
+ struct nvme_id_nvmset_list expected_id, id = {};
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_identify,
+ .data_len = sizeof(expected_id),
+ .cdw10 = NVME_IDENTIFY_CNS_NVMSET_LIST,
+ .cdw11 = TEST_NVMSETID,
+ .out_data = &expected_id,
+ };
+ int err;
+
+ arbitrary(&expected_id, sizeof(expected_id));
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_identify_nvmset_list(TEST_FD, TEST_NVMSETID, &id);
+ end_mock_cmds();
+ check(err == 0, "identify returned error %d, errno %m", err);
+ cmp(&id, &expected_id, sizeof(id), "incorrect identify data");
+}
+
+static void test_ns_csi(void)
+{
+ uint8_t expected_id[NVME_IDENTIFY_DATA_SIZE];
+ uint8_t id[NVME_IDENTIFY_DATA_SIZE] = {};
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_identify,
+ .nsid = TEST_NSID,
+ .data_len = sizeof(expected_id),
+ .cdw10 = NVME_IDENTIFY_CNS_CSI_NS,
+ .cdw11 = TEST_CSI << 24,
+ .cdw14 = TEST_UUID,
+ .out_data = expected_id,
+ };
+ int err;
+
+ 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);
+ end_mock_cmds();
+ check(err == 0, "identify returned error %d, errno %m", err);
+ cmp(id, expected_id, sizeof(id), "incorrect identify data");
+}
+
+static void test_zns_identify_ns(void)
+{
+ struct nvme_zns_id_ns expected_id, id = {};
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_identify,
+ .nsid = TEST_NSID,
+ .data_len = sizeof(expected_id),
+ .cdw10 = NVME_IDENTIFY_CNS_CSI_NS,
+ .cdw11 = NVME_CSI_ZNS << 24,
+ .out_data = &expected_id,
+ };
+ int err;
+
+ arbitrary(&expected_id, sizeof(expected_id));
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_zns_identify_ns(TEST_FD, 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");
+}
+
+static void test_nvm_identify_ctrl(void)
+{
+ struct nvme_id_ctrl_nvm expected_id, id = {};
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_identify,
+ .data_len = sizeof(expected_id),
+ .cdw10 = NVME_IDENTIFY_CNS_CSI_CTRL,
+ .cdw11 = NVME_CSI_NVM << 24,
+ .out_data = &expected_id,
+ };
+ int err;
+
+ arbitrary(&expected_id, sizeof(expected_id));
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_nvm_identify_ctrl(TEST_FD, &id);
+ end_mock_cmds();
+ check(err == 0, "identify returned error %d, errno %m", err);
+ cmp(&id, &expected_id, sizeof(id), "incorrect identify data");
+}
+
+static void test_zns_identify_ctrl(void)
+{
+ struct nvme_zns_id_ctrl expected_id, id = {};
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_identify,
+ .data_len = sizeof(expected_id),
+ .cdw10 = NVME_IDENTIFY_CNS_CSI_CTRL,
+ .cdw11 = NVME_CSI_ZNS << 24,
+ .out_data = &expected_id,
+ };
+ int err;
+
+ arbitrary(&expected_id, sizeof(expected_id));
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_zns_identify_ctrl(TEST_FD, &id);
+ end_mock_cmds();
+ check(err == 0, "identify returned error %d, errno %m", err);
+ cmp(&id, &expected_id, sizeof(id), "incorrect identify data");
+}
+
+static void test_active_ns_list_csi(void)
+{
+ struct nvme_ns_list expected_id, id = {};
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_identify,
+ .nsid = TEST_NSID,
+ .data_len = sizeof(expected_id),
+ .cdw10 = NVME_IDENTIFY_CNS_CSI_NS_ACTIVE_LIST,
+ .cdw11 = TEST_CSI << 24,
+ .out_data = &expected_id,
+ };
+ int err;
+
+ 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);
+ end_mock_cmds();
+ check(err == 0, "identify returned error %d, errno %m", err);
+ cmp(&id, &expected_id, sizeof(id), "incorrect identify data");
+}
+
+static void test_independent_identify_ns(void)
+{
+ struct nvme_id_independent_id_ns expected_id, id = {};
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_identify,
+ .nsid = TEST_NSID,
+ .data_len = sizeof(expected_id),
+ .cdw10 = NVME_IDENTIFY_CNS_CSI_INDEPENDENT_ID_NS,
+ .out_data = &expected_id,
+ };
+ int err;
+
+ 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);
+ end_mock_cmds();
+ check(err == 0, "identify returned error %d, errno %m", err);
+ cmp(&id, &expected_id, sizeof(id), "incorrect identify data");
+}
+
+static void test_allocated_ns_list(void)
+{
+ struct nvme_ns_list expected_id, id = {};
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_identify,
+ .nsid = TEST_NSID,
+ .data_len = sizeof(expected_id),
+ .cdw10 = NVME_IDENTIFY_CNS_ALLOCATED_NS_LIST,
+ .out_data = &expected_id,
+ };
+ int err;
+
+ 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);
+ end_mock_cmds();
+ check(err == 0, "identify returned error %d, errno %m", err);
+ cmp(&id, &expected_id, sizeof(id), "incorrect identify data");
+}
+
+static void test_allocated_ns(void)
+{
+ struct nvme_id_ns expected_id, id = {};
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_identify,
+ .nsid = TEST_NSID,
+ .data_len = sizeof(expected_id),
+ .cdw10 = NVME_IDENTIFY_CNS_ALLOCATED_NS,
+ .out_data = &expected_id,
+ };
+ int err;
+
+ arbitrary(&expected_id, sizeof(expected_id));
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_identify_allocated_ns(TEST_FD, 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");
+}
+
+static void test_nsid_ctrl_list(void)
+{
+ struct nvme_ctrl_list expected_id, id = {};
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_identify,
+ .nsid = TEST_NSID,
+ .data_len = sizeof(expected_id),
+ .cdw10 = TEST_CNTID << 16
+ | NVME_IDENTIFY_CNS_NS_CTRL_LIST,
+ .out_data = &expected_id,
+ };
+ int err;
+
+ 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);
+ end_mock_cmds();
+ check(err == 0, "identify returned error %d, errno %m", err);
+ cmp(&id, &expected_id, sizeof(id), "incorrect identify data");
+}
+
+static void test_ctrl_list(void)
+{
+ struct nvme_ctrl_list expected_id, id = {};
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_identify,
+ .data_len = sizeof(expected_id),
+ .cdw10 = TEST_CNTID << 16
+ | NVME_IDENTIFY_CNS_CTRL_LIST,
+ .out_data = &expected_id,
+ };
+ int err;
+
+ arbitrary(&expected_id, sizeof(expected_id));
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_identify_ctrl_list(TEST_FD, TEST_CNTID, &id);
+ end_mock_cmds();
+ check(err == 0, "identify returned error %d, errno %m", err);
+ cmp(&id, &expected_id, sizeof(id), "incorrect identify data");
+}
+
+static void test_primary_ctrl(void)
+{
+ struct nvme_primary_ctrl_cap expected_id, id = {};
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_identify,
+ .data_len = sizeof(expected_id),
+ .cdw10 = TEST_CNTID << 16
+ | NVME_IDENTIFY_CNS_PRIMARY_CTRL_CAP,
+ .out_data = &expected_id,
+ };
+ int err;
+
+ arbitrary(&expected_id, sizeof(expected_id));
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_identify_primary_ctrl(TEST_FD, TEST_CNTID, &id);
+ end_mock_cmds();
+ check(err == 0, "identify returned error %d, errno %m", err);
+ cmp(&id, &expected_id, sizeof(id), "incorrect identify data");
+}
+
+static void test_secondary_ctrl_list(void)
+{
+ struct nvme_secondary_ctrl_list expected_id, id = {};
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_identify,
+ .data_len = sizeof(expected_id),
+ .cdw10 = TEST_CNTID << 16
+ | NVME_IDENTIFY_CNS_SECONDARY_CTRL_LIST,
+ .out_data = &expected_id,
+ };
+ int err;
+
+ 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);
+ end_mock_cmds();
+ check(err == 0, "identify returned error %d, errno %m", err);
+ cmp(&id, &expected_id, sizeof(id), "incorrect identify data");
+}
+
+static void test_ns_granularity(void)
+{
+ struct nvme_id_ns_granularity_list expected_id, id = {};
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_identify,
+ .data_len = sizeof(expected_id),
+ .cdw10 = NVME_IDENTIFY_CNS_NS_GRANULARITY,
+ .out_data = &expected_id,
+ };
+ int err;
+
+ arbitrary(&expected_id, sizeof(expected_id));
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_identify_ns_granularity(TEST_FD, &id);
+ end_mock_cmds();
+ check(err == 0, "identify returned error %d, errno %m", err);
+ cmp(&id, &expected_id, sizeof(id), "incorrect identify data");
+}
+
+static void test_uuid(void)
+{
+ struct nvme_id_uuid_list expected_id, id = {};
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_identify,
+ .data_len = sizeof(expected_id),
+ .cdw10 = NVME_IDENTIFY_CNS_UUID_LIST,
+ .out_data = &expected_id,
+ };
+ int err;
+
+ arbitrary(&expected_id, sizeof(expected_id));
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_identify_uuid(TEST_FD, &id);
+ end_mock_cmds();
+ check(err == 0, "identify returned error %d, errno %m", err);
+ cmp(&id, &expected_id, sizeof(id), "incorrect identify data");
+}
+
+static void test_domain_list(void)
+{
+ struct nvme_id_domain_list expected_id, id = {};
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_identify,
+ .data_len = sizeof(expected_id),
+ .cdw10 = NVME_IDENTIFY_CNS_DOMAIN_LIST,
+ .cdw11 = TEST_DOMID,
+ .out_data = &expected_id,
+ };
+ int err;
+
+ arbitrary(&expected_id, sizeof(expected_id));
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_identify_domain_list(TEST_FD, TEST_DOMID, &id);
+ end_mock_cmds();
+ check(err == 0, "identify returned error %d, errno %m", err);
+ cmp(&id, &expected_id, sizeof(id), "incorrect identify data");
+}
+
+static void test_endurance_group_list(void)
+{
+ struct nvme_id_endurance_group_list expected_id, id = {};
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_identify,
+ .data_len = sizeof(expected_id),
+ .cdw10 = NVME_IDENTIFY_CNS_ENDURANCE_GROUP_ID,
+ .cdw11 = TEST_ENDGID,
+ .out_data = &expected_id,
+ };
+ int err;
+
+ 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);
+ end_mock_cmds();
+ check(err == 0, "identify returned error %d, errno %m", err);
+ cmp(&id, &expected_id, sizeof(id), "incorrect identify data");
+}
+
+static void test_allocated_ns_list_csi(void)
+{
+ struct nvme_ns_list expected_id, id = {};
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_identify,
+ .nsid = TEST_NSID,
+ .data_len = sizeof(expected_id),
+ .cdw10 = NVME_IDENTIFY_CNS_CSI_ALLOCATED_NS_LIST,
+ .cdw11 = TEST_CSI << 24,
+ .out_data = &expected_id,
+ };
+ int err;
+
+ 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);
+ end_mock_cmds();
+ check(err == 0, "identify returned error %d, errno %m", err);
+ cmp(&id, &expected_id, sizeof(id), "incorrect identify data");
+}
+
+static void test_iocs(void)
+{
+ struct nvme_id_iocs expected_id, id = {};
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_identify,
+ .data_len = sizeof(expected_id),
+ .cdw10 = TEST_CNTID << 16
+ | NVME_IDENTIFY_CNS_COMMAND_SET_STRUCTURE,
+ .out_data = &expected_id,
+ };
+ int err;
+
+ arbitrary(&expected_id, sizeof(expected_id));
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_identify_iocs(TEST_FD, TEST_CNTID, &id);
+ end_mock_cmds();
+ check(err == 0, "identify returned error %d, errno %m", err);
+ cmp(&id, &expected_id, sizeof(id), "incorrect identify data");
+}
+
+/*
+ * All identify functions tail-call nvme_identify(),
+ * so testing errors in any of them will do
+ */
+
+static void test_status_code_error(void)
+{
+ struct nvme_id_nvmset_list id = {};
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_identify,
+ .data_len = sizeof(id),
+ .cdw10 = NVME_IDENTIFY_CNS_NVMSET_LIST,
+ .cdw11 = TEST_NVMSETID,
+ .err = TEST_SC,
+ };
+ int err;
+
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_identify_nvmset_list(TEST_FD, TEST_NVMSETID, &id);
+ end_mock_cmds();
+ check(err == TEST_SC, "got error %d, expected %d", err, TEST_SC);
+}
+
+static void test_kernel_error(void)
+{
+ struct nvme_id_ns id = {};
+ struct mock_cmd mock_admin_cmd = {
+ .opcode = nvme_admin_identify,
+ .nsid = TEST_NSID,
+ .data_len = sizeof(id),
+ .cdw10 = NVME_IDENTIFY_CNS_NS,
+ .err = -EIO,
+ };
+ int err;
+
+ set_mock_admin_cmds(&mock_admin_cmd, 1);
+ err = nvme_identify_ns(TEST_FD, TEST_NSID, &id);
+ end_mock_cmds();
+ check(err == -1, "got error %d, expected -1", err);
+ check(errno == EIO, "unexpected error %m");
+}
+
+static void run_test(const char *test_name, void (*test_fn)(void))
+{
+ printf("Running test %s...", test_name);
+ fflush(stdout);
+ test_fn();
+ puts(" OK");
+}
+
+#define RUN_TEST(name) run_test(#name, test_ ## name)
+
+int main(void)
+{
+ set_mock_fd(TEST_FD);
+ RUN_TEST(ns);
+ RUN_TEST(ctrl);
+ RUN_TEST(active_ns_list);
+ RUN_TEST(ns_descs);
+ RUN_TEST(nvmset_list);
+ RUN_TEST(ns_csi);
+ RUN_TEST(zns_identify_ns);
+ RUN_TEST(nvm_identify_ctrl);
+ RUN_TEST(zns_identify_ctrl);
+ RUN_TEST(active_ns_list_csi);
+ RUN_TEST(independent_identify_ns);
+ RUN_TEST(allocated_ns_list);
+ RUN_TEST(allocated_ns);
+ RUN_TEST(nsid_ctrl_list);
+ RUN_TEST(ctrl_list);
+ RUN_TEST(primary_ctrl);
+ RUN_TEST(secondary_ctrl_list);
+ RUN_TEST(ns_granularity);
+ RUN_TEST(uuid);
+ RUN_TEST(domain_list);
+ RUN_TEST(endurance_group_list);
+ RUN_TEST(allocated_ns_list_csi);
+ RUN_TEST(iocs);
+ RUN_TEST(status_code_error);
+ RUN_TEST(kernel_error);
+}
diff --git a/test/ioctl/meson.build b/test/ioctl/meson.build
new file mode 100644
index 0000000..b329d27
--- /dev/null
+++ b/test/ioctl/meson.build
@@ -0,0 +1,42 @@
+mock_ioctl = library(
+ 'mock-ioctl',
+ ['mock.c', 'util.c'],
+)
+
+# Add mock-ioctl to the LD_PRELOAD path so it overrides libc.
+# Append to LD_PRELOAD so existing libraries, e.g. libasan, are kept.
+# If libasan isn't specified in the LD_PRELOAD path, ASAN warns about mock-ioctl
+# being loaded first because its memory allocations might not get intercepted.
+# But it appears this isn't a problem; ASAN errors in mock-ioctl are reported.
+# This is likely because the executable still links with libasan before libc.
+mock_ioctl_env = environment()
+mock_ioctl_env.append('LD_PRELOAD', mock_ioctl.full_path())
+mock_ioctl_env.set('ASAN_OPTIONS', 'verify_asan_link_order=0')
+
+discovery = executable(
+ 'test-discovery',
+ 'discovery.c',
+ dependencies: libnvme_dep,
+ include_directories: [incdir, internal_incdir],
+ link_with: mock_ioctl,
+)
+
+test('discovery', discovery, env: mock_ioctl_env)
+
+features = executable(
+ 'test-features',
+ 'features.c',
+ dependencies: libnvme_dep,
+ link_with: mock_ioctl,
+)
+
+test('features', features, env: mock_ioctl_env)
+
+identify = executable(
+ 'test-identify',
+ 'identify.c',
+ dependencies: libnvme_dep,
+ link_with: mock_ioctl,
+)
+
+test('identify', identify, env: mock_ioctl_env)
diff --git a/test/ioctl/mock.c b/test/ioctl/mock.c
new file mode 100644
index 0000000..a97a357
--- /dev/null
+++ b/test/ioctl/mock.c
@@ -0,0 +1,174 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+
+#include "mock.h"
+
+#include <errno.h>
+#include <inttypes.h>
+#include <stdarg.h>
+#include <string.h>
+#include <sys/ioctl.h>
+
+#include "../../src/nvme/ioctl.h"
+#include "util.h"
+
+struct mock_cmds {
+ const char *name;
+ const struct mock_cmd *cmds;
+ size_t remaining_cmds;
+};
+
+static int mock_fd = -1;
+static struct mock_cmds mock_admin_cmds = {.name = "admin"};
+static struct mock_cmds mock_io_cmds = {.name = "IO"};
+
+static void set_mock_cmds(
+ struct mock_cmds *mock_cmds, const struct mock_cmd *cmds, size_t len)
+{
+ mock_cmds->cmds = cmds;
+ mock_cmds->remaining_cmds = len;
+}
+
+static void mock_cmds_done(const struct mock_cmds *mock_cmds)
+{
+ check(!mock_cmds->remaining_cmds,
+ "%zu %s commands not executed",
+ mock_cmds->remaining_cmds, mock_cmds->name);
+}
+
+void set_mock_fd(int fd)
+{
+ mock_fd = fd;
+}
+
+void set_mock_admin_cmds(const struct mock_cmd *cmds, size_t len)
+{
+ set_mock_cmds(&mock_admin_cmds, cmds, len);
+}
+
+void set_mock_io_cmds(const struct mock_cmd *cmds, size_t len)
+{
+ set_mock_cmds(&mock_io_cmds, cmds, len);
+}
+
+void end_mock_cmds(void)
+{
+ mock_cmds_done(&mock_admin_cmds);
+ mock_cmds_done(&mock_io_cmds);
+}
+
+#define execute_ioctl(cmd, mock_cmd) ({ \
+ check((cmd)->opcode == (mock_cmd)->opcode, \
+ "got opcode %" PRIu8 ", expected %" PRIu8, \
+ (cmd)->opcode, (mock_cmd)->opcode); \
+ check((cmd)->flags == (mock_cmd)->flags, \
+ "got flags %" PRIu8 ", expected %" PRIu8, \
+ (cmd)->flags, (mock_cmd)->flags); \
+ check((cmd)->nsid == (mock_cmd)->nsid, \
+ "got nsid %" PRIu32 ", expected %" PRIu32, \
+ (cmd)->nsid, (mock_cmd)->nsid); \
+ check((cmd)->cdw2 == (mock_cmd)->cdw2, \
+ "got cdw2 %" PRIu32 ", expected %" PRIu32, \
+ (cmd)->cdw2, (mock_cmd)->cdw2); \
+ check((cmd)->cdw3 == (mock_cmd)->cdw3, \
+ "got cdw3 %" PRIu32 ", expected %" PRIu32, \
+ (cmd)->cdw3, (mock_cmd)->cdw3); \
+ check((cmd)->metadata_len == (mock_cmd)->metadata_len, \
+ "got metadata_len %" PRIu32 ", expected %" PRIu32, \
+ (cmd)->metadata_len, (mock_cmd)->metadata_len); \
+ if ((cmd)->metadata_len) { \
+ cmp((void const *)(uintptr_t)(cmd)->metadata, \
+ (mock_cmd)->metadata, \
+ (cmd)->metadata_len, \
+ "incorrect metadata"); \
+ } \
+ __u32 data_len = (cmd)->data_len; \
+ check(data_len == (mock_cmd)->data_len, \
+ "got data_len %" PRIu32 ", expected %" PRIu32, \
+ data_len, (mock_cmd)->data_len); \
+ void *data = (void *)(uintptr_t)(cmd)->addr; \
+ if ((mock_cmd)->in_data) { \
+ cmp(data, (mock_cmd)->in_data, data_len, "incorrect data"); \
+ } \
+ check((cmd)->cdw10 == (mock_cmd)->cdw10, \
+ "got cdw10 %" PRIu32 ", expected %" PRIu32, \
+ (cmd)->cdw10, (mock_cmd)->cdw10); \
+ check((cmd)->cdw11 == (mock_cmd)->cdw11, \
+ "got cdw11 %" PRIu32 ", expected %" PRIu32, \
+ (cmd)->cdw11, (mock_cmd)->cdw11); \
+ check((cmd)->cdw12 == (mock_cmd)->cdw12, \
+ "got cdw12 %" PRIu32 ", expected %" PRIu32, \
+ (cmd)->cdw12, (mock_cmd)->cdw12); \
+ check((cmd)->cdw13 == (mock_cmd)->cdw13, \
+ "got cdw13 %" PRIu32 ", expected %" PRIu32, \
+ (cmd)->cdw13, (mock_cmd)->cdw13); \
+ check((cmd)->cdw14 == (mock_cmd)->cdw14, \
+ "got cdw14 %" PRIu32 ", expected %" PRIu32, \
+ (cmd)->cdw14, (mock_cmd)->cdw14); \
+ check((cmd)->cdw15 == (mock_cmd)->cdw15, \
+ "got cdw15 %" PRIu32 ", expected %" PRIu32, \
+ (cmd)->cdw15, (mock_cmd)->cdw15); \
+ check((cmd)->timeout_ms == (mock_cmd)->timeout_ms, \
+ "got timeout_ms %" PRIu32 ", expected %" PRIu32, \
+ (cmd)->timeout_ms, (mock_cmd)->timeout_ms); \
+ (cmd)->result = (mock_cmd)->result; \
+ if ((mock_cmd)->out_data) { \
+ memcpy(data, (mock_cmd)->out_data, data_len); \
+ } \
+})
+
+#ifdef HAVE_GLIBC_IOCTL
+int ioctl(int fd, unsigned long request, ...)
+#else
+int ioctl(int fd, int request, ...)
+#endif
+{
+ struct mock_cmds *mock_cmds;
+ bool result64;
+ const struct mock_cmd *mock_cmd;
+ va_list args;
+ void *cmd;
+
+ check(fd == mock_fd, "got fd %d, expected %d", fd, mock_fd);
+ switch (request) {
+ case NVME_IOCTL_ADMIN_CMD:
+ mock_cmds = &mock_admin_cmds;
+ result64 = false;
+ break;
+ case NVME_IOCTL_ADMIN64_CMD:
+ mock_cmds = &mock_admin_cmds;
+ result64 = true;
+ break;
+ case NVME_IOCTL_IO_CMD:
+ mock_cmds = &mock_io_cmds;
+ result64 = false;
+ break;
+ case NVME_IOCTL_IO64_CMD:
+ mock_cmds = &mock_io_cmds;
+ result64 = true;
+ break;
+ default:
+ fail("unexpected %s %lu", __func__, (unsigned long) request);
+ }
+ check(mock_cmds->remaining_cmds,
+ "unexpected %s command", mock_cmds->name);
+ mock_cmd = mock_cmds->cmds++;
+ mock_cmds->remaining_cmds--;
+
+ va_start(args, request);
+ cmd = va_arg(args, void *);
+ va_end(args);
+ if (result64) {
+ execute_ioctl((struct nvme_passthru_cmd64 *)cmd, mock_cmd);
+ } else {
+ check((uint32_t)mock_cmd->result == mock_cmd->result,
+ "expected 64-bit %s for result %" PRIu64,
+ __func__, mock_cmd->result);
+ execute_ioctl((struct nvme_passthru_cmd *)cmd, mock_cmd);
+ }
+ if (mock_cmd->err < 0) {
+ errno = -mock_cmd->err;
+ return -1;
+ }
+
+ return mock_cmd->err;
+}
diff --git a/test/ioctl/mock.h b/test/ioctl/mock.h
new file mode 100644
index 0000000..192eba8
--- /dev/null
+++ b/test/ioctl/mock.h
@@ -0,0 +1,104 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#ifndef _LIBNVME_TEST_IOCTL_MOCK_H
+#define _LIBNVME_TEST_IOCTL_MOCK_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+/**
+ * struct mock_cmd - a mock NVMe passthru ioctl() invocation
+ * @opcode: the expected `opcode` passed to ioctl()
+ * @flags: the expected `flags` passed to ioctl()
+ * @nsid: the expected `nsid` passed to ioctl()
+ * @cdw2: the expected `cdw2` passed to ioctl()
+ * @cdw3: the expected `cdw3` passed to ioctl()
+ * @metadata: the expected `metadata` of length `metadata_len` passed to ioctl()
+ * @in_data: the expected `addr` of length `data_len` passed to ioctl().
+ * Set this to NULL to skip checking the data,
+ * for example if the command is in the read direction.
+ * @metadata_len: the expected `metadata_len` passed to ioctl()
+ * @data_len: the expected `data_len` passed to ioctl()
+ * @cdw10: the expected `cdw10` passed to ioctl()
+ * @cdw11: the expected `cdw11` passed to ioctl()
+ * @cdw12: the expected `cdw12` passed to ioctl()
+ * @cdw13: the expected `cdw13` passed to ioctl()
+ * @cdw14: the expected `cdw14` passed to ioctl()
+ * @cdw15: the expected `cdw15` passed to ioctl()
+ * @timeout_ms: the expected `timeout_ms` passed to ioctl()
+ * @out_data: if not NULL, `data_len` bytes to copy to the caller's `addr`
+ * @result: copied to the caller's `result`.
+ * If `result` doesn't fit in a u32, the ioctl() must be the 64-bit one.
+ * @err: If negative, ioctl() returns -1 and sets `errno` to `-err`.
+ * Otherwise, ioctl() returns `err`, representing a NVMe status code.
+ */
+struct mock_cmd {
+ uint8_t opcode;
+ uint8_t flags;
+ uint32_t nsid;
+ uint32_t cdw2;
+ uint32_t cdw3;
+ const void *metadata;
+ const void *in_data;
+ uint32_t metadata_len;
+ uint32_t data_len;
+ uint32_t cdw10;
+ uint32_t cdw11;
+ uint32_t cdw12;
+ uint32_t cdw13;
+ uint32_t cdw14;
+ uint32_t cdw15;
+ uint32_t timeout_ms;
+ const void *out_data;
+ uint64_t result;
+ int err;
+};
+
+/**
+ * set_mock_fd() - sets the expected file descriptor for NVMe passthru ioctls()
+ * @fd: file descriptor expected to be passed to ioctl()
+ */
+void set_mock_fd(int fd);
+
+/**
+ * set_mock_admin_cmds() - mocks NVMe admin passthru ioctl() invocations
+ * @cmds: pointer to start of the mock_cmd slice
+ * @len: length of the mock_cmd slice (number of ioctl() invocations)
+ *
+ * Provides a sequence of mocks for NVMe admin passthru ioctl() invocations.
+ * Each ioctl() consumes the next mock from the sequence.
+ * Its arguments are checked against the mock's expected arguments,
+ * aborting the process if unexpected arguments are passed.
+ * The mock results (return value, NVMe result and data)
+ * are returned from the ioctl().
+ *
+ * Analogous to set_mock_io_cmds(), but for admin commands.
+ * Both admin and IO mocks can be active at the same time.
+ */
+void set_mock_admin_cmds(const struct mock_cmd *cmds, size_t len);
+
+/**
+ * set_mock_io_cmds() - mocks NVMe IO passthru ioctl() invocations
+ * @cmds: pointer to start of the mock_cmd slice
+ * @len: length of the mock_cmd slice (number of ioctl() invocations)
+ *
+ * Provides a sequence of mocks for NVMe IO passthru ioctl() invocations.
+ * Each ioctl() consumes the next mock from the sequence.
+ * Its arguments are checked against the mock's expected arguments,
+ * aborting the process if unexpected arguments are passed.
+ * The mock results (return value, NVMe result and data)
+ * are returned from the ioctl().
+ *
+ * Analogous to set_mock_admin_cmds(), but for IO commands.
+ * Both admin and IO mocks can be active at the same time.
+ */
+void set_mock_io_cmds(const struct mock_cmd *cmds, size_t len);
+
+/**
+ * end_mock_cmds() - finishes mocking NVMe passthru ioctl() invocations
+ *
+ * Checks that all mock ioctl() invocations were performed.
+ */
+void end_mock_cmds(void);
+
+#endif /* #ifndef _LIBNVME_TEST_IOCTL_MOCK_H */
diff --git a/test/ioctl/util.c b/test/ioctl/util.c
new file mode 100644
index 0000000..09c6e7f
--- /dev/null
+++ b/test/ioctl/util.c
@@ -0,0 +1,65 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+
+#include "util.h"
+
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static void hexdump(const uint8_t *buf, size_t len)
+{
+ size_t i = 0;
+
+ if (!len)
+ return;
+
+ for (;;) {
+ fprintf(stderr, "%02X", buf[i++]);
+ if (i >= len)
+ break;
+
+ fputc(i % 16 > 0 ? ' ' : '\n', stderr);
+ }
+ fputc('\n', stderr);
+}
+
+void fail(const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ fputc('\n', stderr);
+ abort();
+}
+
+void cmp(const void *actual, const void *expected, size_t len, const char *msg)
+{
+ if (memcmp(actual, expected, len) == 0)
+ return;
+
+ fputs(msg, stderr);
+ fputs("\nactual:\n", stderr);
+ hexdump(actual, len);
+ fputs("expected:\n", stderr);
+ hexdump(expected, len);
+ abort();
+}
+
+void arbitrary(void *buf_, size_t len)
+{
+ uint8_t *buf = buf_;
+
+ while (len--)
+ *(buf++) = rand();
+}
+
+size_t arbitrary_range(size_t max)
+{
+ size_t value;
+ arbitrary(&value, sizeof(value));
+ return value % max;
+}
diff --git a/test/ioctl/util.h b/test/ioctl/util.h
new file mode 100644
index 0000000..aa86422
--- /dev/null
+++ b/test/ioctl/util.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#ifndef _LIBNVME_TEST_IOCTL_UTIL_H
+#define _LIBNVME_TEST_IOCTL_UTIL_H
+
+#include <stddef.h>
+#include <stdnoreturn.h>
+
+noreturn void fail(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
+
+#define check(condition, fmt...) ((condition) || (fail(fmt), 0))
+
+void cmp(const void *actual, const void *expected, size_t len, const char *msg);
+
+void arbitrary(void *buf, size_t len);
+
+size_t arbitrary_range(size_t max);
+
+#endif /* #ifndef _LIBNVME_TEST_IOCTL_UTIL_H */
diff --git a/test/meson.build b/test/meson.build
index 49cd1ac..2b4c6d8 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -67,21 +67,33 @@ uuid = executable(
test('uuid', uuid)
if conf.get('HAVE_NETDB')
+ mock_ifaddrs = library(
+ 'mock-ifaddrs',
+ ['mock-ifaddrs.c', ],
+ )
+
+ # See comment in test/ioctl/meson.build explaining how LD_PRELOAD is used
+ mock_ifaddrs_env = environment()
+ mock_ifaddrs_env.append('LD_PRELOAD', mock_ifaddrs.full_path())
+ mock_ifaddrs_env.set('ASAN_OPTIONS', 'verify_asan_link_order=0')
+
tree = executable(
'tree',
['tree.c'],
dependencies: libnvme_dep,
- include_directories: [incdir, internal_incdir]
+ include_directories: [incdir, internal_incdir],
+ link_with: mock_ifaddrs,
)
- test('tree', tree)
+ test('tree', tree, env: mock_ifaddrs_env)
test_util = executable(
'test-util',
['test-util.c'],
include_directories: [incdir, internal_incdir]
)
- test('Test util.c', test_util)
+ test('util', test_util)
endif
+subdir('ioctl')
subdir('nbft')
diff --git a/test/mi-mctp.c b/test/mi-mctp.c
index 6d83d42..5711c03 100644
--- a/test/mi-mctp.c
+++ b/test/mi-mctp.c
@@ -83,12 +83,14 @@ static void test_set_tx_mic(struct test_peer *peer)
{
extern __u32 nvme_mi_crc32_update(__u32 crc, void *data, size_t len);
__u32 crc = 0xffffffff;
+ __le32 crc_le;
- assert(peer->tx_buf_len + sizeof(crc) <= MAX_BUFSIZ);
+ assert(peer->tx_buf_len + sizeof(crc_le) <= MAX_BUFSIZ);
crc = nvme_mi_crc32_update(crc, peer->tx_buf, peer->tx_buf_len);
- *(uint32_t *)(peer->tx_buf + peer->tx_buf_len) = cpu_to_le32(~crc);
- peer->tx_buf_len += sizeof(crc);
+ crc_le = cpu_to_le32(~crc);
+ memcpy(peer->tx_buf + peer->tx_buf_len, &crc_le, sizeof(crc_le));
+ peer->tx_buf_len += sizeof(crc_le);
}
int __wrap_socket(int family, int type, int protocol)
@@ -293,6 +295,89 @@ static void test_mi_resp_err(nvme_mi_ep_t ep, struct test_peer *peer)
assert(rc == 0x2);
}
+static void setup_unaligned_ctrl_list_resp(struct test_peer *peer)
+{
+ /* even number of controllers */
+ peer->tx_buf[8] = 0x02;
+ peer->tx_buf[9] = 0x00;
+
+ /* controller ID 1 */
+ peer->tx_buf[10] = 0x01;
+ peer->tx_buf[11] = 0x00;
+
+ /* controller ID 2 */
+ peer->tx_buf[12] = 0x02;
+ peer->tx_buf[13] = 0x00;
+
+ peer->tx_buf_len = 14;
+}
+
+/* Will call through the xfer/submit API expecting a full-sized list (so
+ * resp->data_len is set to sizeof(list)), but the endpoint will return an
+ * unaligned short list.
+ */
+static void test_mi_resp_unaligned(nvme_mi_ep_t ep, struct test_peer *peer)
+{
+ struct nvme_ctrl_list list;
+ int rc;
+
+ setup_unaligned_ctrl_list_resp(peer);
+
+ memset(&list, 0, sizeof(list));
+
+ rc = nvme_mi_mi_read_mi_data_ctrl_list(ep, 0, &list);
+ assert(rc == 0);
+
+ assert(le16_to_cpu(list.num) == 2);
+ assert(le16_to_cpu(list.identifier[0]) == 1);
+ assert(le16_to_cpu(list.identifier[1]) == 2);
+}
+
+/* Will call through the xfer/submit API expecting an unaligned list,
+ * and get a response of exactly that size.
+ */
+static void test_mi_resp_unaligned_expected(nvme_mi_ep_t ep,
+ struct test_peer *peer)
+{
+ /* direct access to the raw submit() API */
+ extern int nvme_mi_submit(nvme_mi_ep_t ep, struct nvme_mi_req *req,
+ struct nvme_mi_resp *resp);
+ struct nvme_mi_mi_resp_hdr resp_hdr;
+ struct nvme_mi_mi_req_hdr req_hdr;
+ struct nvme_ctrl_list list;
+ struct nvme_mi_resp resp;
+ struct nvme_mi_req req;
+ int rc;
+
+ setup_unaligned_ctrl_list_resp(peer);
+
+ memset(&list, 0, sizeof(list));
+
+ memset(&req_hdr, 0, sizeof(req_hdr));
+ req_hdr.hdr.type = NVME_MI_MSGTYPE_NVME;
+ req_hdr.hdr.nmp = (NVME_MI_ROR_REQ << 7) | (NVME_MI_MT_MI << 3);
+ req_hdr.opcode = nvme_mi_mi_opcode_mi_data_read;
+ req_hdr.cdw0 = cpu_to_le32(nvme_mi_dtyp_ctrl_list << 24);
+
+ memset(&req, 0, sizeof(req));
+ req.hdr = &req_hdr.hdr;
+ req.hdr_len = sizeof(req_hdr);
+
+ memset(&resp, 0, sizeof(resp));
+ resp.hdr = &resp_hdr.hdr;
+ resp.hdr_len = sizeof(resp_hdr);
+ resp.data = &list;
+ resp.data_len = peer->tx_buf_len;
+
+ rc = nvme_mi_submit(ep, &req, &resp);
+ assert(rc == 0);
+ assert(resp.data_len == 6); /* 2-byte length, 2*2 byte controller IDs */
+
+ assert(le16_to_cpu(list.num) == 2);
+ assert(le16_to_cpu(list.identifier[0]) == 1);
+ assert(le16_to_cpu(list.identifier[1]) == 2);
+}
+
static void test_admin_resp_err(nvme_mi_ep_t ep, struct test_peer *peer)
{
struct nvme_id_ctrl id;
@@ -340,30 +425,6 @@ static void test_admin_resp_sizes(nvme_mi_ep_t ep, struct test_peer *peer)
nvme_mi_close_ctrl(ctrl);
}
-/* test: unaligned response sizes - should always report a transport error */
-static void test_admin_resp_sizes_unaligned(nvme_mi_ep_t ep, struct test_peer *peer)
-{
- struct nvme_id_ctrl id;
- nvme_mi_ctrl_t ctrl;
- unsigned int i;
- int rc;
-
- ctrl = nvme_mi_init_ctrl(ep, 1);
- assert(ctrl);
-
- peer->tx_buf[4] = 0x02; /* internal error */
-
- for (i = 8; i <= 4096 + 8; i++) {
- peer->tx_buf_len = i;
- if (!(i & 0x3))
- continue;
- rc = nvme_mi_admin_identify_ctrl(ctrl, &id);
- assert(rc < 0);
- }
-
- nvme_mi_close_ctrl(ctrl);
-}
-
/* test: timeout value passed to poll */
static int poll_fn_timeout_value(struct test_peer *peer, struct pollfd *fds,
nfds_t nfds, int timeout)
@@ -664,9 +725,10 @@ struct test {
DEFINE_TEST(read_mi_data),
DEFINE_TEST(poll_err),
DEFINE_TEST(mi_resp_err),
+ DEFINE_TEST(mi_resp_unaligned),
+ DEFINE_TEST(mi_resp_unaligned_expected),
DEFINE_TEST(admin_resp_err),
DEFINE_TEST(admin_resp_sizes),
- DEFINE_TEST(admin_resp_sizes_unaligned),
DEFINE_TEST(poll_timeout_value),
DEFINE_TEST(poll_timeout),
DEFINE_TEST(mpr_mi),
diff --git a/test/mi.c b/test/mi.c
index 7f8e005..a09c108 100644
--- a/test/mi.c
+++ b/test/mi.c
@@ -44,7 +44,8 @@ static int test_transport_submit(struct nvme_mi_ep *ep,
/* start from a minimal response: zeroed data, nmp to match request */
memset(resp->hdr, 0, resp->hdr_len);
- memset(resp->data, 0, resp->data_len);
+ if (resp->data_len)
+ memset(resp->data, 0, resp->data_len);
resp->hdr->type = NVME_MI_MSGTYPE_NVME;
resp->hdr->nmp = req->hdr->nmp | (NVME_MI_ROR_RSP << 7);
@@ -1245,7 +1246,6 @@ static int test_admin_id_secondary_ctrl_list_cb(struct nvme_mi_ep *ep,
void *data)
{
__u16 cns, ctrlid;
- __u32 nsid;
__u8 *hdr;
hdr = (__u8 *)req->hdr;
@@ -1256,9 +1256,6 @@ static int test_admin_id_secondary_ctrl_list_cb(struct nvme_mi_ep *ep,
cns = hdr[45] << 8 | hdr[44];
assert(cns == NVME_IDENTIFY_CNS_SECONDARY_CTRL_LIST);
- nsid = hdr[11] << 24 | hdr[10] << 16 | hdr[9] << 8 | hdr[8];
- assert(nsid == 0x01020304);
-
ctrlid = hdr[47] << 8 | hdr[46];
assert(ctrlid == 5);
@@ -1280,8 +1277,7 @@ static void test_admin_id_secondary_ctrl_list(struct nvme_mi_ep *ep)
ctrl = nvme_mi_init_ctrl(ep, 5);
assert(ctrl);
- rc = nvme_mi_admin_identify_secondary_ctrl_list(ctrl, 0x01020304,
- 5, &list);
+ rc = nvme_mi_admin_identify_secondary_ctrl_list(ctrl, 5, &list);
assert(!rc);
}
@@ -1651,7 +1647,10 @@ static int test_admin_format_nvm_cb(struct nvme_mi_ep *ep,
assert(rq_hdr[4] == nvme_admin_format_nvm);
- nsid = rq_hdr[11] << 24 | rq_hdr[10] << 16 | rq_hdr[9] << 8 | rq_hdr[8];
+ nsid = (__u32)rq_hdr[11] << 24
+ | rq_hdr[10] << 16
+ | rq_hdr[9] << 8
+ | rq_hdr[8];
assert(nsid == args->nsid);
assert(((rq_hdr[44] >> 0) & 0xf) == args->lbaf);
@@ -1726,7 +1725,7 @@ static int test_admin_sanitize_nvm_cb(struct nvme_mi_ep *ep,
assert(((rq_hdr[45] >> 0) & 0x1) == args->oipbp);
assert(((rq_hdr[45] >> 1) & 0x1) == args->nodas);
- ovrpat = rq_hdr[51] << 24 | rq_hdr[50] << 16 |
+ ovrpat = (__u32)rq_hdr[51] << 24 | rq_hdr[50] << 16 |
rq_hdr[49] << 8 | rq_hdr[48];
assert(ovrpat == args->ovrpat);
diff --git a/test/mock-ifaddrs.c b/test/mock-ifaddrs.c
new file mode 100644
index 0000000..87a2e50
--- /dev/null
+++ b/test/mock-ifaddrs.c
@@ -0,0 +1,123 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+/**
+ * This file is part of libnvme.
+ * Copyright (c) 2023 Martin Belanger, Dell Technologies Inc.
+ */
+#include <sys/types.h>
+#include <ifaddrs.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include <arpa/inet.h>
+
+struct ifaddrs_storage {
+ struct ifaddrs ifa;
+ union {
+ /* Reserve space for the biggest of the sockaddr types */
+ struct sockaddr_in s4;
+ struct sockaddr_in6 s6;
+ } addr, netmask, broadaddr;
+ char name[IF_NAMESIZE + 1];
+};
+
+static void init_entry(struct ifaddrs_storage *storage,
+ const char *ifname,
+ int family,
+ uint32_t addr1,
+ uint32_t addr2,
+ uint32_t addr3,
+ uint32_t addr4,
+ bool last)
+{
+ struct ifaddrs *p;
+
+ p = &storage->ifa;
+ p->ifa_next = last ? NULL : &storage[1].ifa;
+ p->ifa_name = storage->name;
+ strcpy(p->ifa_name, ifname);
+ p->ifa_flags = 0;
+
+ if (family == AF_INET) {
+ struct sockaddr_in *ipv4;
+
+ ipv4 = &storage->addr.s4;
+ ipv4->sin_family = family;
+ ipv4->sin_port = 0;
+ ipv4->sin_addr.s_addr = htonl(addr1);
+ p->ifa_addr = (struct sockaddr *)ipv4;
+
+ ipv4 = &storage->netmask.s4;
+ ipv4->sin_family = family;
+ ipv4->sin_port = 0;
+ ipv4->sin_addr.s_addr = 0xffffff00;
+ p->ifa_netmask = (struct sockaddr *)ipv4;
+
+ ipv4 = &storage->broadaddr.s4;
+ ipv4->sin_family = family;
+ ipv4->sin_port = 0;
+ ipv4->sin_addr.s_addr = 0;
+ p->ifa_broadaddr = (struct sockaddr *)ipv4;;
+ } else {
+ struct sockaddr_in6 *ipv6;
+
+ ipv6 = &storage->addr.s6;
+ ipv6->sin6_family = family;
+ ipv6->sin6_port = 0;
+ ipv6->sin6_flowinfo = 0;
+ ipv6->sin6_addr.s6_addr32[0] = htonl(addr1);
+ ipv6->sin6_addr.s6_addr32[1] = htonl(addr2);
+ ipv6->sin6_addr.s6_addr32[2] = htonl(addr3);
+ ipv6->sin6_addr.s6_addr32[3] = htonl(addr4);
+ ipv6->sin6_scope_id = 0;
+ p->ifa_addr = (struct sockaddr *)ipv6;
+
+ ipv6 = &storage->netmask.s6;
+ ipv6->sin6_family = family;
+ ipv6->sin6_port = 0;
+ ipv6->sin6_flowinfo = 0;
+ ipv6->sin6_addr.s6_addr32[0] = 0xffffffff;
+ ipv6->sin6_addr.s6_addr32[1] = 0xffffffff;
+ ipv6->sin6_addr.s6_addr32[2] = 0xffffffff;
+ ipv6->sin6_addr.s6_addr32[3] = 0;
+ ipv6->sin6_scope_id = 0;
+ p->ifa_netmask = (struct sockaddr *)ipv6;
+
+ ipv6 = &storage->broadaddr.s6;
+ ipv6->sin6_family = family;
+ ipv6->sin6_port = 0;
+ ipv6->sin6_flowinfo = 0;
+ ipv6->sin6_addr.s6_addr32[0] = 0;
+ ipv6->sin6_addr.s6_addr32[1] = 0;
+ ipv6->sin6_addr.s6_addr32[2] = 0;
+ ipv6->sin6_addr.s6_addr32[3] = 0;
+ ipv6->sin6_scope_id = 0;
+ p->ifa_broadaddr = (struct sockaddr *)ipv6;
+ }
+
+ p->ifa_data = NULL;
+}
+
+int getifaddrs(struct ifaddrs **ifap) {
+ struct ifaddrs_storage *storage;
+
+ /* Allocate memory for 4 interfaces */
+ storage = (struct ifaddrs_storage *)calloc(4, sizeof(struct ifaddrs_storage));
+ *ifap = &storage[0].ifa;
+
+ init_entry(&storage[0], "eth0", AF_INET, 0xc0a80114, 0, 0, 0, false); /* 192.168.1.20 */
+ init_entry(&storage[1], "eth0", AF_INET6, 0xfe800000, 0, 0, 0xdeadbeef, false); /* fe80::dead:beef */
+
+ /* Loopback interface */
+ init_entry(&storage[2], "lo", AF_INET, 0x7f000001, 0, 0, 0, false); /* 127.0.0.1 */
+ init_entry(&storage[3], "lo", AF_INET6, 0, 0, 0, 1, true); /* ::1 */
+
+ return 0;
+}
+
+void freeifaddrs(struct ifaddrs *ifa) {
+ free(ifa);
+}
+
diff --git a/test/test-util.c b/test/test-util.c
index e32f030..88a3f42 100644
--- a/test/test-util.c
+++ b/test/test-util.c
@@ -20,7 +20,6 @@
#include <netdb.h>
#include <string.h>
-#include "nvme/cleanup.c" /* to resolve cleanup_charp() */
#include "nvme/log.c" /* to resolve __nvme_msg() */
#include "nvme/util.c"
diff --git a/test/test.c b/test/test.c
index 2f24e1e..23036bb 100644
--- a/test/test.c
+++ b/test/test.c
@@ -16,6 +16,7 @@
* somewhere.
*/
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <inttypes.h>
@@ -112,7 +113,7 @@ static int test_ctrl(nvme_ctrl_t c)
printf(" PASSED: Identify Primary\n");
else
printf(" ERROR: Identify Primary:%x\n", ret);
- ret = nvme_identify_secondary_ctrl_list(fd, 1, 0, &sec);
+ ret = nvme_identify_secondary_ctrl_list(fd, 0, &sec);
if (!ret)
printf(" PASSED: Identify Secondary\n");
else
@@ -197,7 +198,7 @@ static int test_ctrl(nvme_ctrl_t c)
printf(" Temperature Threshold:%x\n", result);
else if (ret > 0)
printf(" ERROR: Temperature Threshold:%x\n", ret);
- ret = nvme_get_features_err_recovery(fd, sel, &result);
+ ret = nvme_get_features_err_recovery2(fd, sel, 0, &result);
if (!ret)
printf(" Error Recovery:%x\n", result);
else if (ret > 0)
@@ -257,12 +258,12 @@ static int test_ctrl(nvme_ctrl_t c)
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, &result);
+ ret = nvme_get_features_resv_mask2(fd, 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, &result);
+ ret = nvme_get_features_resv_persist2(fd, sel, 0, &result);
if (!ret)
printf(" Reservation Persistence:%x\n", result);
else if (ret > 0)
@@ -274,7 +275,7 @@ static int test_namespace(nvme_ns_t n)
{
int ret, nsid = nvme_ns_get_nsid(n), fd = nvme_ns_get_fd(n);
struct nvme_id_ns ns = { 0 }, allocated = { 0 };
- struct nvme_ns_id_desc descs = { 0 };
+ struct nvme_ns_id_desc *descs;
__u32 result = 0;
__u8 flbas;
@@ -292,11 +293,16 @@ static int test_namespace(nvme_ns_t n)
printf(" Identify allocated ns\n");
else
printf(" ERROR: Identify allocated ns:%x\n", ret);
- ret = nvme_identify_ns_descs(fd, nsid, &descs);
+ descs = malloc(NVME_IDENTIFY_DATA_SIZE);
+ if (!descs)
+ return -1;
+
+ ret = nvme_identify_ns_descs(fd, 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,
NVME_GET_FEATURES_SEL_CURRENT, &result);
if (!ret)
diff --git a/test/tree.c b/test/tree.c
index b3baac8..c9370f9 100644
--- a/test/tree.c
+++ b/test/tree.c
@@ -6,10 +6,14 @@
#include <assert.h>
#include <string.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <arpa/inet.h>
#include <ccan/array_size/array_size.h>
#include <libnvme.h>
+#include <nvme/private.h>
struct test_data {
/* input data */
@@ -29,6 +33,8 @@ struct test_data {
#define DEFAULT_SUBSYSNAME "subsysname"
#define DEFAULT_SUBSYSNQN "subsysnqn"
+#define SRC_ADDR4 "192.168.56.100"
+#define SRC_ADDR6 "1234:5678:abcd:EF01:1234:5678:abcd:EF01"
struct test_data test_data[] = {
{ DEFAULT_SUBSYSNAME, DEFAULT_SUBSYSNQN, "tcp", "192.168.1.1", "192.168.1.20", NULL, "4420" },
@@ -65,8 +71,10 @@ static void show_ctrl(nvme_ctrl_t c)
if (d)
printf("ctrl%d ", d->ctrl_id);
+ else
+ printf(" ");
- printf("0x%p: %s %s %s %s %s\n",
+ printf("0x%p: %s %s %s %s %s ",
c,
nvme_ctrl_get_transport(c),
nvme_ctrl_get_traddr(c),
@@ -75,6 +83,41 @@ static void show_ctrl(nvme_ctrl_t c)
nvme_ctrl_get_trsvcid(c));
}
+static bool match_ctrl(struct test_data *d, nvme_ctrl_t c)
+{
+ bool pass = true;
+ const char *trsvid, *host_traddr, *host_iface;
+
+ if (d->c != c)
+ pass = false;
+
+ if (strcmp(d->transport, nvme_ctrl_get_transport(d->c)))
+ pass = false;
+
+ if (strcmp(d->traddr, nvme_ctrl_get_traddr(d->c)))
+ pass = false;
+
+
+ host_traddr = nvme_ctrl_get_host_traddr(c);
+ if (d->host_traddr &&
+ (!host_traddr || strcmp(d->host_traddr, host_traddr)))
+ pass = false;
+
+ host_iface = nvme_ctrl_get_host_iface(c);
+ if (d->host_iface &&
+ (!host_iface || strcmp(d->host_iface, host_iface)))
+ pass = false;
+
+ trsvid = nvme_ctrl_get_trsvcid(c);
+ if (d->trsvcid &&
+ (!trsvid || strcmp(d->trsvcid, trsvid)))
+ pass = false;
+
+ printf("[%s]", pass? "PASS" : "FAILED");
+
+ return pass;
+}
+
static nvme_root_t create_tree()
{
nvme_root_t r;
@@ -97,14 +140,10 @@ static nvme_root_t create_tree()
assert(d->c);
d->ctrl_id = i;
- assert(!strcmp(d->transport, nvme_ctrl_get_transport(d->c)));
- assert(!strcmp(d->traddr, nvme_ctrl_get_traddr(d->c)));
- assert(!d->host_traddr || !strcmp(d->host_traddr, nvme_ctrl_get_host_traddr(d->c)));
- assert(!d->host_iface || !strcmp(d->host_iface, nvme_ctrl_get_host_iface(d->c)));
- assert(!d->trsvcid || !strcmp(d->trsvcid, nvme_ctrl_get_trsvcid(d->c)));
-
printf(" ");
show_ctrl(d->c);
+ match_ctrl(d, d->c);
+ printf("\n");
}
printf("\n");
@@ -118,146 +157,1028 @@ static unsigned int count_entries(nvme_root_t r)
nvme_ctrl_t c;
unsigned int i = 0;
- nvme_for_each_host(r, h) {
- nvme_for_each_subsystem(h, s) {
- nvme_subsystem_for_each_ctrl(s, c) {
+ nvme_for_each_host(r, h)
+ nvme_for_each_subsystem(h, s)
+ nvme_subsystem_for_each_ctrl(s, c)
i++;
- }
- }
- }
return i;
}
-static void ctrl_lookups(nvme_root_t r)
+static bool tcp_ctrl_lookup(nvme_subsystem_t s, struct test_data *d)
{
- nvme_host_t h;
- nvme_subsystem_t s;
nvme_ctrl_t c;
+ bool pass = true;
- h = nvme_first_host(r);
- s = nvme_lookup_subsystem(h, DEFAULT_SUBSYSNAME, DEFAULT_SUBSYSNQN);
+ c = nvme_lookup_ctrl(s, d->transport, d->traddr, NULL,
+ NULL, d->trsvcid, NULL);
+ printf("%10s %12s %10s -> ", d->trsvcid, "", "");
+ show_ctrl(c);
+ pass &= match_ctrl(d, c);
+ printf("\n");
- printf(" lookup controller:\n");
- for (int i = 0; i < ARRAY_SIZE(test_data); i++) {
- struct test_data *d = &test_data[i];
+ if (d->host_traddr) {
+ c = nvme_lookup_ctrl(s, d->transport, d->traddr, d->host_traddr,
+ NULL, d->trsvcid, NULL);
+ printf("%10s %12s %10s -> ", d->trsvcid, d->host_traddr, "");
+ show_ctrl(c);
+ pass &= match_ctrl(d, c);
+ printf("\n");
+ }
- printf("%10s %10s ", "", "");
- show_ctrl(d->c);
+ if (d->host_iface) {
+ c = nvme_lookup_ctrl(s, d->transport, d->traddr, NULL,
+ d->host_iface, d->trsvcid, NULL);
+ printf("%10s %12s %10s -> ", d->trsvcid, "", d->host_iface);
+ show_ctrl(c);
+ pass &= match_ctrl(d, c);
+ printf("\n");
+ }
+
+ if (d->host_iface && d->traddr) {
c = nvme_lookup_ctrl(s, d->transport, d->traddr, d->host_traddr,
- NULL, NULL, NULL);
- printf("%10s %10s -> ", "-", "-");
+ d->host_iface, d->trsvcid, NULL);
+ printf("%10s %12s %10s -> ", d->trsvcid, d->host_traddr, d->host_iface);
show_ctrl(c);
+ pass &= match_ctrl(d, c);
+ printf("\n");
+ }
- assert(!strcmp(d->transport, nvme_ctrl_get_transport(c)));
- assert(!strcmp(d->traddr, nvme_ctrl_get_traddr(c)));
- assert(!strcmp(d->host_traddr, nvme_ctrl_get_host_traddr(c)));
+ return pass;
+}
- if (d->host_iface) {
- c = nvme_lookup_ctrl(s, d->transport, d->traddr, d->host_traddr,
- d->host_iface, NULL, NULL);
- printf("%10s %10s -> ", d->host_iface, "-");
- show_ctrl(c);
+static bool default_ctrl_lookup(nvme_subsystem_t s, struct test_data *d)
+{
+ nvme_ctrl_t c;
+ bool pass = true;
- assert(!strcmp(d->transport, nvme_ctrl_get_transport(c)));
- assert(!strcmp(d->traddr, nvme_ctrl_get_traddr(c)));
- assert(!strcmp(d->host_traddr, nvme_ctrl_get_host_traddr(c)));
- assert(!strcmp(d->host_iface, nvme_ctrl_get_host_iface(c)));
- }
+ c = nvme_lookup_ctrl(s, d->transport, d->traddr, d->host_traddr,
+ NULL, NULL, NULL);
+ printf("%10s %12s %10s -> ", "", "", "");
+ show_ctrl(c);
+ pass &= match_ctrl(d, c);
+ printf("\n");
- if (d->trsvcid) {
- c = nvme_lookup_ctrl(s, d->transport, d->traddr, d->host_traddr,
- NULL, d->trsvcid, NULL);
- printf("%10s %10s -> ", "-", d->trsvcid);
- show_ctrl(c);
+ return pass;
+}
- assert(!strcmp(d->transport, nvme_ctrl_get_transport(c)));
- assert(!strcmp(d->traddr, nvme_ctrl_get_traddr(c)));
- assert(!strcmp(d->host_traddr, nvme_ctrl_get_host_traddr(c)));
- assert(!strcmp(d->trsvcid, nvme_ctrl_get_trsvcid(c)));
- }
+static bool ctrl_lookups(nvme_root_t r)
+{
+ nvme_host_t h;
+ nvme_subsystem_t s;
+ bool pass = true;
- if (d->host_iface && d->trsvcid) {
- c = nvme_lookup_ctrl(s, d->transport, d->traddr, d->host_traddr,
- d->host_iface, d->trsvcid, NULL);
- printf("%10s %10s -> ", d->host_iface, d->trsvcid);
- show_ctrl(c);
-
- assert(!strcmp(d->transport, nvme_ctrl_get_transport(c)));
- assert(!strcmp(d->traddr, nvme_ctrl_get_traddr(c)));
- assert(!strcmp(d->host_traddr, nvme_ctrl_get_host_traddr(c)));
- assert(!strcmp(d->trsvcid, nvme_ctrl_get_trsvcid(c)));
- assert(!strcmp(d->host_iface, nvme_ctrl_get_host_iface(c)));
- }
+ h = nvme_first_host(r);
+ s = nvme_lookup_subsystem(h, DEFAULT_SUBSYSNAME, DEFAULT_SUBSYSNQN);
+
+ printf(" lookup controller:\n");
+ for (int i = 0; i < ARRAY_SIZE(test_data); i++) {
+ struct test_data *d = &test_data[i];
+
+ printf("%10s %12s %10s ", "", "", "");
+ show_ctrl(d->c);
+ printf("\n");
+
+ if (!strcmp("tcp", d->transport))
+ pass &= tcp_ctrl_lookup(s, d);
+ else
+ pass &= default_ctrl_lookup(s, d);
printf("\n");
}
+
+ return pass;
}
-static void test_lookup_1(void)
+static bool test_lookup(void)
{
nvme_root_t r;
+ bool pass;
- printf("test_lookup_1:\n");
+ printf("test_lookup:\n");
r = create_tree();
- assert(count_entries(r) == ARRAY_SIZE(test_data));
- ctrl_lookups(r);
+ pass = count_entries(r) == ARRAY_SIZE(test_data);
+ pass &= ctrl_lookups(r);
nvme_free_tree(r);
+
+ return pass;
}
-static void test_lookup_2(void)
+static bool test_src_addr()
{
+ bool pass = true;
nvme_root_t r;
- nvme_subsystem_t s;
nvme_host_t h;
- nvme_ctrl_t c1, c2, c3, c4;
+ nvme_ctrl_t c;
+ nvme_subsystem_t s;
+ char *src_addr, buffer[100]; /* big enough for IPv6 max length */
- printf("test_lookup_2:\n");
+ printf("\n"
+ "test_src_addr:\n");
r = nvme_create_root(stdout, LOG_DEBUG);
assert(r);
+
h = nvme_default_host(r);
assert(h);
s = nvme_lookup_subsystem(h, DEFAULT_SUBSYSNAME, DEFAULT_SUBSYSNQN);
assert(s);
- assert(nvme_lookup_ctrl(s, "tcp", "192.168.2.1", "192.168.2.20",
- "eth0", "4420", NULL));
-
- c1 = nvme_lookup_ctrl(s, "tcp", "192.168.1.1", "192.168.1.20",
- NULL, NULL, NULL);
- assert(c1);
- printf("%10s %10s ", "", "");
- show_ctrl(c1);
-
- c2 = nvme_lookup_ctrl(s, "tcp", "192.168.1.1", "192.168.1.20",
- "eth0", NULL, NULL);
- assert(c1 == c2);
- printf("%10s %10s ", "eth0", "-");
- show_ctrl(c2);
-
- c3 = nvme_lookup_ctrl(s, "tcp", "192.168.1.1", "192.168.1.20",
- NULL, "4420", NULL);
- assert(c1 == c3);
- printf("%10s %10s ", "-", "4420");
- show_ctrl(c3);
-
- c4 = nvme_lookup_ctrl(s, "tcp", "192.168.1.1", "192.168.1.20",
- "eth0", "4420", NULL);
- assert(c1 == c4);
- printf("%10s %10s ", "eth0", "4420");
- show_ctrl(c4);
+ c = nvme_lookup_ctrl(s, "tcp", "192.168.56.1", NULL, NULL, "8009", NULL);
+ assert(c);
+
+ c->address = NULL;
+ printf(" - Test c->address = NULL : src_addr = NULL ");
+ src_addr = nvme_ctrl_get_src_addr(c, buffer, sizeof(buffer));
+ if (src_addr != NULL) {
+ printf("[FAIL]\n");
+ fprintf(stderr,
+ "nvme_ctrl_get_src_addr() c->address=NULL should return src_addr=NULL\n");
+ pass = false;
+ } else {
+ printf("[PASS]\n");
+ }
+
+ c->address = "";
+ printf(" - Test c->address = \"\" : src_addr = NULL ");
+ src_addr = nvme_ctrl_get_src_addr(c, buffer, sizeof(buffer));
+ if (src_addr != NULL) {
+ printf("[FAIL]\n");
+ fprintf(stderr,
+ "nvme_ctrl_get_src_addr() c->address="" should return src_addr=NULL\n");
+ pass = false;
+ } else {
+ printf("[PASS]\n");
+ }
+
+ c->address = "traddr=192.168.56.1,trsvcid=8009";
+ printf(" - Test c->address = \"%s\" : src_addr = NULL ", c->address);
+ src_addr = nvme_ctrl_get_src_addr(c, buffer, sizeof(buffer));
+ if (src_addr != NULL) {
+ printf("[FAIL]\n");
+ fprintf(stderr,
+ "nvme_ctrl_get_src_addr() c->address=%s should return src_addr=NULL\n",
+ c->address);
+ pass = false;
+ } else {
+ printf("[PASS]\n");
+ }
+
+ c->address = "traddr=192.168.56.1,trsvcid=8009,src_addr=" SRC_ADDR4;
+ printf(" - Test c->address = \"%s\" : src_addr = \"" SRC_ADDR4 "\" ", c->address);
+ src_addr = nvme_ctrl_get_src_addr(c, buffer, sizeof(buffer));
+ if (!src_addr || strcmp(src_addr, SRC_ADDR4)) {
+ printf("[FAIL]\n");
+ fprintf(stderr,
+ "nvme_ctrl_get_src_addr() c->address=%s should return src_addr=" SRC_ADDR4 "\n",
+ c->address);
+ pass = false;
+ } else {
+ printf("[PASS]\n");
+ }
+
+ c->address = "traddr=192.168.56.1,src_addr=" SRC_ADDR4 ",trsvcid=8009";
+ printf(" - Test c->address = \"%s\" : src_addr = \"" SRC_ADDR4 "\" ", c->address);
+ src_addr = nvme_ctrl_get_src_addr(c, buffer, sizeof(buffer));
+ if (!src_addr || strcmp(src_addr, SRC_ADDR4)) {
+ printf("[FAIL]\n");
+ fprintf(stderr,
+ "nvme_ctrl_get_src_addr() c->address=%s should return src_addr=" SRC_ADDR4 "\n",
+ c->address);
+ pass = false;
+ } else {
+ printf("[PASS]\n");
+ }
+
+ c->address = "traddr=1234::abcd,trsvcid=8009,src_addr=" SRC_ADDR6;
+ printf(" - Test c->address = \"%s\" : src_addr = \"" SRC_ADDR6 "\" ", c->address);
+ src_addr = nvme_ctrl_get_src_addr(c, buffer, sizeof(buffer));
+ if (!src_addr || strcmp(src_addr, SRC_ADDR6)) {
+ printf("[FAIL]\n");
+ fprintf(stderr,
+ "nvme_ctrl_get_src_addr() c->address=%s should return src_addr=" SRC_ADDR6 "\n",
+ c->address);
+ pass = false;
+ } else {
+ printf("[PASS]\n");
+ }
+
+ c->address = "traddr=1234::abcd,src_addr=" SRC_ADDR6 ",trsvcid=8009";
+ printf(" - Test c->address = \"%s\" : src_addr = \"" SRC_ADDR6 "\" ", c->address);
+ src_addr = nvme_ctrl_get_src_addr(c, buffer, sizeof(buffer));
+ if (!src_addr || strcmp(src_addr, SRC_ADDR6)) {
+ printf("[FAIL]\n");
+ fprintf(stderr,
+ "nvme_ctrl_get_src_addr() c->address=%s should return src_addr=" SRC_ADDR6 "\n",
+ c->address);
+ pass = false;
+ } else {
+ printf("[PASS]\n");
+ }
+
+ c->address = "traddr=1234::abcd,trsvcid=8009,src_addr=" SRC_ADDR6 "%scope";
+ printf(" - Test c->address = \"%s\" : src_addr = \"" SRC_ADDR6 "\" ", c->address);
+ src_addr = nvme_ctrl_get_src_addr(c, buffer, sizeof(buffer));
+ if (!src_addr || strcmp(src_addr, SRC_ADDR6)) {
+ printf("[FAIL]\n");
+ fprintf(stderr,
+ "nvme_ctrl_get_src_addr() c->address=%s should return src_addr=" SRC_ADDR6 "\n",
+ c->address);
+ pass = false;
+ } else {
+ printf("[PASS]\n");
+ }
+
+ c->address = "traddr=1234::abcd,src_addr=" SRC_ADDR6 "%scope,trsvcid=8009";
+ printf(" - Test c->address = \"%s\" : src_addr = \"" SRC_ADDR6 "\" ", c->address);
+ src_addr = nvme_ctrl_get_src_addr(c, buffer, sizeof(buffer));
+ if (!src_addr || strcmp(src_addr, SRC_ADDR6)) {
+ printf("[FAIL]\n");
+ fprintf(stderr,
+ "nvme_ctrl_get_src_addr() c->address=%s should return src_addr=" SRC_ADDR6 "\n",
+ c->address);
+ pass = false;
+ } else {
+ printf("[PASS]\n");
+ }
+
+ c->address = NULL; /* Needed to avoid freeing non-malloced memory (see above) */
+
+ nvme_free_tree(r);
+
+ return pass;
+}
+
+struct ctrl_args {
+ const char *transport;
+ const char *traddr;
+ const char *trsvcid;
+ const char *host_traddr;
+ const char *host_iface;
+ const char *address;
+ const char *subsysnqn;
+};
+
+static void set_ctrl_args(struct ctrl_args *args,
+ const char *transport,
+ const char *traddr,
+ const char *trsvcid,
+ const char *host_traddr,
+ const char *host_iface,
+ const char *address,
+ const char *subsysnqn)
+{
+ args->transport = transport;
+ args->traddr = traddr;
+ args->trsvcid = trsvcid;
+ args->host_traddr = host_traddr;
+ args->host_iface = host_iface;
+ args->address = address;
+ args->subsysnqn = subsysnqn;
+}
+
+static bool ctrl_match(const char *tag,
+ int reference_id,
+ int candidate_id,
+ struct ctrl_args *reference,
+ struct ctrl_args *candidate,
+ bool should_match)
+{
+ nvme_root_t r;
+ nvme_host_t h;
+ nvme_ctrl_t reference_ctrl; /* Existing controller (from sysfs) */
+ nvme_ctrl_t candidate_ctrl;
+ nvme_ctrl_t found_ctrl;
+ nvme_subsystem_t s;
+
+ r = nvme_create_root(stdout, LOG_INFO);
+ assert(r);
+
+ h = nvme_default_host(r);
+ assert(h);
+
+ s = nvme_lookup_subsystem(h, DEFAULT_SUBSYSNAME, reference->subsysnqn ? reference->subsysnqn : DEFAULT_SUBSYSNQN);
+ assert(s);
+
+ reference_ctrl = nvme_lookup_ctrl(s, reference->transport, reference->traddr,
+ reference->host_traddr, reference->host_iface,
+ reference->trsvcid, NULL);
+ assert(reference_ctrl);
+ reference_ctrl->name = "nvme1"; /* fake the device name */
+ if (reference->address) {
+ reference_ctrl->address = (char *)reference->address;
+ }
+
+ /* nvme_ctrl_find() MUST BE RUN BEFORE nvme_lookup_ctrl() */
+ found_ctrl = nvme_ctrl_find(s, candidate->transport, candidate->traddr,
+ candidate->trsvcid, candidate->subsysnqn,
+ candidate->host_traddr,
+ candidate->host_iface);
+
+ candidate_ctrl = nvme_lookup_ctrl(s, candidate->transport, candidate->traddr,
+ candidate->host_traddr, candidate->host_iface,
+ candidate->trsvcid, NULL);
+
+ if (should_match) {
+ if (candidate_ctrl != reference_ctrl) {
+ printf("%s-%d-%d: Candidate (%s, %s, %s, %s, %s, %s) failed to match (%s, %s, %s, %s, %s, %s, %s)\n",
+ tag, reference_id, candidate_id,
+ candidate->transport, candidate->traddr, candidate->trsvcid,
+ candidate->subsysnqn, candidate->host_traddr, candidate->host_iface,
+ reference->transport, reference->traddr, reference->trsvcid, reference->subsysnqn,
+ reference->host_traddr, reference->host_iface, reference->address);
+ return false;
+ }
+
+ if (!found_ctrl) {
+ printf("%s-%d-%d: Candidate (%s, %s, %s, %s, %s, %s) failed to find controller\n",
+ tag, reference_id, candidate_id,
+ candidate->transport, candidate->traddr, candidate->trsvcid,
+ candidate->subsysnqn, candidate->host_traddr, candidate->host_iface);
+ return false;
+ }
+ } else {
+ if (candidate_ctrl == reference_ctrl) {
+ printf("%s-%d-%d: Candidate (%s, %s, %s, %s, %s, %s) should not match (%s, %s, %s, %s, %s, %s, %s)\n",
+ tag, reference_id, candidate_id,
+ candidate->transport, candidate->traddr, candidate->trsvcid,
+ candidate->subsysnqn, candidate->host_traddr, candidate->host_iface,
+ reference->transport, reference->traddr, reference->trsvcid, reference->subsysnqn,
+ reference->host_traddr, reference->host_iface, reference->address);
+ return false;
+ }
+
+ if (found_ctrl) {
+ printf("%s-%d-%d: Candidate (%s, %s, %s, %s, %s, %s) should not have found controller. found_ctrl=%p reference=%p\n",
+ tag, reference_id, candidate_id,
+ candidate->transport, candidate->traddr, candidate->trsvcid, candidate->subsysnqn,
+ candidate->host_traddr, candidate->host_iface, found_ctrl, reference_ctrl);
+ return false;
+ }
+ }
+
+ /* Set the faked data back to NULL before freeing the tree */
+ reference_ctrl->name = NULL;
+ reference_ctrl->address = NULL;
nvme_free_tree(r);
+
+ return true;
}
+/**
+ * test_ctrl_match_fc - Test that we can look up FC controllers
+ *
+ * @return true when all tests have passed. false otherwise.
+ */
+static bool test_ctrl_match_fc(void)
+{
+ bool pass = true;
+ struct ctrl_args reference = {0};
+ struct ctrl_args candidate = {0};
+
+ printf("test_ctrl_match_fc:\n");
+
+ /*******************************************************************/
+ /* Reference ID 1 */
+ set_ctrl_args(&reference, "fc", "21:00:00:e0:8b:05:05:01", "4420", "21:00:00:e0:8b:05:05:20", NULL, NULL, NULL);
+
+ set_ctrl_args(&candidate, "fc", "21:00:00:e0:8b:05:05:01", "4420", "21:00:00:e0:8b:05:05:20", NULL, NULL, NULL);
+ pass &= ctrl_match("FC", 1, 0, &reference, &candidate, true);
+
+ set_ctrl_args(&candidate, "fc", "21:00:00:e0:8b:05:05:01", "4420", NULL, NULL, NULL, NULL);
+ pass &= ctrl_match("FC", 1, 1, &reference, &candidate, true);
+
+ set_ctrl_args(&candidate, "fc", "21:00:00:e0:8b:05:05:01", "4420", NULL, "eth0", NULL, NULL);
+ pass &= ctrl_match("FC", 1, 2, &reference, &candidate, true);
+
+ set_ctrl_args(&candidate, "fc", "192.168.2.2", "4420", NULL, "eth0", NULL, NULL);
+ pass &= ctrl_match("FC", 1, 3, &reference, &candidate, false);
+
+ set_ctrl_args(&candidate, "fc", "21:00:00:e0:8b:05:05:01", "8009", NULL, NULL, NULL, NULL);
+ pass &= ctrl_match("FC", 1, 4, &reference, &candidate, false);
+
+ set_ctrl_args(&candidate, "fc", "21:00:00:e0:8b:05:05:01", "4420", "21:00:00:e0:8b:05:05:21", NULL, NULL, NULL);
+ pass &= ctrl_match("FC", 1, 5, &reference, &candidate, false);
+
+ set_ctrl_args(&candidate, "fc", "21:00:00:e0:8b:05:05:01", "8009", NULL, "", NULL, NULL);
+ pass &= ctrl_match("FC", 1, 6, &reference, &candidate, false);
+
+
+ /*******************************************************************/
+ /* Reference ID 2 */
+ set_ctrl_args(&reference, "fc", "21:00:00:e0:8b:05:05:01", "4420", NULL, NULL, NULL, NULL);
+
+ set_ctrl_args(&candidate, "fc", "21:00:00:e0:8b:05:05:01", "4420", "21:00:00:e0:8b:05:05:20", NULL, NULL, NULL);
+ pass &= ctrl_match("FC", 2, 0, &reference, &candidate, true);
+
+ set_ctrl_args(&candidate, "fc", "21:00:00:e0:8b:05:05:01", "4420", NULL, NULL, NULL, NULL);
+ pass &= ctrl_match("FC", 2, 1, &reference, &candidate, true);
+
+ set_ctrl_args(&candidate, "fc", "21:00:00:e0:8b:05:05:01", "4420", NULL, "eth0", NULL, NULL);
+ pass &= ctrl_match("FC", 2, 2, &reference, &candidate, true);
+
+ set_ctrl_args(&candidate, "fc", "192.168.2.2", "4420", NULL, "eth0", NULL, NULL);
+ pass &= ctrl_match("FC", 2, 3, &reference, &candidate, false);
+
+ set_ctrl_args(&candidate, "fc", "21:00:00:e0:8b:05:05:01", "8009", NULL, NULL, NULL, NULL);
+ pass &= ctrl_match("FC", 2, 4, &reference, &candidate, false);
+
+ set_ctrl_args(&candidate, "fc", "21:00:00:e0:8b:05:05:01", "8009", NULL, "", NULL, NULL);
+ pass &= ctrl_match("FC", 2, 5, &reference, &candidate, false);
+
+
+ /*******************************************************************/
+ /* Reference ID 3 */
+ set_ctrl_args(&reference, "fc", "21:00:00:e0:8b:05:05:01", "4420", NULL, "eth0", NULL, NULL);
+
+ set_ctrl_args(&candidate, "fc", "21:00:00:e0:8b:05:05:01", "4420", "21:00:00:e0:8b:05:05:20", NULL, NULL, NULL);
+ pass &= ctrl_match("FC", 3, 0, &reference, &candidate, true);
+
+ set_ctrl_args(&candidate, "fc", "21:00:00:e0:8b:05:05:01", "4420", NULL, NULL, NULL, NULL);
+ pass &= ctrl_match("FC", 3, 1, &reference, &candidate, true);
+
+ set_ctrl_args(&candidate, "fc", "21:00:00:e0:8b:05:05:01", "4420", NULL, "eth0", NULL, NULL);
+ pass &= ctrl_match("FC", 3, 2, &reference, &candidate, true);
+
+ set_ctrl_args(&candidate, "fc", "192.168.2.2", "4420", NULL, "eth0", NULL, NULL);
+ pass &= ctrl_match("FC", 3, 3, &reference, &candidate, false);
+
+ set_ctrl_args(&candidate, "fc", "21:00:00:e0:8b:05:05:01", "8009", NULL, NULL, NULL, NULL);
+ pass &= ctrl_match("FC", 3, 4, &reference, &candidate, false);
+
+ set_ctrl_args(&candidate, "fc", "21:00:00:e0:8b:05:05:01", "8009", NULL, "", NULL, NULL);
+ pass &= ctrl_match("FC", 3, 5, &reference, &candidate, false);
+
+ return pass;
+}
+
+/**
+ * test_ctrl_match_rdma - Test that we can look up RDMA controllers
+ *
+ * @return true when all tests have passed. false otherwise.
+ */
+static bool test_ctrl_match_rdma(void)
+{
+ bool pass = true;
+ struct ctrl_args reference = {0};
+ struct ctrl_args candidate = {0};
+
+ printf("test_ctrl_match_rdma:\n");
+
+ /*******************************************************************/
+ /* Reference ID 1 */
+ set_ctrl_args(&reference, "rdma", "192.168.2.1", "4420", "192.168.1.20", NULL, NULL, NULL);
+
+ set_ctrl_args(&candidate, "rdma", "192.168.2.1", "4420", "192.168.1.20", NULL, NULL, NULL);
+ pass &= ctrl_match("RDMA", 1, 0, &reference, &candidate, true);
+
+ set_ctrl_args(&candidate, "rdma", "192.168.2.1", "4420", NULL, NULL, NULL, NULL);
+ pass &= ctrl_match("RDMA", 1, 1, &reference, &candidate, true);
+
+ set_ctrl_args(&candidate, "rdma", "192.168.2.1", "4420", NULL, "eth0", NULL, NULL);
+ pass &= ctrl_match("RDMA", 1, 2, &reference, &candidate, true);
+
+ set_ctrl_args(&candidate, "rdma", "192.168.2.2", "4420", NULL, "eth0", NULL, NULL);
+ pass &= ctrl_match("RDMA", 1, 3, &reference, &candidate, false);
+
+ set_ctrl_args(&candidate, "rdma", "192.168.2.1", "8009", NULL, NULL, NULL, NULL);
+ pass &= ctrl_match("RDMA", 1, 4, &reference, &candidate, false);
+
+ set_ctrl_args(&candidate, "rdma", "192.168.2.1", "4420", "192.168.1.21", NULL, NULL, NULL);
+ pass &= ctrl_match("RDMA", 1, 5, &reference, &candidate, false);
+
+ set_ctrl_args(&candidate, "rdma", "192.168.2.1", "8009", NULL, "", NULL, NULL);
+ pass &= ctrl_match("RDMA", 1, 6, &reference, &candidate, false);
+
+
+ /*******************************************************************/
+ /* Reference ID 2 */
+ set_ctrl_args(&reference, "rdma", "192.168.2.1", "4420", NULL, NULL, NULL, NULL);
+
+ set_ctrl_args(&candidate, "rdma", "192.168.2.1", "4420", "192.168.1.20", NULL, NULL, NULL);
+ pass &= ctrl_match("RDMA", 2, 0, &reference, &candidate, true);
+
+ set_ctrl_args(&candidate, "rdma", "192.168.2.1", "4420", NULL, NULL, NULL, NULL);
+ pass &= ctrl_match("RDMA", 2, 1, &reference, &candidate, true);
+
+ set_ctrl_args(&candidate, "rdma", "192.168.2.1", "4420", NULL, "eth0", NULL, NULL);
+ pass &= ctrl_match("RDMA", 2, 2, &reference, &candidate, true);
+
+ set_ctrl_args(&candidate, "rdma", "192.168.2.2", "4420", NULL, "eth0", NULL, NULL);
+ pass &= ctrl_match("RDMA", 2, 3, &reference, &candidate, false);
+
+ set_ctrl_args(&candidate, "rdma", "192.168.2.1", "8009", NULL, NULL, NULL, NULL);
+ pass &= ctrl_match("RDMA", 2, 4, &reference, &candidate, false);
+
+ set_ctrl_args(&candidate, "rdma", "192.168.2.1", "8009", NULL, "", NULL, NULL);
+ pass &= ctrl_match("RDMA", 2, 5, &reference, &candidate, false);
+
+
+ /*******************************************************************/
+ /* Reference ID 3 */
+ set_ctrl_args(&reference, "rdma", "192.168.2.1", "4420", NULL, "eth0", NULL, NULL);
+
+ set_ctrl_args(&candidate, "rdma", "192.168.2.1", "4420", "192.168.1.20", NULL, NULL, NULL);
+ pass &= ctrl_match("RDMA", 3, 0, &reference, &candidate, true);
+
+ set_ctrl_args(&candidate, "rdma", "192.168.2.1", "4420", NULL, NULL, NULL, NULL);
+ pass &= ctrl_match("RDMA", 3, 1, &reference, &candidate, true);
+
+ set_ctrl_args(&candidate, "rdma", "192.168.2.1", "4420", NULL, "eth0", NULL, NULL);
+ pass &= ctrl_match("RDMA", 3, 2, &reference, &candidate, true);
+
+ set_ctrl_args(&candidate, "rdma", "192.168.2.2", "4420", NULL, "eth0", NULL, NULL);
+ pass &= ctrl_match("RDMA", 3, 3, &reference, &candidate, false);
+
+ set_ctrl_args(&candidate, "rdma", "192.168.2.1", "8009", NULL, NULL, NULL, NULL);
+ pass &= ctrl_match("RDMA", 3, 4, &reference, &candidate, false);
+
+ set_ctrl_args(&candidate, "rdma", "192.168.2.1", "8009", NULL, "", NULL, NULL);
+ pass &= ctrl_match("RDMA", 3, 5, &reference, &candidate, false);
+
+ return pass;
+}
+
+/**
+ * test_ctrl_match_tcp - Test that we can look up TCP controllers
+ *
+ * @note: The mocked getifaddrs() returns 2 interface entries with the
+ * following addresses. Therefore the tests must use IP addresses
+ * that match these.
+ *
+ * eth0
+ * \_ 192.168.1.20
+ * \_ fe80::dead:beef
+ *
+ * lo
+ * \_ 127.0.0.1
+ * \_ ::1
+ *
+ * @return true when all tests have passed. false otherwise.
+ */
+static bool test_ctrl_match_tcp()
+{
+ bool pass = true;
+ struct ctrl_args reference = {0};
+ struct ctrl_args candidate = {0};
+
+ printf("\n"
+ "test_ctrl_match_tcp:\n");
+
+ /*******************************************************************/
+ /* IPv4: Reference ID 1 */
+ set_ctrl_args(&reference, "tcp", "123.123.123.123", "8009", NULL, NULL, NULL, NULL);
+
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", NULL, NULL, NULL, NULL);
+ pass &= ctrl_match("IPv4", 1, 0, &reference, &candidate, true);
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.20", NULL, NULL, NULL);
+ pass &= ctrl_match("IPv4", 1, 1, &reference, &candidate, true);
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", NULL, "eth0", NULL, NULL);
+ pass &= ctrl_match("IPv4", 1, 2, &reference, &candidate, true);
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.20", "eth0", NULL, NULL);
+ pass &= ctrl_match("IPv4", 1, 3, &reference, &candidate, true);
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.21", NULL, NULL, NULL);
+ pass &= ctrl_match("IPv4", 1, 4, &reference, &candidate, true);
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.21", "eth0", NULL, NULL);
+ pass &= ctrl_match("IPv4", 1, 5, &reference, &candidate, true);
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", NULL, "lo", NULL, NULL);
+ pass &= ctrl_match("IPv4", 1, 6, &reference, &candidate, true);
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.20", "lo", NULL, NULL);
+ pass &= ctrl_match("IPv4", 1, 7, &reference, &candidate, true);
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.21", "lo", NULL, NULL);
+ pass &= ctrl_match("IPv4", 1, 8, &reference, &candidate, true);
+
+ /*******************************************************************/
+ /* IPv4: Reference ID 2 */
+ set_ctrl_args(&reference, "tcp", "123.123.123.123", "8009", "192.168.1.20", NULL, NULL, NULL);
+
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", NULL, NULL, NULL, NULL);
+ pass &= ctrl_match("IPv4", 2, 0, &reference, &candidate, true);
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.20", NULL, NULL, NULL);
+ pass &= ctrl_match("IPv4", 2, 1, &reference, &candidate, true);
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", NULL, "eth0", NULL, NULL);
+ pass &= ctrl_match("IPv4", 2, 2, &reference, &candidate, true);
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.20", "eth0", NULL, NULL);
+ pass &= ctrl_match("IPv4", 2, 3, &reference, &candidate, true);
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.21", NULL, NULL, NULL);
+ pass &= ctrl_match("IPv4", 2, 4, &reference, &candidate, false);
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.21", "eth0", NULL, NULL);
+ pass &= ctrl_match("IPv4", 2, 5, &reference, &candidate, false);
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", NULL, "lo", NULL, NULL);
+ pass &= ctrl_match("IPv4", 2, 6, &reference, &candidate, false);
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.20", "lo", NULL, NULL);
+ pass &= ctrl_match("IPv4", 2, 7, &reference, &candidate, false);
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.21", "lo", NULL, NULL);
+ pass &= ctrl_match("IPv4", 2, 8, &reference, &candidate, false);
+
+ /*******************************************************************/
+ /* IPv4: Reference ID 3 */
+ set_ctrl_args(&reference, "tcp", "123.123.123.123", "8009", NULL, "eth0", NULL, NULL);
+
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", NULL, NULL, NULL, NULL);
+ pass &= ctrl_match("IPv4", 3, 0, &reference, &candidate, true);
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.20", NULL, NULL, NULL);
+ pass &= ctrl_match("IPv4", 3, 1, &reference, &candidate, true);
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", NULL, "eth0", NULL, NULL);
+ pass &= ctrl_match("IPv4", 3, 2, &reference, &candidate, true);
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.20", "eth0", NULL, NULL);
+ pass &= ctrl_match("IPv4", 3, 3, &reference, &candidate, true);
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.21", NULL, NULL, NULL);
+ pass &= ctrl_match("IPv4", 3, 4, &reference, &candidate, false);
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.21", "eth0", NULL, NULL);
+ pass &= ctrl_match("IPv4", 3, 5, &reference, &candidate, false);
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", NULL, "lo", NULL, NULL);
+ pass &= ctrl_match("IPv4", 3, 6, &reference, &candidate, false);
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.20", "lo", NULL, NULL);
+ pass &= ctrl_match("IPv4", 3, 7, &reference, &candidate, false);
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.21", "lo", NULL, NULL);
+ pass &= ctrl_match("IPv4", 3, 8, &reference, &candidate, false);
+
+ /*******************************************************************/
+ /* IPv4: Reference ID 4 */
+ set_ctrl_args(&reference, "tcp", "123.123.123.123", "8009", "192.168.1.20", "eth0", NULL, NULL);
+
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", NULL, NULL, NULL, NULL);
+ pass &= ctrl_match("IPv4", 4, 0, &reference, &candidate, true);
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.20", NULL, NULL, NULL);
+ pass &= ctrl_match("IPv4", 4, 1, &reference, &candidate, true);
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", NULL, "eth0", NULL, NULL);
+ pass &= ctrl_match("IPv4", 4, 2, &reference, &candidate, true);
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.20", "eth0", NULL, NULL);
+ pass &= ctrl_match("IPv4", 4, 3, &reference, &candidate, true);
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.21", NULL, NULL, NULL);
+ pass &= ctrl_match("IPv4", 4, 4, &reference, &candidate, false);
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.21", "eth0", NULL, NULL);
+ pass &= ctrl_match("IPv4", 4, 5, &reference, &candidate, false);
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", NULL, "lo", NULL, NULL);
+ pass &= ctrl_match("IPv4", 4, 6, &reference, &candidate, false);
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.20", "lo", NULL, NULL);
+ pass &= ctrl_match("IPv4", 4, 7, &reference, &candidate, false);
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.21", "lo", NULL, NULL);
+ pass &= ctrl_match("IPv4", 4, 8, &reference, &candidate, false);
+
+ /*******************************************************************/
+ /* IPv4: Reference ID 5 */
+ set_ctrl_args(&reference, "tcp", "123.123.123.123", "8009", "192.168.1.21", NULL, NULL, NULL);
+
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", NULL, NULL, NULL, NULL);
+ pass &= ctrl_match("IPv4", 5, 0, &reference, &candidate, true);
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.20", NULL, NULL, NULL);
+ pass &= ctrl_match("IPv4", 5, 1, &reference, &candidate, false);
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", NULL, "eth0", NULL, NULL);
+ pass &= ctrl_match("IPv4", 5, 2, &reference, &candidate, false);
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.20", "eth0", NULL, NULL);
+ pass &= ctrl_match("IPv4", 5, 3, &reference, &candidate, false);
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.21", NULL, NULL, NULL);
+ pass &= ctrl_match("IPv4", 5, 4, &reference, &candidate, true);
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.21", "eth0", NULL, NULL);
+ pass &= ctrl_match("IPv4", 5, 5, &reference, &candidate, false);
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", NULL, "lo", NULL, NULL);
+ pass &= ctrl_match("IPv4", 5, 6, &reference, &candidate, false);
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.20", "lo", NULL, NULL);
+ pass &= ctrl_match("IPv4", 5, 7, &reference, &candidate, false);
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.21", "lo", NULL, NULL);
+ pass &= ctrl_match("IPv4", 5, 8, &reference, &candidate, false);
+
+ /*******************************************************************/
+ /* IPv4: Reference ID 6 */
+ set_ctrl_args(&reference, "tcp", "123.123.123.123", "8009", NULL, NULL, "traddr=123.123.123.123,trsvcid=8009,src_addr=192.168.1.20", NULL);
+
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", NULL, NULL, NULL, NULL);
+ pass &= ctrl_match("IPv4", 6, 0, &reference, &candidate, true);
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.20", NULL, NULL, NULL);
+ pass &= ctrl_match("IPv4", 6, 1, &reference, &candidate, true);
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", NULL, "eth0", NULL, NULL);
+ pass &= ctrl_match("IPv4", 6, 2, &reference, &candidate, true);
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.20", "eth0", NULL, NULL);
+ pass &= ctrl_match("IPv4", 6, 3, &reference, &candidate, true);
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.21", NULL, NULL, NULL);
+ pass &= ctrl_match("IPv4", 6, 4, &reference, &candidate, false);
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.21", "eth0", NULL, NULL);
+ pass &= ctrl_match("IPv4", 6, 5, &reference, &candidate, false);
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", NULL, "lo", NULL, NULL);
+ pass &= ctrl_match("IPv4", 6, 6, &reference, &candidate, false);
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.20", "lo", NULL, NULL);
+ pass &= ctrl_match("IPv4", 6, 7, &reference, &candidate, false);
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.21", "lo", NULL, NULL);
+ pass &= ctrl_match("IPv4", 6, 8, &reference, &candidate, false);
+
+ /*******************************************************************/
+ /* IPv4: Reference ID 7 */
+ set_ctrl_args(&reference, "tcp", "123.123.123.123", "8009", NULL, NULL, "traddr=123.123.123.123,trsvcid=8009,src_addr=127.0.0.1", NULL);
+
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", NULL, NULL, NULL, NULL);
+ pass &= ctrl_match("IPv4", 7, 0, &reference, &candidate, true);
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.20", NULL, NULL, NULL);
+ pass &= ctrl_match("IPv4", 7, 1, &reference, &candidate, false);
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", NULL, "eth0", NULL, NULL);
+ pass &= ctrl_match("IPv4", 7, 2, &reference, &candidate, false);
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.20", "eth0", NULL, NULL);
+ pass &= ctrl_match("IPv4", 7, 3, &reference, &candidate, false);
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.21", NULL, NULL, NULL);
+ pass &= ctrl_match("IPv4", 7, 4, &reference, &candidate, false);
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.21", "eth0", NULL, NULL);
+ pass &= ctrl_match("IPv4", 7, 5, &reference, &candidate, false);
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", NULL, "lo", NULL, NULL);
+ pass &= ctrl_match("IPv4", 7, 6, &reference, &candidate, true);
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.20", "lo", NULL, NULL);
+ pass &= ctrl_match("IPv4", 7, 7, &reference, &candidate, false);
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.21", "lo", NULL, NULL);
+ pass &= ctrl_match("IPv4", 7, 8, &reference, &candidate, false);
+
+ /*******************************************************************/
+ /* IPv6: Reference ID 1 */
+ set_ctrl_args(&reference, "tcp", "aaaa::bbbb", "8009", NULL, NULL, NULL, NULL);
+
+ set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", NULL, NULL, NULL, NULL);
+ pass &= ctrl_match("IPv6", 1, 0, &reference, &candidate, true);
+ set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:beef", NULL, NULL, NULL);
+ pass &= ctrl_match("IPv6", 1, 1, &reference, &candidate, true);
+ set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", NULL, "eth0", NULL, NULL);
+ pass &= ctrl_match("IPv6", 1, 2, &reference, &candidate, true);
+ set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:beef", "eth0", NULL, NULL);
+ pass &= ctrl_match("IPv6", 1, 3, &reference, &candidate, true);
+ set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:cafe", NULL, NULL, NULL);
+ pass &= ctrl_match("IPv6", 1, 4, &reference, &candidate, true);
+ set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:cafe", "eth0", NULL, NULL);
+ pass &= ctrl_match("IPv6", 1, 5, &reference, &candidate, true);
+ set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", NULL, "lo", NULL, NULL);
+ pass &= ctrl_match("IPv6", 1, 6, &reference, &candidate, true);
+ set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:beef", "lo", NULL, NULL);
+ pass &= ctrl_match("IPv6", 1, 7, &reference, &candidate, true);
+ set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:cafe", "lo", NULL, NULL);
+ pass &= ctrl_match("IPv6", 1, 8, &reference, &candidate, true);
+
+ /*******************************************************************/
+ /* IPv6: Reference ID 2 */
+ set_ctrl_args(&reference, "tcp", "aaaa::bbbb", "8009", "fe80::dead:beef", NULL, NULL, NULL);
+
+ set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", NULL, NULL, NULL, NULL);
+ pass &= ctrl_match("IPv6", 2, 0, &reference, &candidate, true);
+ set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:beef", NULL, NULL, NULL);
+ pass &= ctrl_match("IPv6", 2, 1, &reference, &candidate, true);
+ set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", NULL, "eth0", NULL, NULL);
+ pass &= ctrl_match("IPv6", 2, 2, &reference, &candidate, true);
+ set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:beef", "eth0", NULL, NULL);
+ pass &= ctrl_match("IPv6", 2, 3, &reference, &candidate, true);
+ set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:cafe", NULL, NULL, NULL);
+ pass &= ctrl_match("IPv6", 2, 4, &reference, &candidate, false);
+ set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:cafe", "eth0", NULL, NULL);
+ pass &= ctrl_match("IPv6", 2, 5, &reference, &candidate, false);
+ set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", NULL, "lo", NULL, NULL);
+ pass &= ctrl_match("IPv6", 2, 6, &reference, &candidate, false);
+ set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:beef", "lo", NULL, NULL);
+ pass &= ctrl_match("IPv6", 2, 7, &reference, &candidate, false);
+ set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:cafe", "lo", NULL, NULL);
+ pass &= ctrl_match("IPv6", 2, 8, &reference, &candidate, false);
+
+ /*******************************************************************/
+ /* IPv6: Reference ID 3 */
+ set_ctrl_args(&reference, "tcp", "aaaa::bbbb", "8009", NULL, "eth0", NULL, NULL);
+
+ set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", NULL, NULL, NULL, NULL);
+ pass &= ctrl_match("IPv6", 3, 0, &reference, &candidate, true);
+ set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:beef", NULL, NULL, NULL);
+ pass &= ctrl_match("IPv6", 3, 1, &reference, &candidate, true);
+ set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", NULL, "eth0", NULL, NULL);
+ pass &= ctrl_match("IPv6", 3, 2, &reference, &candidate, true);
+ set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:beef", "eth0", NULL, NULL);
+ pass &= ctrl_match("IPv6", 3, 3, &reference, &candidate, true);
+ set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:cafe", NULL, NULL, NULL);
+ pass &= ctrl_match("IPv6", 3, 4, &reference, &candidate, false);
+ set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:cafe", "eth0", NULL, NULL);
+ pass &= ctrl_match("IPv6", 3, 5, &reference, &candidate, false);
+ set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", NULL, "lo", NULL, NULL);
+ pass &= ctrl_match("IPv6", 3, 6, &reference, &candidate, false);
+ set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:beef", "lo", NULL, NULL);
+ pass &= ctrl_match("IPv6", 3, 7, &reference, &candidate, false);
+ set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:cafe", "lo", NULL, NULL);
+ pass &= ctrl_match("IPv6", 3, 8, &reference, &candidate, false);
+
+ /*******************************************************************/
+ /* IPv6: Reference ID 4 */
+ set_ctrl_args(&reference, "tcp", "aaaa::bbbb", "8009", "fe80::dead:beef", "eth0", NULL, NULL);
+
+ set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", NULL, NULL, NULL, NULL);
+ pass &= ctrl_match("IPv6", 4, 0, &reference, &candidate, true);
+ set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:beef", NULL, NULL, NULL);
+ pass &= ctrl_match("IPv6", 4, 1, &reference, &candidate, true);
+ set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", NULL, "eth0", NULL, NULL);
+ pass &= ctrl_match("IPv6", 4, 2, &reference, &candidate, true);
+ set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:beef", "eth0", NULL, NULL);
+ pass &= ctrl_match("IPv6", 4, 3, &reference, &candidate, true);
+ set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:cafe", NULL, NULL, NULL);
+ pass &= ctrl_match("IPv6", 4, 4, &reference, &candidate, false);
+ set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:cafe", "eth0", NULL, NULL);
+ pass &= ctrl_match("IPv6", 4, 5, &reference, &candidate, false);
+ set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", NULL, "lo", NULL, NULL);
+ pass &= ctrl_match("IPv6", 4, 6, &reference, &candidate, false);
+ set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:beef", "lo", NULL, NULL);
+ pass &= ctrl_match("IPv6", 4, 7, &reference, &candidate, false);
+ set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:cafe", "lo", NULL, NULL);
+ pass &= ctrl_match("IPv6", 4, 8, &reference, &candidate, false);
+
+ /*******************************************************************/
+ /* IPv6: Reference ID 5 */
+ set_ctrl_args(&reference, "tcp", "aaaa::bbbb", "8009", "fe80::dead:cafe", NULL, NULL, NULL);
+
+ set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", NULL, NULL, NULL, NULL);
+ pass &= ctrl_match("IPv6", 5, 0, &reference, &candidate, true);
+ set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:beef", NULL, NULL, NULL);
+ pass &= ctrl_match("IPv6", 5, 1, &reference, &candidate, false);
+ set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", NULL, "eth0", NULL, NULL);
+ pass &= ctrl_match("IPv6", 5, 2, &reference, &candidate, false);
+ set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:beef", "eth0", NULL, NULL);
+ pass &= ctrl_match("IPv6", 5, 3, &reference, &candidate, false);
+ set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:cafe", NULL, NULL, NULL);
+ pass &= ctrl_match("IPv6", 5, 4, &reference, &candidate, true);
+ set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:cafe", "eth0", NULL, NULL);
+ pass &= ctrl_match("IPv6", 5, 5, &reference, &candidate, false);
+ set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", NULL, "lo", NULL, NULL);
+ pass &= ctrl_match("IPv6", 5, 6, &reference, &candidate, false);
+ set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:beef", "lo", NULL, NULL);
+ pass &= ctrl_match("IPv6", 5, 7, &reference, &candidate, false);
+ set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:cafe", "lo", NULL, NULL);
+ pass &= ctrl_match("IPv6", 5, 8, &reference, &candidate, false);
+
+ /*******************************************************************/
+ /* IPv6: Reference ID 6 */
+ set_ctrl_args(&reference, "tcp", "aaaa::bbbb", "8009", NULL, NULL, "traddr=aaaa::bbbb,trsvcid=8009,src_addr=fe80::dead:beef", NULL);
+
+ set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", NULL, NULL, NULL, NULL);
+ pass &= ctrl_match("IPv6", 6, 0, &reference, &candidate, true);
+ set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:beef", NULL, NULL, NULL);
+ pass &= ctrl_match("IPv6", 6, 1, &reference, &candidate, true);
+ set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", NULL, "eth0", NULL, NULL);
+ pass &= ctrl_match("IPv6", 6, 2, &reference, &candidate, true);
+ set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:beef", "eth0", NULL, NULL);
+ pass &= ctrl_match("IPv6", 6, 3, &reference, &candidate, true);
+ set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:cafe", NULL, NULL, NULL);
+ pass &= ctrl_match("IPv6", 6, 4, &reference, &candidate, false);
+ set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:cafe", "eth0", NULL, NULL);
+ pass &= ctrl_match("IPv6", 6, 5, &reference, &candidate, false);
+ set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", NULL, "lo", NULL, NULL);
+ pass &= ctrl_match("IPv6", 6, 6, &reference, &candidate, false);
+ set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:beef", "lo", NULL, NULL);
+ pass &= ctrl_match("IPv6", 6, 7, &reference, &candidate, false);
+ set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:cafe", "lo", NULL, NULL);
+ pass &= ctrl_match("IPv6", 6, 8, &reference, &candidate, false);
+
+ /*******************************************************************/
+ /* IPv6: Reference ID 7 */
+ set_ctrl_args(&reference, "tcp", "aaaa::bbbb", "8009", NULL, NULL, "traddr=aaaa::bbbb,trsvcid=8009,src_addr=::1", NULL);
+
+ set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", NULL, NULL, NULL, NULL);
+ pass &= ctrl_match("IPv6", 7, 0, &reference, &candidate, true);
+ set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:beef", NULL, NULL, NULL);
+ pass &= ctrl_match("IPv6", 7, 1, &reference, &candidate, false);
+ set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", NULL, "eth0", NULL, NULL);
+ pass &= ctrl_match("IPv6", 7, 2, &reference, &candidate, false);
+ set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:beef", "eth0", NULL, NULL);
+ pass &= ctrl_match("IPv6", 7, 3, &reference, &candidate, false);
+ set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:cafe", NULL, NULL, NULL);
+ pass &= ctrl_match("IPv6", 7, 4, &reference, &candidate, false);
+ set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:cafe", "eth0", NULL, NULL);
+ pass &= ctrl_match("IPv6", 7, 5, &reference, &candidate, false);
+ set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", NULL, "lo", NULL, NULL);
+ pass &= ctrl_match("IPv6", 7, 6, &reference, &candidate, true);
+ set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:beef", "lo", NULL, NULL);
+ pass &= ctrl_match("IPv6", 7, 7, &reference, &candidate, false);
+ set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:cafe", "lo", NULL, NULL);
+ pass &= ctrl_match("IPv6", 7, 8, &reference, &candidate, false);
+
+ return pass;
+}
+
+static bool ctrl_config_match(const char *tag,
+ int reference_id,
+ int candidate_id,
+ struct ctrl_args *reference,
+ struct ctrl_args *candidate,
+ bool should_match)
+{
+ bool match;
+ nvme_root_t r;
+ nvme_host_t h;
+ nvme_ctrl_t reference_ctrl; /* Existing controller (from sysfs) */
+ nvme_subsystem_t s;
+
+ r = nvme_create_root(stdout, LOG_INFO);
+ assert(r);
+
+ h = nvme_default_host(r);
+ assert(h);
+
+ s = nvme_lookup_subsystem(h, DEFAULT_SUBSYSNAME, reference->subsysnqn ? reference->subsysnqn : DEFAULT_SUBSYSNQN);
+ assert(s);
+
+ reference_ctrl = nvme_lookup_ctrl(s, reference->transport, reference->traddr,
+ reference->host_traddr, reference->host_iface,
+ reference->trsvcid, NULL);
+ assert(reference_ctrl);
+ reference_ctrl->name = "nvme1"; /* fake the device name */
+ if (reference->address) {
+ reference_ctrl->address = (char *)reference->address;
+ }
+
+ match = nvme_ctrl_config_match(reference_ctrl, candidate->transport, candidate->traddr,
+ candidate->trsvcid, candidate->subsysnqn,
+ candidate->host_traddr, candidate->host_iface);
+
+ if (should_match) {
+ if (!match) {
+ printf("%s-%d-%d: Failed to match config for Candidate (%s, %s, %s, %s, %s, %s)\n",
+ tag, reference_id, candidate_id,
+ candidate->transport, candidate->traddr, candidate->trsvcid,
+ candidate->subsysnqn, candidate->host_traddr, candidate->host_iface);
+ return false;
+ }
+ } else {
+ if (match) {
+ printf("%s-%d-%d: Config should not have matched for Candidate (%s, %s, %s, %s, %s, %s)\n",
+ tag, reference_id, candidate_id,
+ candidate->transport, candidate->traddr, candidate->trsvcid,
+ candidate->subsysnqn, candidate->host_traddr, candidate->host_iface);
+ return false;
+ }
+ }
+
+ /* Set the faked data back to NULL before freeing the tree */
+ reference_ctrl->name = NULL;
+ reference_ctrl->address = NULL;
+
+ nvme_free_tree(r);
+
+ return true;
+}
+
+static bool test_ctrl_config_match()
+{
+ bool pass = true;
+ struct ctrl_args reference = {0};
+ struct ctrl_args candidate = {0};
+
+ printf("\n"
+ "test_ctrl_config_match:\n");
+
+ set_ctrl_args(&reference, "tcp", "123.123.123.123", "8009", NULL, NULL, NULL, NULL);
+
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", NULL, NULL, NULL, NULL);
+ pass &= ctrl_config_match("IPv4", 1, 0, &reference, &candidate, true);
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.20", NULL, NULL, NULL);
+ pass &= ctrl_config_match("IPv4", 1, 1, &reference, &candidate, true);
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", NULL, "eth0", NULL, NULL);
+ pass &= ctrl_config_match("IPv4", 1, 2, &reference, &candidate, true);
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.20", "eth0", NULL, NULL);
+ pass &= ctrl_config_match("IPv4", 1, 3, &reference, &candidate, true);
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.21", NULL, NULL, NULL);
+ pass &= ctrl_config_match("IPv4", 1, 4, &reference, &candidate, true);
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.21", "eth0", NULL, NULL);
+ pass &= ctrl_config_match("IPv4", 1, 5, &reference, &candidate, true);
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", NULL, "lo", NULL, NULL);
+ pass &= ctrl_config_match("IPv4", 1, 6, &reference, &candidate, true);
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.20", "lo", NULL, NULL);
+ pass &= ctrl_config_match("IPv4", 1, 7, &reference, &candidate, true);
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.21", "lo", NULL, NULL);
+ pass &= ctrl_config_match("IPv4", 1, 8, &reference, &candidate, true);
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.21", "lo", NULL, "hello");
+ pass &= ctrl_config_match("IPv4", 1, 9, &reference, &candidate, false);
+ set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.21", "lo", NULL, DEFAULT_SUBSYSNQN);
+ pass &= ctrl_config_match("IPv4", 1, 9, &reference, &candidate, true);
+
+ return pass;
+}
+
+
+/**
+ * This test module uses a mocked ifaddrs library (mock-ifaddrs.c)
+ * such that there are 2 fake interfaces (eth0 and lo) with the
+ * following IP addresses:
+ *
+ * - eth0
+ * \_ IPv4: 192.168.1.20
+ * \_ IPv6: fe80::dead:beef
+ *
+ * - lo
+ * \_ IPv4: 127.0.0.1
+ * \_ IPv6: ::1
+ */
int main(int argc, char *argv[])
{
- test_lookup_1();
- test_lookup_2();
+ bool pass = true;
+
+ pass &= test_lookup();
+ pass &= test_src_addr();
+ pass &= test_ctrl_match_fc();
+ pass &= test_ctrl_match_rdma();
+ pass &= test_ctrl_match_tcp();
+ pass &= test_ctrl_config_match();
+
+ fflush(stdout);
- return 0;
+ exit(pass ? EXIT_SUCCESS : EXIT_FAILURE);
}