// Copyright(c) 2018, Intel Corporation // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // * Neither the name of Intel Corporation nor the names of its contributors // may be used to endorse or promote products derived from this software // without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. /* * @file bmcinfo.h * * @brief */ #ifndef BMCINFO_H #define BMCINFO_H #include #include #include "bmc_types.h" #ifdef __cplusplus extern "C" { #endif #ifdef DEBUG #define DBG_PRINT(...) \ do { \ fprintf(stderr, __VA_ARGS__); \ fflush(stdout); \ fflush(stderr); \ } while (0) #else #define DBG_PRINT(...) \ do { \ fflush(stdout); \ fflush(stderr); \ } while (0) #endif #define SYSFS_PATH_MAX 256 // sysfs file names for power and temperature #define SYSFS_SDR_FILE "avmmi-bmc.*.auto/bmc_info/sdr" #define SYSFS_SENSOR_FILE "avmmi-bmc.*.auto/bmc_info/sensors" #define SYSFS_DEVID_FILE "avmmi-bmc.*.auto/bmc_info/device_id" #define SYSFS_RESET_FILE "avmmi-bmc.*.auto/bmc_info/reset_cause" #define SYSFS_PWRDN_FILE "avmmi-bmc.*.auto/bmc_info/power_down_cause" #define SYSFS_AVMMI_DIR "avmmi-bmc.*.auto" #define SYSFS_THERMAL_FILE "thermal_mgmt/temperature" #pragma pack(push, 1) // Structures used to read and decode Sensor Data Records (SDR) typedef struct _sdr_header { uint16_t record_id; uint8_t sdr_version; uint8_t record_type; uint8_t record_length; } sdr_header; typedef struct _sdr_key { uint8_t sensor_owner_id; uint8_t sensor_owner_lun; uint8_t sensor_number; } sdr_key; typedef struct _sdr_body { uint8_t entity_id; union _entity_instance { struct { uint8_t instance_number : 7; uint8_t physical_logical : 1; } bits; uint8_t _value; } entity_instance; union _sensor_initialization { struct { uint8_t scanning_enabled : 1; uint8_t events_enabled : 1; uint8_t init_sensor_type : 1; uint8_t init_hysteresis : 1; uint8_t init_thresholds : 1; uint8_t init_events : 1; uint8_t init_scanning : 1; uint8_t settable_sensor : 1; } bits; uint8_t _value; } sensor_initialization; union _sensor_capabilities { struct { uint8_t msg_control_support : 2; uint8_t threshold_access_support : 2; uint8_t hysteresis_support : 2; uint8_t auto_rearm : 1; uint8_t ignore_sensor : 1; } bits; uint8_t _value; } sensor_capabilities; uint8_t sensor_type; #define SDR_SENSOR_IS_TEMP(psdr) ((psdr)->sensor_type == 0x1) #define SDR_SENSOR_IS_POWER(psdr) \ (((psdr)->sensor_type == 0x2) || ((psdr)->sensor_type == 0x3) \ || ((psdr)->sensor_type == 0x8)) uint8_t event_reading_type_code; union _assertion_event_lower_threshold_mask { struct { uint16_t event_offset_0 : 1; uint16_t event_offset_1 : 1; uint16_t event_offset_2 : 1; uint16_t event_offset_3 : 1; uint16_t event_offset_4 : 1; uint16_t event_offset_5 : 1; uint16_t event_offset_6 : 1; uint16_t event_offset_7 : 1; uint16_t event_offset_8 : 1; uint16_t event_offset_9 : 1; uint16_t event_offset_10 : 1; uint16_t event_offset_11 : 1; uint16_t event_offset_12 : 1; uint16_t event_offset_13 : 1; uint16_t event_offset_14 : 1; uint16_t _reserved : 1; } assertion_event_mask; struct { uint16_t _unused : 12; uint16_t lower_nc_thresh_comparison : 1; uint16_t lower_c_thresh_comparison : 1; uint16_t lower_nr_thresh_comparison : 1; uint16_t _reserved : 1; } lower_threshold_mask; struct { uint16_t assertion_event_lower_nc_going_low_supported : 1; uint16_t assertion_event_lower_nc_going_high_supported : 1; uint16_t assertion_event_lower_c_going_low_supported : 1; uint16_t assertion_event_lower_c_going_high_supported : 1; uint16_t assertion_event_lower_nr_going_low_supported : 1; uint16_t assertion_event_lower_nr_going_high_supported : 1; uint16_t assertion_event_upper_nc_going_low_supported : 1; uint16_t assertion_event_upper_nc_going_high_supported : 1; uint16_t assertion_event_upper_c_going_low_supported : 1; uint16_t assertion_event_upper_c_going_high_supported : 1; uint16_t assertion_event_upper_nr_going_low_supported : 1; uint16_t assertion_event_upper_nr_going_high_supported : 1; uint16_t _unused : 4; } threshold_assertion_event_mask; uint16_t _value; } assertion_event_lower_threshold_mask; union _deassertion_event_upper_threshold_mask { struct { uint16_t event_offset_0 : 1; uint16_t event_offset_1 : 1; uint16_t event_offset_2 : 1; uint16_t event_offset_3 : 1; uint16_t event_offset_4 : 1; uint16_t event_offset_5 : 1; uint16_t event_offset_6 : 1; uint16_t event_offset_7 : 1; uint16_t event_offset_8 : 1; uint16_t event_offset_9 : 1; uint16_t event_offset_10 : 1; uint16_t event_offset_11 : 1; uint16_t event_offset_12 : 1; uint16_t event_offset_13 : 1; uint16_t event_offset_14 : 1; uint16_t _reserved : 1; } deassertion_event_mask; struct { uint16_t _unused : 12; uint16_t upper_nc_thresh_comparison : 1; uint16_t upper_c_thresh_comparison : 1; uint16_t upper_nr_thresh_comparison : 1; uint16_t _reserved : 1; } upper_threshold_mask; struct { uint16_t deassertion_event_lower_nc_going_low_supported : 1; uint16_t deassertion_event_lower_nc_going_high_supported : 1; uint16_t deassertion_event_lower_c_going_low_supported : 1; uint16_t deassertion_event_lower_c_going_high_supported : 1; uint16_t deassertion_event_lower_nr_going_low_supported : 1; uint16_t deassertion_event_lower_nr_going_high_supported : 1; uint16_t deassertion_event_upper_nc_going_low_supported : 1; uint16_t deassertion_event_upper_nc_going_high_supported : 1; uint16_t deassertion_event_upper_c_going_low_supported : 1; uint16_t deassertion_event_upper_c_going_high_supported : 1; uint16_t deassertion_event_upper_nr_going_low_supported : 1; uint16_t deassertion_event_upper_nr_going_high_supported : 1; uint16_t _unused : 4; } threshold_deassertion_event_mask; uint16_t _value; } deassertion_event_upper_threshold_mask; union _discrete_settable_readable_threshold_mask { struct { uint16_t discrete_state_enable_0 : 1; uint16_t discrete_state_enable_1 : 1; uint16_t discrete_state_enable_2 : 1; uint16_t discrete_state_enable_3 : 1; uint16_t discrete_state_enable_4 : 1; uint16_t discrete_state_enable_5 : 1; uint16_t discrete_state_enable_6 : 1; uint16_t discrete_state_enable_7 : 1; uint16_t discrete_state_enable_8 : 1; uint16_t discrete_state_enable_9 : 1; uint16_t discrete_state_enable_10 : 1; uint16_t discrete_state_enable_11 : 1; uint16_t discrete_state_enable_12 : 1; uint16_t discrete_state_enable_13 : 1; uint16_t discrete_state_enable_14 : 1; uint16_t _reserved : 1; } discrete_reading_mask; struct { uint16_t _unused : 8; uint16_t lower_nc_thresh_settable : 1; uint16_t lower_c_thresh_settable : 1; uint16_t lower_nr_thresh_settable : 1; uint16_t upper_nc_thresh_settable : 1; uint16_t upper_c_thresh_settable : 1; uint16_t upper_nr_thresh_settable : 1; uint16_t _reserved : 2; } settable_threshold_mask; struct { uint16_t lower_nc_thresh_readable : 1; uint16_t lower_c_thresh_readable : 1; uint16_t lower_nr_thresh_readable : 1; uint16_t upper_nc_thresh_readable : 1; uint16_t upper_c_thresh_readable : 1; uint16_t upper_nr_thresh_readable : 1; uint16_t _unused : 10; } readable_threshold_mask; uint16_t _value; } discrete_settable_readable_threshold_mask; union _sensor_units_1 { struct { uint8_t percentage : 1; uint8_t modifier_unit : 2; uint8_t rate_unit : 3; uint8_t analog_data_format : 2; } bits; uint8_t _value; } sensor_units_1; uint8_t sensor_units_2; uint8_t sensor_units_3; union _linearization { struct { uint8_t linearity_enum : 7; uint8_t _reserved : 1; } bits; uint8_t _value; } linearization; uint8_t M_8_lsb; union _M_tolerance { struct { uint8_t tolerance : 6; uint8_t M_2_msb : 2; } bits; uint8_t _value; } M_tolerance; uint8_t B_8_lsb; union _B_accuracy { struct { uint8_t accuracy_6_lsb : 6; uint8_t B_2_msb : 2; } bits; uint8_t _value; } B_accuracy; union _accuracy_accexp_sensor_direction { struct { uint8_t sensor_direction : 2; uint8_t accuracy_exp : 2; uint8_t accuracy_4_msb : 4; } bits; uint8_t _value; } accuracy_accexp_sensor_direction; union _R_exp_B_exp { struct { uint8_t B_exp : 4; uint8_t R_exp : 4; } bits; uint8_t _value; } R_exp_B_exp; union _analog_characteristic_flags { struct { uint8_t nominal_reading_specified : 1; uint8_t normal_max_specified : 1; uint8_t normal_min_specified : 1; uint8_t _reserved : 5; } bits; uint8_t _value; } analog_characteristic_flags; uint8_t nominal_reading; uint8_t normal_maximum; uint8_t normal_minimum; uint8_t sensor_maximum_reading; uint8_t sensor_minimum_reading; uint8_t upper_nr_threshold; uint8_t upper_c_threshold; uint8_t upper_nc_threshold; uint8_t lower_nr_threshold; uint8_t lower_c_threshold; uint8_t lower_nc_threshold; uint8_t pos_going_threshold_hysteresis_val; uint8_t neg_going_threshold_hysteresis_val; uint8_t _reserved0; uint8_t _reserved1; uint8_t oem; union _id_string_type_length_code { struct { uint8_t len_in_characters : 5; // 11111b reserved, // 00000b means none // following uint8_t _reserved : 1; uint8_t format : 2; // using TLC_FORMAT enum } bits; uint8_t _value; } id_string_type_length_code; uint8_t string_bytes[26]; // Interpreted based on type/length code } sdr_body; typedef enum _TLC_FORMAT { unicode = 0x0, BCD_plus = 0x1, ASCII_6 = 0x2, // packed ASCII_8 = 0x3 } TLC_FORMAT; extern uint8_t bcd_plus[]; extern uint8_t ASCII_6_bit_translation[]; typedef struct _sensor_reading { uint8_t _header[3]; // Ignored uint8_t completion_code; uint8_t sens_reading; union { struct { uint8_t _unused : 5; uint8_t reading_state_unavailable : 1; uint8_t sensor_scanning_disabled : 1; uint8_t event_messages_disabled : 1; } sensor_state; uint8_t _value; } sensor_validity; union { struct { uint8_t at_or_below_lower_nc_threshold : 1; uint8_t at_or_below_lower_c_threshold : 1; uint8_t at_or_below_lower_nr_threshold : 1; uint8_t at_or_above_upper_nc_threshold : 1; uint8_t at_or_above_upper_c_threshold : 1; uint8_t at_or_above_upper_nr_threshold : 1; uint8_t _unused : 2; } threshold_sensors; struct { uint8_t state_asserted_0 : 1; uint8_t state_asserted_1 : 1; uint8_t state_asserted_2 : 1; uint8_t state_asserted_3 : 1; uint8_t state_asserted_4 : 1; uint8_t state_asserted_5 : 1; uint8_t state_asserted_6 : 1; uint8_t state_asserted_7 : 1; } discrete_sensors; uint8_t _value; } threshold_events; } sensor_reading; typedef struct _device_id { uint8_t _header[3]; // Ignored uint8_t completion_code; uint8_t device_id; union { struct { uint8_t device_revision : 3; uint8_t _unused : 3; uint8_t provides_sdrs : 2; } bits; uint8_t _value; } device_revision; union { struct { uint8_t device_available : 7; uint8_t major_fw_revision : 1; } bits; uint8_t _value; } firmware_revision_1; uint8_t firmware_revision_2; uint8_t ipmi_version; union { struct { uint8_t sensor_device : 1; uint8_t sdr_repository_device : 1; uint8_t sel_device : 1; uint8_t fru_inventory_device : 1; uint8_t ipmb_event_receiver : 1; uint8_t ipmb_event_generator : 1; uint8_t bridge : 1; uint8_t chassis_device : 1; } bits; uint8_t _value; } additional_device_support; uint8_t manufacturer_id_0_7; uint8_t manufacturer_id_8_15; uint8_t manufacturer_id_16_23; uint8_t product_id_0_7; uint8_t product_id_8_15; uint8_t aux_fw_rev_0_7; uint8_t aux_fw_rev_8_15; uint8_t aux_fw_rev_16_23; uint8_t aux_fw_rev_24_31; } device_id; typedef struct _powerdown_cause { uint8_t _header[3]; // Ignored uint8_t completion_code; uint8_t iana[3]; uint8_t count; uint8_t message[40]; } powerdown_cause; typedef struct _reset_cause { uint8_t _header[3]; // Ignored uint8_t completion_code; uint8_t iana[3]; uint8_t reset_cause; // * TODO: Not sure about this } reset_cause; struct _sdr_content { sdr_header header; sdr_key key; sdr_body body; }; #pragma pack(pop) typedef enum { SENSOR_INT, SENSOR_FLOAT } sensor_value_type; typedef struct _Values { struct _Values *next; char *name; wchar_t *units; char *annotation_1; char *annotation_2; char *annotation_3; uint8_t raw_value; uint8_t is_valid; uint32_t tolerance; double accuracy; double M; double B; int32_t A_exp; int32_t result_exp; union { double f_val; uint64_t i_val; } value; uint8_t sensor_number; BMC_SENSOR_TYPE sensor_type; sensor_value_type val_type; struct _sdr_content *sdr; } Values; #define BMC_SDR_MAGIC (0x4922ab56) struct _sdr_rec { uint32_t magic; fpga_token token; uint32_t num_records; char sysfs_path[SYSFS_PATH_MAX]; struct _sdr_content *contents; }; #define BMC_VALUES_MAGIC (0x493afb56) struct _bmc_values { uint32_t magic; uint32_t num_records; sensor_reading *contents; Values **values; }; Values *bmc_build_values(sensor_reading *reading, sdr_header *header, sdr_key *key, sdr_body *body); #ifdef __cplusplus } #endif #endif /* !BMCINFO_H */