From 7e691c813bdf26bf9c51f03ee926818c00cc6e39 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Tue, 31 Jan 2023 05:17:04 +0100 Subject: Merging upstream version 1.3. Signed-off-by: Daniel Baumann --- .github/cross/ubuntu-armhf.txt | 1 + .github/cross/ubuntu-ppc64le.txt | 1 + .github/cross/ubuntu-s390x.txt | 18 + .github/cross/ubuntu-static.txt | 6 + .github/workflows/meson.yml | 72 ++- .gitignore | 2 + .readthedocs.yaml | 26 + doc/api.rst | 18 - doc/conf.py | 2 +- doc/config-schema.json | 4 + doc/config-schema.json.in | 4 + doc/installation.rst | 52 -- doc/man/nvme_admin_opcode.2 | 2 +- doc/man/nvme_admin_passthru.2 | 2 +- doc/man/nvme_admin_passthru64.2 | 2 +- doc/man/nvme_ae_info_css_nvm.2 | 2 +- doc/man/nvme_ae_info_error.2 | 2 +- doc/man/nvme_ae_info_notice.2 | 2 +- doc/man/nvme_ae_info_smart.2 | 2 +- doc/man/nvme_ae_type.2 | 2 +- doc/man/nvme_aggregate_endurance_group_event.2 | 2 +- doc/man/nvme_aggregate_predictable_lat_event.2 | 2 +- doc/man/nvme_ana_group_desc.2 | 2 +- doc/man/nvme_ana_log.2 | 2 +- doc/man/nvme_ana_state.2 | 2 +- doc/man/nvme_apst_entry.2 | 2 +- doc/man/nvme_boot_partition.2 | 2 +- doc/man/nvme_capacity_config_desc.2 | 2 +- doc/man/nvme_capacity_mgmt.2 | 2 +- doc/man/nvme_change_ns_event.2 | 2 +- doc/man/nvme_channel_config_desc.2 | 2 +- doc/man/nvme_cmb_size.2 | 2 +- doc/man/nvme_cmd_effects.2 | 2 +- doc/man/nvme_cmd_effects_log.2 | 2 +- doc/man/nvme_cmd_format_mset.2 | 2 +- doc/man/nvme_cmd_format_pi.2 | 2 +- doc/man/nvme_cmd_format_pil.2 | 2 +- doc/man/nvme_cmd_format_ses.2 | 2 +- doc/man/nvme_cmd_get_log_lid.2 | 26 +- doc/man/nvme_cmd_get_log_telemetry_host_lsp.2 | 2 +- doc/man/nvme_compare.2 | 2 +- doc/man/nvme_connect_err.2 | 8 +- doc/man/nvme_constants.2 | 2 +- doc/man/nvme_copy.2 | 2 +- doc/man/nvme_copy_range.2 | 2 +- doc/man/nvme_copy_range_f1.2 | 2 +- doc/man/nvme_create_ctrl.2 | 2 +- doc/man/nvme_create_root.2 | 2 +- doc/man/nvme_csi.2 | 2 +- doc/man/nvme_ctrl_first_ns.2 | 2 +- doc/man/nvme_ctrl_first_path.2 | 2 +- doc/man/nvme_ctrl_for_each_ns.2 | 2 +- doc/man/nvme_ctrl_for_each_ns_safe.2 | 2 +- doc/man/nvme_ctrl_for_each_path.2 | 2 +- doc/man/nvme_ctrl_for_each_path_safe.2 | 2 +- doc/man/nvme_ctrl_get_address.2 | 2 +- doc/man/nvme_ctrl_get_config.2 | 2 +- doc/man/nvme_ctrl_get_dhchap_host_key.2 | 2 +- doc/man/nvme_ctrl_get_dhchap_key.2 | 2 +- doc/man/nvme_ctrl_get_fd.2 | 2 +- doc/man/nvme_ctrl_get_firmware.2 | 2 +- doc/man/nvme_ctrl_get_host_iface.2 | 2 +- doc/man/nvme_ctrl_get_host_traddr.2 | 2 +- doc/man/nvme_ctrl_get_model.2 | 2 +- doc/man/nvme_ctrl_get_name.2 | 2 +- doc/man/nvme_ctrl_get_numa_node.2 | 2 +- doc/man/nvme_ctrl_get_queue_count.2 | 2 +- doc/man/nvme_ctrl_get_serial.2 | 2 +- doc/man/nvme_ctrl_get_sqsize.2 | 2 +- doc/man/nvme_ctrl_get_state.2 | 2 +- doc/man/nvme_ctrl_get_subsysnqn.2 | 2 +- doc/man/nvme_ctrl_get_subsystem.2 | 2 +- doc/man/nvme_ctrl_get_sysfs_dir.2 | 2 +- doc/man/nvme_ctrl_get_traddr.2 | 2 +- doc/man/nvme_ctrl_get_transport.2 | 2 +- doc/man/nvme_ctrl_get_trsvcid.2 | 2 +- doc/man/nvme_ctrl_identify.2 | 2 +- doc/man/nvme_ctrl_is_discovered.2 | 2 +- doc/man/nvme_ctrl_is_discovery_ctrl.2 | 2 +- doc/man/nvme_ctrl_is_persistent.2 | 2 +- doc/man/nvme_ctrl_is_unique_discovery_ctrl.2 | 11 + doc/man/nvme_ctrl_list.2 | 2 +- doc/man/nvme_ctrl_metadata_type.2 | 2 +- doc/man/nvme_ctrl_next_ns.2 | 2 +- doc/man/nvme_ctrl_next_path.2 | 2 +- doc/man/nvme_ctrl_reset.2 | 2 +- doc/man/nvme_ctrl_set_dhchap_host_key.2 | 2 +- doc/man/nvme_ctrl_set_dhchap_key.2 | 2 +- doc/man/nvme_ctrl_set_discovered.2 | 2 +- doc/man/nvme_ctrl_set_discovery_ctrl.2 | 2 +- doc/man/nvme_ctrl_set_persistent.2 | 2 +- doc/man/nvme_ctrl_set_unique_discovery_ctrl.2 | 15 + doc/man/nvme_ctrls_filter.2 | 2 +- doc/man/nvme_data_tfr.2 | 2 +- doc/man/nvme_default_host.2 | 2 +- doc/man/nvme_dev_self_test.2 | 4 +- doc/man/nvme_directive_dtype.2 | 2 +- doc/man/nvme_directive_receive_doper.2 | 2 +- doc/man/nvme_directive_recv.2 | 2 +- doc/man/nvme_directive_recv_identify_parameters.2 | 2 +- doc/man/nvme_directive_recv_stream_allocate.2 | 2 +- doc/man/nvme_directive_recv_stream_parameters.2 | 2 +- doc/man/nvme_directive_recv_stream_status.2 | 2 +- doc/man/nvme_directive_send.2 | 2 +- doc/man/nvme_directive_send_doper.2 | 2 +- doc/man/nvme_directive_send_id_endir.2 | 2 +- doc/man/nvme_directive_send_identify_endir.2 | 2 +- ...nvme_directive_send_stream_release_identifier.2 | 2 +- .../nvme_directive_send_stream_release_resource.2 | 2 +- doc/man/nvme_directive_types.2 | 2 +- doc/man/nvme_disconnect_ctrl.2 | 2 +- doc/man/nvme_dsm.2 | 2 +- doc/man/nvme_dsm_attributes.2 | 2 +- doc/man/nvme_dsm_range.2 | 2 +- doc/man/nvme_dst_stc.2 | 2 +- doc/man/nvme_dump_config.2 | 2 +- doc/man/nvme_dump_tree.2 | 2 +- doc/man/nvme_eg_critical_warning_flags.2 | 2 +- doc/man/nvme_eg_event_aggregate_log.2 | 2 +- doc/man/nvme_end_grp_chan_desc.2 | 2 +- doc/man/nvme_end_grp_config_desc.2 | 2 +- doc/man/nvme_endurance_group_log.2 | 2 +- doc/man/nvme_errno_to_string.2 | 2 +- doc/man/nvme_error_log_page.2 | 2 +- doc/man/nvme_fabrics_config.2 | 2 +- doc/man/nvme_fctype.2 | 2 +- doc/man/nvme_fdp_config_desc.2 | 55 ++ doc/man/nvme_fdp_config_fdpa.2 | 42 ++ doc/man/nvme_fdp_config_log.2 | 35 + doc/man/nvme_fdp_event.2 | 51 ++ doc/man/nvme_fdp_event_flags.2 | 24 + doc/man/nvme_fdp_event_realloc.2 | 31 + doc/man/nvme_fdp_event_realloc_flags.2 | 12 + doc/man/nvme_fdp_event_type.2 | 42 ++ doc/man/nvme_fdp_events_log.2 | 23 + doc/man/nvme_fdp_reclaim_unit_handle_status.2 | 21 + doc/man/nvme_fdp_reclaim_unit_handle_update.2 | 21 + doc/man/nvme_fdp_ruh_desc.2 | 19 + doc/man/nvme_fdp_ruh_status.2 | 23 + doc/man/nvme_fdp_ruh_status_desc.2 | 31 + doc/man/nvme_fdp_ruh_type.2 | 18 + doc/man/nvme_fdp_ruha.2 | 30 + doc/man/nvme_fdp_ruhu_desc.2 | 19 + doc/man/nvme_fdp_ruhu_log.2 | 23 + doc/man/nvme_fdp_stats_log.2 | 27 + doc/man/nvme_fdp_supported_event_attributes.2 | 18 + doc/man/nvme_fdp_supported_event_desc.2 | 19 + doc/man/nvme_feat.2 | 32 +- doc/man/nvme_feat_auto_pst.2 | 2 +- doc/man/nvme_feat_fdp_events_cdw11.2 | 23 + doc/man/nvme_feat_host_behavior.2 | 2 +- doc/man/nvme_feat_nswpcfg_state.2 | 2 +- doc/man/nvme_feat_plm_window_select.2 | 2 +- doc/man/nvme_feat_resv_notify_flags.2 | 2 +- doc/man/nvme_feat_tmpthresh_thsel.2 | 2 +- doc/man/nvme_features_async_event_config_flags.2 | 2 +- doc/man/nvme_features_id.2 | 14 +- doc/man/nvme_fid_supported_effects.2 | 2 +- doc/man/nvme_fid_supported_effects_log.2 | 2 +- doc/man/nvme_firmware_slot.2 | 2 +- doc/man/nvme_first_host.2 | 2 +- doc/man/nvme_first_subsystem.2 | 2 +- doc/man/nvme_flush.2 | 2 +- doc/man/nvme_for_each_host.2 | 2 +- doc/man/nvme_for_each_host_safe.2 | 2 +- doc/man/nvme_for_each_subsystem.2 | 2 +- doc/man/nvme_for_each_subsystem_safe.2 | 2 +- doc/man/nvme_format_nvm.2 | 2 +- doc/man/nvme_format_nvm_compln_event.2 | 2 +- doc/man/nvme_format_nvm_start_event.2 | 2 +- doc/man/nvme_free_ctrl.2 | 2 +- doc/man/nvme_free_host.2 | 2 +- doc/man/nvme_free_ns.2 | 2 +- doc/man/nvme_free_subsystem.2 | 2 +- doc/man/nvme_free_tree.2 | 2 +- doc/man/nvme_fw_commit.2 | 2 +- doc/man/nvme_fw_commit_ca.2 | 2 +- doc/man/nvme_fw_commit_event.2 | 2 +- doc/man/nvme_fw_download.2 | 2 +- doc/man/nvme_fw_download_seq.2 | 2 +- doc/man/nvme_gen_dhchap_key.2 | 2 +- doc/man/nvme_get_ana_log_len.2 | 2 +- doc/man/nvme_get_attr.2 | 2 +- doc/man/nvme_get_ctrl_attr.2 | 2 +- doc/man/nvme_get_ctrl_telemetry.2 | 2 +- doc/man/nvme_get_directive_receive_length.2 | 2 +- doc/man/nvme_get_discovery_args.2 | 2 +- doc/man/nvme_get_feature_length.2 | 2 +- doc/man/nvme_get_feature_length2.2 | 2 +- doc/man/nvme_get_features.2 | 2 +- doc/man/nvme_get_features_arbitration.2 | 2 +- doc/man/nvme_get_features_async_event.2 | 2 +- doc/man/nvme_get_features_auto_pst.2 | 2 +- doc/man/nvme_get_features_data.2 | 2 +- doc/man/nvme_get_features_endurance_event_cfg.2 | 2 +- doc/man/nvme_get_features_err_recovery.2 | 2 +- doc/man/nvme_get_features_hctm.2 | 2 +- doc/man/nvme_get_features_host_behavior.2 | 2 +- doc/man/nvme_get_features_host_id.2 | 2 +- doc/man/nvme_get_features_host_mem_buf.2 | 2 +- doc/man/nvme_get_features_iocs_profile.2 | 2 +- doc/man/nvme_get_features_irq_coalesce.2 | 2 +- doc/man/nvme_get_features_irq_config.2 | 2 +- doc/man/nvme_get_features_kato.2 | 2 +- doc/man/nvme_get_features_lba_range.2 | 2 +- doc/man/nvme_get_features_lba_sts_interval.2 | 2 +- doc/man/nvme_get_features_nopsc.2 | 2 +- doc/man/nvme_get_features_num_queues.2 | 2 +- doc/man/nvme_get_features_plm_config.2 | 2 +- doc/man/nvme_get_features_plm_window.2 | 2 +- doc/man/nvme_get_features_power_mgmt.2 | 2 +- doc/man/nvme_get_features_resv_mask.2 | 2 +- doc/man/nvme_get_features_resv_persist.2 | 2 +- doc/man/nvme_get_features_rrl.2 | 2 +- doc/man/nvme_get_features_sanitize.2 | 2 +- doc/man/nvme_get_features_sel.2 | 2 +- doc/man/nvme_get_features_simple.2 | 2 +- doc/man/nvme_get_features_sw_progress.2 | 2 +- doc/man/nvme_get_features_temp_thresh.2 | 2 +- doc/man/nvme_get_features_timestamp.2 | 2 +- doc/man/nvme_get_features_volatile_wc.2 | 2 +- doc/man/nvme_get_features_write_atomic.2 | 2 +- doc/man/nvme_get_features_write_protect.2 | 2 +- doc/man/nvme_get_host_telemetry.2 | 2 +- doc/man/nvme_get_lba_status.2 | 2 +- doc/man/nvme_get_lba_status_log.2 | 2 +- doc/man/nvme_get_log.2 | 2 +- doc/man/nvme_get_log_ana.2 | 2 +- doc/man/nvme_get_log_ana_groups.2 | 2 +- doc/man/nvme_get_log_boot_partition.2 | 2 +- doc/man/nvme_get_log_changed_ns_list.2 | 2 +- doc/man/nvme_get_log_cmd_effects.2 | 2 +- doc/man/nvme_get_log_create_telemetry_host.2 | 2 +- doc/man/nvme_get_log_device_self_test.2 | 2 +- doc/man/nvme_get_log_discovery.2 | 2 +- doc/man/nvme_get_log_endurance_group.2 | 2 +- doc/man/nvme_get_log_endurance_grp_evt.2 | 2 +- doc/man/nvme_get_log_error.2 | 2 +- doc/man/nvme_get_log_fdp_configurations.2 | 21 + doc/man/nvme_get_log_fdp_events.2 | 24 + doc/man/nvme_get_log_fdp_stats.2 | 21 + doc/man/nvme_get_log_fid_supported_effects.2 | 2 +- doc/man/nvme_get_log_fw_slot.2 | 2 +- doc/man/nvme_get_log_lba_status.2 | 2 +- doc/man/nvme_get_log_media_unit_stat.2 | 2 +- doc/man/nvme_get_log_mi_cmd_supported_effects.2 | 2 +- doc/man/nvme_get_log_page.2 | 2 +- doc/man/nvme_get_log_persistent_event.2 | 2 +- doc/man/nvme_get_log_predictable_lat_event.2 | 2 +- doc/man/nvme_get_log_predictable_lat_nvmset.2 | 2 +- doc/man/nvme_get_log_reclaim_unit_handle_usage.2 | 21 + doc/man/nvme_get_log_reservation.2 | 2 +- doc/man/nvme_get_log_sanitize.2 | 2 +- doc/man/nvme_get_log_smart.2 | 2 +- doc/man/nvme_get_log_support_cap_config_list.2 | 2 +- doc/man/nvme_get_log_supported_log_pages.2 | 2 +- doc/man/nvme_get_log_telemetry_ctrl.2 | 2 +- doc/man/nvme_get_log_telemetry_host.2 | 2 +- doc/man/nvme_get_log_zns_changed_zones.2 | 2 +- doc/man/nvme_get_logical_block_size.2 | 2 +- doc/man/nvme_get_new_host_telemetry.2 | 2 +- doc/man/nvme_get_ns_attr.2 | 2 +- doc/man/nvme_get_nsid.2 | 2 +- doc/man/nvme_get_path_attr.2 | 2 +- doc/man/nvme_get_property.2 | 2 +- doc/man/nvme_get_subsys_attr.2 | 2 +- doc/man/nvme_hmac_alg.2 | 2 +- doc/man/nvme_host_behavior_support.2 | 2 +- doc/man/nvme_host_get_dhchap_key.2 | 2 +- doc/man/nvme_host_get_hostid.2 | 2 +- doc/man/nvme_host_get_hostnqn.2 | 2 +- doc/man/nvme_host_get_hostsymname.2 | 2 +- doc/man/nvme_host_get_root.2 | 2 +- doc/man/nvme_host_is_pdc_enabled.2 | 16 + doc/man/nvme_host_mem_buf_attrs.2 | 2 +- doc/man/nvme_host_metadata.2 | 2 +- doc/man/nvme_host_set_dhchap_key.2 | 2 +- doc/man/nvme_host_set_hostsymname.2 | 2 +- doc/man/nvme_host_set_pdc_enabled.2 | 16 + doc/man/nvme_id_ctrl.2 | 2 +- doc/man/nvme_id_ctrl_anacap.2 | 2 +- doc/man/nvme_id_ctrl_apsta.2 | 2 +- doc/man/nvme_id_ctrl_avscc.2 | 2 +- doc/man/nvme_id_ctrl_cmic.2 | 2 +- doc/man/nvme_id_ctrl_cntrltype.2 | 2 +- doc/man/nvme_id_ctrl_cqes.2 | 2 +- doc/man/nvme_id_ctrl_ctratt.2 | 8 +- doc/man/nvme_id_ctrl_dctype.2 | 2 +- doc/man/nvme_id_ctrl_dsto.2 | 2 +- doc/man/nvme_id_ctrl_fcatt.2 | 2 +- doc/man/nvme_id_ctrl_fna.2 | 2 +- doc/man/nvme_id_ctrl_frmw.2 | 2 +- doc/man/nvme_id_ctrl_fuses.2 | 2 +- doc/man/nvme_id_ctrl_hctm.2 | 2 +- doc/man/nvme_id_ctrl_lpa.2 | 2 +- doc/man/nvme_id_ctrl_mec.2 | 2 +- doc/man/nvme_id_ctrl_nvm.2 | 2 +- doc/man/nvme_id_ctrl_nvmsr.2 | 2 +- doc/man/nvme_id_ctrl_nvscc.2 | 2 +- doc/man/nvme_id_ctrl_nwpc.2 | 2 +- doc/man/nvme_id_ctrl_oacs.2 | 2 +- doc/man/nvme_id_ctrl_oaes.2 | 2 +- doc/man/nvme_id_ctrl_ofcs.2 | 2 +- doc/man/nvme_id_ctrl_oncs.2 | 2 +- doc/man/nvme_id_ctrl_rpmbs.2 | 2 +- doc/man/nvme_id_ctrl_sanicap.2 | 2 +- doc/man/nvme_id_ctrl_sgls.2 | 2 +- doc/man/nvme_id_ctrl_sqes.2 | 2 +- doc/man/nvme_id_ctrl_vwc.2 | 2 +- doc/man/nvme_id_ctrl_vwci.2 | 2 +- doc/man/nvme_id_directives.2 | 2 +- doc/man/nvme_id_domain_attr.2 | 2 +- doc/man/nvme_id_domain_list.2 | 2 +- doc/man/nvme_id_endurance_group_list.2 | 2 +- doc/man/nvme_id_independent_id_ns.2 | 2 +- doc/man/nvme_id_iocs.2 | 2 +- doc/man/nvme_id_ns.2 | 2 +- doc/man/nvme_id_ns_attr.2 | 2 +- doc/man/nvme_id_ns_dlfeat.2 | 2 +- doc/man/nvme_id_ns_dpc.2 | 2 +- doc/man/nvme_id_ns_dps.2 | 2 +- doc/man/nvme_id_ns_flbas.2 | 2 +- doc/man/nvme_id_ns_granularity_desc.2 | 2 +- doc/man/nvme_id_ns_granularity_list.2 | 2 +- doc/man/nvme_id_ns_mc.2 | 2 +- doc/man/nvme_id_ns_nmic.2 | 2 +- doc/man/nvme_id_ns_rescap.2 | 2 +- doc/man/nvme_id_nsfeat.2 | 2 +- doc/man/nvme_id_nvmset_list.2 | 2 +- doc/man/nvme_id_psd.2 | 2 +- doc/man/nvme_id_uuid.2 | 2 +- doc/man/nvme_id_uuid_list.2 | 2 +- doc/man/nvme_id_uuid_list_entry.2 | 2 +- doc/man/nvme_identify.2 | 2 +- doc/man/nvme_identify_active_ns_list.2 | 2 +- doc/man/nvme_identify_active_ns_list_csi.2 | 2 +- doc/man/nvme_identify_allocated_ns.2 | 2 +- doc/man/nvme_identify_allocated_ns_list.2 | 2 +- doc/man/nvme_identify_allocated_ns_list_csi.2 | 2 +- doc/man/nvme_identify_cns.2 | 2 +- doc/man/nvme_identify_ctrl.2 | 2 +- doc/man/nvme_identify_ctrl_csi.2 | 2 +- doc/man/nvme_identify_ctrl_list.2 | 2 +- doc/man/nvme_identify_domain_list.2 | 2 +- doc/man/nvme_identify_endurance_group_list.2 | 2 +- doc/man/nvme_identify_independent_identify_ns.2 | 2 +- doc/man/nvme_identify_iocs.2 | 2 +- .../nvme_identify_iocs_ns_csi_user_data_format.2 | 2 +- doc/man/nvme_identify_ns.2 | 2 +- doc/man/nvme_identify_ns_csi.2 | 2 +- doc/man/nvme_identify_ns_csi_user_data_format.2 | 2 +- doc/man/nvme_identify_ns_descs.2 | 2 +- doc/man/nvme_identify_ns_granularity.2 | 2 +- doc/man/nvme_identify_nsid_ctrl_list.2 | 2 +- doc/man/nvme_identify_nvmset_list.2 | 2 +- doc/man/nvme_identify_primary_ctrl.2 | 2 +- doc/man/nvme_identify_secondary_ctrl_list.2 | 2 +- doc/man/nvme_identify_uuid.2 | 2 +- doc/man/nvme_init_copy_range.2 | 2 +- doc/man/nvme_init_copy_range_f1.2 | 2 +- doc/man/nvme_init_ctrl.2 | 2 +- doc/man/nvme_init_ctrl_list.2 | 2 +- doc/man/nvme_init_dsm_range.2 | 2 +- doc/man/nvme_init_logging.2 | 2 +- doc/man/nvme_io.2 | 2 +- doc/man/nvme_io_control_flags.2 | 2 +- doc/man/nvme_io_dsm_flags.2 | 2 +- doc/man/nvme_io_mgmt_recv.2 | 12 + doc/man/nvme_io_mgmt_recv_mo.2 | 12 + doc/man/nvme_io_mgmt_send.2 | 12 + doc/man/nvme_io_mgmt_send_mo.2 | 12 + doc/man/nvme_io_opcode.2 | 14 +- doc/man/nvme_io_passthru.2 | 2 +- doc/man/nvme_io_passthru64.2 | 2 +- doc/man/nvme_is_64bit_reg.2 | 2 +- doc/man/nvme_lba_range_type.2 | 2 +- doc/man/nvme_lba_range_type_entry.2 | 2 +- doc/man/nvme_lba_rd.2 | 2 +- doc/man/nvme_lba_status.2 | 2 +- doc/man/nvme_lba_status_atype.2 | 2 +- doc/man/nvme_lba_status_desc.2 | 2 +- doc/man/nvme_lba_status_log.2 | 2 +- doc/man/nvme_lbaf.2 | 2 +- doc/man/nvme_lbaf_rp.2 | 2 +- doc/man/nvme_lbart.2 | 2 +- doc/man/nvme_lbas_ns_element.2 | 2 +- doc/man/nvme_lockdown.2 | 2 +- doc/man/nvme_log_ana_lsp.2 | 2 +- doc/man/nvme_lookup_ctrl.2 | 2 +- doc/man/nvme_lookup_host.2 | 2 +- doc/man/nvme_lookup_subsystem.2 | 2 +- doc/man/nvme_media_unit_config_desc.2 | 2 +- doc/man/nvme_media_unit_stat_desc.2 | 2 +- doc/man/nvme_media_unit_stat_log.2 | 2 +- doc/man/nvme_metadata_element_desc.2 | 2 +- doc/man/nvme_mi_admin_admin_passthru.2 | 74 +++ doc/man/nvme_mi_admin_format_nvm.2 | 2 +- doc/man/nvme_mi_admin_fw_commit.2 | 2 +- doc/man/nvme_mi_admin_fw_download.2 | 2 +- doc/man/nvme_mi_admin_get_features_data.2 | 2 +- doc/man/nvme_mi_admin_get_log.2 | 2 +- doc/man/nvme_mi_admin_get_log_ana.2 | 2 +- doc/man/nvme_mi_admin_get_log_ana_groups.2 | 2 +- doc/man/nvme_mi_admin_get_log_boot_partition.2 | 2 +- doc/man/nvme_mi_admin_get_log_changed_ns_list.2 | 2 +- doc/man/nvme_mi_admin_get_log_cmd_effects.2 | 2 +- .../nvme_mi_admin_get_log_create_telemetry_host.2 | 2 +- doc/man/nvme_mi_admin_get_log_device_self_test.2 | 2 +- doc/man/nvme_mi_admin_get_log_discovery.2 | 2 +- doc/man/nvme_mi_admin_get_log_endurance_group.2 | 2 +- doc/man/nvme_mi_admin_get_log_endurance_grp_evt.2 | 2 +- doc/man/nvme_mi_admin_get_log_error.2 | 2 +- .../nvme_mi_admin_get_log_fid_supported_effects.2 | 2 +- doc/man/nvme_mi_admin_get_log_fw_slot.2 | 2 +- doc/man/nvme_mi_admin_get_log_lba_status.2 | 2 +- doc/man/nvme_mi_admin_get_log_media_unit_stat.2 | 2 +- ...vme_mi_admin_get_log_mi_cmd_supported_effects.2 | 2 +- doc/man/nvme_mi_admin_get_log_persistent_event.2 | 2 +- .../nvme_mi_admin_get_log_predictable_lat_event.2 | 2 +- .../nvme_mi_admin_get_log_predictable_lat_nvmset.2 | 2 +- doc/man/nvme_mi_admin_get_log_reservation.2 | 2 +- doc/man/nvme_mi_admin_get_log_sanitize.2 | 2 +- doc/man/nvme_mi_admin_get_log_simple.2 | 2 +- doc/man/nvme_mi_admin_get_log_smart.2 | 2 +- ...nvme_mi_admin_get_log_support_cap_config_list.2 | 2 +- .../nvme_mi_admin_get_log_supported_log_pages.2 | 2 +- doc/man/nvme_mi_admin_get_log_telemetry_ctrl.2 | 2 +- doc/man/nvme_mi_admin_get_log_telemetry_host.2 | 2 +- doc/man/nvme_mi_admin_get_log_zns_changed_zones.2 | 2 +- doc/man/nvme_mi_admin_get_nsid_log.2 | 2 +- doc/man/nvme_mi_admin_identify.2 | 2 +- doc/man/nvme_mi_admin_identify_active_ns_list.2 | 2 +- doc/man/nvme_mi_admin_identify_allocated_ns.2 | 2 +- doc/man/nvme_mi_admin_identify_allocated_ns_list.2 | 2 +- doc/man/nvme_mi_admin_identify_cns_nsid.2 | 2 +- doc/man/nvme_mi_admin_identify_ctrl.2 | 2 +- doc/man/nvme_mi_admin_identify_ctrl_list.2 | 2 +- doc/man/nvme_mi_admin_identify_ns.2 | 2 +- doc/man/nvme_mi_admin_identify_ns_descs.2 | 2 +- doc/man/nvme_mi_admin_identify_nsid_ctrl_list.2 | 2 +- doc/man/nvme_mi_admin_identify_partial.2 | 2 +- doc/man/nvme_mi_admin_identify_primary_ctrl.2 | 2 +- .../nvme_mi_admin_identify_secondary_ctrl_list.2 | 2 +- doc/man/nvme_mi_admin_ns_attach.2 | 2 +- doc/man/nvme_mi_admin_ns_attach_ctrls.2 | 2 +- doc/man/nvme_mi_admin_ns_detach_ctrls.2 | 2 +- doc/man/nvme_mi_admin_req_hdr.2 | 2 +- doc/man/nvme_mi_admin_resp_hdr.2 | 2 +- doc/man/nvme_mi_admin_sanitize_nvm.2 | 2 +- doc/man/nvme_mi_admin_security_recv.2 | 2 +- doc/man/nvme_mi_admin_security_send.2 | 2 +- doc/man/nvme_mi_admin_xfer.2 | 2 +- doc/man/nvme_mi_ccs.2 | 2 +- doc/man/nvme_mi_close.2 | 2 +- doc/man/nvme_mi_close_ctrl.2 | 2 +- doc/man/nvme_mi_cmd_supported_effects.2 | 2 +- doc/man/nvme_mi_cmd_supported_effects_log.2 | 2 +- doc/man/nvme_mi_config_id.2 | 2 +- doc/man/nvme_mi_config_smbus_freq.2 | 2 +- doc/man/nvme_mi_create_root.2 | 2 +- doc/man/nvme_mi_csts.2 | 2 +- doc/man/nvme_mi_ctrl_health_status.2 | 2 +- doc/man/nvme_mi_cwarn.2 | 2 +- doc/man/nvme_mi_dtyp.2 | 2 +- doc/man/nvme_mi_elem.2 | 2 +- doc/man/nvme_mi_free_root.2 | 2 +- doc/man/nvme_mi_init_ctrl.2 | 2 +- doc/man/nvme_mi_message_type.2 | 2 +- doc/man/nvme_mi_mi_opcode.2 | 2 +- doc/man/nvme_mi_mi_read_mi_data_ctrl.2 | 2 +- doc/man/nvme_mi_mi_read_mi_data_ctrl_list.2 | 2 +- doc/man/nvme_mi_mi_read_mi_data_port.2 | 2 +- doc/man/nvme_mi_mi_read_mi_data_subsys.2 | 2 +- doc/man/nvme_mi_mi_req_hdr.2 | 2 +- doc/man/nvme_mi_mi_resp_hdr.2 | 2 +- doc/man/nvme_mi_mi_subsystem_health_status_poll.2 | 2 +- doc/man/nvme_mi_msg_hdr.2 | 2 +- doc/man/nvme_mi_msg_resp.2 | 2 +- doc/man/nvme_mi_nvm_ss_health_status.2 | 2 +- doc/man/nvme_mi_open_mctp.2 | 2 +- doc/man/nvme_mi_osc.2 | 2 +- doc/man/nvme_mi_port_pcie.2 | 2 +- doc/man/nvme_mi_port_smb.2 | 2 +- doc/man/nvme_mi_read_ctrl_info.2 | 2 +- doc/man/nvme_mi_read_nvm_ss_info.2 | 2 +- doc/man/nvme_mi_read_port_info.2 | 2 +- doc/man/nvme_mi_read_sc_list.2 | 2 +- doc/man/nvme_mi_resp_status.2 | 2 +- doc/man/nvme_mi_set_probe_enabled.2 | 16 + doc/man/nvme_mi_status_to_string.2 | 2 +- doc/man/nvme_mi_vpd_hdr.2 | 2 +- doc/man/nvme_mi_vpd_mr_common.2 | 2 +- doc/man/nvme_mi_vpd_mra.2 | 2 +- doc/man/nvme_mi_vpd_ppmra.2 | 2 +- doc/man/nvme_mi_vpd_telem.2 | 2 +- doc/man/nvme_mi_vpd_tra.2 | 2 +- doc/man/nvme_namespace_attach_ctrls.2 | 2 +- doc/man/nvme_namespace_detach_ctrls.2 | 2 +- doc/man/nvme_namespace_filter.2 | 2 +- doc/man/nvme_namespace_first_path.2 | 2 +- doc/man/nvme_namespace_for_each_path.2 | 2 +- doc/man/nvme_namespace_for_each_path_safe.2 | 2 +- doc/man/nvme_namespace_next_path.2 | 2 +- doc/man/nvme_nd_ns_fpi.2 | 2 +- doc/man/nvme_next_host.2 | 2 +- doc/man/nvme_next_subsystem.2 | 2 +- doc/man/nvme_ns_attach.2 | 2 +- doc/man/nvme_ns_attach_ctrls.2 | 2 +- doc/man/nvme_ns_attach_sel.2 | 2 +- doc/man/nvme_ns_compare.2 | 2 +- doc/man/nvme_ns_detach_ctrls.2 | 2 +- doc/man/nvme_ns_flush.2 | 2 +- doc/man/nvme_ns_get_csi.2 | 2 +- doc/man/nvme_ns_get_ctrl.2 | 2 +- doc/man/nvme_ns_get_eui64.2 | 2 +- doc/man/nvme_ns_get_fd.2 | 2 +- doc/man/nvme_ns_get_firmware.2 | 2 +- doc/man/nvme_ns_get_generic_name.2 | 2 +- doc/man/nvme_ns_get_lba_count.2 | 2 +- doc/man/nvme_ns_get_lba_size.2 | 2 +- doc/man/nvme_ns_get_lba_util.2 | 2 +- doc/man/nvme_ns_get_meta_size.2 | 2 +- doc/man/nvme_ns_get_model.2 | 2 +- doc/man/nvme_ns_get_name.2 | 2 +- doc/man/nvme_ns_get_nguid.2 | 2 +- doc/man/nvme_ns_get_nsid.2 | 2 +- doc/man/nvme_ns_get_serial.2 | 2 +- doc/man/nvme_ns_get_subsystem.2 | 2 +- doc/man/nvme_ns_get_sysfs_dir.2 | 2 +- doc/man/nvme_ns_get_uuid.2 | 2 +- doc/man/nvme_ns_id_desc.2 | 2 +- doc/man/nvme_ns_id_desc_nidt.2 | 2 +- doc/man/nvme_ns_identify.2 | 2 +- doc/man/nvme_ns_identify_descs.2 | 2 +- doc/man/nvme_ns_list.2 | 2 +- doc/man/nvme_ns_metadata_type.2 | 2 +- doc/man/nvme_ns_mgmt.2 | 2 +- doc/man/nvme_ns_mgmt_create.2 | 2 +- doc/man/nvme_ns_mgmt_delete.2 | 2 +- doc/man/nvme_ns_mgmt_sel.2 | 2 +- doc/man/nvme_ns_read.2 | 2 +- doc/man/nvme_ns_rescan.2 | 2 +- doc/man/nvme_ns_verify.2 | 2 +- doc/man/nvme_ns_write.2 | 2 +- doc/man/nvme_ns_write_protect_cfg.2 | 2 +- doc/man/nvme_ns_write_uncorrectable.2 | 2 +- doc/man/nvme_ns_write_zeros.2 | 2 +- doc/man/nvme_nss_hw_err_event.2 | 2 +- doc/man/nvme_nvm_id_ns.2 | 2 +- doc/man/nvme_nvm_id_ns_elbaf.2 | 2 +- doc/man/nvme_nvm_identify_ctrl.2 | 2 +- doc/man/nvme_nvmeset_pl_status.2 | 2 +- doc/man/nvme_nvmset_attr.2 | 2 +- doc/man/nvme_nvmset_pl_events.2 | 2 +- doc/man/nvme_nvmset_predictable_lat_log.2 | 2 +- doc/man/nvme_open.2 | 2 +- doc/man/nvme_passthru_cmd.2 | 2 +- doc/man/nvme_passthru_cmd64.2 | 2 +- doc/man/nvme_path_get_ana_state.2 | 2 +- doc/man/nvme_path_get_ctrl.2 | 2 +- doc/man/nvme_path_get_name.2 | 2 +- doc/man/nvme_path_get_ns.2 | 2 +- doc/man/nvme_path_get_sysfs_dir.2 | 2 +- doc/man/nvme_paths_filter.2 | 2 +- doc/man/nvme_persistent_event_entry.2 | 2 +- doc/man/nvme_persistent_event_log.2 | 2 +- doc/man/nvme_persistent_event_types.2 | 2 +- doc/man/nvme_pevent_log_action.2 | 2 +- doc/man/nvme_plm_config.2 | 2 +- doc/man/nvme_pmr_size.2 | 2 +- doc/man/nvme_pmr_throughput.2 | 2 +- doc/man/nvme_power_on_reset_info_list.2 | 2 +- doc/man/nvme_primary_ctrl_cap.2 | 2 +- doc/man/nvme_psd_flags.2 | 2 +- doc/man/nvme_psd_power_scale.2 | 2 +- doc/man/nvme_psd_ps.2 | 2 +- doc/man/nvme_psd_workload.2 | 2 +- doc/man/nvme_read.2 | 2 +- doc/man/nvme_read_config.2 | 2 +- doc/man/nvme_refresh_topology.2 | 2 +- doc/man/nvme_register_offsets.2 | 2 +- doc/man/nvme_registered_ctrl.2 | 2 +- doc/man/nvme_registered_ctrl_ext.2 | 2 +- doc/man/nvme_rescan_ctrl.2 | 2 +- doc/man/nvme_resv_acquire.2 | 2 +- doc/man/nvme_resv_cptpl.2 | 2 +- doc/man/nvme_resv_notification_log.2 | 2 +- doc/man/nvme_resv_notify_rnlpt.2 | 2 +- doc/man/nvme_resv_racqa.2 | 2 +- doc/man/nvme_resv_register.2 | 2 +- doc/man/nvme_resv_release.2 | 2 +- doc/man/nvme_resv_report.2 | 2 +- doc/man/nvme_resv_rrega.2 | 2 +- doc/man/nvme_resv_rrela.2 | 2 +- doc/man/nvme_resv_rtype.2 | 2 +- doc/man/nvme_resv_status.2 | 2 +- doc/man/nvme_sanitize_compln_event.2 | 2 +- doc/man/nvme_sanitize_log_page.2 | 2 +- doc/man/nvme_sanitize_nvm.2 | 2 +- doc/man/nvme_sanitize_sanact.2 | 2 +- doc/man/nvme_sanitize_sstat.2 | 2 +- doc/man/nvme_sanitize_start_event.2 | 2 +- doc/man/nvme_scan.2 | 2 +- doc/man/nvme_scan_ctrl.2 | 2 +- doc/man/nvme_scan_ctrl_namespace_paths.2 | 2 +- doc/man/nvme_scan_ctrl_namespaces.2 | 2 +- doc/man/nvme_scan_ctrls.2 | 2 +- doc/man/nvme_scan_namespace.2 | 2 +- doc/man/nvme_scan_subsystem_namespaces.2 | 2 +- doc/man/nvme_scan_subsystems.2 | 2 +- doc/man/nvme_scan_topology.2 | 2 +- doc/man/nvme_secondary_ctrl.2 | 2 +- doc/man/nvme_secondary_ctrl_list.2 | 2 +- doc/man/nvme_security_receive.2 | 2 +- doc/man/nvme_security_send.2 | 2 +- doc/man/nvme_self_test_log.2 | 2 +- doc/man/nvme_set_feature_event.2 | 2 +- doc/man/nvme_set_features.2 | 2 +- doc/man/nvme_set_features_arbitration.2 | 2 +- doc/man/nvme_set_features_async_event.2 | 2 +- doc/man/nvme_set_features_auto_pst.2 | 2 +- doc/man/nvme_set_features_data.2 | 2 +- doc/man/nvme_set_features_endurance_evt_cfg.2 | 2 +- doc/man/nvme_set_features_err_recovery.2 | 2 +- doc/man/nvme_set_features_hctm.2 | 2 +- doc/man/nvme_set_features_host_behavior.2 | 2 +- doc/man/nvme_set_features_host_id.2 | 4 +- doc/man/nvme_set_features_irq_coalesce.2 | 2 +- doc/man/nvme_set_features_irq_config.2 | 2 +- doc/man/nvme_set_features_lba_range.2 | 2 +- doc/man/nvme_set_features_lba_sts_interval.2 | 2 +- doc/man/nvme_set_features_nopsc.2 | 2 +- doc/man/nvme_set_features_plm_config.2 | 2 +- doc/man/nvme_set_features_plm_window.2 | 2 +- doc/man/nvme_set_features_power_mgmt.2 | 2 +- doc/man/nvme_set_features_resv_mask.2 | 2 +- doc/man/nvme_set_features_resv_persist.2 | 2 +- doc/man/nvme_set_features_rrl.2 | 2 +- doc/man/nvme_set_features_sanitize.2 | 2 +- doc/man/nvme_set_features_simple.2 | 2 +- doc/man/nvme_set_features_sw_progress.2 | 2 +- doc/man/nvme_set_features_temp_thresh.2 | 2 +- doc/man/nvme_set_features_timestamp.2 | 2 +- doc/man/nvme_set_features_volatile_wc.2 | 2 +- doc/man/nvme_set_features_write_atomic.2 | 2 +- doc/man/nvme_set_features_write_protect.2 | 2 +- doc/man/nvme_set_property.2 | 2 +- doc/man/nvme_smart_crit.2 | 2 +- doc/man/nvme_smart_egcw.2 | 2 +- doc/man/nvme_smart_log.2 | 2 +- doc/man/nvme_st_code.2 | 8 +- doc/man/nvme_st_curr_op.2 | 2 +- doc/man/nvme_st_result.2 | 2 +- doc/man/nvme_st_valid_diag_info.2 | 2 +- doc/man/nvme_status_code.2 | 2 +- doc/man/nvme_status_code_type.2 | 2 +- doc/man/nvme_status_equals.2 | 2 +- doc/man/nvme_status_field.2 | 2 +- doc/man/nvme_status_get_type.2 | 2 +- doc/man/nvme_status_get_value.2 | 2 +- doc/man/nvme_status_result.2 | 2 +- doc/man/nvme_status_to_errno.2 | 2 +- doc/man/nvme_status_to_string.2 | 2 +- doc/man/nvme_status_type.2 | 2 +- doc/man/nvme_streams_directive_params.2 | 2 +- doc/man/nvme_streams_directive_status.2 | 2 +- doc/man/nvme_submit_admin_passthru.2 | 2 +- doc/man/nvme_submit_admin_passthru64.2 | 2 +- doc/man/nvme_submit_io_passthru.2 | 2 +- doc/man/nvme_submit_io_passthru64.2 | 2 +- doc/man/nvme_subsys_filter.2 | 2 +- doc/man/nvme_subsys_type.2 | 2 +- doc/man/nvme_subsystem_first_ctrl.2 | 2 +- doc/man/nvme_subsystem_first_ns.2 | 2 +- doc/man/nvme_subsystem_for_each_ctrl.2 | 2 +- doc/man/nvme_subsystem_for_each_ctrl_safe.2 | 2 +- doc/man/nvme_subsystem_for_each_ns.2 | 2 +- doc/man/nvme_subsystem_for_each_ns_safe.2 | 2 +- doc/man/nvme_subsystem_get_host.2 | 2 +- doc/man/nvme_subsystem_get_name.2 | 2 +- doc/man/nvme_subsystem_get_nqn.2 | 2 +- doc/man/nvme_subsystem_get_sysfs_dir.2 | 2 +- doc/man/nvme_subsystem_get_type.2 | 2 +- doc/man/nvme_subsystem_lookup_namespace.2 | 2 +- doc/man/nvme_subsystem_next_ctrl.2 | 2 +- doc/man/nvme_subsystem_next_ns.2 | 2 +- doc/man/nvme_subsystem_reset.2 | 2 +- doc/man/nvme_supported_cap_config_list_log.2 | 2 +- doc/man/nvme_supported_log_pages.2 | 2 +- doc/man/nvme_telemetry_da.2 | 2 +- doc/man/nvme_telemetry_log.2 | 2 +- doc/man/nvme_thermal_exc_event.2 | 2 +- doc/man/nvme_time_stamp_change_event.2 | 2 +- doc/man/nvme_timestamp.2 | 2 +- doc/man/nvme_unlink_ctrl.2 | 2 +- doc/man/nvme_update_config.2 | 2 +- doc/man/nvme_uring_cmd.2 | 2 +- doc/man/nvme_verify.2 | 2 +- doc/man/nvme_version.2 | 2 +- doc/man/nvme_virt_mgmt_act.2 | 2 +- doc/man/nvme_virt_mgmt_rt.2 | 2 +- doc/man/nvme_virtual_mgmt.2 | 2 +- doc/man/nvme_write.2 | 2 +- doc/man/nvme_write_uncorrectable.2 | 2 +- doc/man/nvme_write_zeros.2 | 2 +- doc/man/nvme_zns_append.2 | 2 +- doc/man/nvme_zns_changed_zone_log.2 | 2 +- doc/man/nvme_zns_desc.2 | 2 +- doc/man/nvme_zns_id_ctrl.2 | 2 +- doc/man/nvme_zns_id_ns.2 | 2 +- doc/man/nvme_zns_identify_ctrl.2 | 2 +- doc/man/nvme_zns_identify_ns.2 | 2 +- doc/man/nvme_zns_lbafe.2 | 2 +- doc/man/nvme_zns_mgmt_recv.2 | 2 +- doc/man/nvme_zns_mgmt_send.2 | 2 +- doc/man/nvme_zns_recv_action.2 | 2 +- doc/man/nvme_zns_report_options.2 | 2 +- doc/man/nvme_zns_report_zones.2 | 2 +- doc/man/nvme_zns_send_action.2 | 2 +- doc/man/nvme_zns_za.2 | 2 +- doc/man/nvme_zns_zs.2 | 2 +- doc/man/nvme_zns_zt.2 | 2 +- doc/man/nvme_zone_report.2 | 2 +- doc/man/nvmf_add_ctrl.2 | 2 +- doc/man/nvmf_addr_family.2 | 2 +- doc/man/nvmf_adrfam_str.2 | 2 +- doc/man/nvmf_cms_str.2 | 2 +- doc/man/nvmf_connect_data.2 | 2 +- doc/man/nvmf_connect_disc_entry.2 | 2 +- doc/man/nvmf_default_config.2 | 2 +- doc/man/nvmf_dim_data.2 | 2 +- doc/man/nvmf_dim_entfmt.2 | 2 +- doc/man/nvmf_dim_etype.2 | 2 +- doc/man/nvmf_dim_tas.2 | 2 +- doc/man/nvmf_disc_eflags.2 | 2 +- doc/man/nvmf_disc_log_entry.2 | 2 +- doc/man/nvmf_discovery_log.2 | 2 +- doc/man/nvmf_eflags_str.2 | 2 +- doc/man/nvmf_exat_len.2 | 6 +- doc/man/nvmf_exattype.2 | 2 +- doc/man/nvmf_ext_attr.2 | 2 +- doc/man/nvmf_ext_die.2 | 2 +- doc/man/nvmf_get_discovery_log.2 | 2 +- doc/man/nvmf_get_discovery_wargs.2 | 2 +- doc/man/nvmf_hostid_from_file.2 | 4 +- doc/man/nvmf_hostnqn_from_file.2 | 4 +- doc/man/nvmf_hostnqn_generate.2 | 2 +- doc/man/nvmf_log_discovery_lid_support.2 | 2 +- doc/man/nvmf_log_discovery_lsp.2 | 2 +- doc/man/nvmf_prtype_str.2 | 2 +- doc/man/nvmf_qptype_str.2 | 2 +- doc/man/nvmf_rdma_cms.2 | 2 +- doc/man/nvmf_rdma_prtype.2 | 2 +- doc/man/nvmf_rdma_qptype.2 | 2 +- doc/man/nvmf_register_ctrl.2 | 2 +- doc/man/nvmf_sectype_str.2 | 2 +- doc/man/nvmf_subtype_str.2 | 2 +- doc/man/nvmf_tcp_sectype.2 | 2 +- doc/man/nvmf_treq.2 | 2 +- doc/man/nvmf_treq_str.2 | 2 +- doc/man/nvmf_trtype.2 | 2 +- doc/man/nvmf_trtype_str.2 | 2 +- doc/man/nvmf_update_config.2 | 2 +- doc/mi.rst | 43 -- doc/mi.rst.in | 11 + doc/quickstart.rst | 5 - doc/rst/fabrics.rst | 4 +- doc/rst/ioctl.rst | 194 +++++- doc/rst/linux.rst | 21 - doc/rst/meson.build | 4 +- doc/rst/mi.rst | 98 +++ doc/rst/tree.rst | 70 ++ doc/rst/types.rst | 716 ++++++++++++++++++++- doc/rst/util.rst | 7 +- examples/meson.build | 4 +- examples/mi-conf.c | 61 +- examples/mi-mctp.c | 6 +- libnvme.pc.in | 12 - libnvme/nvme.i | 19 +- meson.build | 62 +- meson_options.txt | 2 +- src/libnvme-mi.map | 8 + src/libnvme.map | 12 + src/meson.build | 2 +- src/nvme/api-types.h | 44 ++ src/nvme/fabrics.c | 93 ++- src/nvme/ioctl.c | 84 +++ src/nvme/ioctl.h | 245 ++++++- src/nvme/json.c | 9 + src/nvme/linux.c | 39 -- src/nvme/linux.h | 11 - src/nvme/mi-mctp.c | 354 +++++----- src/nvme/mi.c | 351 +++++++++- src/nvme/mi.h | 53 +- src/nvme/private.h | 20 + src/nvme/tree.c | 26 +- src/nvme/tree.h | 41 ++ src/nvme/types.h | 361 ++++++++++- src/nvme/util.c | 26 +- src/nvme/util.h | 6 +- subprojects/dbus.wrap | 4 + subprojects/uuid.wrap | 6 - test/mi.c | 119 +++- 803 files changed, 4578 insertions(+), 1309 deletions(-) create mode 100644 .github/cross/ubuntu-s390x.txt create mode 100644 .github/cross/ubuntu-static.txt create mode 100644 .readthedocs.yaml delete mode 100644 doc/api.rst delete mode 100644 doc/installation.rst create mode 100644 doc/man/nvme_ctrl_is_unique_discovery_ctrl.2 create mode 100644 doc/man/nvme_ctrl_set_unique_discovery_ctrl.2 create mode 100644 doc/man/nvme_fdp_config_desc.2 create mode 100644 doc/man/nvme_fdp_config_fdpa.2 create mode 100644 doc/man/nvme_fdp_config_log.2 create mode 100644 doc/man/nvme_fdp_event.2 create mode 100644 doc/man/nvme_fdp_event_flags.2 create mode 100644 doc/man/nvme_fdp_event_realloc.2 create mode 100644 doc/man/nvme_fdp_event_realloc_flags.2 create mode 100644 doc/man/nvme_fdp_event_type.2 create mode 100644 doc/man/nvme_fdp_events_log.2 create mode 100644 doc/man/nvme_fdp_reclaim_unit_handle_status.2 create mode 100644 doc/man/nvme_fdp_reclaim_unit_handle_update.2 create mode 100644 doc/man/nvme_fdp_ruh_desc.2 create mode 100644 doc/man/nvme_fdp_ruh_status.2 create mode 100644 doc/man/nvme_fdp_ruh_status_desc.2 create mode 100644 doc/man/nvme_fdp_ruh_type.2 create mode 100644 doc/man/nvme_fdp_ruha.2 create mode 100644 doc/man/nvme_fdp_ruhu_desc.2 create mode 100644 doc/man/nvme_fdp_ruhu_log.2 create mode 100644 doc/man/nvme_fdp_stats_log.2 create mode 100644 doc/man/nvme_fdp_supported_event_attributes.2 create mode 100644 doc/man/nvme_fdp_supported_event_desc.2 create mode 100644 doc/man/nvme_feat_fdp_events_cdw11.2 create mode 100644 doc/man/nvme_get_log_fdp_configurations.2 create mode 100644 doc/man/nvme_get_log_fdp_events.2 create mode 100644 doc/man/nvme_get_log_fdp_stats.2 create mode 100644 doc/man/nvme_get_log_reclaim_unit_handle_usage.2 create mode 100644 doc/man/nvme_host_is_pdc_enabled.2 create mode 100644 doc/man/nvme_host_set_pdc_enabled.2 create mode 100644 doc/man/nvme_io_mgmt_recv.2 create mode 100644 doc/man/nvme_io_mgmt_recv_mo.2 create mode 100644 doc/man/nvme_io_mgmt_send.2 create mode 100644 doc/man/nvme_io_mgmt_send_mo.2 create mode 100644 doc/man/nvme_mi_admin_admin_passthru.2 create mode 100644 doc/man/nvme_mi_set_probe_enabled.2 delete mode 100644 doc/mi.rst delete mode 100644 doc/quickstart.rst delete mode 100644 libnvme.pc.in create mode 100644 subprojects/dbus.wrap delete mode 100644 subprojects/uuid.wrap diff --git a/.github/cross/ubuntu-armhf.txt b/.github/cross/ubuntu-armhf.txt index 2eee70b..41c8328 100644 --- a/.github/cross/ubuntu-armhf.txt +++ b/.github/cross/ubuntu-armhf.txt @@ -4,6 +4,7 @@ ar = '/usr/arm-linux-gnueabihf/bin/ar' strip = '/usr/arm-linux-gnueabihf/bin/strip' pkgconfig = '/usr/bin/arm-linux-gnueabihf-pkg-config' ld = '/usr/bin/arm-linux/gnueabihf-ld' +exe_wrapper = '/usr/bin/qemu-arm-static' [properties] root = '/usr/arm-linux-gnueabihf' diff --git a/.github/cross/ubuntu-ppc64le.txt b/.github/cross/ubuntu-ppc64le.txt index 4cf6a92..6baaefb 100644 --- a/.github/cross/ubuntu-ppc64le.txt +++ b/.github/cross/ubuntu-ppc64le.txt @@ -4,6 +4,7 @@ ar = '/usr/powerpc64le-linux-gnu/bin/ar' strip = '/usr/powerpc64le-linux-gnu/bin/strip' pkgconfig = '/usr/bin/powerpc64le-linux-gnu-pkg-config' ld = '/usr/bin/powerpc64le-linux-gnu-ld' +exe_wrapper = '/usr/bin/qemu-ppc64le-static' [properties] root = '/usr/powerpc64le-linux-gnu' diff --git a/.github/cross/ubuntu-s390x.txt b/.github/cross/ubuntu-s390x.txt new file mode 100644 index 0000000..51a3511 --- /dev/null +++ b/.github/cross/ubuntu-s390x.txt @@ -0,0 +1,18 @@ +[binaries] +c = '/usr/bin/s390x-linux-gnu-gcc' +ar = '/usr/s390x-linux-gnu/bin/ar' +strip = '/usr/s390x-linux-gnu/bin/strip' +pkgconfig = '/usr/bin/s390x-linux-gnu-pkg-config' +ld = '/usr/bin/s390x-linux-gnu-ld' +exe_wrapper = '/usr/bin/qemu-s390x-static' + +[properties] +root = '/usr/s390x-linux-gnu' +has_function_printf = true +skip_sanity_check = true + +[host_machine] +system = 'linux' +cpu_family = 's390x' +cpu = '' +endian = 'big' diff --git a/.github/cross/ubuntu-static.txt b/.github/cross/ubuntu-static.txt new file mode 100644 index 0000000..d4d6c9a --- /dev/null +++ b/.github/cross/ubuntu-static.txt @@ -0,0 +1,6 @@ +[properties] +c_args = '-static' +cpp_args = c_args + +[binaries] +c = '/usr/bin/gcc' diff --git a/.github/workflows/meson.yml b/.github/workflows/meson.yml index 52b2b6a..340cff3 100644 --- a/.github/workflows/meson.yml +++ b/.github/workflows/meson.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - name: install libraries - run: sudo apt-get install libjson-c-dev + run: sudo apt-get install libjson-c-dev libdbus-1-dev - uses: actions/checkout@v3 - uses: actions/setup-python@v4 with: @@ -44,16 +44,16 @@ jobs: EOF sudo apt update - name: install armhf compiler - run: sudo apt install gcc-arm-linux-gnueabihf pkg-config + run: sudo apt install gcc-arm-linux-gnueabihf pkg-config qemu-user-static - name: install libraries - run: sudo apt install uuid-dev:armhf libjson-c-dev:armhf + run: sudo apt install libjson-c-dev:armhf - uses: actions/checkout@v3 - uses: BSFishy/meson-build@v1.0.3 with: # suppress python for now; the python headers currently assume native setup-options: --werror --cross-file=.github/cross/ubuntu-armhf.txt --wrap-mode=nofallback -Dpython=false options: --verbose - action: build + action: test - uses: actions/upload-artifact@v3 if: failure() with: @@ -74,16 +74,46 @@ jobs: EOF sudo apt update - name: install powerpc64le compiler - run: sudo apt install gcc-powerpc64le-linux-gnu pkg-config + run: sudo apt install gcc-powerpc64le-linux-gnu pkg-config qemu-user-static - name: install libraries - run: sudo apt install uuid-dev:ppc64el libjson-c-dev:ppc64el + run: sudo apt install libjson-c-dev:ppc64el - uses: actions/checkout@v3 - uses: BSFishy/meson-build@v1.0.3 with: # suppress python for now; the python headers currently assume native setup-options: --werror --cross-file=.github/cross/ubuntu-ppc64le.txt --wrap-mode=nofallback -Dpython=false options: --verbose - action: build + action: test + - uses: actions/upload-artifact@v3 + if: failure() + with: + name: Linux_Meson_Testlog + path: build/meson-logs/testlog.txt + + build-cross-s390x: + runs-on: ubuntu-latest + steps: + - name: set up s390x architecture + run: | + export release=$(lsb_release -c -s) + sudo dpkg --add-architecture s390x + sudo sed -i -e 's/deb http/deb [arch=amd64] http/g' /etc/apt/sources.list + sudo dd of=/etc/apt/sources.list.d/s390x.list <`) or -1 with errno set otherwise. +.. c:function:: int nvme_get_log_page (int fd, __u32 xfer_len, struct nvme_get_log_args *args) + + Get log page data + +**Parameters** + +``int fd`` + File descriptor of nvme device + +``__u32 xfer_len`` + Max log transfer size per request to split the total. + +``struct nvme_get_log_args *args`` + :c:type:`struct nvme_get_log_args ` argument structure + +**Return** + +The nvme command status if a response was received (see +:c:type:`enum nvme_status_field `) or -1 with errno set otherwise. + + .. c:function:: int nvme_get_log_supported_log_pages (int fd, bool rae, struct nvme_supported_log_pages *log) Retrieve nmve supported log pages @@ -1883,6 +1904,97 @@ The nvme command status if a response was received (see :c:type:`enum nvme_status_field `) or -1 with errno set otherwise. +.. c:function:: int nvme_get_log_fdp_configurations (int fd, __u16 egid, __u32 offset, __u32 len, void *log) + + Get list of Flexible Data Placement configurations + +**Parameters** + +``int fd`` + File descriptor of nvme device + +``__u16 egid`` + Endurance group identifier + +``__u32 offset`` + Offset into log page + +``__u32 len`` + Length (in bytes) of provided user buffer to hold the log data + +``void *log`` + Log page data buffer + + +.. c:function:: int nvme_get_log_reclaim_unit_handle_usage (int fd, __u16 egid, __u32 offset, __u32 len, void *log) + + Get reclaim unit handle usage + +**Parameters** + +``int fd`` + File descriptor of nvme device + +``__u16 egid`` + Endurance group identifier + +``__u32 offset`` + Offset into log page + +``__u32 len`` + Length (in bytes) of provided user buffer to hold the log data + +``void *log`` + Log page data buffer + + +.. c:function:: int nvme_get_log_fdp_stats (int fd, __u16 egid, __u32 offset, __u32 len, void *log) + + Get Flexible Data Placement statistics + +**Parameters** + +``int fd`` + File descriptor of nvme device + +``__u16 egid`` + Endurance group identifier + +``__u32 offset`` + Offset into log page + +``__u32 len`` + Length (in bytes) of provided user buffer to hold the log data + +``void *log`` + Log page data buffer + + +.. c:function:: int nvme_get_log_fdp_events (int fd, __u16 egid, bool host_events, __u32 offset, __u32 len, void *log) + + Get Flexible Data Placement events + +**Parameters** + +``int fd`` + File descriptor of nvme device + +``__u16 egid`` + Endurance group identifier + +``bool host_events`` + Whether to report host or controller events + +``__u32 offset`` + Offset into log page + +``__u32 len`` + Length (in bytes) of provided user buffer to hold the log data + +``void *log`` + Log page data buffer + + .. c:function:: int nvme_get_log_ana (int fd, enum nvme_log_ana_lsp lsp, bool rae, __u64 offset, __u32 len, void *log) Retrieve Asymmetric Namespace Access log page @@ -2911,7 +3023,7 @@ The nvme command status if a response was received (see .. c:function:: int nvme_set_features_host_id (int fd, bool exhid, bool save, __u8 *hostid) - Set enable extended host identifers feature + Set enable extended host identifiers feature **Parameters** @@ -4307,7 +4419,7 @@ controller and may include testing of the media associated with namespaces. The controller may return a response to this command immediately while running the self-test in the background. -Set the 'nsid' field to 0 to not include namepsaces in the test. Set to +Set the 'nsid' field to 0 to not include namespaces in the test. Set to 0xffffffff to test all namespaces. All other values tests a specific namespace, if present. @@ -4608,6 +4720,84 @@ The nvme command status if a response was received (see :c:type:`enum nvme_status_field `) or -1 with errno set otherwise. +.. c:function:: int nvme_io_mgmt_recv (struct nvme_io_mgmt_recv_args *args) + + I/O Management Receive command + +**Parameters** + +``struct nvme_io_mgmt_recv_args *args`` + :c:type:`struct nvme_io_mgmt_recv_args ` argument structure + +**Return** + +The nvme command status if a response was received (see +:c:type:`enum nvme_status_field `) or -1 with errno set otherwise. + + +.. c:function:: int nvme_fdp_reclaim_unit_handle_status (int fd, __u32 nsid, __u32 data_len, void *data) + + Get reclaim unit handle status + +**Parameters** + +``int fd`` + File descriptor of nvme device + +``__u32 nsid`` + Namespace identifier + +``__u32 data_len`` + Length of response buffer + +``void *data`` + Response buffer + +**Return** + +The nvme command status if a response was received (see +:c:type:`enum nvme_status_field `) or -1 with errno set otherwise. + + +.. c:function:: int nvme_io_mgmt_send (struct nvme_io_mgmt_send_args *args) + + I/O Management Send command + +**Parameters** + +``struct nvme_io_mgmt_send_args *args`` + :c:type:`struct nvme_io_mgmt_send_args ` argument structure + +**Return** + +The nvme command status if a response was received (see +:c:type:`enum nvme_status_field `) or -1 with errno set otherwise. + + +.. c:function:: int nvme_fdp_reclaim_unit_handle_update (int fd, __u32 nsid, unsigned int npids, __u16 *pids) + + Update a list of reclaim unit handles + +**Parameters** + +``int fd`` + File descriptor of nvme device + +``__u32 nsid`` + Namespace identifier + +``unsigned int npids`` + Number of placement identifiers + +``__u16 *pids`` + List of placement identifiers + +**Return** + +The nvme command status if a response was received (see +:c:type:`enum nvme_status_field `) or -1 with errno set otherwise. + + .. c:function:: int nvme_zns_mgmt_send (struct nvme_zns_mgmt_send_args *args) ZNS management send command diff --git a/doc/rst/linux.rst b/doc/rst/linux.rst index 83dbca9..4f159f1 100644 --- a/doc/rst/linux.rst +++ b/doc/rst/linux.rst @@ -143,27 +143,6 @@ The nvme command status if a response was received (see :c:type:`enum nvme_status_field `) or -1 with errno set otherwise. -.. c:function:: int nvme_get_log_page (int fd, __u32 xfer_len, struct nvme_get_log_args *args) - - Get log page data - -**Parameters** - -``int fd`` - File descriptor of nvme device - -``__u32 xfer_len`` - Max log transfer size per request to split the total. - -``struct nvme_get_log_args *args`` - :c:type:`struct nvme_get_log_args ` argument structure - -**Return** - -The nvme command status if a response was received (see -:c:type:`enum nvme_status_field `) or -1 with errno set otherwise. - - .. c:function:: int nvme_get_ana_log_len (int fd, size_t *analen) Retrieve size of the current ANA log diff --git a/doc/rst/meson.build b/doc/rst/meson.build index 43874f0..ea79115 100644 --- a/doc/rst/meson.build +++ b/doc/rst/meson.build @@ -29,8 +29,6 @@ if want_docs != 'false' endforeach endif else - if want_docs == 'all' or want_docs == 'rst' - install_subdir('rst', install_dir: rstdir) - endif + # no prebuild docs endif endif diff --git a/doc/rst/mi.rst b/doc/rst/mi.rst index 3eaa20c..7e82918 100644 --- a/doc/rst/mi.rst +++ b/doc/rst/mi.rst @@ -635,6 +635,25 @@ new root object, or NULL on failure. root to free +.. c:function:: void nvme_mi_set_probe_enabled (nvme_root_t root, bool enabled) + + enable/disable the probe for new endpoints + +**Parameters** + +``nvme_root_t root`` + :c:type:`nvme_root_t` object + +``bool enabled`` + whether to probe new endpoints + +**Description** + +Controls whether newly-created endpoints are probed for quirks on creation. +Defaults to enabled, which results in some initial messaging with the +endpoint to determine model-specific details. + + .. c:type:: nvme_mi_ep_t @@ -1427,6 +1446,85 @@ The nvme command status if a response was received (see :c:type:`enum nvme_status_field `) or -1 with errno set otherwise.. +.. c:function:: int nvme_mi_admin_admin_passthru (nvme_mi_ctrl_t ctrl, __u8 opcode, __u8 flags, __u16 rsvd, __u32 nsid, __u32 cdw2, __u32 cdw3, __u32 cdw10, __u32 cdw11, __u32 cdw12, __u32 cdw13, __u32 cdw14, __u32 cdw15, __u32 data_len, void *data, __u32 metadata_len, void *metadata, __u32 timeout_ms, __u32 *result) + + Submit an nvme admin passthrough command + +**Parameters** + +``nvme_mi_ctrl_t ctrl`` + Controller to send command to + +``__u8 opcode`` + The nvme admin command to send + +``__u8 flags`` + NVMe command flags (not used) + +``__u16 rsvd`` + Reserved for future use + +``__u32 nsid`` + Namespace identifier + +``__u32 cdw2`` + Command dword 2 + +``__u32 cdw3`` + Command dword 3 + +``__u32 cdw10`` + Command dword 10 + +``__u32 cdw11`` + Command dword 11 + +``__u32 cdw12`` + Command dword 12 + +``__u32 cdw13`` + Command dword 13 + +``__u32 cdw14`` + Command dword 14 + +``__u32 cdw15`` + Command dword 15 + +``__u32 data_len`` + Length of the data transferred in this command in bytes + +``void *data`` + Pointer to user address of the data buffer + +``__u32 metadata_len`` + Length of metadata transferred in this command(not used) + +``void *metadata`` + Pointer to user address of the metadata buffer(not used) + +``__u32 timeout_ms`` + How long to wait for the command to complete + +``__u32 *result`` + Optional field to return the result from the CQE dword 0 + +**Description** + +Send a customized NVMe Admin command request message and get the corresponding +response message. + +This interface supports no data, host to controller and controller to +host but it doesn't support bidirectional data transfer. +Also this interface only supports data transfer size range [0, 4096] (bytes) +so the & data_len parameter must be less than 4097. + +**Return** + +The nvme command status if a response was received (see +:c:type:`enum nvme_status_field `) or -1 with errno set otherwise. + + .. c:function:: int nvme_mi_admin_identify_partial (nvme_mi_ctrl_t ctrl, struct nvme_identify_args *args, off_t offset, size_t size) Perform an Admin identify command, and retrieve partial response data. diff --git a/doc/rst/tree.rst b/doc/rst/tree.rst index d6f270d..9a8bb3f 100644 --- a/doc/rst/tree.rst +++ b/doc/rst/tree.rst @@ -133,6 +133,44 @@ DH-HMAC-CHAP host key or NULL if not set DH-HMAC-CHAP Key to set or NULL to clear existing key +.. c:function:: void nvme_host_set_pdc_enabled (nvme_host_t h, bool enabled) + + Set Persistent Discovery Controller flag + +**Parameters** + +``nvme_host_t h`` + Host for which the falg should be set + +``bool enabled`` + The bool to set the enabled flag + +**Description** + +When nvme_host_set_pdc_enabled() is not used to set the PDC flag, +nvme_host_is_pdc_enabled() will return the default value which was +passed into the function and not the undefined flag value. + + +.. c:function:: bool nvme_host_is_pdc_enabled (nvme_host_t h, bool fallback) + + Is Persistenct Discovery Controller enabled + +**Parameters** + +``nvme_host_t h`` + Host which to check if PDC is enabled + +``bool fallback`` + The fallback default value of the flag when + **nvme_host_set_pdc_enabled** has not be used + to set the flag. + +**Return** + +true if PDC is enabled for **h**, else false + + .. c:function:: nvme_host_t nvme_default_host (nvme_root_t r) Initializes the default host @@ -1644,6 +1682,38 @@ Returns the value of the 'discovery_ctrl' flag which specifies whether Value of the 'discover_ctrl' flag +.. c:function:: void nvme_ctrl_set_unique_discovery_ctrl (nvme_ctrl_t c, bool unique) + + Set the 'unique_discovery_ctrl' flag + +**Parameters** + +``nvme_ctrl_t c`` + Controller to be modified + +``bool unique`` + value of the unique_disc_ctrl flag + +**Description** + +Sets the 'unique_discovery_ctrl' flag in **c** to specify wheter +**c** is a unique discovery controller + + +.. c:function:: bool nvme_ctrl_is_unique_discovery_ctrl (nvme_ctrl_t c) + + Check the 'unique_discovery_ctrl' flag + +**Parameters** + +``nvme_ctrl_t c`` + Controller to be checked + +**Return** + +Value of the 'unique_discovery_ctrl' flag + + .. c:function:: int nvme_ctrl_identify (nvme_ctrl_t c, struct nvme_id_ctrl *id) Issues an 'identify controller' command diff --git a/doc/rst/types.rst b/doc/rst/types.rst index 9140821..0435c87 100644 --- a/doc/rst/types.rst +++ b/doc/rst/types.rst @@ -1155,6 +1155,9 @@ power scale value ``NVME_CTRL_CTRATT_ELBAS`` Extended LBA Formats supported +``NVME_CTRL_CTRATT_FDPS`` + Flexible Data Placement supported + @@ -3944,6 +3947,9 @@ Supported Log Pages (Log Identifier 00h) ``NVME_ST_CODE_VS`` Vendor specific. +``NVME_ST_CODE_ABORT`` + Abort device self-test operation. + ``NVME_ST_CODE_SHIFT`` Shift amount to get the code value from the :c:type:`struct nvme_st_result `.dsts field. @@ -4775,6 +4781,35 @@ bytes, in size. This log captures the controller’s internal state. +.. c:struct:: nvme_timestamp + + Timestamp - Data Structure for Get Features + +**Definition** + +:: + + struct nvme_timestamp { + __u8 timestamp[6]; + __u8 attr; + __u8 rsvd; + }; + +**Members** + +``timestamp`` + Timestamp value based on origin and synch field + +``attr`` + Attribute + +``rsvd`` + Reserved + + + + + .. c:struct:: nvme_time_stamp_change_event Timestamp Change Event @@ -6175,6 +6210,598 @@ bytes, in size. This log captures the controller’s internal state. +.. c:enum:: nvme_fdp_ruh_type + + Reclaim Unit Handle Type + +**Constants** + +``NVME_FDP_RUHT_INITIALLY_ISOLATED`` + Initially Isolated + +``NVME_FDP_RUHT_PERSISTENTLY_ISOLATED`` + Persistently Isolated + + + + +.. c:struct:: nvme_fdp_ruh_desc + + Reclaim Unit Handle Descriptor + +**Definition** + +:: + + struct nvme_fdp_ruh_desc { + __u8 ruht; + __u8 rsvd1[3]; + }; + +**Members** + +``ruht`` + Reclaim Unit Handle Type + +``rsvd1`` + Reserved + + + + + +.. c:enum:: nvme_fdp_config_fdpa + + FDP Attributes + +**Constants** + +``NVME_FDP_CONFIG_FDPA_RGIF_SHIFT`` + Reclaim Group Identifier Format Shift + +``NVME_FDP_CONFIG_FDPA_RGIF_MASK`` + Reclaim Group Identifier Format Mask + +``NVME_FDP_CONFIG_FDPA_FDPVWC_SHIFT`` + FDP Volatile Write Cache Shift + +``NVME_FDP_CONFIG_FDPA_FDPVWC_MASK`` + FDP Volatile Write Cache Mask + +``NVME_FDP_CONFIG_FDPA_VALID_SHIFT`` + FDP Configuration Valid Shift + +``NVME_FDP_CONFIG_FDPA_VALID_MASK`` + FDP Configuration Valid Mask + + + + +.. c:struct:: nvme_fdp_config_desc + + FDP Configuration Descriptor + +**Definition** + +:: + + struct nvme_fdp_config_desc { + __u16 size; + __u8 fdpa; + __u8 vss; + __u32 nrg; + __u16 nruh; + __u16 maxpids; + __u32 nnss; + __u64 runs; + __u32 erutl; + __u8 rsvd28[36]; + struct nvme_fdp_ruh_desc ruhs[]; + }; + +**Members** + +``size`` + Descriptor size + +``fdpa`` + FDP Attributes (:c:type:`enum nvme_fdp_config_fdpa `) + +``vss`` + Vendor Specific Size + +``nrg`` + Number of Reclaim Groups + +``nruh`` + Number of Reclaim Unit Handles + +``maxpids`` + Max Placement Identifiers + +``nnss`` + Number of Namespaces Supported + +``runs`` + Reclaim Unit Nominal Size + +``erutl`` + Estimated Reclaim Unit Time Limit + +``rsvd28`` + Reserved + +``ruhs`` + Reclaim Unit Handle descriptors (:c:type:`struct nvme_fdp_ruh_desc `) + + + + + +.. c:struct:: nvme_fdp_config_log + + FDP Configurations Log Page + +**Definition** + +:: + + struct nvme_fdp_config_log { + __u16 n; + __u8 version; + __u8 rsvd3; + __u32 size; + __u8 rsvd8[8]; + struct nvme_fdp_config_desc configs[]; + }; + +**Members** + +``n`` + Number of FDP Configurations + +``version`` + Log page version + +``rsvd3`` + Reserved + +``size`` + Log page size in bytes + +``rsvd8`` + Reserved + +``configs`` + FDP Configuration descriptors (:c:type:`struct nvme_fdp_config_desc `) + + + + + +.. c:enum:: nvme_fdp_ruha + + Reclaim Unit Handle Attributes + +**Constants** + +``NVME_FDP_RUHA_HOST_SHIFT`` + Host Specified Reclaim Unit Handle Shift + +``NVME_FDP_RUHA_HOST_MASK`` + Host Specified Reclaim Unit Handle Mask + +``NVME_FDP_RUHA_CTRL_SHIFT`` + Controller Specified Reclaim Unit Handle Shift + +``NVME_FDP_RUHA_CTRL_MASK`` + Controller Specified Reclaim Unit Handle Mask + + + + +.. c:struct:: nvme_fdp_ruhu_desc + + Reclaim Unit Handle Usage Descriptor + +**Definition** + +:: + + struct nvme_fdp_ruhu_desc { + __u8 ruha; + __u8 rsvd1[7]; + }; + +**Members** + +``ruha`` + Reclaim Unit Handle Attributes (:c:type:`enum nvme_fdp_ruha `) + +``rsvd1`` + Reserved + + + + + +.. c:struct:: nvme_fdp_ruhu_log + + Reclaim Unit Handle Usage Log Page + +**Definition** + +:: + + struct nvme_fdp_ruhu_log { + __u16 nruh; + __u8 rsvd2[6]; + struct nvme_fdp_ruhu_desc ruhus[]; + }; + +**Members** + +``nruh`` + Number of Reclaim Unit Handles + +``rsvd2`` + Reserved + +``ruhus`` + Reclaim Unit Handle Usage descriptors + + + + + +.. c:struct:: nvme_fdp_stats_log + + FDP Statistics Log Page + +**Definition** + +:: + + struct nvme_fdp_stats_log { + __u8 hbmw[16]; + __u8 mbmw[16]; + __u8 mbe[16]; + __u8 rsvd48[16]; + }; + +**Members** + +``hbmw`` + Host Bytes with Metadata Written + +``mbmw`` + Media Bytes with Metadata Written + +``mbe`` + Media Bytes Erased + +``rsvd48`` + Reserved + + + + + +.. c:enum:: nvme_fdp_event_type + + FDP Event Types + +**Constants** + +``NVME_FDP_EVENT_RUNFW`` + Reclaim Unit Not Fully Written + +``NVME_FDP_EVENT_RUTLE`` + Reclaim Unit Time Limit Exceeded + +``NVME_FDP_EVENT_RESET`` + Controller Level Reset Modified Reclaim Unit Handles + +``NVME_FDP_EVENT_PID`` + Invalid Placement Identifier + +``NVME_FDP_EVENT_REALLOC`` + Media Reallocated + +``NVME_FDP_EVENT_MODIFY`` + Implicitly Modified Reclaim Unit Handle + + + + +.. c:enum:: nvme_fdp_event_realloc_flags + + Media Reallocated Event Type Specific Flags + +**Constants** + +``NVME_FDP_EVENT_REALLOC_F_LBAV`` + LBA Valid + + + + +.. c:struct:: nvme_fdp_event_realloc + + Media Reallocated Event Type Specific Information + +**Definition** + +:: + + struct nvme_fdp_event_realloc { + __u8 flags; + __u8 rsvd1; + __u16 nlbam; + __u64 lba; + __u8 rsvd12[4]; + }; + +**Members** + +``flags`` + Event Type Specific flags (:c:type:`enum nvme_fdp_event_realloc_flags `) + +``rsvd1`` + Reserved + +``nlbam`` + Number of LBAs Moved + +``lba`` + Logical Block Address + +``rsvd12`` + Reserved + + + + + +.. c:enum:: nvme_fdp_event_flags + + FDP Event Flags + +**Constants** + +``NVME_FDP_EVENT_F_PIV`` + Placement Identifier Valid + +``NVME_FDP_EVENT_F_NSIDV`` + Namespace Identifier Valid + +``NVME_FDP_EVENT_F_LV`` + Location Valid + + + + +.. c:struct:: nvme_fdp_event + + FDP Event + +**Definition** + +:: + + struct nvme_fdp_event { + __u8 type; + __u8 flags; + __u16 pid; + struct nvme_timestamp ts; + __u32 nsid; + __u8 type_specific[16]; + __u16 rgid; + __u8 ruhid; + __u8 rsvd35[5]; + __u8 vs[24]; + }; + +**Members** + +``type`` + Event Type (:c:type:`enum nvme_fdp_event_type `) + +``flags`` + Event Flags (:c:type:`enum nvme_fdp_event_flags `) + +``pid`` + Placement Identifier + +``ts`` + Timestamp + +``nsid`` + Namespace Identifier + +``type_specific`` + Event Type Specific Information + +``rgid`` + Reclaim Group Identifier + +``ruhid`` + Reclaim Unit Handle Identifier + +``rsvd35`` + Reserved + +``vs`` + Vendor Specific + + + + + +.. c:struct:: nvme_fdp_events_log + + FDP Events Log Page + +**Definition** + +:: + + struct nvme_fdp_events_log { + __u32 n; + __u8 rsvd4[60]; + struct nvme_fdp_event events[63]; + }; + +**Members** + +``n`` + Number of FDP Events + +``rsvd4`` + Reserved + +``events`` + FDP Events (:c:type:`struct nvme_fdp_event `) + + + + + +.. c:struct:: nvme_feat_fdp_events_cdw11 + + FDP Events Feature Command Dword 11 + +**Definition** + +:: + + struct nvme_feat_fdp_events_cdw11 { + __u16 phndl; + __u8 noet; + __u8 rsvd24; + }; + +**Members** + +``phndl`` + Placement Handle + +``noet`` + Number of FDP Event Types + +``rsvd24`` + Reserved + + + + + +.. c:enum:: nvme_fdp_supported_event_attributes + + Supported FDP Event Attributes + +**Constants** + +``NVME_FDP_SUPP_EVENT_ENABLED_SHIFT`` + FDP Event Enable Shift + +``NVME_FDP_SUPP_EVENT_ENABLED_MASK`` + FDP Event Enable Mask + + + + +.. c:struct:: nvme_fdp_supported_event_desc + + Supported FDP Event Descriptor + +**Definition** + +:: + + struct nvme_fdp_supported_event_desc { + __u8 evt; + __u8 evta; + }; + +**Members** + +``evt`` + FDP Event Type + +``evta`` + FDP Event Type Attributes (:c:type:`enum nvme_fdp_supported_event_attributes `) + + + + + +.. c:struct:: nvme_fdp_ruh_status_desc + + Reclaim Unit Handle Status Descriptor + +**Definition** + +:: + + struct nvme_fdp_ruh_status_desc { + __u16 pid; + __u16 ruhid; + __u32 earutr; + __u64 ruamw; + __u8 rsvd16[16]; + }; + +**Members** + +``pid`` + Placement Identifier + +``ruhid`` + Reclaim Unit Handle Identifier + +``earutr`` + Estimated Active Reclaim Unit Time Remaining + +``ruamw`` + Reclaim Unit Available Media Writes + +``rsvd16`` + Reserved + + + + + +.. c:struct:: nvme_fdp_ruh_status + + Reclaim Unit Handle Status + +**Definition** + +:: + + struct nvme_fdp_ruh_status { + __u8 rsvd0[14]; + __u16 nruhsd; + struct nvme_fdp_ruh_status_desc ruhss[]; + }; + +**Members** + +``rsvd0`` + Reserved + +``nruhsd`` + Number of Reclaim Unit Handle Status Descriptors + +``ruhss`` + Reclaim Unit Handle Status descriptors + + + + + .. c:struct:: nvme_lba_status_desc LBA Status Descriptor Entry @@ -6446,35 +7073,6 @@ bytes, in size. This log captures the controller’s internal state. -.. c:struct:: nvme_timestamp - - Timestamp - Data Structure for Get Features - -**Definition** - -:: - - struct nvme_timestamp { - __u8 timestamp[6]; - __u8 attr; - __u8 rsvd; - }; - -**Members** - -``timestamp`` - Timestamp value based on origin and synch field - -``attr`` - Attribute - -``rsvd`` - Reserved - - - - - .. c:struct:: nvme_lba_range_type_entry LBA Range Type - Data Structure Entry @@ -9884,6 +10482,18 @@ true if **status** is of the specified type and value ``NVME_LOG_LID_BOOT_PARTITION`` Boot Partition +``NVME_LOG_LID_FDP_CONFIGS`` + FDP Configurations + +``NVME_LOG_LID_FDP_RUH_USAGE`` + Reclaim Unit Handle Usage + +``NVME_LOG_LID_FDP_STATS`` + FDP Statistics + +``NVME_LOG_LID_FDP_EVENTS`` + FDP Events + ``NVME_LOG_LID_DISCOVER`` Discovery @@ -9983,6 +10593,12 @@ true if **status** is of the specified type and value ``NVME_FEAT_FID_SPINUP_CONTROL`` Spinup Control +``NVME_FEAT_FID_FDP`` + Flexible Data Placement + +``NVME_FEAT_FID_FDP_EVENTS`` + FDP Events + ``NVME_FEAT_FID_ENH_CTRL_METADATA`` Enhanced Controller Metadata @@ -10212,6 +10828,18 @@ true if **status** is of the specified type and value ``NVME_FEAT_IOCSP_IOCSCI_MASK`` +``NVME_FEAT_FDP_ENABLED_SHIFT`` + +``NVME_FEAT_FDP_ENABLED_MASK`` + +``NVME_FEAT_FDP_INDEX_SHIFT`` + +``NVME_FEAT_FDP_INDEX_MASK`` + +``NVME_FEAT_FDP_EVENTS_ENABLE_SHIFT`` + +``NVME_FEAT_FDP_EVENTS_ENABLE_MASK`` + @@ -10776,12 +11404,18 @@ true if **status** is of the specified type and value ``nvme_cmd_resv_acquire`` Reservation Acquire +``nvme_cmd_io_mgmt_recv`` + I/O Management Receive + ``nvme_cmd_resv_release`` Reservation Release ``nvme_cmd_copy`` Copy +``nvme_cmd_io_mgmt_send`` + I/O Management Send + ``nvme_zns_cmd_mgmt_send`` Zone Management Send @@ -11079,3 +11713,27 @@ true if **status** is of the specified type and value List the zones in the ZSO:Offline state + + +.. c:enum:: nvme_io_mgmt_recv_mo + + I/O Management Receive - Management Operation + +**Constants** + +``NVME_IO_MGMT_RECV_RUH_STATUS`` + Reclaim Unit Handle Status + + + + +.. c:enum:: nvme_io_mgmt_send_mo + + I/O Management Send - Management Operation + +**Constants** + +``NVME_IO_MGMT_SEND_RUH_UPDATE`` + Reclaim Unit Handle Update + + diff --git a/doc/rst/util.rst b/doc/rst/util.rst index 87ea945..4b85492 100644 --- a/doc/rst/util.rst +++ b/doc/rst/util.rst @@ -64,6 +64,9 @@ libnvme utility functions ``ENVME_CONNECT_OPNOTSUPP`` not supported +``ENVME_CONNECT_CONNREFUSED`` + connection refused + .. c:function:: __u8 nvme_status_to_errno (int status, bool fabrics) @@ -433,7 +436,7 @@ usage: int x = round_up(13, sizeof(__u32)); // 13 -> 16 **Parameters** ``size_t val_len`` - Value lenght + Value length **Description** @@ -443,7 +446,7 @@ __u32), of the buffer needed to hold the exat value of size **Return** -Lenght rounded up by 4 +Length rounded up by 4 .. c:function:: __u16 nvmf_exat_size (size_t val_len) diff --git a/examples/meson.build b/examples/meson.build index 31d05d7..3139311 100644 --- a/examples/meson.build +++ b/examples/meson.build @@ -40,11 +40,11 @@ executable( include_directories: [incdir, internal_incdir] ) -if libsystemd_dep.found() +if libdbus_dep.found() executable( 'mi-conf', ['mi-conf.c'], - dependencies: [libnvme_mi_dep, libsystemd_dep], + dependencies: [libnvme_mi_dep, libdbus_dep], include_directories: [incdir, internal_incdir] ) endif diff --git a/examples/mi-conf.c b/examples/mi-conf.c index 90d590e..4fdd405 100644 --- a/examples/mi-conf.c +++ b/examples/mi-conf.c @@ -23,7 +23,7 @@ #include #include -#include +#include #define MCTP_DBUS_NAME "xyz.openbmc_project.MCTP" #define MCTP_DBUS_PATH "/xyz/openbmc_project/mctp" @@ -79,10 +79,11 @@ int find_port(nvme_mi_ep_t ep, uint8_t *portp, uint16_t *mtup) return found ? 0 : 1; } -int set_local_mtu(sd_bus *bus, unsigned int net, uint8_t eid, uint32_t mtu) +int set_local_mtu(DBusConnection *bus, unsigned int net, uint8_t eid, + uint32_t mtu) { - sd_bus_error err = SD_BUS_ERROR_NULL; - sd_bus_message *resp; + DBusMessage *msg, *resp; + DBusError berr; char *ep_path; int rc; @@ -99,26 +100,50 @@ int set_local_mtu(sd_bus *bus, unsigned int net, uint8_t eid, uint32_t mtu) */ mtu += 4; - rc = sd_bus_call_method(bus, MCTP_DBUS_NAME, ep_path, - MCTP_DBUS_EP_IFACE, "SetMTU", &err, &resp, - "u", mtu); - if (rc < 0) { - warnx("Failed to set local MTU: %s", strerror(-rc)); - return -1; + rc = -1; + dbus_error_init(&berr); + msg = dbus_message_new_method_call(MCTP_DBUS_NAME, ep_path, + MCTP_DBUS_EP_IFACE, "SetMTU"); + if (!msg) { + warnx("Can't create D-Bus message"); + goto out; } - return 0; + rc = dbus_message_append_args(msg, + DBUS_TYPE_UINT32, &mtu, + DBUS_TYPE_INVALID); + if (!rc) { + warnx("Can't construct D-Bus message arguments"); + goto out_free_msg; + } + + resp = dbus_connection_send_with_reply_and_block(bus, msg, + 2000, &berr); + if (!resp) { + warnx("Failed to set local MTU: %s (%s)", berr.message, + berr.name); + } else { + dbus_message_unref(resp); + rc = 0; + } + +out_free_msg: + dbus_message_unref(msg); +out: + dbus_error_free(&berr); + return rc; } int main(int argc, char **argv) { uint16_t cur_mtu, mtu; + DBusConnection *bus; const char *devstr; uint8_t eid, port; nvme_root_t root; unsigned int net; nvme_mi_ep_t ep; - sd_bus *bus; + DBusError berr; int rc; if (argc != 2) { @@ -141,10 +166,13 @@ int main(int argc, char **argv) goto out_free_root; } - rc = sd_bus_default_system(&bus); - if (rc < 0) { + dbus_error_init(&berr); + bus = dbus_bus_get(DBUS_BUS_SYSTEM, &berr); + if (!bus) { + warnx("Failed opening D-Bus: %s (%s)\n", + berr.message, berr.name); + rc = -1; goto out_close_ep; - warnx("Failed opening D-Bus: %s\n", strerror(-rc)); } rc = find_port(ep, &port, &mtu); @@ -185,8 +213,9 @@ int main(int argc, char **argv) } out_close_bus: - sd_bus_close(bus); + dbus_connection_unref(bus); out_close_ep: + dbus_error_free(&berr); nvme_mi_close(ep); out_free_root: nvme_mi_free_root(root); diff --git a/examples/mi-mctp.c b/examples/mi-mctp.c index 8d660af..c9a3852 100644 --- a/examples/mi-mctp.c +++ b/examples/mi-mctp.c @@ -347,14 +347,14 @@ int do_admin_raw(nvme_mi_ep_t ep, int argc, char **argv) } tmp = atoi(argv[1]); - if (tmp < 0 || tmp > 0xffff) { + if (tmp > 0xffff) { fprintf(stderr, "invalid controller ID\n"); return -1; } ctrl_id = tmp & 0xffff; tmp = atoi(argv[2]); - if (tmp < 0 || tmp > 0xff) { + if (tmp > 0xff) { fprintf(stderr, "invalid opcode\n"); return -1; } @@ -461,7 +461,7 @@ int do_security_info(nvme_mi_ep_t ep, int argc, char **argv) } tmp = atoi(argv[1]); - if (tmp < 0 || tmp > 0xffff) { + if (tmp > 0xffff) { fprintf(stderr, "invalid controller ID\n"); return -1; } diff --git a/libnvme.pc.in b/libnvme.pc.in deleted file mode 100644 index a1867aa..0000000 --- a/libnvme.pc.in +++ /dev/null @@ -1,12 +0,0 @@ -prefix=@prefix@ -exec_prefix=${prefix} -libdir=@libdir@ -includedir=@includedir@ - -Name: @NAME@ -Version: @VERSION@ -Description: Manage "libnvme" subsystem devices (Non-volatile Memory Express) -URL: http://github.com/linux-nvme/libnvme/ - -Libs: -L${libdir} -lnvme -Cflags: -I${includedir} diff --git a/libnvme/nvme.i b/libnvme/nvme.i index 6f20e2c..0c6b73c 100644 --- a/libnvme/nvme.i +++ b/libnvme/nvme.i @@ -585,7 +585,11 @@ struct nvme_ns { connect_err = 1; return; } + + Py_BEGIN_ALLOW_THREADS /* Release Python GIL */ ret = nvmf_add_ctrl(h, $self, cfg); + Py_END_ALLOW_THREADS /* Reacquire Python GIL */ + if (ret < 0) { connect_err = 2; return; @@ -601,7 +605,9 @@ struct nvme_ns { nvme_rescan_ctrl($self); } void disconnect() { + Py_BEGIN_ALLOW_THREADS /* Release Python GIL */ nvme_disconnect_ctrl($self); + Py_END_ALLOW_THREADS /* Reacquire Python GIL */ } %feature("autodoc", "@return: True if controller supports explicit registration. False otherwise.") is_registration_supported; @@ -614,7 +620,10 @@ struct nvme_ns { __u32 result; int status; + Py_BEGIN_ALLOW_THREADS /* Release Python GIL */ status = nvmf_register_ctrl($self, NVMF_DIM_TAS_REGISTER, &result); + Py_END_ALLOW_THREADS /* Reacquire Python GIL */ + if (status != NVME_SC_SUCCESS) { /* On error, return an error message */ if (status < 0) @@ -629,6 +638,7 @@ struct nvme_ns { %newobject discover; struct nvmf_discovery_log *discover(int lsp = 0, int max_retries = 6) { + struct nvmf_discovery_log *logp; struct nvme_get_discovery_args args = { .c = $self, .args_size = sizeof(args), @@ -637,7 +647,11 @@ struct nvme_ns { .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, .lsp = lsp, }; - struct nvmf_discovery_log *logp = nvmf_get_discovery_wargs(&args); + + Py_BEGIN_ALLOW_THREADS /* Release Python GIL */ + logp = nvmf_get_discovery_wargs(&args); + Py_END_ALLOW_THREADS /* Reacquire Python GIL */ + if (logp == NULL) discover_err = 1; return logp; @@ -649,7 +663,10 @@ struct nvme_ns { PyObject *obj = NULL; int ret = 0; + Py_BEGIN_ALLOW_THREADS /* Release Python GIL */ ret = nvme_get_log_supported_log_pages(nvme_ctrl_get_fd($self), rae, &log); + Py_END_ALLOW_THREADS /* Reacquire Python GIL */ + if (ret < 0) { Py_RETURN_NONE; } diff --git a/meson.build b/meson.build index 5c2e73a..d389cbf 100644 --- a/meson.build +++ b/meson.build @@ -7,14 +7,14 @@ # project( 'libnvme', ['c'], - meson_version: '>= 0.48.0', - version: '1.2', + meson_version: '>= 0.50.0', + version: '1.3', license: 'LGPL-2.1-or-later', default_options: [ 'c_std=gnu99', 'warning_level=1', - 'buildtype=release', - 'prefix=/usr', + 'buildtype=debug', + 'prefix=/usr/local', ] ) @@ -33,8 +33,6 @@ mandir = join_paths(prefixdir, get_option('mandir')) bindir = join_paths(prefixdir, get_option('bindir')) sysconfdir = join_paths(prefixdir, get_option('sysconfdir')) -pkgconfiglibdir = get_option('pkgconfiglibdir') == '' ? join_paths(libdir, 'pkgconfig') : get_option('pkgconfiglibdir') - ################################################################################ conf = configuration_data() @@ -91,9 +89,25 @@ if openssl_dep.found() description: 'OpenSSL/LibreSSL API version @0@'.format(api_version)) endif -# Check for libsystemd availability. Optional, only required for MCTP dbus scan -libsystemd_dep = dependency('libsystemd', version: '>219', required: false) -conf.set('CONFIG_LIBSYSTEMD', libsystemd_dep.found(), description: 'Is libsystemd(>219) available?') +if get_option('libdbus').disabled() + libdbus_dep = dependency('', required: false) +else + # Check for libdus availability. Optional, only required for MCTP dbus scan + libdbus_dep = dependency( + 'dbus-1', + required: true, + fallback: ['dbus', 'libdbus_dep'], + default_options: [ + 'default_library=static', + 'embedded_tests=false', + 'message_bus=false', + 'modular_tests=disabled', + 'tools=false', + ], + ) +endif + +conf.set('CONFIG_DBUS', libdbus_dep.found(), description: 'Enable dbus support?') # local (cross-compilable) implementations of ccan configure steps conf.set10( @@ -182,24 +196,20 @@ conf.set10( description: 'Is linux/mctp.h include-able?' ) -if meson.version().version_compare('>= 0.48') - has_fallthrough = cc.has_function_attribute('fallthrough') -else - has_fallthrough = cc.compiles( - '''int main(int argc, char **argv) { - switch(argc) { - case 0: - __attribute__((__fallthrough__)); - case 1: - return 1; - } - return 0; - } - ''', - name: 'has fallthrough') -endif +conf.set( + 'HAVE_LIBNSS', + cc.links( + '''int main(int argc, char **argv) { + struct addrinfo hints, *result; + return getaddrinfo(argv[1], argv[2], &hints, &result); + } + ''', + name: 'libnss', + ), + description: 'Is network address and service translation available' +) -if has_fallthrough +if cc.has_function_attribute('fallthrough') conf.set('fallthrough', '__attribute__((__fallthrough__))') else conf.set('fallthrough', 'do {} while (0) /* fallthrough */') diff --git a/meson_options.txt b/meson_options.txt index 0df190d..2c093ca 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1,7 +1,6 @@ # -*- mode: meson -*- # SPDX-License-Identifier: LGPL-2.1-or-later option('version-tag', type : 'string', description : 'override the git version string') -option('pkgconfiglibdir', type : 'string', value : '', description : 'directory for standard pkg-config files') option('htmldir', type : 'string', value : '', description : 'directory for HTML documentation') option('rstdir', type : 'string', value : '', description : 'directory for ReST documentation') @@ -10,3 +9,4 @@ option('docs-build', type : 'boolean', value : false, description : 'build docu option('python', type : 'combo', choices : ['auto', 'true', 'false'], description : 'Generate libnvme python bindings') option('openssl', type : 'feature', value: 'auto', description : 'OpenSSL support') +option('libdbus', type : 'feature', value: 'auto', description : 'libdbus support') diff --git a/src/libnvme-mi.map b/src/libnvme-mi.map index 53af942..16b7ad4 100644 --- a/src/libnvme-mi.map +++ b/src/libnvme-mi.map @@ -1,3 +1,11 @@ +LIBNVME_MI_1_3 { + global: + nvme_mi_admin_admin_passthru; + nvme_mi_ep_get_timeout; + nvme_mi_ep_set_timeout; + nvme_mi_set_probe_enabled; +}; + LIBNVME_MI_1_2 { global: nvme_mi_admin_get_features; diff --git a/src/libnvme.map b/src/libnvme.map index be9bca3..85ff6f3 100644 --- a/src/libnvme.map +++ b/src/libnvme.map @@ -1,5 +1,17 @@ # SPDX-License-Identifier: LGPL-2.1-or-later +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; + nvme_host_set_pdc_enabled; +}; + LIBNVME_1_2 { global: nvme_ctrl_get_dhchap_host_key; diff --git a/src/meson.build b/src/meson.build index 9e49a07..1186e81 100644 --- a/src/meson.build +++ b/src/meson.build @@ -33,7 +33,7 @@ deps = [ ] mi_deps = [ - libsystemd_dep, + libdbus_dep, ] source_dir = meson.current_source_dir() diff --git a/src/nvme/api-types.h b/src/nvme/api-types.h index 0de41a6..dac50ae 100644 --- a/src/nvme/api-types.h +++ b/src/nvme/api-types.h @@ -792,6 +792,50 @@ struct nvme_resv_report_args { bool eds; }; +/** + * struct nvme_io_mgmt_recv_args - Arguments for the NVMe I/O Management Receive command + * @data: Userspace address of the data + * @args_size: Size of &struct nvme_io_mgmt_recv_args + * @fd: File descriptor of nvme device + * @nsid: Namespace identifier + * @data_len: Length of @data + * @timeout: Timeout in ms + * @mos Management Operation Specific + * @mo Management Operation + */ +struct nvme_io_mgmt_recv_args { + void *data; + int args_size; + int fd; + __u32 nsid; + __u32 data_len; + __u32 timeout; + __u16 mos; + __u8 mo; +}; + +/** + * struct nvme_io_mgmt_send_args - Arguments for the NVMe I/O Management Send command + * @data: Userspace address of the data + * @args_size: Size of &struct nvme_io_mgmt_send_args + * @fd: File descriptor of nvme device + * @nsid: Namespace identifier + * @data_len: Length of @data + * @timeout: Timeout in ms + * @mos Management Operation Specific + * @mo Management Operation + */ +struct nvme_io_mgmt_send_args { + void *data; + int args_size; + int fd; + __u32 nsid; + __u32 data_len; + __u32 timeout; + __u16 mos; + __u8 mo; +}; + /** * struct nvme_zns_mgmt_send_args - Arguments for the NVMe ZNS Management Send command * @slba: Starting logical block address diff --git a/src/nvme/fabrics.c b/src/nvme/fabrics.c index a501f79..7134dba 100644 --- a/src/nvme/fabrics.c +++ b/src/nvme/fabrics.c @@ -47,13 +47,19 @@ const char *nvmf_dev = "/dev/nvme-fabrics"; /** * strchomp() - Strip trailing white space - * @s: String to strip - * @l: Maximum length of string + * @str: String to strip + * @max: Maximum length of string */ -static void strchomp(char *s, int l) +static void strchomp(char *str, int max) { - while (l && (s[l] == '\0' || s[l] == ' ')) - s[l--] = '\0'; + int i; + + for (i = max - 1; i >= 0; i--) { + if (str[i] != '\0' && str[i] != ' ') + return; + else + str[i] = '\0'; + } } const char *arg_str(const char * const *strings, @@ -114,7 +120,7 @@ const char *nvmf_treq_str(__u8 treq) } static const char * const eflags_strings[] = { - [NVMF_DISC_EFLAGS_NONE] = "not specified", + [NVMF_DISC_EFLAGS_NONE] = "none", [NVMF_DISC_EFLAGS_EPCSD] = "explicit discovery connections", [NVMF_DISC_EFLAGS_DUPRETINFO] = "duplicate discovery information", [NVMF_DISC_EFLAGS_EPCSD | @@ -459,6 +465,7 @@ static int build_options(nvme_host_t h, nvme_ctrl_t c, char **argstr) } if (!strcmp(nvme_ctrl_get_subsysnqn(c), NVME_DISC_SUBSYS_NAME)) { nvme_ctrl_set_discovery_ctrl(c, true); + nvme_ctrl_set_unique_discovery_ctrl(c, false); discovery_nqn = true; } if (nvme_ctrl_is_discovery_ctrl(c)) @@ -561,6 +568,9 @@ static int __nvmf_add_ctrl(nvme_root_t r, const char *argstr) case EOPNOTSUPP: ret = -ENVME_CONNECT_OPNOTSUPP; break; + case ECONNREFUSED : + ret = -ENVME_CONNECT_CONNREFUSED; + break; default: ret = -ENVME_CONNECT_WRITE; break; @@ -658,7 +668,8 @@ int nvmf_add_ctrl(nvme_host_t h, nvme_ctrl_t c, return -1; } - nvme_msg(h->r, LOG_INFO, "nvme%d: ctrl connected\n", ret); + nvme_msg(h->r, LOG_INFO, "nvme%d: %s connected\n", ret, + nvme_ctrl_get_subsysnqn(c)); return nvme_init_ctrl(h, c, ret); } @@ -678,8 +689,6 @@ nvme_ctrl_t nvmf_connect_disc_entry(nvme_host_t h, switch (e->adrfam) { case NVMF_ADDR_FAMILY_IP4: case NVMF_ADDR_FAMILY_IP6: - strchomp(e->traddr, NVMF_TRADDR_SIZE - 1); - strchomp(e->trsvcid, NVMF_TRSVCID_SIZE - 1); traddr = e->traddr; trsvcid = e->trsvcid; break; @@ -694,7 +703,6 @@ nvme_ctrl_t nvmf_connect_disc_entry(nvme_host_t h, case NVMF_TRTYPE_FC: switch (e->adrfam) { case NVMF_ADDR_FAMILY_FC: - strchomp(e->traddr, NVMF_TRADDR_SIZE - 1); traddr = e->traddr; break; default: @@ -706,7 +714,6 @@ nvme_ctrl_t nvmf_connect_disc_entry(nvme_host_t h, } break; case NVMF_TRTYPE_LOOP: - strchomp(e->traddr, NVMF_TRADDR_SIZE - 1); traddr = strlen(e->traddr) ? e->traddr : NULL; break; default: @@ -734,11 +741,15 @@ nvme_ctrl_t nvmf_connect_disc_entry(nvme_host_t h, switch (e->subtype) { case NVME_NQN_CURR: nvme_ctrl_set_discovered(c, true); + nvme_ctrl_set_unique_discovery_ctrl(c, + strcmp(e->subnqn, NVME_DISC_SUBSYS_NAME)); break; case NVME_NQN_DISC: if (discover) *discover = true; nvme_ctrl_set_discovery_ctrl(c, true); + nvme_ctrl_set_unique_discovery_ctrl(c, + strcmp(e->subnqn, NVME_DISC_SUBSYS_NAME)); break; default: nvme_msg(h->r, LOG_ERR, "unsupported subtype %d\n", @@ -746,6 +757,7 @@ nvme_ctrl_t nvmf_connect_disc_entry(nvme_host_t h, fallthrough; case NVME_NQN_NVME: nvme_ctrl_set_discovery_ctrl(c, false); + nvme_ctrl_set_unique_discovery_ctrl(c, false); break; } @@ -874,9 +886,37 @@ out_free_log: return NULL; } +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 - 1); + strchomp(e->trsvcid, NVMF_TRSVCID_SIZE - 1); + break; + } + break; + case NVMF_TRTYPE_FC: + switch (e->adrfam) { + case NVMF_ADDR_FAMILY_FC: + strchomp(e->traddr, NVMF_TRADDR_SIZE - 1); + break; + } + break; + case NVMF_TRTYPE_LOOP: + strchomp(e->traddr, NVMF_TRADDR_SIZE - 1); + break; + } +} + 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), @@ -893,12 +933,22 @@ int nvmf_get_discovery_log(nvme_ctrl_t c, struct nvmf_discovery_log **logp, .rae = false, .ot = false, }; - *logp = nvme_discovery_log(c, &args, max_retries); - return logp ? 0 : -1; + + 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; } 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), @@ -916,7 +966,14 @@ struct nvmf_discovery_log *nvmf_get_discovery_wargs(struct nvme_get_discovery_ar .ot = false, }; - return nvme_discovery_log(args->c, &_args, args->max_retries); + log = nvme_discovery_log(args->c, &_args, args->max_retries); + if (!log) + return NULL; + + for (int i = 0; i < le64_to_cpu(log->numrec); i++) + sanitize_discovery_log_entry(&log->entries[i]); + + return log; } #define PATH_UUID_IBM "/proc/device-tree/ibm,partition-uuid" @@ -946,7 +1003,7 @@ static int uuid_from_dmi_entries(char *system_uuid) int f; DIR *d; struct dirent *de; - char buf[512]; + char buf[512] = {0}; system_uuid[0] = '\0'; d = opendir(PATH_DMI_ENTRIES); @@ -964,7 +1021,7 @@ static int uuid_from_dmi_entries(char *system_uuid) continue; len = read(f, buf, 512); close(f); - if (len < 0) + if (len <= 0) continue; if (sscanf(buf, "%d", &type) != 1) continue; @@ -976,7 +1033,7 @@ static int uuid_from_dmi_entries(char *system_uuid) continue; len = read(f, buf, 512); close(f); - if (len < 0) + if (len <= 0) continue; /* Sigh. https://en.wikipedia.org/wiki/Overengineering */ /* DMTF SMBIOS 3.0 Section 7.2.1 System UUID */ @@ -1127,7 +1184,7 @@ static __u32 nvmf_get_tel(const char *hostsymname) __u16 len; /* Host ID is mandatory */ - tel += nvmf_exat_size(NVME_UUID_LEN_STRING); + tel += nvmf_exat_size(NVME_UUID_LEN); /* Symbolic name is optional */ len = hostsymname ? strlen(hostsymname) : 0; diff --git a/src/nvme/ioctl.c b/src/nvme/ioctl.c index 3333993..b2d92ef 100644 --- a/src/nvme/ioctl.c +++ b/src/nvme/ioctl.c @@ -430,6 +430,46 @@ int nvme_get_log(struct nvme_get_log_args *args) return nvme_submit_admin_passthru(args->fd, &cmd, args->result); } +int nvme_get_log_page(int fd, __u32 xfer_len, struct nvme_get_log_args *args) +{ + __u64 offset = 0, xfer, data_len = args->len; + __u64 start = args->lpo; + bool retain = true; + void *ptr = args->log; + int ret; + + /* + * 4k is the smallest possible transfer unit, so restricting to 4k + * avoids having to check the MDTS value of the controller. + */ + do { + xfer = data_len - offset; + if (xfer > xfer_len) + xfer = xfer_len; + + /* + * Always retain regardless of the RAE parameter until the very + * last portion of this log page so the data remains latched + * during the fetch sequence. + */ + if (offset + xfer == data_len) + retain = args->rae; + + args->lpo = start + offset; + args->len = xfer; + args->log = ptr; + args->rae = retain; + ret = nvme_get_log(args); + if (ret) + return ret; + + offset += xfer; + ptr += xfer; + } while (offset < data_len); + + return 0; +} + int nvme_set_features(struct nvme_set_features_args *args) { __u32 cdw10 = NVME_SET(args->fid, FEATURES_CDW10_FID) | @@ -1857,6 +1897,50 @@ int nvme_resv_report(struct nvme_resv_report_args *args) return nvme_submit_io_passthru(args->fd, &cmd, args->result); } +int nvme_io_mgmt_recv(struct nvme_io_mgmt_recv_args *args) +{ + __u32 cdw10 = (args->mo & 0xf) | (args->mos & 0xff << 16); + __u32 cdw11 = (args->data_len >> 2) - 1; + + struct nvme_passthru_cmd cmd = { + .opcode = nvme_cmd_io_mgmt_recv, + .nsid = args->nsid, + .cdw10 = cdw10, + .cdw11 = cdw11, + .addr = (__u64)(uintptr_t)args->data, + .data_len = args->data_len, + .timeout_ms = args->timeout, + }; + + if (args->args_size < sizeof(*args)) { + errno = EINVAL; + return -1; + } + + return nvme_submit_io_passthru(args->fd, &cmd, NULL); +} + +int nvme_io_mgmt_send(struct nvme_io_mgmt_send_args *args) +{ + __u32 cdw10 = (args->mo & 0xf) | ((args->mos & 0xff) << 16); + + struct nvme_passthru_cmd cmd = { + .opcode = nvme_cmd_io_mgmt_send, + .nsid = args->nsid, + .cdw10 = cdw10, + .addr = (__u64)(uintptr_t)args->data, + .data_len = args->data_len, + .timeout_ms = args->timeout, + }; + + if (args->args_size < sizeof(*args)) { + errno = EINVAL; + return -1; + } + + return nvme_submit_io_passthru(args->fd, &cmd, NULL); +} + int nvme_zns_mgmt_send(struct nvme_zns_mgmt_send_args *args) { __u32 cdw10 = args->slba & 0xffffffff; diff --git a/src/nvme/ioctl.h b/src/nvme/ioctl.h index af95851..32e722e 100644 --- a/src/nvme/ioctl.h +++ b/src/nvme/ioctl.h @@ -34,6 +34,12 @@ /* '0' is interpreted by the kernel to mean 'apply the default timeout' */ #define NVME_DEFAULT_IOCTL_TIMEOUT 0 +/* + * 4k is the smallest possible transfer unit, so restricting to 4k + * avoids having to check the MDTS value of the controller. + */ +#define NVME_LOG_PAGE_PDU_SIZE 4096 + /** * struct nvme_passthru_cmd - nvme passthrough command structure * @opcode: Operation code, see &enum nvme_io_opcodes and &enum nvme_admin_opcodes @@ -1226,6 +1232,17 @@ static inline int nvme_zns_identify_ctrl(int fd, struct nvme_zns_id_ctrl *id) */ int nvme_get_log(struct nvme_get_log_args *args); +/** + * nvme_get_log_page() - Get log page data + * @fd: File descriptor of nvme device + * @xfer_len: Max log transfer size per request to split the total. + * @args: &struct nvme_get_log_args argument structure + * + * Return: The nvme command status if a response was received (see + * &enum nvme_status_field) or -1 with errno set otherwise. + */ +int nvme_get_log_page(int fd, __u32 xfer_len, struct nvme_get_log_args *args); + static inline int nvme_get_nsid_log(int fd, bool rae, enum nvme_cmd_get_log_lid lid, __u32 nsid, __u32 len, void *log) @@ -1248,7 +1265,7 @@ static inline int nvme_get_nsid_log(int fd, bool rae, .ot = false, }; - return nvme_get_log(&args); + return nvme_get_log_page(fd, NVME_LOG_PAGE_PDU_SIZE, &args); } static inline int nvme_get_log_simple(int fd, enum nvme_cmd_get_log_lid lid, @@ -1391,7 +1408,7 @@ static inline int nvme_get_log_cmd_effects(int fd, enum nvme_csi csi, .rae = false, .ot = false, }; - return nvme_get_log(&args); + return nvme_get_log_page(fd, NVME_LOG_PAGE_PDU_SIZE, &args); } /** @@ -1441,7 +1458,7 @@ static inline int nvme_get_log_create_telemetry_host(int fd, .rae = false, .ot = false, }; - return nvme_get_log(&args); + return nvme_get_log_page(fd, NVME_LOG_PAGE_PDU_SIZE, &args); } /** @@ -1477,7 +1494,7 @@ static inline int nvme_get_log_telemetry_host(int fd, __u64 offset, .rae = false, .ot = false, }; - return nvme_get_log(&args); + return nvme_get_log_page(fd, NVME_LOG_PAGE_PDU_SIZE, &args); } /** @@ -1514,7 +1531,7 @@ static inline int nvme_get_log_telemetry_ctrl(int fd, bool rae, .rae = rae, .ot = false, }; - return nvme_get_log(&args); + return nvme_get_log_page(fd, NVME_LOG_PAGE_PDU_SIZE, &args); } /** @@ -1553,7 +1570,7 @@ static inline int nvme_get_log_endurance_group(int fd, __u16 endgid, .rae = false, .ot = false, }; - return nvme_get_log(&args); + return nvme_get_log_page(fd, NVME_LOG_PAGE_PDU_SIZE, &args); } /** @@ -1585,7 +1602,7 @@ static inline int nvme_get_log_predictable_lat_nvmset(int fd, __u16 nvmsetid, .rae = false, .ot = false, }; - return nvme_get_log(&args); + return nvme_get_log_page(fd, NVME_LOG_PAGE_PDU_SIZE, &args); } /** @@ -1619,6 +1636,126 @@ static inline int nvme_get_log_predictable_lat_event(int fd, bool rae, .rae = rae, .ot = false, }; + return nvme_get_log_page(fd, NVME_LOG_PAGE_PDU_SIZE, &args); +} + +/** + * nvme_get_log_fdp_configurations() - Get list of Flexible Data Placement configurations + * @fd: File descriptor of nvme device + * @egid: Endurance group identifier + * @offset: Offset into log page + * @len: Length (in bytes) of provided user buffer to hold the log data + * @log: Log page data buffer + */ +static inline int nvme_get_log_fdp_configurations(int fd, __u16 egid, + __u32 offset, __u32 len, void *log) +{ + struct nvme_get_log_args args = { + .lpo = offset, + .result = NULL, + .log = log, + .args_size = sizeof(args), + .fd = fd, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .lid = NVME_LOG_LID_FDP_CONFIGS, + .len = len, + .nsid = NVME_NSID_NONE, + .csi = NVME_CSI_NVM, + .lsi = egid, + .lsp = NVME_LOG_LSP_NONE, + .uuidx = NVME_UUID_NONE, + }; + + return nvme_get_log(&args); +} + +/** + * nvme_get_log_reclaim_unit_handle_usage() - Get reclaim unit handle usage + * @fd: File descriptor of nvme device + * @egid: Endurance group identifier + * @offset: Offset into log page + * @len: Length (in bytes) of provided user buffer to hold the log data + * @log: Log page data buffer + */ +static inline int nvme_get_log_reclaim_unit_handle_usage(int fd, __u16 egid, + __u32 offset, __u32 len, void *log) +{ + struct nvme_get_log_args args = { + .lpo = offset, + .result = NULL, + .log = log, + .args_size = sizeof(args), + .fd = fd, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .lid = NVME_LOG_LID_FDP_RUH_USAGE, + .len = len, + .nsid = NVME_NSID_NONE, + .csi = NVME_CSI_NVM, + .lsi = egid, + .lsp = NVME_LOG_LSP_NONE, + .uuidx = NVME_UUID_NONE, + }; + + return nvme_get_log(&args); +} + +/** + * nvme_get_log_fdp_stats() - Get Flexible Data Placement statistics + * @fd: File descriptor of nvme device + * @egid: Endurance group identifier + * @offset: Offset into log page + * @len: Length (in bytes) of provided user buffer to hold the log data + * @log: Log page data buffer + */ +static inline int nvme_get_log_fdp_stats(int fd, __u16 egid, __u32 offset, __u32 len, void *log) +{ + struct nvme_get_log_args args = { + .lpo = offset, + .result = NULL, + .log = log, + .args_size = sizeof(args), + .fd = fd, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .lid = NVME_LOG_LID_FDP_STATS, + .len = len, + .nsid = NVME_NSID_NONE, + .csi = NVME_CSI_NVM, + .lsi = egid, + .lsp = NVME_LOG_LSP_NONE, + .uuidx = NVME_UUID_NONE, + }; + + return nvme_get_log(&args); +} + +/** + * nvme_get_log_fdp_events() - Get Flexible Data Placement events + * @fd: File descriptor of nvme device + * @egid: Endurance group identifier + * @host_events: Whether to report host or controller events + * @offset: Offset into log page + * @len: Length (in bytes) of provided user buffer to hold the log data + * @log: Log page data buffer + */ +static inline int nvme_get_log_fdp_events(int fd, __u16 egid, bool host_events, __u32 offset, + __u32 len, void *log) +{ + struct nvme_get_log_args args = { + .lpo = offset, + .result = NULL, + .log = log, + .args_size = sizeof(args), + .fd = fd, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .lid = NVME_LOG_LID_FDP_EVENTS, + .len = len, + .nsid = NVME_NSID_NONE, + .csi = NVME_CSI_NVM, + .lsi = egid, + .lsp = (__u8)(host_events ? 0x1 : 0x0), + .uuidx = NVME_UUID_NONE, + }; + return nvme_get_log(&args); } @@ -1660,7 +1797,7 @@ static inline int nvme_get_log_ana(int fd, enum nvme_log_ana_lsp lsp, bool rae, .rae = false, .ot = false, }; - return nvme_get_log(&args); + return nvme_get_log_page(fd, NVME_LOG_PAGE_PDU_SIZE, &args); } /** @@ -1713,7 +1850,7 @@ static inline int nvme_get_log_lba_status(int fd, bool rae, .rae = rae, .ot = false, }; - return nvme_get_log(&args); + return nvme_get_log_page(fd, NVME_LOG_PAGE_PDU_SIZE, &args); } /** @@ -1747,7 +1884,7 @@ static inline int nvme_get_log_endurance_grp_evt(int fd, bool rae, .rae = rae, .ot = false, }; - return nvme_get_log(&args); + return nvme_get_log_page(fd, NVME_LOG_PAGE_PDU_SIZE, &args); } /** @@ -1814,7 +1951,7 @@ static inline int nvme_get_log_boot_partition(int fd, bool rae, .rae = rae, .ot = false, }; - return nvme_get_log(&args); + return nvme_get_log_page(fd, NVME_LOG_PAGE_PDU_SIZE, &args); } /** @@ -1851,7 +1988,7 @@ static inline int nvme_get_log_discovery(int fd, bool rae, .rae = rae, .ot = false, }; - return nvme_get_log(&args); + return nvme_get_log_page(fd, NVME_LOG_PAGE_PDU_SIZE, &args); } /** @@ -1883,7 +2020,7 @@ static inline int nvme_get_log_media_unit_stat(int fd, __u16 domid, .rae = false, .ot = false, }; - return nvme_get_log(&args); + return nvme_get_log_page(fd, NVME_LOG_PAGE_PDU_SIZE, &args); } /** @@ -1915,7 +2052,7 @@ static inline int nvme_get_log_support_cap_config_list(int fd, __u16 domid, .rae = false, .ot = false, }; - return nvme_get_log(&args); + return nvme_get_log_page(fd, NVME_LOG_PAGE_PDU_SIZE, &args); } /** @@ -1985,7 +2122,7 @@ static inline int nvme_get_log_zns_changed_zones(int fd, __u32 nsid, bool rae, .rae = rae, .ot = false, }; - return nvme_get_log(&args); + return nvme_get_log_page(fd, NVME_LOG_PAGE_PDU_SIZE, &args); } /** @@ -2019,7 +2156,7 @@ static inline int nvme_get_log_persistent_event(int fd, .rae = false, .ot = false, }; - return nvme_get_log(&args); + return nvme_get_log_page(fd, NVME_LOG_PAGE_PDU_SIZE, &args); } /** @@ -2392,7 +2529,7 @@ int nvme_set_features_sw_progress(int fd, __u8 pbslc, bool save, __u32 *result); /** - * nvme_set_features_host_id() - Set enable extended host identifers feature + * nvme_set_features_host_id() - Set enable extended host identifiers feature * @fd: File descriptor of nvme device * @exhid: Enable Extended Host Identifier * @save: Save value across power states @@ -3372,7 +3509,7 @@ int nvme_sanitize_nvm(struct nvme_sanitize_nvm_args *args); * The controller may return a response to this command immediately while * running the self-test in the background. * - * Set the 'nsid' field to 0 to not include namepsaces in the test. Set to + * Set the 'nsid' field to 0 to not include namespaces in the test. Set to * 0xffffffff to test all namespaces. All other values tests a specific * namespace, if present. * @@ -3587,6 +3724,78 @@ int nvme_resv_release(struct nvme_resv_release_args *args); */ int nvme_resv_report(struct nvme_resv_report_args *args); +/** + * nvme_io_mgmt_recv() - I/O Management Receive command + * @args: &struct nvme_io_mgmt_recv_args argument structure + * + * Return: The nvme command status if a response was received (see + * &enum nvme_status_field) or -1 with errno set otherwise. + */ +int nvme_io_mgmt_recv(struct nvme_io_mgmt_recv_args *args); + +/** + * nvme_fdp_reclaim_unit_handle_status() - Get reclaim unit handle status + * @fd: File descriptor of nvme device + * @nsid: Namespace identifier + * @data_len: Length of response buffer + * @data: Response buffer + * + * Return: The nvme command status if a response was received (see + * &enum nvme_status_field) or -1 with errno set otherwise. + */ +static inline int nvme_fdp_reclaim_unit_handle_status(int fd, __u32 nsid, + __u32 data_len, void *data) +{ + struct nvme_io_mgmt_recv_args args = { + .data = data, + .args_size = sizeof(args), + .fd = fd, + .nsid = nsid, + .data_len = data_len, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .mos = 0, + .mo = NVME_IO_MGMT_RECV_RUH_STATUS, + }; + + return nvme_io_mgmt_recv(&args); +} + +/** + * nvme_io_mgmt_send() - I/O Management Send command + * @args: &struct nvme_io_mgmt_send_args argument structure + * + * Return: The nvme command status if a response was received (see + * &enum nvme_status_field) or -1 with errno set otherwise. + */ +int nvme_io_mgmt_send(struct nvme_io_mgmt_send_args *args); + +/** + * nvme_fdp_reclaim_unit_handle_update() - Update a list of reclaim unit handles + * @fd: File descriptor of nvme device + * @nsid: Namespace identifier + * @npids: Number of placement identifiers + * @pids: List of placement identifiers + * + * Return: The nvme command status if a response was received (see + * &enum nvme_status_field) or -1 with errno set otherwise. + */ +static inline int nvme_fdp_reclaim_unit_handle_update(int fd, __u32 nsid, + unsigned int npids, __u16 *pids) +{ + struct nvme_io_mgmt_send_args args = { + .data = (void *)pids, + .args_size = sizeof(args), + .fd = fd, + .nsid = nsid, + .data_len = (__u32)(npids * sizeof(__u16)), + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .mos = (__u16)(npids - 1), + .mo = NVME_IO_MGMT_SEND_RUH_UPDATE, + }; + + return nvme_io_mgmt_send(&args); +} + /** * nvme_zns_mgmt_send() - ZNS management send command * @args: &struct nvme_zns_mgmt_send_args argument structure diff --git a/src/nvme/json.c b/src/nvme/json.c index f0c2ab4..072b622 100644 --- a/src/nvme/json.c +++ b/src/nvme/json.c @@ -148,6 +148,9 @@ static void json_parse_host(nvme_root_t r, struct json_object *host_obj) attr_obj = json_object_object_get(host_obj, "hostsymname"); if (attr_obj) nvme_host_set_hostsymname(h, json_object_get_string(attr_obj)); + attr_obj = json_object_object_get(host_obj, "persistent_discovery_ctrl"); + if (attr_obj) + nvme_host_set_pdc_enabled(h, json_object_get_boolean(attr_obj)); subsys_array = json_object_object_get(host_obj, "subsystems"); if (!subsys_array) return; @@ -354,6 +357,9 @@ int json_update_config(nvme_root_t r, const char *config_file) if (hostsymname) json_object_object_add(host_obj, "hostsymname", json_object_new_string(hostsymname)); + if (h->pdc_enabled_valid) + json_object_object_add(host_obj, "persistent_discovery_ctrl", + json_object_new_boolean(h->pdc_enabled)); subsys_array = json_object_new_array(); nvme_for_each_subsystem(h, s) { json_update_subsys(subsys_array, s); @@ -492,6 +498,9 @@ int json_dump_tree(nvme_root_t r) if (dhchap_key) json_object_object_add(host_obj, "dhchap_key", json_object_new_string(dhchap_key)); + if (h->pdc_enabled_valid) + json_object_object_add(host_obj, "persistent_discovery_ctrl", + json_object_new_boolean(h->pdc_enabled)); subsys_array = json_object_new_array(); nvme_for_each_subsystem(h, s) { json_dump_subsys(subsys_array, s); diff --git a/src/nvme/linux.c b/src/nvme/linux.c index c9b6bbf..cae4036 100644 --- a/src/nvme/linux.c +++ b/src/nvme/linux.c @@ -117,45 +117,6 @@ int nvme_fw_download_seq(int fd, __u32 size, __u32 xfer, __u32 offset, return err; } -int nvme_get_log_page(int fd, __u32 xfer_len, struct nvme_get_log_args *args) -{ - __u64 offset = 0, xfer, data_len = args->len; - bool retain = true; - void *ptr = args->log; - int ret; - - /* - * 4k is the smallest possible transfer unit, so restricting to 4k - * avoids having to check the MDTS value of the controller. - */ - do { - xfer = data_len - offset; - if (xfer > xfer_len) - xfer = xfer_len; - - /* - * Always retain regardless of the RAE parameter until the very - * last portion of this log page so the data remains latched - * during the fetch sequence. - */ - if (offset + xfer == data_len) - retain = args->rae; - - args->lpo = offset; - args->len = xfer; - args->log = ptr; - args->rae = retain; - ret = nvme_get_log(args); - if (ret) - return ret; - - offset += xfer; - ptr += xfer; - } while (offset < data_len); - - return 0; -} - 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) diff --git a/src/nvme/linux.h b/src/nvme/linux.h index 8a6d426..aa4c91a 100644 --- a/src/nvme/linux.h +++ b/src/nvme/linux.h @@ -97,17 +97,6 @@ int nvme_get_host_telemetry(int fd, struct nvme_telemetry_log **log, int nvme_get_new_host_telemetry(int fd, struct nvme_telemetry_log **log, enum nvme_telemetry_da da, size_t *size); -/** - * nvme_get_log_page() - Get log page data - * @fd: File descriptor of nvme device - * @xfer_len: Max log transfer size per request to split the total. - * @args: &struct nvme_get_log_args argument structure - * - * Return: The nvme command status if a response was received (see - * &enum nvme_status_field) or -1 with errno set otherwise. - */ -int nvme_get_log_page(int fd, __u32 xfer_len, struct nvme_get_log_args *args); - /** * nvme_get_ana_log_len() - Retrieve size of the current ANA log * @fd: File descriptor of nvme device diff --git a/src/nvme/mi-mctp.c b/src/nvme/mi-mctp.c index 86f5df6..0c5972a 100644 --- a/src/nvme/mi-mctp.c +++ b/src/nvme/mi-mctp.c @@ -23,10 +23,8 @@ #include -#ifdef CONFIG_LIBSYSTEMD -#include -#include -#include +#ifdef CONFIG_DBUS +#include #define MCTP_DBUS_PATH "/xyz/openbmc_project/mctp" #define MCTP_DBUS_IFACE "xyz.openbmc_project.MCTP" @@ -510,29 +508,19 @@ nvme_mi_ep_t nvme_mi_open_mctp(nvme_root_t root, unsigned int netid, __u8 eid) */ ep->timeout = 5000; + nvme_mi_ep_probe(ep); + return ep; err_free_ep: errno_save = errno; - free(ep); + nvme_mi_close(ep); free(mctp); errno = errno_save; return NULL; } -#ifdef CONFIG_LIBSYSTEMD - -/* helper for handling dbus errors: D-Bus API returns a negtive errno on - * failure; set errno and log. - */ -static void _dbus_err(nvme_root_t root, int rc, int line) -{ - nvme_msg(root, LOG_ERR, "MCTP D-Bus failed line %d: %s %d\n", - line, strerror(-rc), rc); - errno = -rc; -} - -#define dbus_err(r, rc) _dbus_err(r, rc, __LINE__) +#ifdef CONFIG_DBUS static int nvme_mi_mctp_add(nvme_root_t root, unsigned int netid, __u8 eid) { @@ -556,84 +544,99 @@ static int nvme_mi_mctp_add(nvme_root_t root, unsigned int netid, __u8 eid) return 0; } -/* We can't rely on sd_bus_message_enter_container() == 0 at the end of - a dictionary (it returns -ENXIO) so we test separately */ -static bool container_end(sd_bus_message *m) +static bool dbus_object_is_type(DBusMessageIter *obj, int type) +{ + return dbus_message_iter_get_arg_type(obj) == type; +} + +static bool dbus_object_is_dict(DBusMessageIter *obj) +{ + return dbus_object_is_type(obj, DBUS_TYPE_ARRAY) && + dbus_message_iter_get_element_type(obj) == DBUS_TYPE_DICT_ENTRY; +} + +static int read_variant_basic(DBusMessageIter *var, int type, void *val) +{ + if (!dbus_object_is_type(var, type)) + return -1; + + dbus_message_iter_get_basic(var, val); + + return 0; +} + +static bool has_message_type(DBusMessageIter *prop, uint8_t type) { - return sd_bus_message_peek_type(m, NULL, NULL) == 0; + DBusMessageIter inner; + uint8_t *types; + int i, n; + + if (!dbus_object_is_type(prop, DBUS_TYPE_ARRAY) || + dbus_message_iter_get_element_type(prop) != DBUS_TYPE_BYTE) + return false; + + dbus_message_iter_recurse(prop, &inner); + + dbus_message_iter_get_fixed_array(&inner, &types, &n); + + for (i = 0; i < n; i++) { + if (types[i] == type) + return true; + } + + return false; } static int handle_mctp_endpoint(nvme_root_t root, const char* objpath, - sd_bus_message *m) + DBusMessageIter *props) { bool have_eid = false, have_net = false, have_nvmemi = false; mctp_eid_t eid; int net; int rc; - /* Iterate properties on this interface */ - while (!container_end(m)) { - /* Enter property dict */ - rc = sd_bus_message_enter_container(m, 'a', "{sv}"); - if (rc < 0) { - dbus_err(root, rc); + /* for each property */ + for (;;) { + DBusMessageIter prop, val; + const char *propname; + + dbus_message_iter_recurse(props, &prop); + + if (!dbus_object_is_type(&prop, DBUS_TYPE_STRING)) { + nvme_msg(root, LOG_ERR, + "error unmashalling object (propname)\n"); return -1; } - while (!container_end(m)) { - char *propname = NULL; - size_t sz; - const uint8_t *types = NULL; - /* Enter property item */ - rc = sd_bus_message_enter_container(m, 'e', "sv"); - if (rc < 0) { - dbus_err(root, rc); - return -1; - } - - rc = sd_bus_message_read(m, "s", &propname); - if (rc < 0) { - dbus_err(root, rc); - return -1; - } - - if (strcmp(propname, "EID") == 0) { - rc = sd_bus_message_read(m, "v", "y", &eid); - have_eid = true; - } else if (strcmp(propname, "NetworkId") == 0) { - rc = sd_bus_message_read(m, "v", "i", &net); - have_net = true; - } else if (strcmp(propname, "SupportedMessageTypes") == 0) { - sd_bus_message_enter_container(m, 'v', "ay"); - rc = sd_bus_message_read_array(m, 'y', (const void**)&types, &sz); - if (rc >= 0) - for (size_t s = 0; s < sz; s++) - if (types[s] == MCTP_TYPE_NVME) - have_nvmemi = true; - sd_bus_message_exit_container(m); - } else { - rc = sd_bus_message_skip(m, "v"); - } - - if (rc < 0) { - dbus_err(root, rc); - return -1; - } - - /* Exit prop item */ - rc = sd_bus_message_exit_container(m); - if (rc < 0) { - dbus_err(root, rc); - return -1; - } - } + dbus_message_iter_get_basic(&prop, &propname); - /* Exit property dict */ - rc = sd_bus_message_exit_container(m); - if (rc < 0) { - dbus_err(root, rc); + dbus_message_iter_next(&prop); + + if (!dbus_object_is_type(&prop, DBUS_TYPE_VARIANT)) { + nvme_msg(root, LOG_ERR, + "error unmashalling object (propval)\n"); return -1; } + + dbus_message_iter_recurse(&prop, &val); + + if (!strcmp(propname, "EID")) { + rc = read_variant_basic(&val, DBUS_TYPE_BYTE, &eid); + have_eid = true; + + } else if (!strcmp(propname, "NetworkId")) { + rc = read_variant_basic(&val, DBUS_TYPE_INT32, &net); + have_net = true; + + } else if (!strcmp(propname, "SupportedMessageTypes")) { + have_nvmemi = has_message_type(&val, MCTP_TYPE_NVME); + } + + if (rc) + return rc; + + if (!dbus_message_iter_next(props)) + break; } if (have_nvmemi) { @@ -657,70 +660,61 @@ static int handle_mctp_endpoint(nvme_root_t root, const char* objpath, return rc; } -static int handle_mctp_obj(nvme_root_t root, sd_bus_message *m) +/* obj is an array of (object path, interfaces) dict entries - ie., dbus type + * a{oa{sa{sv}}} + */ +static int handle_mctp_obj(nvme_root_t root, DBusMessageIter *obj) { - char *objpath = NULL; - char *ifname = NULL; - int rc; + const char *objpath = NULL; + DBusMessageIter intfs; - rc = sd_bus_message_read(m, "o", &objpath); - if (rc < 0) { - dbus_err(root, rc); + if (!dbus_object_is_type(obj, DBUS_TYPE_OBJECT_PATH)) { + nvme_msg(root, LOG_ERR, "error unmashalling object (path)\n"); return -1; } - /* Enter response object: our array of (string, property dict) - * values */ - rc = sd_bus_message_enter_container(m, 'a', "{sa{sv}}"); - if (rc < 0) { - dbus_err(root, rc); + dbus_message_iter_get_basic(obj, &objpath); + + dbus_message_iter_next(obj); + + if (!dbus_object_is_dict(obj)) { + nvme_msg(root, LOG_ERR, "error unmashalling object (intfs)\n"); return -1; } + dbus_message_iter_recurse(obj, &intfs); /* for each interface */ - while (!container_end(m)) { - /* Enter interface item */ - rc = sd_bus_message_enter_container(m, 'e', "sa{sv}"); - if (rc < 0) { - dbus_err(root, rc); - return -1; - } + for (;;) { + DBusMessageIter props, intf; + const char *intfname; - rc = sd_bus_message_read(m, "s", &ifname); - if (rc < 0) { - dbus_err(root, rc); + dbus_message_iter_recurse(&intfs, &intf); + + if (!dbus_object_is_type(&intf, DBUS_TYPE_STRING)) { + nvme_msg(root, LOG_ERR, + "error unmashalling object (intf)\n"); return -1; } - if (!strcmp(ifname, MCTP_DBUS_IFACE_ENDPOINT)) { - - rc = handle_mctp_endpoint(root, objpath, m); - if (rc < 0) { - /* continue to next object */ - } - } else { - /* skip the interfaces we don't care about */ - rc = sd_bus_message_skip(m, "a{sv}"); - if (rc < 0) { - dbus_err(root, rc); - return -1; - } + dbus_message_iter_get_basic(&intf, &intfname); + + if (strcmp(intfname, MCTP_DBUS_IFACE_ENDPOINT)) { + if (!dbus_message_iter_next(&intfs)) + break; + continue; } - /* Exit interface item */ - rc = sd_bus_message_exit_container(m); - if (rc < 0) { - dbus_err(root, rc); + dbus_message_iter_next(&intf); + + if (!dbus_object_is_dict(&intf)) { + nvme_msg(root, LOG_ERR, + "error unmarshalling object (props)\n"); return -1; } - } - /* Exit response object */ - rc = sd_bus_message_exit_container(m); - if (rc < 0) { - dbus_err(root, rc); - return -1; + dbus_message_iter_recurse(&intf, &props); + return handle_mctp_endpoint(root, objpath, &props); } return 0; @@ -728,85 +722,85 @@ static int handle_mctp_obj(nvme_root_t root, sd_bus_message *m) nvme_root_t nvme_mi_scan_mctp(void) { - sd_bus *bus = NULL; - sd_bus_message *resp = NULL; - sd_bus_error berr = SD_BUS_ERROR_NULL; - int rc, errno_save; + DBusMessage *msg, *resp = NULL; + DBusConnection *bus = NULL; + DBusMessageIter args, objs; + int errno_save, rc = -1; nvme_root_t root; + dbus_bool_t drc; + DBusError berr; root = nvme_mi_create_root(NULL, DEFAULT_LOGLEVEL); if (!root) { errno = ENOMEM; - rc = -1; + return NULL; + } + + dbus_error_init(&berr); + + bus = dbus_bus_get(DBUS_BUS_SYSTEM, &berr); + if (!bus) { + nvme_msg(root, LOG_ERR, "Failed connecting to D-Bus: %s (%s)\n", + berr.message, berr.name); goto out; } - rc = sd_bus_default_system(&bus); - if (rc < 0) { - nvme_msg(root, LOG_ERR, "Failed opening D-Bus: %s\n", - strerror(-rc)); - errno = -rc; - rc = -1; + msg = dbus_message_new_method_call(MCTP_DBUS_IFACE, + MCTP_DBUS_PATH, + "org.freedesktop.DBus.ObjectManager", + "GetManagedObjects"); + if (!msg) { + nvme_msg(root, LOG_ERR, "Failed creating call message\n"); goto out; } - rc = sd_bus_call_method(bus, - MCTP_DBUS_IFACE, - MCTP_DBUS_PATH, - "org.freedesktop.DBus.ObjectManager", - "GetManagedObjects", - &berr, - &resp, - ""); - if (rc < 0) { + resp = dbus_connection_send_with_reply_and_block(bus, msg, + DBUS_TIMEOUT_USE_DEFAULT, + &berr); + dbus_message_unref(msg); + if (!resp) { nvme_msg(root, LOG_ERR, "Failed querying MCTP D-Bus: %s (%s)\n", berr.message, berr.name); - errno = -rc; - rc = -1; goto out; } - rc = sd_bus_message_enter_container(resp, 'a', "{oa{sa{sv}}}"); - if (rc != 1) { - dbus_err(root, rc); - if (rc == 0) - errno = EPROTO; - rc = -1; + /* argument container */ + drc = dbus_message_iter_init(resp, &args); + if (!drc) { + nvme_msg(root, LOG_ERR, "can't read dbus reply args\n"); goto out; } - /* Iterate over all managed objects */ - while (!container_end(resp)) { - rc = sd_bus_message_enter_container(resp, 'e', "oa{sa{sv}}"); - if (rc < 0) { - dbus_err(root, rc); - rc = -1; - goto out; - } + if (!dbus_object_is_dict(&args)) { + nvme_msg(root, LOG_ERR, "error unmashalling args\n"); + goto out; + } - handle_mctp_obj(root, resp); + /* objects container */ + dbus_message_iter_recurse(&args, &objs); - rc = sd_bus_message_exit_container(resp); - if (rc < 0) { - dbus_err(root, rc); - rc = -1; - goto out; - } - } + rc = 0; - rc = sd_bus_message_exit_container(resp); - if (rc < 0) { - dbus_err(root, rc); - rc = -1; - goto out; + for (;;) { + DBusMessageIter ent; + + dbus_message_iter_recurse(&objs, &ent); + + rc = handle_mctp_obj(root, &ent); + if (rc) + break; + + if (!dbus_message_iter_next(&objs)) + break; } - rc = 0; out: errno_save = errno; - sd_bus_error_free(&berr); - sd_bus_message_unref(resp); - sd_bus_unref(bus); + if (resp) + dbus_message_unref(resp); + if (bus) + dbus_connection_unref(bus); + dbus_error_free(&berr); if (rc < 0) { if (root) { @@ -818,11 +812,11 @@ out: return root; } -#else /* CONFIG_LIBSYSTEMD */ +#else /* CONFIG_DBUS */ nvme_root_t nvme_mi_scan_mctp(void) { return NULL; } -#endif /* CONFIG_LIBSYSTEMD */ +#endif /* CONFIG_DBUS */ diff --git a/src/nvme/mi.c b/src/nvme/mi.c index 6ff0a6f..adf1753 100644 --- a/src/nvme/mi.c +++ b/src/nvme/mi.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -21,6 +22,20 @@ static const int default_timeout = 1000; /* milliseconds; endpoints may override */ +static bool nvme_mi_probe_enabled_default(void) +{ + char *val; + + val = getenv("LIBNVME_MI_PROBE_ENABLED"); + if (!val) + return true; + + return strcmp(val, "0") && + strcasecmp(val, "false") && + strncasecmp(val, "disable", 7); + +} + /* MI-equivalent of nvme_create_root, but avoids clashing symbol names * when linking against both libnvme and libnvme-mi. */ @@ -33,6 +48,7 @@ nvme_root_t nvme_mi_create_root(FILE *fp, int log_level) } r->log_level = log_level; r->fp = stderr; + r->mi_probe_enabled = nvme_mi_probe_enabled_default(); if (fp) r->fp = fp; list_head_init(&r->hosts); @@ -50,6 +66,180 @@ void nvme_mi_free_root(nvme_root_t root) free(root); } +void nvme_mi_set_probe_enabled(nvme_root_t root, bool enabled) +{ + root->mi_probe_enabled = enabled; +} + +static void nvme_mi_record_resp_time(struct nvme_mi_ep *ep) +{ + int rc; + + rc = clock_gettime(CLOCK_MONOTONIC, &ep->last_resp_time); + ep->last_resp_time_valid = !rc; +} + +static bool nvme_mi_compare_vid_mn(struct nvme_mi_ep *ep, + struct nvme_id_ctrl *id, + __u16 vid, const char *mn) + +{ + int len; + + len = strlen(mn); + if (len >= sizeof(id->mn)) { + nvme_msg(ep->root, LOG_ERR, + "Internal error: invalid model number for %s\n", + __func__); + return false; + } + + return le16_to_cpu(id->vid) == vid && !strncmp(id->mn, mn, len); +} + +static void __nvme_mi_format_mn(struct nvme_id_ctrl *id, + char *mn, size_t mn_len) +{ + const size_t id_mn_size = sizeof(id->mn); + int i; + + /* A BUILD_ASSERT() would be nice here, but we're not const enough for + * that + */ + if (mn_len <= id_mn_size) + abort(); + + memcpy(mn, id->mn, id_mn_size); + mn[id_mn_size] = '\0'; + + for (i = id_mn_size - 1; i >= 0; i--) { + if (mn[i] != '\0' && mn[i] != ' ') + break; + mn[i] = '\0'; + } +} + +#define nvme_mi_format_mn(id, m) __nvme_mi_format_mn(id, m, sizeof(m)) + +void nvme_mi_ep_probe(struct nvme_mi_ep *ep) +{ + struct nvme_identify_args id_args = { 0 }; + struct nvme_id_ctrl id = { 0 }; + struct nvme_mi_ctrl *ctrl; + int rc; + + if (!ep->root->mi_probe_enabled) + return; + + /* start with no quirks, detect as we go */ + ep->quirks = 0; + + ctrl = nvme_mi_init_ctrl(ep, 0); + if (!ctrl) + return; + + /* Do enough of an identify (assuming controller 0) to retrieve + * device and firmware identification information. This gives us the + * following fields in id: + * + * - vid (PCI vendor ID) + * - ssvid (PCI subsystem vendor ID) + * - sn (Serial number) + * - mn (Model number) + * - fr (Firmware revision) + * + * all other fields - rab and onwards - will be zero! + */ + id_args.args_size = sizeof(id_args); + id_args.data = &id; + id_args.cns = NVME_IDENTIFY_CNS_CTRL; + id_args.nsid = NVME_NSID_NONE; + id_args.cntid = 0; + id_args.csi = NVME_CSI_NVM; + + rc = nvme_mi_admin_identify_partial(ctrl, &id_args, 0, + offsetof(struct nvme_id_ctrl, rab)); + if (rc) { + nvme_msg(ep->root, LOG_WARNING, + "Identify Controller failed, no quirks applied\n"); + goto out_close; + } + + /* Samsung MZUL2512: cannot receive commands sent within ~1ms of + * the previous response. Set an inter-command delay of 1.2ms for + * a little extra tolerance. + */ + if (nvme_mi_compare_vid_mn(ep, &id, 0x144d, "MZUL2512HCJQ")) { + ep->quirks |= NVME_QUIRK_MIN_INTER_COMMAND_TIME; + ep->inter_command_us = 1200; + } + + /* If we're quirking for the inter-command time, record the last + * command time now, so we don't conflict with the just-sent identify. + */ + if (ep->quirks & NVME_QUIRK_MIN_INTER_COMMAND_TIME) + nvme_mi_record_resp_time(ep); + + if (ep->quirks) { + char tmp[sizeof(id.mn) + 1]; + + nvme_mi_format_mn(&id, tmp); + nvme_msg(ep->root, LOG_DEBUG, + "device %02x:%s: applying quirks 0x%08lx\n", + id.vid, tmp, ep->quirks); + } + +out_close: + nvme_mi_close_ctrl(ctrl); +} + +static const int nsec_per_sec = 1000 * 1000 * 1000; +/* timercmp and timersub, but for struct timespec */ +#define timespec_cmp(a, b, CMP) \ + (((a)->tv_sec == (b)->tv_sec) \ + ? ((a)->tv_nsec CMP (b)->tv_nsec) \ + : ((a)->tv_sec CMP (b)->tv_sec)) + +#define timespec_sub(a, b, result) \ + do { \ + (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ + (result)->tv_nsec = (a)->tv_nsec - (b)->tv_nsec; \ + if ((result)->tv_nsec < 0) { \ + --(result)->tv_sec; \ + (result)->tv_nsec += nsec_per_sec; \ + } \ + } while (0) + +static void nvme_mi_insert_delay(struct nvme_mi_ep *ep) +{ + struct timespec now, next, delay; + int rc; + + if (!ep->last_resp_time_valid) + return; + + /* calculate earliest next command time */ + next.tv_nsec = ep->last_resp_time.tv_nsec + ep->inter_command_us * 1000; + next.tv_sec = ep->last_resp_time.tv_sec; + if (next.tv_nsec > nsec_per_sec) { + next.tv_nsec -= nsec_per_sec; + next.tv_sec += 1; + } + + rc = clock_gettime(CLOCK_MONOTONIC, &now); + if (rc) { + /* not much we can do; continue immediately */ + return; + } + + if (timespec_cmp(&now, &next, >=)) + return; + + timespec_sub(&next, &now, &delay); + + nanosleep(&delay, NULL); +} + struct nvme_mi_ep *nvme_mi_init_ep(nvme_root_t root) { struct nvme_mi_ep *ep; @@ -93,6 +283,11 @@ unsigned int nvme_mi_ep_get_timeout(nvme_mi_ep_t ep) return ep->timeout; } +static bool nvme_mi_ep_has_quirk(nvme_mi_ep_t ep, unsigned long quirk) +{ + return ep->quirks & quirk; +} + struct nvme_mi_ctrl *nvme_mi_init_ctrl(nvme_mi_ep_t ep, __u16 ctrl_id) { struct nvme_mi_ctrl *ctrl; @@ -139,9 +334,7 @@ int nvme_mi_scan_ep(nvme_mi_ep_t ep, bool force_rescan) struct nvme_mi_ctrl *ctrl; __u16 id; - id = le32_to_cpu(list.identifier[i]); - if (!id) - continue; + id = le16_to_cpu(list.identifier[i]); ctrl = nvme_mi_init_ctrl(ep, id); if (!ctrl) @@ -223,7 +416,14 @@ int nvme_mi_submit(nvme_mi_ep_t ep, struct nvme_mi_req *req, if (ep->transport->mic_enabled) nvme_mi_calc_req_mic(req); + if (nvme_mi_ep_has_quirk(ep, NVME_QUIRK_MIN_INTER_COMMAND_TIME)) + nvme_mi_insert_delay(ep); + rc = ep->transport->submit(ep, req, resp); + + if (nvme_mi_ep_has_quirk(ep, NVME_QUIRK_MIN_INTER_COMMAND_TIME)) + nvme_mi_record_resp_time(ep); + if (rc) { nvme_msg(ep->root, LOG_INFO, "transport failure\n"); return rc; @@ -333,7 +533,12 @@ static int nvme_mi_admin_parse_status(struct nvme_mi_resp *resp, __u32 *result) admin_hdr = (struct nvme_mi_admin_resp_hdr *)resp->hdr; nvme_result = le32_to_cpu(admin_hdr->cdw0); - nvme_status = le32_to_cpu(admin_hdr->cdw3) >> 16; + + /* Shift down 17 here: the SC starts at bit 17, and the NVME_SC_* + * definitions align to this bit (and up). The CRD, MORE and DNR + * bits are defined accordingly (eg., DNR is 0x4000). + */ + nvme_status = le32_to_cpu(admin_hdr->cdw3) >> 17; /* the result pointer, optionally stored if the caller needs it */ if (result) @@ -419,6 +624,96 @@ int nvme_mi_admin_xfer(nvme_mi_ctrl_t ctrl, return 0; } +int nvme_mi_admin_admin_passthru(nvme_mi_ctrl_t ctrl, __u8 opcode, __u8 flags, + __u16 rsvd, __u32 nsid, __u32 cdw2, __u32 cdw3, + __u32 cdw10, __u32 cdw11, __u32 cdw12, + __u32 cdw13, __u32 cdw14, __u32 cdw15, + __u32 data_len, void *data, __u32 metadata_len, + void *metadata, __u32 timeout_ms, __u32 *result) +{ + /* Input parameters flags, rsvd, metadata, metadata_len are not used */ + struct nvme_mi_admin_resp_hdr resp_hdr; + struct nvme_mi_admin_req_hdr req_hdr; + struct nvme_mi_resp resp; + struct nvme_mi_req req; + int rc; + int direction = opcode & 0x3; + bool has_write_data = false; + bool has_read_data = false; + + if (direction == NVME_DATA_TFR_BIDIRECTIONAL) { + nvme_msg(ctrl->ep->root, LOG_ERR, + "nvme_mi_admin_admin_passthru doesn't support bidirectional commands\n"); + errno = EINVAL; + return -1; + } + + if (data_len > 4096) { + nvme_msg(ctrl->ep->root, LOG_ERR, + "nvme_mi_admin_admin_passthru doesn't support data_len over 4096 bytes.\n"); + errno = EINVAL; + return -1; + } + + if (data != NULL && data_len != 0) { + if (direction == NVME_DATA_TFR_HOST_TO_CTRL) + has_write_data = true; + if (direction == NVME_DATA_TFR_CTRL_TO_HOST) + has_read_data = true; + } + + if (timeout_ms > nvme_mi_ep_get_timeout(ctrl->ep)) { + /* Set timeout if user needs a bigger timeout */ + nvme_mi_ep_set_timeout(ctrl->ep, timeout_ms); + } + + nvme_mi_admin_init_req(&req, &req_hdr, ctrl->id, opcode); + req_hdr.cdw1 = cpu_to_le32(nsid); + req_hdr.cdw2 = cpu_to_le32(cdw2); + req_hdr.cdw3 = cpu_to_le32(cdw3); + req_hdr.cdw10 = cpu_to_le32(cdw10); + req_hdr.cdw11 = cpu_to_le32(cdw11); + req_hdr.cdw12 = cpu_to_le32(cdw12); + req_hdr.cdw13 = cpu_to_le32(cdw13); + req_hdr.cdw14 = cpu_to_le32(cdw14); + req_hdr.cdw15 = cpu_to_le32(cdw15); + req_hdr.doff = 0; + if (data_len != 0) { + req_hdr.dlen = cpu_to_le32(data_len); + /* Bit 0 set to 1 means DLEN contains a value */ + req_hdr.flags = 0x1; + } + + if (has_write_data) { + req.data = data; + req.data_len = data_len; + } + + nvme_mi_calc_req_mic(&req); + + nvme_mi_admin_init_resp(&resp, &resp_hdr); + + if (has_read_data) { + resp.data = data; + resp.data_len = data_len; + } + + rc = nvme_mi_submit(ctrl->ep, &req, &resp); + if (rc) + return rc; + + rc = nvme_mi_admin_parse_status(&resp, result); + if (rc) + return rc; + + if (has_read_data && (resp.data_len != data_len)) { + errno = EPROTO; + return -1; + } + + return 0; +} + int nvme_mi_admin_identify_partial(nvme_mi_ctrl_t ctrl, struct nvme_identify_args *args, off_t offset, size_t size) @@ -477,11 +772,19 @@ int nvme_mi_admin_identify_partial(nvme_mi_ctrl_t ctrl, } /* retrieves a MCTP-messsage-sized chunk of log page data. offset and len are - * specified within the args->data area */ + * specified within the args->data area. The `offset` parameter is a relative + * offset to the args->lpo ! + * + * What's more, we change the LPO of original command to chunk the request + * message into proper size which is allowed by MI interface. One reason is that + * this option seems to be supported better by devices. For more information + * about this option, please check https://github.com/linux-nvme/libnvme/pull/539 + * */ static int __nvme_mi_admin_get_log(nvme_mi_ctrl_t ctrl, const struct nvme_get_log_args *args, off_t offset, size_t *lenp, bool final) { + __u64 log_page_offset = args->lpo + offset; struct nvme_mi_admin_resp_hdr resp_hdr; struct nvme_mi_admin_req_hdr req_hdr; struct nvme_mi_resp resp; @@ -513,17 +816,13 @@ static int __nvme_mi_admin_get_log(nvme_mi_ctrl_t ctrl, (args->lid & 0xff)); req_hdr.cdw11 = cpu_to_le32(args->lsi << 16 | ndw >> 16); - req_hdr.cdw12 = cpu_to_le32(args->lpo & 0xffffffff); - req_hdr.cdw13 = cpu_to_le32(args->lpo >> 32); + req_hdr.cdw12 = cpu_to_le32(log_page_offset & 0xffffffff); + req_hdr.cdw13 = cpu_to_le32(log_page_offset >> 32); req_hdr.cdw14 = cpu_to_le32(args->csi << 24 | (args->ot ? 1 : 0) << 23 | args->uuidx); req_hdr.flags = 0x1; req_hdr.dlen = cpu_to_le32(len & 0xffffffff); - if (offset) { - req_hdr.flags |= 0x2; - req_hdr.doff = cpu_to_le32(offset); - } nvme_mi_calc_req_mic(&req); @@ -544,7 +843,7 @@ static int __nvme_mi_admin_get_log(nvme_mi_ctrl_t ctrl, int nvme_mi_admin_get_log(nvme_mi_ctrl_t ctrl, struct nvme_get_log_args *args) { - const size_t xfer_size = 4096; + const size_t max_xfer_size = 4096; off_t xfer_offset; int rc = 0; @@ -553,26 +852,32 @@ int nvme_mi_admin_get_log(nvme_mi_ctrl_t ctrl, struct nvme_get_log_args *args) return -1; } + if (args->ot && (args->len > max_xfer_size)) { + errno = EINVAL; + return -1; + } + for (xfer_offset = 0; xfer_offset < args->len;) { - size_t tmp, cur_xfer_size = xfer_size; + size_t xfered_size, cur_xfer_size = max_xfer_size; bool final; if (xfer_offset + cur_xfer_size > args->len) cur_xfer_size = args->len - xfer_offset; - tmp = cur_xfer_size; + xfered_size = cur_xfer_size; final = xfer_offset + cur_xfer_size >= args->len; + /* xfered_size is used as both input and output parameter */ rc = __nvme_mi_admin_get_log(ctrl, args, xfer_offset, - &tmp, final); + &xfered_size, final); if (rc) break; - xfer_offset += tmp; + xfer_offset += xfered_size; /* if we returned less data than expected, consider that * the end of the log page */ - if (tmp != cur_xfer_size) + if (xfered_size != cur_xfer_size) break; } @@ -606,8 +911,8 @@ int nvme_mi_admin_security_send(nvme_mi_ctrl_t ctrl, nvme_admin_security_send); req_hdr.cdw10 = cpu_to_le32(args->secp << 24 | - args->spsp0 << 16 | - args->spsp1 << 8 | + args->spsp1 << 16 | + args->spsp0 << 8 | args->nssf); req_hdr.cdw11 = cpu_to_le32(args->data_len & 0xffffffff); @@ -652,8 +957,8 @@ int nvme_mi_admin_security_recv(nvme_mi_ctrl_t ctrl, nvme_admin_security_recv); req_hdr.cdw10 = cpu_to_le32(args->secp << 24 | - args->spsp0 << 16 | - args->spsp1 << 8 | + args->spsp1 << 16 | + args->spsp0 << 8 | args->nssf); req_hdr.cdw11 = cpu_to_le32(args->data_len & 0xffffffff); @@ -985,7 +1290,7 @@ static int nvme_mi_read_data(nvme_mi_ep_t ep, __u32 cdw0, req_hdr.hdr.nmp = (NVME_MI_ROR_REQ << 7) | (NVME_MI_MT_MI << 3); /* we always use command slot 0 */ req_hdr.opcode = nvme_mi_mi_opcode_mi_data_read; - req_hdr.cdw0 = cdw0; + req_hdr.cdw0 = cpu_to_le32(cdw0); memset(&req, 0, sizeof(req)); req.hdr = &req_hdr.hdr; @@ -1222,7 +1527,7 @@ void nvme_mi_close(nvme_mi_ep_t ep) nvme_mi_for_each_ctrl_safe(ep, ctrl, tmp) nvme_mi_close_ctrl(ctrl); - if (ep->transport->close) + if (ep->transport && ep->transport->close) ep->transport->close(ep); list_del(&ep->root_entry); free(ep); diff --git a/src/nvme/mi.h b/src/nvme/mi.h index ab4216d..5659159 100644 --- a/src/nvme/mi.h +++ b/src/nvme/mi.h @@ -403,6 +403,17 @@ nvme_root_t nvme_mi_create_root(FILE *fp, int log_level); */ void nvme_mi_free_root(nvme_root_t root); +/** + * nvme_mi_set_probe_enabled() - enable/disable the probe for new endpoints + * @root: &nvme_root_t object + * @enabled: whether to probe new endpoints + * + * Controls whether newly-created endpoints are probed for quirks on creation. + * Defaults to enabled, which results in some initial messaging with the + * endpoint to determine model-specific details. + */ +void nvme_mi_set_probe_enabled(nvme_root_t root, bool enabled); + /* Top level management object: NVMe-MI Management Endpoint */ struct nvme_mi_ep; @@ -955,6 +966,46 @@ int nvme_mi_admin_xfer(nvme_mi_ctrl_t ctrl, off_t resp_data_offset, size_t *resp_data_size); +/** + * nvme_mi_admin_admin_passthru() - Submit an nvme admin passthrough command + * @ctrl: Controller to send command to + * @opcode: The nvme admin command to send + * @flags: NVMe command flags (not used) + * @rsvd: Reserved for future use + * @nsid: Namespace identifier + * @cdw2: Command dword 2 + * @cdw3: Command dword 3 + * @cdw10: Command dword 10 + * @cdw11: Command dword 11 + * @cdw12: Command dword 12 + * @cdw13: Command dword 13 + * @cdw14: Command dword 14 + * @cdw15: Command dword 15 + * @data_len: Length of the data transferred in this command in bytes + * @data: Pointer to user address of the data buffer + * @metadata_len:Length of metadata transferred in this command(not used) + * @metadata: Pointer to user address of the metadata buffer(not used) + * @timeout_ms: How long to wait for the command to complete + * @result: Optional field to return the result from the CQE dword 0 + * + * Send a customized NVMe Admin command request message and get the corresponding + * response message. + * + * This interface supports no data, host to controller and controller to + * host but it doesn't support bidirectional data transfer. + * Also this interface only supports data transfer size range [0, 4096] (bytes) + * so the & data_len parameter must be less than 4097. + * + * Return: The nvme command status if a response was received (see + * &enum nvme_status_field) or -1 with errno set otherwise. + */ +int nvme_mi_admin_admin_passthru(nvme_mi_ctrl_t ctrl, __u8 opcode, __u8 flags, + __u16 rsvd, __u32 nsid, __u32 cdw2, __u32 cdw3, + __u32 cdw10, __u32 cdw11, __u32 cdw12, + __u32 cdw13, __u32 cdw14, __u32 cdw15, + __u32 data_len, void *data, __u32 metadata_len, + void *metadata, __u32 timeout_ms, __u32 *result); + /** * nvme_mi_admin_identify_partial() - Perform an Admin identify command, * and retrieve partial response data. @@ -1202,7 +1253,7 @@ static inline int nvme_mi_admin_identify_nsid_ctrl_list(nvme_mi_ctrl_t ctrl, .result = NULL, .data = list, .args_size = sizeof(args), - .cns = NVME_IDENTIFY_CNS_CTRL_LIST, + .cns = NVME_IDENTIFY_CNS_NS_CTRL_LIST, .csi = NVME_CSI_NVM, .nsid = nsid, .cntid = cntid, diff --git a/src/nvme/private.h b/src/nvme/private.h index cdd1bbf..a6ded21 100644 --- a/src/nvme/private.h +++ b/src/nvme/private.h @@ -85,6 +85,7 @@ struct nvme_ctrl { char *cntrltype; char *dctype; bool discovery_ctrl; + bool unique_discovery_ctrl; bool discovered; bool persistent; struct nvme_fabrics_config cfg; @@ -114,6 +115,9 @@ struct nvme_host { char *hostid; char *dhchap_key; char *hostsymname; + bool pdc_enabled; + bool pdc_enabled_valid; /* set if pdc_enabled doesn't have an undefined + * value */ }; struct nvme_root { @@ -125,6 +129,7 @@ struct nvme_root { bool log_pid; bool log_timestamp; bool modified; + bool mi_probe_enabled; }; int nvme_set_attr(const char *dir, const char *attr, const char *value); @@ -186,6 +191,14 @@ struct nvme_mi_transport { int (*check_timeout)(struct nvme_mi_ep *ep, unsigned int timeout); }; +/* quirks */ + +/* Set a minimum time between receiving a response from one command and + * sending the next request. Some devices may ignore new commands sent too soon + * after the previous request, so manually insert a delay + */ +#define NVME_QUIRK_MIN_INTER_COMMAND_TIME (1 << 0) + struct nvme_mi_ep { struct nvme_root *root; const struct nvme_mi_transport *transport; @@ -195,6 +208,12 @@ struct nvme_mi_ep { bool controllers_scanned; unsigned int timeout; unsigned int mprt_max; + unsigned long quirks; + + /* inter-command delay, for NVME_QUIRK_MIN_INTER_COMMAND_TIME */ + unsigned int inter_command_us; + struct timespec last_resp_time; + bool last_resp_time_valid; }; struct nvme_mi_ctrl { @@ -204,6 +223,7 @@ struct nvme_mi_ctrl { }; struct nvme_mi_ep *nvme_mi_init_ep(struct nvme_root *root); +void nvme_mi_ep_probe(struct nvme_mi_ep *ep); /* for tests, we need to calculate the correct MICs */ __u32 nvme_mi_crc32_update(__u32 crc, void *data, size_t len); diff --git a/src/nvme/tree.c b/src/nvme/tree.c index b992824..18826bf 100644 --- a/src/nvme/tree.c +++ b/src/nvme/tree.c @@ -252,6 +252,19 @@ void nvme_host_set_dhchap_key(nvme_host_t h, const char *key) h->dhchap_key = strdup(key); } +void nvme_host_set_pdc_enabled(nvme_host_t h, bool enabled) +{ + h->pdc_enabled_valid = true; + h->pdc_enabled = enabled; +} + +bool nvme_host_is_pdc_enabled(nvme_host_t h, bool fallback) +{ + if (h->pdc_enabled_valid) + return h->pdc_enabled; + return fallback; +} + nvme_subsystem_t nvme_first_subsystem(nvme_host_t h) { return list_top(&h->subsystems, struct nvme_subsystem, entry); @@ -870,6 +883,16 @@ bool nvme_ctrl_is_discovery_ctrl(nvme_ctrl_t c) return c->discovery_ctrl; } +void nvme_ctrl_set_unique_discovery_ctrl(nvme_ctrl_t c, bool unique) +{ + c->unique_discovery_ctrl = unique; +} + +bool nvme_ctrl_is_unique_discovery_ctrl(nvme_ctrl_t c) +{ + return c->unique_discovery_ctrl; +} + int nvme_ctrl_identify(nvme_ctrl_t c, struct nvme_id_ctrl *id) { return nvme_identify_ctrl(nvme_ctrl_get_fd(c), id); @@ -931,7 +954,7 @@ int nvme_disconnect_ctrl(nvme_ctrl_t c) c->name, errno); return ret; } - nvme_msg(r, LOG_INFO, "%s: disconnected\n", c->name); + nvme_msg(r, LOG_INFO, "%s: %s disconnected\n", c->name, c->subsysnqn); nvme_deconfigure_ctrl(c); return 0; } @@ -1833,6 +1856,7 @@ static nvme_ns_t nvme_ns_open(const char *name) close_fd: close(n->fd); free_ns: + free(n->generic_name); free(n->name); free(n); return NULL; diff --git a/src/nvme/tree.h b/src/nvme/tree.h index 156cb79..e4a5126 100644 --- a/src/nvme/tree.h +++ b/src/nvme/tree.h @@ -106,6 +106,28 @@ const char *nvme_host_get_dhchap_key(nvme_host_t h); */ void nvme_host_set_dhchap_key(nvme_host_t h, const char *key); +/** + * nvme_host_set_pdc_enabled() - Set Persistent Discovery Controller flag + * @h: Host for which the falg should be set + * @enabled: The bool to set the enabled flag + * + * When nvme_host_set_pdc_enabled() is not used to set the PDC flag, + * nvme_host_is_pdc_enabled() will return the default value which was + * passed into the function and not the undefined flag value. + */ +void nvme_host_set_pdc_enabled(nvme_host_t h, bool enabled); + +/** + * nvme_host_is_pdc_enabled() - Is Persistenct Discovery Controller enabled + * @h: Host which to check if PDC is enabled + * @fallback: The fallback default value of the flag when + * @nvme_host_set_pdc_enabled has not be used + * to set the flag. + * + * Return: true if PDC is enabled for @h, else false + */ +bool nvme_host_is_pdc_enabled(nvme_host_t h, bool fallback); + /** * nvme_default_host() - Initializes the default host * @r: &nvme_root_t object @@ -968,6 +990,25 @@ void nvme_ctrl_set_discovery_ctrl(nvme_ctrl_t c, bool discovery); */ bool nvme_ctrl_is_discovery_ctrl(nvme_ctrl_t c); +/** + * nvme_ctrl_set_unique_discovery_ctrl() - Set the 'unique_discovery_ctrl' flag + * @c: Controller to be modified + * @unique: value of the unique_disc_ctrl flag + * + * Sets the 'unique_discovery_ctrl' flag in @c to specify wheter + * @c is a unique discovery controller + * + */ +void nvme_ctrl_set_unique_discovery_ctrl(nvme_ctrl_t c, bool unique); + +/** + * nvme_ctrl_is_unique_discovery_ctrl() - Check the 'unique_discovery_ctrl' flag + * @c: Controller to be checked + * + * Return: Value of the 'unique_discovery_ctrl' flag + */ +bool nvme_ctrl_is_unique_discovery_ctrl(nvme_ctrl_t c); + /** * nvme_ctrl_identify() - Issues an 'identify controller' command * @c: Controller instance diff --git a/src/nvme/types.h b/src/nvme/types.h index 94066fc..929d658 100644 --- a/src/nvme/types.h +++ b/src/nvme/types.h @@ -1127,6 +1127,7 @@ enum nvme_id_ctrl_oaes { * @NVME_CTRL_CTRATT_DEL_ENDURANCE_GROUPS: Delete Endurance Groups supported * @NVME_CTRL_CTRATT_DEL_NVM_SETS: Delete NVM Sets supported * @NVME_CTRL_CTRATT_ELBAS: Extended LBA Formats supported + * @NVME_CTRL_CTRATT_FDPS: Flexible Data Placement supported */ enum nvme_id_ctrl_ctratt { NVME_CTRL_CTRATT_128_ID = 1 << 0, @@ -1145,6 +1146,7 @@ enum nvme_id_ctrl_ctratt { NVME_CTRL_CTRATT_DEL_ENDURANCE_GROUPS = 1 << 13, NVME_CTRL_CTRATT_DEL_NVM_SETS = 1 << 14, NVME_CTRL_CTRATT_ELBAS = 1 << 15, + NVME_CTRL_CTRATT_FDPS = 1 << 19, }; /** @@ -2913,6 +2915,7 @@ enum nvme_status_result { * @NVME_ST_CODE_SHORT: Short device self-test operation. * @NVME_ST_CODE_EXTENDED: Extended device self-test operation. * @NVME_ST_CODE_VS: Vendor specific. + * @NVME_ST_CODE_ABORT: Abort device self-test operation. * @NVME_ST_CODE_SHIFT: Shift amount to get the code value from the * &struct nvme_st_result.dsts field. */ @@ -2921,6 +2924,7 @@ enum nvme_st_code { NVME_ST_CODE_SHORT = 0x1, NVME_ST_CODE_EXTENDED = 0x2, NVME_ST_CODE_VS = 0xe, + NVME_ST_CODE_ABORT = 0xf, NVME_ST_CODE_SHIFT = 4, }; @@ -3366,6 +3370,18 @@ struct nvme_fw_commit_event { __le16 vndr_assign_fw_commit_rc; } __attribute__((packed)); +/** + * struct nvme_timestamp - Timestamp - Data Structure for Get Features + * @timestamp: Timestamp value based on origin and synch field + * @attr: Attribute + * @rsvd: Reserved + */ +struct nvme_timestamp { + __u8 timestamp[6]; + __u8 attr; + __u8 rsvd; +}; + /** * struct nvme_time_stamp_change_event - Timestamp Change Event * @previous_timestamp: Previous Timestamp @@ -4078,6 +4094,295 @@ struct nvme_zone_report { struct nvme_zns_desc entries[]; }; +/** + * enum nvme_fdp_ruh_type - Reclaim Unit Handle Type + * @NVME_FDP_RUHT_INITIALLY_ISOLATED: Initially Isolated + * @NVME_FDP_RUHT_PERSISTENTLY_ISOLATED: Persistently Isolated + */ +enum nvme_fdp_ruh_type { + NVME_FDP_RUHT_INITIALLY_ISOLATED = 1, + NVME_FDP_RUHT_PERSISTENTLY_ISOLATED = 2, +}; + +/** + * struct nvme_fdp_ruh_desc - Reclaim Unit Handle Descriptor + * @ruht: Reclaim Unit Handle Type + * @rsvd1: Reserved + */ +struct nvme_fdp_ruh_desc { + __u8 ruht; + __u8 rsvd1[3]; +}; + +/** + * enum nvme_fdp_config_fdpa - FDP Attributes + * @NVME_FDP_CONFIG_FDPA_RGIF_SHIFT: Reclaim Group Identifier Format Shift + * @NVME_FDP_CONFIG_FDPA_RGIF_MASK: Reclaim Group Identifier Format Mask + * @NVME_FDP_CONFIG_FDPA_FDPVWC_SHIFT: FDP Volatile Write Cache Shift + * @NVME_FDP_CONFIG_FDPA_FDPVWC_MASK: FDP Volatile Write Cache Mask + * @NVME_FDP_CONFIG_FDPA_VALID_SHIFT: FDP Configuration Valid Shift + * @NVME_FDP_CONFIG_FDPA_VALID_MASK: FDP Configuration Valid Mask + */ +enum nvme_fdp_config_fdpa { + NVME_FDP_CONFIG_FDPA_RGIF_SHIFT = 0, + NVME_FDP_CONFIG_FDPA_RGIF_MASK = 0xf, + NVME_FDP_CONFIG_FDPA_FDPVWC_SHIFT = 4, + NVME_FDP_CONFIG_FDPA_FDPVWC_MASK = 0x1, + NVME_FDP_CONFIG_FDPA_VALID_SHIFT = 7, + NVME_FDP_CONFIG_FDPA_VALID_MASK = 0x1, +}; + +/** + * struct nvme_fdp_config_desc - FDP Configuration Descriptor + * @size: Descriptor size + * @fdpa: FDP Attributes (&enum nvme_fdp_config_fdpa) + * @vss: Vendor Specific Size + * @nrg: Number of Reclaim Groups + * @nruh: Number of Reclaim Unit Handles + * @maxpids: Max Placement Identifiers + * @nnss: Number of Namespaces Supported + * @runs: Reclaim Unit Nominal Size + * @erutl: Estimated Reclaim Unit Time Limit + * @rsvd28: Reserved + * @ruhs: Reclaim Unit Handle descriptors (&struct nvme_fdp_ruh_desc) + */ +struct nvme_fdp_config_desc { + __u16 size; + __u8 fdpa; + __u8 vss; + __u32 nrg; + __u16 nruh; + __u16 maxpids; + __u32 nnss; + __u64 runs; + __u32 erutl; + __u8 rsvd28[36]; + struct nvme_fdp_ruh_desc ruhs[]; +}; + +/** + * struct nvme_fdp_config_log - FDP Configurations Log Page + * @n: Number of FDP Configurations + * @version: Log page version + * @rsvd3: Reserved + * @size: Log page size in bytes + * @rsvd8: Reserved + * @configs: FDP Configuration descriptors (&struct nvme_fdp_config_desc) + */ +struct nvme_fdp_config_log { + __u16 n; + __u8 version; + __u8 rsvd3; + __u32 size; + __u8 rsvd8[8]; + struct nvme_fdp_config_desc configs[]; +}; + +/** + * enum nvme_fdp_ruha - Reclaim Unit Handle Attributes + * @NVME_FDP_RUHA_HOST_SHIFT: Host Specified Reclaim Unit Handle Shift + * @NVME_FDP_RUHA_HOST_MASK: Host Specified Reclaim Unit Handle Mask + * @NVME_FDP_RUHA_CTRL_SHIFT: Controller Specified Reclaim Unit Handle Shift + * @NVME_FDP_RUHA_CTRL_MASK: Controller Specified Reclaim Unit Handle Mask + */ +enum nvme_fdp_ruha { + NVME_FDP_RUHA_HOST_SHIFT = 0, + NVME_FDP_RUHA_HOST_MASK = 0x1, + NVME_FDP_RUHA_CTRL_SHIFT = 1, + NVME_FDP_RUHA_CTRL_MASK = 0x1, +}; + +/** + * struct nvme_fdp_ruhu_desc - Reclaim Unit Handle Usage Descriptor + * @ruha: Reclaim Unit Handle Attributes (&enum nvme_fdp_ruha) + * @rsvd1: Reserved + */ +struct nvme_fdp_ruhu_desc { + __u8 ruha; + __u8 rsvd1[7]; +}; + +/** + * struct nvme_fdp_ruhu_log - Reclaim Unit Handle Usage Log Page + * @nruh: Number of Reclaim Unit Handles + * @rsvd2: Reserved + * @ruhus: Reclaim Unit Handle Usage descriptors + */ +struct nvme_fdp_ruhu_log { + __u16 nruh; + __u8 rsvd2[6]; + struct nvme_fdp_ruhu_desc ruhus[]; +}; + +/** + * struct nvme_fdp_stats_log - FDP Statistics Log Page + * @hbmw: Host Bytes with Metadata Written + * @mbmw: Media Bytes with Metadata Written + * @mbe: Media Bytes Erased + * @rsvd48: Reserved + */ +struct nvme_fdp_stats_log { + __u8 hbmw[16]; + __u8 mbmw[16]; + __u8 mbe[16]; + __u8 rsvd48[16]; +}; + +/** + * enum nvme_fdp_event_type - FDP Event Types + * @NVME_FDP_EVENT_RUNFW: Reclaim Unit Not Fully Written + * @NVME_FDP_EVENT_RUTLE: Reclaim Unit Time Limit Exceeded + * @NVME_FDP_EVENT_RESET: Controller Level Reset Modified Reclaim Unit Handles + * @NVME_FDP_EVENT_PID: Invalid Placement Identifier + * @NVME_FDP_EVENT_REALLOC: Media Reallocated + * @NVME_FDP_EVENT_MODIFY: Implicitly Modified Reclaim Unit Handle + */ +enum nvme_fdp_event_type { + /* Host Events */ + NVME_FDP_EVENT_RUNFW = 0x0, + NVME_FDP_EVENT_RUTLE = 0x1, + NVME_FDP_EVENT_RESET = 0x2, + NVME_FDP_EVENT_PID = 0x3, + + /* Controller Events */ + NVME_FDP_EVENT_REALLOC = 0x80, + NVME_FDP_EVENT_MODIFY = 0x81, +}; + +/** + * enum nvme_fdp_event_realloc_flags - Media Reallocated Event Type Specific Flags + * @NVME_FDP_EVENT_REALLOC_F_LBAV: LBA Valid + */ +enum nvme_fdp_event_realloc_flags { + NVME_FDP_EVENT_REALLOC_F_LBAV = 1 << 0, +}; + +/** + * struct nvme_fdp_event_realloc - Media Reallocated Event Type Specific Information + * @flags: Event Type Specific flags (&enum nvme_fdp_event_realloc_flags) + * @rsvd1: Reserved + * @nlbam: Number of LBAs Moved + * @lba: Logical Block Address + * @rsvd12: Reserved + */ +struct nvme_fdp_event_realloc { + __u8 flags; + __u8 rsvd1; + __u16 nlbam; + __u64 lba; + __u8 rsvd12[4]; +}; + +/** + * enum nvme_fdp_event_flags - FDP Event Flags + * @NVME_FDP_EVENT_F_PIV: Placement Identifier Valid + * @NVME_FDP_EVENT_F_NSIDV: Namespace Identifier Valid + * @NVME_FDP_EVENT_F_LV: Location Valid + */ +enum nvme_fdp_event_flags { + NVME_FDP_EVENT_F_PIV = 1 << 0, + NVME_FDP_EVENT_F_NSIDV = 1 << 1, + NVME_FDP_EVENT_F_LV = 1 << 2, +}; + +/** + * struct nvme_fdp_event - FDP Event + * @type: Event Type (&enum nvme_fdp_event_type) + * @flags: Event Flags (&enum nvme_fdp_event_flags) + * @pid: Placement Identifier + * @ts: Timestamp + * @nsid: Namespace Identifier + * @type_specific: Event Type Specific Information + * @rgid: Reclaim Group Identifier + * @ruhid: Reclaim Unit Handle Identifier + * @rsvd35: Reserved + * @vs: Vendor Specific + */ +struct nvme_fdp_event { + __u8 type; + __u8 flags; + __u16 pid; + struct nvme_timestamp ts; + __u32 nsid; + __u8 type_specific[16]; + __u16 rgid; + __u8 ruhid; + __u8 rsvd35[5]; + __u8 vs[24]; +}; + +/** + * struct nvme_fdp_events_log - FDP Events Log Page + * @n: Number of FDP Events + * @rsvd4: Reserved + * @events: FDP Events (&struct nvme_fdp_event) + */ +struct nvme_fdp_events_log { + __u32 n; + __u8 rsvd4[60]; + struct nvme_fdp_event events[63]; +}; + +/** + * struct nvme_feat_fdp_events_cdw11 - FDP Events Feature Command Dword 11 + * @phndl: Placement Handle + * @noet: Number of FDP Event Types + * @rsvd24: Reserved + */ +struct nvme_feat_fdp_events_cdw11 { + __u16 phndl; + __u8 noet; + __u8 rsvd24; +}; + +/** + * enum nvme_fdp_supported_event_attributes - Supported FDP Event Attributes + * @NVME_FDP_SUPP_EVENT_ENABLED_SHIFT: FDP Event Enable Shift + * @NVME_FDP_SUPP_EVENT_ENABLED_MASK: FDP Event Enable Mask + */ +enum nvme_fdp_supported_event_attributes { + NVME_FDP_SUPP_EVENT_ENABLED_SHIFT = 0, + NVME_FDP_SUPP_EVENT_ENABLED_MASK = 0x1, +}; + +/** + * struct nvme_fdp_supported_event_desc - Supported FDP Event Descriptor + * @evt: FDP Event Type + * @evta: FDP Event Type Attributes (&enum nvme_fdp_supported_event_attributes) + */ +struct nvme_fdp_supported_event_desc { + __u8 evt; + __u8 evta; +}; + +/** + * struct nvme_fdp_ruh_status_desc - Reclaim Unit Handle Status Descriptor + * @pid: Placement Identifier + * @ruhid: Reclaim Unit Handle Identifier + * @earutr: Estimated Active Reclaim Unit Time Remaining + * @ruamw: Reclaim Unit Available Media Writes + * @rsvd16: Reserved + */ +struct nvme_fdp_ruh_status_desc { + __u16 pid; + __u16 ruhid; + __u32 earutr; + __u64 ruamw; + __u8 rsvd16[16]; +}; + +/** + * struct nvme_fdp_ruh_status - Reclaim Unit Handle Status + * @rsvd0: Reserved + * @nruhsd: Number of Reclaim Unit Handle Status Descriptors + * @ruhss: Reclaim Unit Handle Status descriptors + */ +struct nvme_fdp_ruh_status { + __u8 rsvd0[14]; + __u16 nruhsd; + struct nvme_fdp_ruh_status_desc ruhss[]; +}; + /** * struct nvme_lba_status_desc - LBA Status Descriptor Entry * @dslba: Descriptor Starting LBA @@ -4222,18 +4527,6 @@ enum nvme_ns_metadata_type { NVME_NS_METADATA_OS_NS_QUAL_2 = 0x04, }; -/** - * struct nvme_timestamp - Timestamp - Data Structure for Get Features - * @timestamp: Timestamp value based on origin and synch field - * @attr: Attribute - * @rsvd: Reserved - */ -struct nvme_timestamp { - __u8 timestamp[6]; - __u8 attr; - __u8 rsvd; -}; - /** * struct nvme_lba_range_type_entry - LBA Range Type - Data Structure Entry * @type: Specifies the Type of the LBA range @@ -6376,6 +6669,10 @@ 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_FDP_CONFIGS: FDP Configurations + * @NVME_LOG_LID_FDP_RUH_USAGE: Reclaim Unit Handle Usage + * @NVME_LOG_LID_FDP_STATS: FDP Statistics + * @NVME_LOG_LID_FDP_EVENTS: FDP Events * @NVME_LOG_LID_DISCOVER: Discovery * @NVME_LOG_LID_RESERVATION: Reservation Notification * @NVME_LOG_LID_SANITIZE: Sanitize Status @@ -6403,6 +6700,10 @@ 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_FDP_CONFIGS = 0x20, + NVME_LOG_LID_FDP_RUH_USAGE = 0x21, + NVME_LOG_LID_FDP_STATS = 0x22, + NVME_LOG_LID_FDP_EVENTS = 0x23, NVME_LOG_LID_DISCOVER = 0x70, NVME_LOG_LID_RESERVATION = 0x80, NVME_LOG_LID_SANITIZE = 0x81, @@ -6437,6 +6738,8 @@ enum nvme_cmd_get_log_lid { * @NVME_FEAT_FID_ENDURANCE_EVT_CFG: Endurance Group Event Configuration * @NVME_FEAT_FID_IOCS_PROFILE: I/O Command Set Profile * @NVME_FEAT_FID_SPINUP_CONTROL: Spinup Control + * @NVME_FEAT_FID_FDP: Flexible Data Placement + * @NVME_FEAT_FID_FDP_EVENTS: FDP Events * @NVME_FEAT_FID_ENH_CTRL_METADATA: Enhanced Controller Metadata * @NVME_FEAT_FID_CTRL_METADATA: Controller Metadata * @NVME_FEAT_FID_NS_METADATA: Namespace Metadata @@ -6473,6 +6776,8 @@ enum nvme_features_id { NVME_FEAT_FID_ENDURANCE_EVT_CFG = 0x18, NVME_FEAT_FID_IOCS_PROFILE = 0x19, /* XXX: Placeholder until assigned */ NVME_FEAT_FID_SPINUP_CONTROL = 0x1a, + NVME_FEAT_FID_FDP = 0x1d, + NVME_FEAT_FID_FDP_EVENTS = 0x1e, NVME_FEAT_FID_ENH_CTRL_METADATA = 0x7d, NVME_FEAT_FID_CTRL_METADATA = 0x7e, NVME_FEAT_FID_NS_METADATA = 0x7f, @@ -6583,6 +6888,12 @@ enum nvme_features_id { * @NVME_FEAT_WP_WPS_MASK: * @NVME_FEAT_IOCSP_IOCSCI_SHIFT: * @NVME_FEAT_IOCSP_IOCSCI_MASK: + * @NVME_FEAT_FDP_ENABLED_SHIFT: + * @NVME_FEAT_FDP_ENABLED_MASK: + * @NVME_FEAT_FDP_INDEX_SHIFT: + * @NVME_FEAT_FDP_INDEX_MASK: + * @NVME_FEAT_FDP_EVENTS_ENABLE_SHIFT: + * @NVME_FEAT_FDP_EVENTS_ENABLE_MASK: */ enum nvme_feat { NVME_FEAT_ARBITRATION_BURST_SHIFT = 0, @@ -6683,6 +6994,12 @@ enum nvme_feat { NVME_FEAT_WP_WPS_MASK = 0x7, NVME_FEAT_IOCSP_IOCSCI_SHIFT = 0, NVME_FEAT_IOCSP_IOCSCI_MASK = 0xff, + NVME_FEAT_FDP_ENABLED_SHIFT = 0, + NVME_FEAT_FDP_ENABLED_MASK = 0x1, + NVME_FEAT_FDP_INDEX_SHIFT = 8, + NVME_FEAT_FDP_INDEX_MASK = 0xf, + NVME_FEAT_FDP_EVENTS_ENABLE_SHIFT = 0, + NVME_FEAT_FDP_EVENTS_ENABLE_MASK = 0x1, }; /** @@ -7073,8 +7390,10 @@ enum nvme_data_tfr { * @nvme_cmd_resv_register: Reservation Register * @nvme_cmd_resv_report: Reservation Report * @nvme_cmd_resv_acquire: Reservation Acquire + * @nvme_cmd_io_mgmt_recv: I/O Management Receive * @nvme_cmd_resv_release: Reservation Release * @nvme_cmd_copy: Copy + * @nvme_cmd_io_mgmt_send: I/O Management Send * @nvme_zns_cmd_mgmt_send: Zone Management Send * @nvme_zns_cmd_mgmt_recv: Zone Management Receive * @nvme_zns_cmd_append: Zone Append @@ -7091,8 +7410,10 @@ enum nvme_io_opcode { nvme_cmd_resv_register = 0x0d, nvme_cmd_resv_report = 0x0e, nvme_cmd_resv_acquire = 0x11, + nvme_cmd_io_mgmt_recv = 0x12, nvme_cmd_resv_release = 0x15, nvme_cmd_copy = 0x19, + nvme_cmd_io_mgmt_send = 0x1d, nvme_zns_cmd_mgmt_send = 0x79, nvme_zns_cmd_mgmt_recv = 0x7a, nvme_zns_cmd_append = 0x7d, @@ -7295,4 +7616,20 @@ enum nvme_zns_report_options { NVME_ZNS_ZRAS_REPORT_OFFLINE = 0x7, }; +/** + * enum nvme_io_mgmt_recv_mo - I/O Management Receive - Management Operation + * @NVME_IO_MGMT_RECV_RUH_STATUS: Reclaim Unit Handle Status + */ +enum nvme_io_mgmt_recv_mo { + NVME_IO_MGMT_RECV_RUH_STATUS = 0x1, +}; + +/** + * enum nvme_io_mgmt_send_mo - I/O Management Send - Management Operation + * @NVME_IO_MGMT_SEND_RUH_UPDATE: Reclaim Unit Handle Update + */ +enum nvme_io_mgmt_send_mo { + NVME_IO_MGMT_SEND_RUH_UPDATE = 0x1, +}; + #endif /* _LIBNVME_TYPES_H */ diff --git a/src/nvme/util.c b/src/nvme/util.c index c61dbe9..0354afe 100644 --- a/src/nvme/util.c +++ b/src/nvme/util.c @@ -325,7 +325,7 @@ static const char * const media_status[] = { }; static const char * const path_status[] = { - [NVME_SC_ANA_INTERNAL_PATH_ERROR] = "Internal Path Error: An internal error specific to the controller processing the commmand prevented completion", + [NVME_SC_ANA_INTERNAL_PATH_ERROR] = "Internal Path Error: An internal error specific to the controller processing the command prevented completion", [NVME_SC_ANA_PERSISTENT_LOSS] = "Asymmetric Access Persistent Loss: The controller is in a persistent loss state with the requested namespace", [NVME_SC_ANA_INACCESSIBLE] = "Asymmetric Access Inaccessible: The controller is in an inaccessible state with the requested namespace", [NVME_SC_ANA_TRANSITION] = "Asymmetric Access Transition: The controller is currently transitioning states with the requested namespace", @@ -559,11 +559,12 @@ static const char * const libnvme_status[] = { [ENVME_CONNECT_INVAL_TR] = "invalid transport type", [ENVME_CONNECT_LOOKUP_SUBSYS_NAME] = "failed to lookup subsystem name", [ENVME_CONNECT_LOOKUP_SUBSYS] = "failed to lookup subsystem", - [ENVME_CONNECT_ALREADY] = "already connnected", + [ENVME_CONNECT_ALREADY] = "already connected", [ENVME_CONNECT_INVAL] = "invalid arguments/configuration", [ENVME_CONNECT_ADDRINUSE] = "hostnqn already in use", [ENVME_CONNECT_NODEV] = "invalid interface", [ENVME_CONNECT_OPNOTSUPP] ="not supported", + [ENVME_CONNECT_CONNREFUSED] = "connection refused", }; const char *nvme_errno_to_string(int status) @@ -573,6 +574,7 @@ const char *nvme_errno_to_string(int status) return s; } +#ifdef HAVE_LIBNSS char *hostname2traddr(struct nvme_root *r, const char *traddr) { struct addrinfo *host_info, hints = {.ai_family = AF_UNSPEC}; @@ -617,6 +619,18 @@ free_addrinfo: return ret_traddr; } +#else /* !HAVE_LIBNSS */ + +char *hostname2traddr(struct nvme_root *r, const char *traddr) +{ + nvme_msg(NULL, LOG_ERR, "No support for hostname IP address resolution; " \ + "recompile with libnss support.\n"); + + errno = -ENOTSUP; + return NULL; +} +#endif /* HAVE_LIBNSS */ + char *startswith(const char *s, const char *prefix) { size_t l; @@ -871,13 +885,11 @@ int nvme_uuid_random(unsigned char uuid[NVME_UUID_LEN]) if (f < 0) return -errno; n = read(f, uuid, NVME_UUID_LEN); - if (n < 0) { - close(f); + close(f); + if (n < 0) return -errno; - } else if (n != NVME_UUID_LEN) { - close(f); + else if (n != NVME_UUID_LEN) return -EIO; - } /* * See https://www.rfc-editor.org/rfc/rfc4122#section-4.4 diff --git a/src/nvme/util.h b/src/nvme/util.h index e72c156..961da18 100644 --- a/src/nvme/util.h +++ b/src/nvme/util.h @@ -36,6 +36,7 @@ * @ENVME_CONNECT_ADDRINUSE: hostnqn already in use * @ENVME_CONNECT_NODEV: invalid interface * @ENVME_CONNECT_OPNOTSUPP: not supported + * @ENVME_CONNECT_CONNREFUSED: connection refused */ enum nvme_connect_err { ENVME_CONNECT_RESOLVE = 1000, @@ -55,6 +56,7 @@ enum nvme_connect_err { ENVME_CONNECT_ADDRINUSE, ENVME_CONNECT_NODEV, ENVME_CONNECT_OPNOTSUPP, + ENVME_CONNECT_CONNREFUSED, }; /** @@ -529,13 +531,13 @@ char *startswith(const char *s, const char *prefix); /** * nvmf_exat_len() - Return length rounded up by 4 - * @val_len: Value lenght + * @val_len: Value length * * Return the size in bytes, rounded to a multiple of 4 (e.g., size of * __u32), of the buffer needed to hold the exat value of size * @val_len. * - * Return: Lenght rounded up by 4 + * Return: Length rounded up by 4 */ static inline __u16 nvmf_exat_len(size_t val_len) { diff --git a/subprojects/dbus.wrap b/subprojects/dbus.wrap new file mode 100644 index 0000000..95ad3af --- /dev/null +++ b/subprojects/dbus.wrap @@ -0,0 +1,4 @@ +[wrap-git] +url = https://gitlab.freedesktop.org/dbus/dbus.git +revision = 218b35a57cdeab667c75d6ef34f901b8ead00056 +depth = 1 diff --git a/subprojects/uuid.wrap b/subprojects/uuid.wrap deleted file mode 100644 index 0692c4e..0000000 --- a/subprojects/uuid.wrap +++ /dev/null @@ -1,6 +0,0 @@ -[wrap-git] -url = https://github.com/util-linux/util-linux.git -revision = eefff5aac7bce6979c950e3931a578efe03acbac - -[provide] -dependency_names = uuid \ No newline at end of file diff --git a/test/mi.c b/test/mi.c index c21f9db..5bbb2f0 100644 --- a/test/mi.c +++ b/test/mi.c @@ -442,8 +442,8 @@ static void test_admin_id(nvme_mi_ep_t ep) assert(rc == 0); } -/* test: simple NVMe error response */ -static int test_admin_err_resp_cb(struct nvme_mi_ep *ep, +/* test: simple NVMe error response, error reported in the MI header */ +static int test_admin_err_mi_resp_cb(struct nvme_mi_ep *ep, struct nvme_mi_req *req, struct nvme_mi_resp *resp, void *data) @@ -481,19 +481,85 @@ static int test_admin_err_resp_cb(struct nvme_mi_ep *ep, return 0; } -static void test_admin_err_resp(nvme_mi_ep_t ep) +static void test_admin_err_mi_resp(nvme_mi_ep_t ep) { struct nvme_id_ctrl id; nvme_mi_ctrl_t ctrl; int rc; - test_set_transport_callback(ep, test_admin_err_resp_cb, NULL); + test_set_transport_callback(ep, test_admin_err_mi_resp_cb, NULL); ctrl = nvme_mi_init_ctrl(ep, 1); assert(ctrl); rc = nvme_mi_admin_identify_ctrl(ctrl, &id); assert(rc != 0); + assert(nvme_status_get_type(rc) == NVME_STATUS_TYPE_MI); + assert(nvme_status_get_value(rc) == NVME_MI_RESP_INTERNAL_ERR); +} + +/* test: NVMe Admin error, with the error reported in the Admin response */ +static int test_admin_err_nvme_resp_cb(struct nvme_mi_ep *ep, + struct nvme_mi_req *req, + struct nvme_mi_resp *resp, + void *data) +{ + __u8 ror, mt, *hdr; + + assert(req->hdr->type == NVME_MI_MSGTYPE_NVME); + + ror = req->hdr->nmp >> 7; + mt = req->hdr->nmp >> 3 & 0x7; + assert(ror == NVME_MI_ROR_REQ); + assert(mt == NVME_MI_MT_ADMIN); + + /* do we have enough for a mi header? */ + assert(req->hdr_len == sizeof(struct nvme_mi_admin_req_hdr)); + + /* inspect response as raw bytes */ + hdr = (__u8 *)req->hdr; + assert(hdr[4] == nvme_admin_identify); + + /* we need at least 8 bytes for error information */ + assert(resp->hdr_len >= sizeof(struct nvme_mi_admin_resp_hdr)); + + /* create error response */ + hdr = (__u8 *)resp->hdr; + hdr[4] = 0; /* MI status: success */ + hdr[5] = 0; + hdr[6] = 0; + hdr[7] = 0; + + hdr[16] = 0; /* cdw3: SC: internal, SCT: generic, DNR */ + hdr[17] = 0; + hdr[18] = 0x0c; + hdr[19] = 0x80; + + resp->hdr_len = sizeof(struct nvme_mi_admin_resp_hdr); + resp->data_len = 0; + + test_transport_resp_calc_mic(resp); + + return 0; +} + +static void test_admin_err_nvme_resp(nvme_mi_ep_t ep) +{ + struct nvme_id_ctrl id; + nvme_mi_ctrl_t ctrl; + int rc; + + test_set_transport_callback(ep, test_admin_err_nvme_resp_cb, NULL); + + ctrl = nvme_mi_init_ctrl(ep, 1); + assert(ctrl); + + rc = nvme_mi_admin_identify_ctrl(ctrl, &id); + assert(rc != 0); + assert(nvme_status_get_type(rc) == NVME_STATUS_TYPE_NVME); + assert(nvme_status_get_value(rc) == + (NVME_SC_INTERNAL | (NVME_SCT_GENERIC << NVME_SCT_SHIFT) + | NVME_SC_DNR)); } /* invalid Admin command transfers */ @@ -509,8 +575,11 @@ static int test_admin_invalid_formats_cb(struct nvme_mi_ep *ep, static void test_admin_invalid_formats(nvme_mi_ep_t ep) { + struct { + struct nvme_mi_admin_req_hdr hdr; + uint8_t data[4]; + } req = { 0 }; struct nvme_mi_admin_resp_hdr resp = { 0 }; - struct nvme_mi_admin_req_hdr req = { 0 }; nvme_mi_ctrl_t ctrl; size_t len; int rc; @@ -522,37 +591,37 @@ static void test_admin_invalid_formats(nvme_mi_ep_t ep) /* unaligned req size */ len = 0; - rc = nvme_mi_admin_xfer(ctrl, &req, 1, &resp, 0, &len); + rc = nvme_mi_admin_xfer(ctrl, &req.hdr, 1, &resp, 0, &len); assert(rc != 0); /* unaligned resp size */ len = 1; - rc = nvme_mi_admin_xfer(ctrl, &req, 0, &resp, 0, &len); + rc = nvme_mi_admin_xfer(ctrl, &req.hdr, 0, &resp, 0, &len); assert(rc != 0); /* unaligned resp offset */ len = 4; - rc = nvme_mi_admin_xfer(ctrl, &req, 0, &resp, 1, &len); + rc = nvme_mi_admin_xfer(ctrl, &req.hdr, 0, &resp, 1, &len); assert(rc != 0); /* resp too large */ len = 4096 + 4; - rc = nvme_mi_admin_xfer(ctrl, &req, 0, &resp, 0, &len); + rc = nvme_mi_admin_xfer(ctrl, &req.hdr, 0, &resp, 0, &len); assert(rc != 0); /* resp offset too large */ len = 4; - rc = nvme_mi_admin_xfer(ctrl, &req, 0, &resp, (off_t)1 << 32, &len); + rc = nvme_mi_admin_xfer(ctrl, &req.hdr, 0, &resp, (off_t)1 << 32, &len); assert(rc != 0); /* resp offset with no len */ len = 0; - rc = nvme_mi_admin_xfer(ctrl, &req, 0, &resp, 4, &len); + rc = nvme_mi_admin_xfer(ctrl, &req.hdr, 0, &resp, 4, &len); assert(rc != 0); /* req and resp payloads */ len = 4; - rc = nvme_mi_admin_xfer(ctrl, &req, 4, &resp, 0, &len); + rc = nvme_mi_admin_xfer(ctrl, &req.hdr, 4, &resp, 0, &len); assert(rc != 0); } @@ -930,7 +999,7 @@ static int test_admin_set_features_cb(struct nvme_mi_ep *ep, static void test_set_features(nvme_mi_ep_t ep) { struct nvme_set_features_args args = { 0 }; - struct nvme_timestamp tstamp; + struct nvme_timestamp tstamp = { 0 }; nvme_mi_ctrl_t ctrl; uint32_t res; int rc, i; @@ -1141,7 +1210,7 @@ static int test_admin_id_nsid_ctrl_list_cb(struct nvme_mi_ep *ep, assert(req->data_len == 0); cns = hdr[45] << 8 | hdr[44]; - assert(cns == NVME_IDENTIFY_CNS_CTRL_LIST); + assert(cns == NVME_IDENTIFY_CNS_NS_CTRL_LIST); nsid = hdr[11] << 24 | hdr[10] << 16 | hdr[9] << 8 | hdr[8]; assert(nsid == 0x01020304); @@ -1273,7 +1342,7 @@ static int test_admin_ns_mgmt_cb(struct nvme_mi_ep *ep, static void test_admin_ns_mgmt_create(struct nvme_mi_ep *ep) { - struct nvme_id_ns nsid; + struct nvme_id_ns nsid = { 0 }; nvme_mi_ctrl_t ctrl; __u32 ns; int rc; @@ -1287,7 +1356,7 @@ static void test_admin_ns_mgmt_create(struct nvme_mi_ep *ep) assert(!rc); assert(ns == 0x01020304); - nsid.nsze = 42; + nsid.nsze = cpu_to_le64(42); rc = nvme_mi_admin_ns_mgmt_create(ctrl, &nsid, 0, &ns); assert(rc); } @@ -1710,6 +1779,7 @@ static int test_admin_get_log_split_cb(struct nvme_mi_ep *ep, struct nvme_mi_resp *resp, void *data) { + uint32_t log_page_offset_lower; struct log_data *ldata = data; uint32_t len, off; __u8 *rq_hdr; @@ -1724,19 +1794,25 @@ static int test_admin_get_log_split_cb(struct nvme_mi_ep *ep, off = rq_hdr[31] << 24 | rq_hdr[30] << 16 | rq_hdr[29] << 8 | rq_hdr[28]; len = rq_hdr[35] << 24 | rq_hdr[34] << 16 | rq_hdr[33] << 8 | rq_hdr[32]; + /* From the MI message's Command Dword 12 */ + log_page_offset_lower = rq_hdr[55] << 24 | rq_hdr[54] << 16 | rq_hdr[53] << 8 | rq_hdr[52]; + /* we should have a full-sized start and middle, and a short end */ switch (ldata->n) { case 0: + assert(log_page_offset_lower == 0); assert(len == 4096); assert(off == 0); break; case 1: + assert(log_page_offset_lower == 4096); assert(len == 4096); - assert(off == 4096); + assert(off == 0); break; case 2: + assert(log_page_offset_lower == 8192); assert(len == 4); - assert(off == 4096 * 2); + assert(off == 0); break; default: assert(0); @@ -1755,8 +1831,8 @@ static int test_admin_get_log_split_cb(struct nvme_mi_ep *ep, static void test_admin_get_log_split(struct nvme_mi_ep *ep) { + struct nvme_get_log_args args = { 0 }; unsigned char buf[4096 * 2 + 4]; - struct nvme_get_log_args args; struct log_data ldata; nvme_mi_ctrl_t ctrl; int rc; @@ -1770,6 +1846,8 @@ static void test_admin_get_log_split(struct nvme_mi_ep *ep) args.lid = 1; args.log = buf; args.len = sizeof(buf); + args.lpo = 0; + args.ot = false; rc = nvme_mi_admin_get_log(ctrl, &args); @@ -1792,7 +1870,8 @@ struct test { DEFINE_TEST(scan_ctrl_list), DEFINE_TEST(invalid_crc), DEFINE_TEST(admin_id), - DEFINE_TEST(admin_err_resp), + DEFINE_TEST(admin_err_mi_resp), + DEFINE_TEST(admin_err_nvme_resp), DEFINE_TEST(admin_invalid_formats), DEFINE_TEST(resp_req), DEFINE_TEST(resp_hdr_small), -- cgit v1.2.3