// 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 <opae/fpga.h>
#include <wchar.h>
#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 */