common/recipes-lib/obmc-pal/files/obmc-pal.c (2,432 lines of code) (raw):

/* * Copyright 2015-present Facebook. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #define _XOPEN_SOURCE #define _GNU_SOURCE #include "obmc-pal.h" #include <stdio.h> #include <stdint.h> #include <stdbool.h> #include <ctype.h> #include <fcntl.h> #include <errno.h> #include <syslog.h> #include <string.h> #include <unistd.h> #include <time.h> #include <sys/time.h> #include <sys/reboot.h> #include <sys/wait.h> #include <openbmc/kv.h> #include <openbmc/ipmi.h> #include <openbmc/ipmb.h> #include <math.h> #define GPIO_VAL "/sys/class/gpio/gpio%d/value" //#define _STRINGIFY(bw) #bw //#define STRINGIFY(bw) _STRINGIFY(bw) #define MACHINE __MACHINE__ #ifndef ARRAY_SIZE #define ARRAY_SIZE(_a) (sizeof(_a) / sizeof((_a)[0])) #endif // PAL Variable size_t pal_pwm_cnt __attribute__((weak)) = 0; size_t pal_tach_cnt __attribute__((weak)) = 0; size_t pal_fan_opt_cnt __attribute__((weak)) = 0; char pal_pwm_list[] __attribute__((weak)) = ""; char pal_tach_list[] __attribute__((weak)) = ""; char pal_fan_opt_list[] __attribute__((weak)) = ""; // PAL functions int __attribute__((weak)) pal_is_bmc_por(void) { return PAL_EOK; } int __attribute__((weak)) pal_bmc_reboot(int cmd) { // sync filesystem caches sync(); if (cmd == 0) { return run_command("/sbin/reboot"); } // flag for healthd logging reboot cause run_command("/etc/init.d/setup-reboot.sh > /dev/null 2>&1"); return reboot(cmd); } int __attribute__((weak)) pal_set_last_boot_time(uint8_t slot, uint8_t *last_boot_time) { return PAL_ENOTSUP; } int __attribute__((weak)) pal_get_last_boot_time(uint8_t slot, uint8_t *last_boot_time) { return PAL_ENOTSUP; } void __attribute__((weak)) pal_get_chassis_status(uint8_t slot, uint8_t *req_data, uint8_t *res_data, uint8_t *res_len) { *res_len = 0; return; } int __attribute__((weak)) pal_chassis_control(uint8_t slot, uint8_t *req_data, uint8_t req_len) { return PAL_ENOTSUP; } void __attribute__((weak)) pal_get_sys_intf_caps(uint8_t slot, uint8_t *req_data, uint8_t *res_data, uint8_t *res_len) { return; } static int pal_lpc_snoop_read_legacy(uint8_t *buf, size_t max_len, size_t *len) { FILE *fp = fopen("/sys/devices/platform/ast-snoop-dma.0/data_history", "r"); uint8_t postcode; size_t i; if (fp == NULL) { syslog(LOG_WARNING, "pal_get_80port_record: Cannot open device"); return PAL_ENOTREADY; } for (i=0; i < max_len; i++) { // %hhx: unsigned char* if (fscanf(fp, "%hhx%*s", &postcode) == 1) { buf[i] = postcode; } else { break; } } if (len) *len = i; fclose(fp); return 0; } static int pal_lpc_snoop_read(uint8_t *buf, size_t max_len, size_t *rlen) { const char *dev_path = "/dev/aspeed-lpc-snoop0"; const char *cache_key = "postcode"; uint8_t cache[MAX_VALUE_LEN * 2]; size_t len = 0, cache_len = 0; int fd; uint8_t postcode; if (kv_get(cache_key, (char *)cache, &len, 0)) { len = cache_len = 0; } else { cache_len = len; } /* Open and read as much as we can store. Our in-mem * cache is twice as the file-backed path. */ fd = open(dev_path, O_RDONLY | O_NONBLOCK); if (fd < 0) { return PAL_ENOTREADY; } while (len < sizeof(cache) && read(fd, &postcode, 1) == 1) { cache[len++] = postcode; } close(fd); /* Update the file-backed cache only if something * changed since we read it */ if (len > cache_len) { /* Since our in-mem cache can be twice of our file-backed * cache, ensure that we are storing the latest but also * limit the number to MAX_VALUE_LEN */ if (len > MAX_VALUE_LEN) { memmove(cache, &cache[len - MAX_VALUE_LEN], MAX_VALUE_LEN); len = MAX_VALUE_LEN; } if (kv_set(cache_key, (char *)cache, len, 0)) { syslog(LOG_CRIT, "%zu postcodes dropped\n", len - cache_len); } } len = len > max_len ? max_len : len; memcpy(buf, cache, len); *rlen = len; return PAL_EOK; } int __attribute__((weak)) pal_get_80port_record(uint8_t slot, uint8_t *buf, size_t max_len, size_t *len) { static bool legacy = false, legacy_checked = false; if (buf == NULL || len == NULL || max_len == 0) return -1; if (!pal_is_slot_server(slot)) { syslog(LOG_WARNING, "pal_get_80port_record: slot %d is not supported", slot); return PAL_ENOTSUP; } if (legacy_checked == false) { if (access("/sys/devices/platform/ast-snoop-dma.0/data_history", F_OK) == 0) { legacy = true; legacy_checked = true; } else if (access("/dev/aspeed-lpc-snoop0", F_OK) == 0) { legacy_checked = true; } else { return PAL_ENOTSUP; } } // Support for snoop-dma on 4.1 kernel. if (legacy) { return pal_lpc_snoop_read_legacy(buf, max_len, len); } return pal_lpc_snoop_read(buf, max_len, len); } int __attribute__((weak)) pal_set_boot_order(uint8_t slot, uint8_t *boot, uint8_t *res_data, uint8_t *res_len) { return PAL_ENOTSUP; } int __attribute__((weak)) pal_get_boot_order(uint8_t slot, uint8_t *req_data, uint8_t *boot, uint8_t *res_len) { return PAL_ENOTSUP; } void __attribute__((weak)) pal_set_boot_option(unsigned char para,unsigned char* pbuff) { return; } int __attribute__((weak)) pal_get_boot_option(unsigned char para,unsigned char* pbuff) { return PAL_ENOTSUP; } int __attribute__((weak)) pal_set_bios_current_boot_list(uint8_t slot, uint8_t *boot_list, uint8_t list_length, uint8_t *cc) { return 0; } int __attribute__((weak)) pal_get_bios_current_boot_list(uint8_t slot, uint8_t *boot_list, uint8_t *list_length) { return 0; } int __attribute__((weak)) pal_set_bios_fixed_boot_device(uint8_t slot, uint8_t *fixed_boot_device) { return 0; } int __attribute__((weak)) pal_get_bios_fixed_boot_device(uint8_t slot, uint8_t *fixed_boot_device) { return 0; } int __attribute__((weak)) pal_set_bios_restores_default_setting(uint8_t slot, uint8_t *default_setting) { return 0; } int __attribute__((weak)) pal_get_bios_restores_default_setting(uint8_t slot, uint8_t *default_setting) { return 0; } uint8_t __attribute__((weak)) pal_set_power_restore_policy(uint8_t slot, uint8_t *pwr_policy, uint8_t *res_data) { return 0; } uint8_t __attribute__((weak)) pal_set_slot_power_policy(uint8_t *pwr_policy, uint8_t *res_data) { return 0; } int __attribute__((weak)) pal_bmc_err_disable(const char *error_item) { return 0; } int __attribute__((weak)) pal_bmc_err_enable(const char *error_item) { return 0; } void __attribute__((weak)) pal_set_post_start(uint8_t slot, uint8_t *req_data, uint8_t *res_data, uint8_t *res_len) { // TODO: For now logging the event, need to find usage for this info syslog (LOG_INFO, "POST Start Event for Payload#%d\n", slot); *res_len = 0; return; } void __attribute__((weak)) pal_set_post_end(uint8_t slot, uint8_t *req_data, uint8_t *res_data, uint8_t *res_len) { // TODO: For now logging the event, need to find usage for this info syslog (LOG_INFO, "POST End Event for Payload#%d\n", slot); *res_len = 0; } int __attribute__((weak)) pal_get_board_id(uint8_t slot, uint8_t *req_data, uint8_t req_len, uint8_t *res_data, uint8_t *res_len) { return PAL_EOK; } int __attribute__((weak)) pal_parse_oem_unified_sel(uint8_t fru, uint8_t *sel, char *error_log) { // // If a platform needs to process a specific type of SEL message // differently from what the common code does, // this function can be overriden to do such unique handling // instead of calling the common SEL parsing logic (pal_parse_oem_unified_sel_common.) // // This default handler will not perform any special handling, and will // just call the default handler (pal_parse_oem_unified_sel_common) for every type of // SEL msessages. // pal_parse_oem_unified_sel_common(fru, sel, error_log); return 0; } static void get_common_dimm_location_str(_dimm_info dimm_info, char* dimm_location_str, char* dimm_str) { // Check Channel and Slot if (dimm_info.channel == 0xFF && dimm_info.slot == 0xFF) { sprintf(dimm_str, "unknown"); sprintf(dimm_location_str, "DIMM Slot Location: Sled %02d/Socket %02d, Channel unknown, Slot unknown, DIMM unknown", dimm_info.sled, dimm_info.socket); } else { dimm_info.channel &= 0x07; // Channel Bit[3:0] dimm_info.slot &= 0x03; // Slot [0-2] pal_convert_to_dimm_str(dimm_info.socket, dimm_info.channel, dimm_info.slot, dimm_str); sprintf(dimm_location_str, "DIMM Slot Location: Sled %02d/Socket %02d, Channel %02d, Slot %02d, DIMM %s", dimm_info.sled, dimm_info.socket, dimm_info.channel, dimm_info.slot, dimm_str); } } int __attribute__((weak)) pal_parse_oem_unified_sel_common(uint8_t fru, uint8_t *sel, char *error_log) { char *mem_err[] = { "Memory training failure", "Memory correctable error", "Memory uncorrectable error", "Memory correctable error (Patrol scrub)", "Memory uncorrectable error (Patrol scrub)", "Memory Parity Error event", "Reserved" }; char *upi_err[] = { "UPI Init error", "Reserved" }; char *post_err[] = { "System PXE boot fail", "CMOS/NVRAM configuration cleared", "TPM Self-Test Fail", "Reserved" }; char *pcie_event[] = { "PCIe DPC Event", "PCIe LER Event", "PCIe Link Retraining and Recovery", "PCIe Link CRC Error Check and Retry", "PCIe Corrupt Data Containment", "PCIe Express ECRC", "Reserved" }; char *mem_event[] = { "Memory PPR event", "Memory Correctable Error logging limit reached", "Memory disable/map-out for FRB", "Memory SDDC", "Memory Address range/Partial mirroring", "Memory ADDDC", "Memory SMBus hang recovery", "No DIMM in System", "Reserved" }; char *upi_event[] = { "Successful LLR without Phy Reinit", "Successful LLR with Phy Reinit", "COR Phy Lane failure, recovery in x8 width", "Reserved" }; uint8_t general_info = sel[3]; uint8_t error_type = general_info & 0xF; uint8_t plat, event_type, estr_idx; _dimm_info dimm_info = { (sel[8]>>4) & 0x03, // Sled sel[8] & 0x0F, // Socket sel[9], // Channel sel[10] // Slot }; char dimm_str[8] = {0}; char dimm_location_str[128] = {0}; char temp_log[128] = {0}; error_log[0] = '\0'; switch (error_type) { case UNIFIED_PCIE_ERR: plat = (general_info & 0x10) >> 4; if (plat == 0) { //x86 sprintf(error_log, "GeneralInfo: x86/PCIeErr(0x%02X), Bus %02X/Dev %02X/Fun %02X, TotalErrID1Cnt: 0x%04X, ErrID2: 0x%02X, ErrID1: 0x%02X", general_info, sel[11], sel[10]>>3, sel[10]&0x7, ((sel[13]<<8)|sel[12]), sel[14], sel[15]); } else { sprintf(error_log, "GeneralInfo: ARM/PCIeErr(0x%02X), Aux. Info: 0x%04X, Bus %02X/Dev %02X/Fun %02X, TotalErrID1Cnt: 0x%04X, ErrID2: 0x%02X, ErrID1: 0x%02X", general_info, ((sel[9]<<8)|sel[8]), sel[11], sel[10]>>3, sel[10]&0x7, ((sel[13]<<8)|sel[12]),sel[14], sel[15]); } sprintf(temp_log, "B %02X D %02X F %02X PCIe err,FRU:%u", sel[11], sel[10]>>3, sel[10]&0x7, fru); pal_add_cri_sel(temp_log); break; case UNIFIED_MEM_ERR: // get dimm location data string. get_common_dimm_location_str(dimm_info, dimm_location_str, dimm_str); plat = (sel[12] & 0x80) >> 7; event_type = sel[12] & 0xF; switch (event_type) { case MEMORY_TRAINING_ERR: if (plat == 0) { //Intel sprintf(error_log, "GeneralInfo: MEMORY_ECC_ERR(0x%02X), %s, DIMM Failure Event: %s, Major Code: 0x%02X, Minor Code: 0x%02X", general_info, dimm_location_str, mem_err[event_type], sel[13], sel[14]); } else { //AMD sprintf(error_log, "GeneralInfo: MEMORY_ECC_ERR(0x%02X), %s, DIMM Failure Event: %s, Major Code: 0x%02X, Minor Code: 0x%04X", general_info, dimm_location_str, mem_err[event_type], sel[13], (sel[15]<<8)|sel[14]); } sprintf(temp_log, "DIMM %s initialization fails", dimm_str); pal_add_cri_sel(temp_log); break; default: pal_convert_to_dimm_str(dimm_info.socket, dimm_info.channel, dimm_info.slot, dimm_str); estr_idx = (event_type < ARRAY_SIZE(mem_err)) ? event_type : (ARRAY_SIZE(mem_err) - 1); sprintf(error_log, "GeneralInfo: MEMORY_ECC_ERR(0x%02X), %s, DIMM Failure Event: %s", general_info, dimm_location_str, mem_err[estr_idx]); if ((event_type == MEMORY_CORRECTABLE_ERR) || (event_type == MEMORY_CORR_ERR_PTRL_SCR)) { sprintf(temp_log, "DIMM%s ECC err,FRU:%u", dimm_str, fru); pal_add_cri_sel(temp_log); } else if ((event_type == MEMORY_UNCORRECTABLE_ERR) || (event_type == MEMORY_UNCORR_ERR_PTRL_SCR)) { sprintf(temp_log, "DIMM%s UECC err,FRU:%u", dimm_str, fru); pal_add_cri_sel(temp_log); } break; } break; case UNIFIED_UPI_ERR: event_type = sel[12] & 0xF; estr_idx = (event_type < ARRAY_SIZE(upi_err)) ? event_type : (ARRAY_SIZE(upi_err) - 1); switch (event_type) { case UPI_INIT_ERR: sprintf(error_log, "GeneralInfo: UPIErr(0x%02X), UPI Port Location: Sled %02d/Socket %02d, Port %02d, UPI Failure Event: %s, Major Code: 0x%02X, Minor Code: 0x%02X", general_info, dimm_info.sled, dimm_info.socket, sel[9]&0xF, upi_err[estr_idx], sel[13], sel[14]); break; default: sprintf(error_log, "GeneralInfo: UPIErr(0x%02X), UPI Port Location: Sled %02d/Socket %02d, Port %02d, UPI Failure Event: %s", general_info, dimm_info.sled, dimm_info.socket, sel[9]&0xF, upi_err[estr_idx]); break; } break; case UNIFIED_IIO_ERR: { uint8_t stack = sel[9]; uint8_t sel_error_type = sel[13]; uint8_t sel_error_severity = sel[14]; uint8_t sel_error_id = sel[15]; sprintf(error_log, "GeneralInfo: IIOErr(0x%02X), IIO Port Location: Sled %02d/Socket %02d, Stack 0x%02X, Error Type: 0x%02X, Error Severity: 0x%02X, Error ID: 0x%02X", general_info, dimm_info.sled, dimm_info.socket, stack, sel_error_type, sel_error_severity, sel_error_id); sprintf(temp_log, "IIO_ERR CPU%d. Error ID(%02X)",dimm_info.socket, sel_error_id); pal_add_cri_sel(temp_log); break; } case UNIFIED_POST_ERR: event_type = sel[8] & 0xF; estr_idx = (event_type < ARRAY_SIZE(post_err)) ? event_type : (ARRAY_SIZE(post_err) - 1); sprintf(error_log, "GeneralInfo: POST(0x%02X), POST Failure Event: %s", general_info, post_err[estr_idx]); break; case UNIFIED_PCIE_EVENT: event_type = sel[8] & 0xF; estr_idx = (event_type < ARRAY_SIZE(pcie_event)) ? event_type : (ARRAY_SIZE(pcie_event) - 1); switch (event_type) { case PCIE_DPC: sprintf(error_log, "GeneralInfo: PCIeEvent(0x%02X), PCIe Failure Event: %s, Status: 0x%04X, Source ID: 0x%04X", general_info, pcie_event[estr_idx], (sel[11]<<8)|sel[10], (sel[13]<<8)|sel[12]); break; default: sprintf(error_log, "GeneralInfo: PCIeEvent(0x%02X), PCIe Failure Event: %s", general_info, pcie_event[estr_idx]); break; } break; case UNIFIED_MEM_EVENT: // get dimm location data string. get_common_dimm_location_str(dimm_info, dimm_location_str, dimm_str); // Event-Type Bit[3:0] event_type = sel[12] & 0x0F; switch (event_type) { case MEM_PPR: sprintf(error_log, "GeneralInfo: MemEvent(0x%02X), %s, DIMM Failure Event: %s", general_info, dimm_location_str, (sel[13]&0x01)?"PPR fail":"PPR success"); break; case MEM_NO_DIMM: sprintf(error_log, "GeneralInfo: MemEvent(0x%02X), DIMM Failure Event: %s", general_info, mem_event[event_type]); break; default: estr_idx = (event_type < ARRAY_SIZE(mem_event)) ? event_type : (ARRAY_SIZE(mem_event) - 1); sprintf(error_log, "GeneralInfo: MemEvent(0x%02X), %s, DIMM Failure Event: %s", general_info, dimm_location_str, mem_event[estr_idx]); break; } break; case UNIFIED_UPI_EVENT: event_type = sel[12] & 0xF; estr_idx = (event_type < ARRAY_SIZE(upi_event)) ? event_type : (ARRAY_SIZE(upi_event) - 1); sprintf(error_log, "GeneralInfo: UPIEvent(0x%02X), UPI Port Location: Sled %02d/Socket %02d, Port %02d, UPI Failure Event: %s", general_info, dimm_info.sled, dimm_info.socket, sel[9]&0xF, upi_event[estr_idx]); break; case UNIFIED_BOOT_GUARD: sprintf(error_log, "GeneralInfo: Boot Guard ACM Failure Events(0x%02X), Error Class(0x%02X), Error Code(0x%02X)", general_info, sel[8], sel[9]); break; default: sprintf(error_log, "Undefined Error Type(0x%02X), Raw: %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", error_type, sel[3], sel[4], sel[5], sel[6], sel[7], sel[8], sel[9], sel[10], sel[11], sel[12], sel[13], sel[14], sel[15]); break; } return 0; } int __attribute__((weak)) pal_parse_mem_mapping_string(uint8_t channel, bool *support_mem_mapping, char *error_log) { if ( support_mem_mapping ) { *support_mem_mapping = false; } if (error_log) { error_log[0] = '\0'; } return PAL_EOK; } int __attribute__((weak)) pal_convert_to_dimm_str(uint8_t cpu, uint8_t channel, uint8_t slot, char *str) { sprintf(str, "%c%d", 'A'+channel, slot); return PAL_EOK; } int __attribute__((weak)) pal_parse_oem_sel(uint8_t fru, uint8_t *sel, char *error_log) { error_log[0] = '\0'; return 0; } int __attribute__((weak)) pal_set_ppin_info(uint8_t slot, uint8_t *req_data, uint8_t req_len, uint8_t *res_data, uint8_t *res_len) { return PAL_EOK; } int __attribute__((weak)) pal_sled_ac_cycle(uint8_t slot, uint8_t *req_data, uint8_t req_len, uint8_t *res_data, uint8_t *res_len) { return PAL_EOK; } int __attribute__((weak)) pal_set_slot_led(uint8_t fru, uint8_t *req_data, uint8_t req_len, uint8_t *res_data, uint8_t *res_len) { return PAL_EOK; } int __attribute__((weak)) pal_get_poss_pcie_config(uint8_t slot, uint8_t *req_data, uint8_t req_len, uint8_t *res_data, uint8_t *res_len) { return PAL_EOK; } int __attribute__((weak)) pal_get_pcie_port_config(uint8_t slot, uint8_t *req_data, uint8_t req_len, uint8_t *res_data, uint8_t *res_len) { return PAL_ENOTSUP; } int __attribute__((weak)) pal_set_pcie_port_config(uint8_t slot, uint8_t *req_data, uint8_t req_len, uint8_t *res_data, uint8_t *res_len) { return PAL_ENOTSUP; } int __attribute__((weak)) pal_set_imc_version(uint8_t slot, uint8_t *req_data, uint8_t req_len, uint8_t *res_data, uint8_t *res_len) { return PAL_EOK; } uint8_t __attribute__((weak)) pal_add_cper_log(uint8_t slot, uint8_t *req_data, uint8_t req_len, uint8_t *res_data, uint8_t *res_len) { return PAL_EOK; } uint8_t __attribute__((weak)) pal_set_psb_info(uint8_t slot, uint8_t *req_data, uint8_t req_len, uint8_t *res_data, uint8_t *res_len) { return PAL_ENOTSUP; } uint8_t __attribute__((weak)) pal_add_imc_log(uint8_t slot, uint8_t *req_data, uint8_t req_len, uint8_t *res_data, uint8_t *res_len) { return PAL_EOK; } uint8_t __attribute__((weak)) pal_parse_ras_sel(uint8_t slot, uint8_t *sel, char *error_log) { return PAL_EOK; } int __attribute__((weak)) pal_set_fru_post(uint8_t fru, uint8_t value) { return PAL_EOK; } int __attribute__((weak)) pal_set_cpu_mem_threshold(const char* threshold_path) { return PAL_EOK; } int __attribute__((weak)) pal_get_platform_name(char *name) { strcpy(name, MACHINE); return PAL_EOK; } int __attribute__((weak)) pal_get_num_slots(uint8_t *num) { *num = 0; return PAL_EOK; } int __attribute__((weak)) pal_get_num_devs(uint8_t slot, uint8_t *num) { *num = 0; return PAL_EOK; } int __attribute__((weak)) pal_is_fru_prsnt(uint8_t fru, uint8_t *status) { *status = 1; return PAL_EOK; } int __attribute__((weak)) pal_get_slot_index(unsigned char payload_id) { return payload_id; } int __attribute__((weak)) pal_get_server_power(uint8_t slot_id, uint8_t *status) { *status = 0; return PAL_EOK; } int __attribute__((weak)) pal_set_server_power(uint8_t slot_id, uint8_t cmd) { return PAL_EOK; } int __attribute__((weak)) pal_get_device_power(uint8_t slot_id, uint8_t dev_id, uint8_t *status, uint8_t *type) { return PAL_EOK; } int __attribute__((weak)) pal_set_device_power(uint8_t slot_id, uint8_t dev_id, uint8_t cmd) { return PAL_EOK; } int __attribute__((weak)) pal_power_button_override(uint8_t slot_id) { return PAL_EOK; } int __attribute__((weak)) pal_sled_cycle(void) { return PAL_EOK; } int __attribute__((weak)) pal_post_handle(uint8_t slot, uint8_t status) { return PAL_EOK; } int __attribute__((weak)) pal_set_rst_btn(uint8_t slot, uint8_t status) { return PAL_EOK; } int __attribute__((weak)) pal_set_led(uint8_t led, uint8_t status) { return PAL_EOK; } int __attribute__((weak)) pal_set_hb_led(uint8_t status) { return PAL_EOK; } int __attribute__((weak)) pal_get_fru_list(char *list) { *list = '\0'; return PAL_EOK; } int __attribute__((weak)) pal_get_dev_list(uint8_t fru, char *list) { return PAL_ENOTSUP; } int __attribute__((weak)) pal_get_fru_id(char *fru_str, uint8_t *fru) { unsigned int _fru; if (sscanf(fru_str, "fru%u", &_fru) == 1) { *fru = (uint8_t)_fru; return PAL_EOK; } return PAL_ENOTSUP; } int __attribute__((weak)) pal_get_dev_id(char *fru_str, uint8_t *fru) { unsigned int _fru; if (sscanf(fru_str, "fru%u", &_fru) == 1) { *fru = (uint8_t)_fru; return PAL_EOK; } return PAL_ENOTSUP; } int __attribute__((weak)) pal_get_fru_name(uint8_t fru, char *name) { sprintf(name, "fru%u", fru); return PAL_EOK; } int __attribute__((weak)) pal_get_fru_capability(uint8_t fru, unsigned int *caps) { *caps = FRU_CAPABILITY_ALL; return 0; } int __attribute__((weak)) pal_get_dev_capability(uint8_t fru, uint8_t dev, unsigned int *caps) { *caps = FRU_CAPABILITY_ALL; return 0; } int __attribute__((weak)) pal_get_dev_fruid_name(uint8_t fru, uint8_t dev, char *name) { char fruname[64]; int ret; if (fru == 0) return -1; ret = pal_get_fruid_name(fru, fruname); if (ret < 0) return ret; sprintf(name, "%s Device %u", fruname, (unsigned int)dev - 1); return PAL_EOK; } int __attribute__((weak)) pal_get_dev_name(uint8_t fru, uint8_t dev, char *name) { if (dev == 0) return -1; sprintf(name, "device%u", (unsigned int)dev - 1); return 0; } int __attribute__((weak)) pal_get_fruid_path(uint8_t fru, char *path) { return PAL_ENOTSUP; } int __attribute__((weak)) pal_get_dev_fruid_path(uint8_t fru, uint8_t dev_id, char *path) { return PAL_ENOTSUP; } int __attribute__((weak)) pal_get_fruid_eeprom_path(uint8_t fru, char *path) { return PAL_ENOTSUP; } int __attribute__((weak)) pal_get_dev_fruid_eeprom_path(uint8_t fru, uint8_t dev_id, char *path, uint8_t path_len) { return PAL_ENOTSUP; } int __attribute__((weak)) pal_get_fruid_name(uint8_t fru, char *name) { return PAL_ENOTSUP; } int __attribute__((weak)) pal_fruid_write(uint8_t slot, char *path) { return PAL_EOK; } int __attribute__((weak)) pal_dev_fruid_write(uint8_t fru, uint8_t dev_id, char *path) { return PAL_EOK; } int __attribute__((weak)) pal_get_fru_devtty(uint8_t fru, char *devtty) { return PAL_EOK; } int __attribute__((weak)) pal_cfg_key_check(char *key) { /* TODO: Leverage the code from * meta-facebook/meta-fbttn/recipes-fbttn/fblibs/files/pal/pal.c; * once all platforms using cfg-util uses cfg_support_key_list[] */ return PAL_EOK; } int __attribute__((weak)) pal_get_key_value(char *key, char *value) { return PAL_EOK; } int __attribute__((weak)) pal_set_key_value(char *key, char *value) { return PAL_EOK; } int __attribute__((weak)) pal_set_def_key_value(void) { return PAL_EOK; } void __attribute__((weak)) pal_dump_key_value(void) { return; } int __attribute__((weak)) pal_get_last_pwr_state(uint8_t fru, char *state) { return PAL_EOK; } int __attribute__((weak)) pal_set_last_pwr_state(uint8_t fru, char *state) { return PAL_EOK; } int __attribute__((weak)) pal_get_sys_guid(uint8_t slot, char *guid) { return PAL_EOK; } int __attribute__((weak)) pal_set_sys_guid(uint8_t fru, char *guid) { return PAL_EOK; } int __attribute__((weak)) pal_get_sysfw_ver(uint8_t slot, uint8_t *ver) { return PAL_EOK; } int __attribute__((weak)) pal_set_sysfw_ver(uint8_t slot, uint8_t *ver) { return PAL_EOK; } int __attribute__((weak)) pal_is_cmd_valid(uint8_t *data) { return PAL_EOK; } /* * Default implementation if pal_is_fru_x86 is to always return true * on all FRU, on all platform. This is because all uServers so far are X86. * This logic can be "OVERRIDDEN" as needed, on any newer platform, * in order to return dynamic value, based on the information which * BMC collected so far. * (therefore mix-and-match supported; not sure if needed.) */ bool __attribute__((weak)) pal_is_fru_x86(uint8_t fru) { return true; } int __attribute__((weak)) pal_get_x86_event_sensor_name(uint8_t fru, uint8_t snr_num, char *name) { if (pal_is_fru_x86(fru)) { switch(snr_num) { case SYSTEM_EVENT: sprintf(name, "SYSTEM_EVENT"); break; case THERM_THRESH_EVT: sprintf(name, "THERM_THRESH_EVT"); break; case CRITICAL_IRQ: sprintf(name, "CRITICAL_IRQ"); break; case POST_ERROR: sprintf(name, "POST_ERROR"); break; case MACHINE_CHK_ERR: sprintf(name, "MACHINE_CHK_ERR"); break; case PCIE_ERR: sprintf(name, "PCIE_ERR"); break; case IIO_ERR: sprintf(name, "IIO_ERR"); break; case SMN_ERR: sprintf(name, "SMN_ERR"); break; case USB_ERR: sprintf(name, "USB_ERR"); break; case PSB_ERR: sprintf(name, "PSB_STS"); break; case MEMORY_ECC_ERR: sprintf(name, "MEMORY_ECC_ERR"); break; case MEMORY_ERR_LOG_DIS: sprintf(name, "MEMORY_ERR_LOG_DIS"); break; case PROCHOT_EXT: sprintf(name, "PROCHOT_EXT"); break; case PWR_ERR: sprintf(name, "PWR_ERR"); break; case CATERR_A: case CATERR_B: sprintf(name, "CATERR"); break; case CPU_DIMM_HOT: sprintf(name, "CPU_DIMM_HOT"); break; case SOFTWARE_NMI: sprintf(name, "SOFTWARE_NMI"); break; case CPU0_THERM_STATUS: sprintf(name, "CPU0_THERM_STATUS"); break; case CPU1_THERM_STATUS: sprintf(name, "CPU1_THERM_STATUS"); break; case CPU2_THERM_STATUS: sprintf(name, "CPU2_THERM_STATUS"); break; case CPU3_THERM_STATUS: sprintf(name, "CPU3_THERM_STATUS"); break; case ME_POWER_STATE: sprintf(name, "ME_POWER_STATE"); break; case SPS_FW_HEALTH: sprintf(name, "SPS_FW_HEALTH"); break; case NM_EXCEPTION_A: sprintf(name, "NM_EXCEPTION"); break; case PCH_THERM_THRESHOLD: sprintf(name, "PCH_THERM_THRESHOLD"); break; case NM_HEALTH: sprintf(name, "NM_HEALTH"); break; case NM_CAPABILITIES: sprintf(name, "NM_CAPABILITIES"); break; case NM_THRESHOLD: sprintf(name, "NM_THRESHOLD"); break; case PWR_THRESH_EVT: sprintf(name, "PWR_THRESH_EVT"); break; case HPR_WARNING: sprintf(name, "HPR_WARNING"); break; default: sprintf(name, "Unknown"); break; } return 0; } else { sprintf(name, "UNDEFINED:NOT_X86"); } return 0; } int __attribute__((weak)) pal_get_event_sensor_name(uint8_t fru, uint8_t *sel, char *name) { uint8_t snr_type = sel[10]; uint8_t snr_num = sel[11]; // If SNR_TYPE is OS_BOOT, sensor name is OS switch (snr_type) { case OS_BOOT: // OS_BOOT used by OS sprintf(name, "OS"); return 0; } // Otherwise, translate it based on snr_num return pal_get_x86_event_sensor_name(fru, snr_num, name); } int __attribute__((weak)) pal_sel_handler(uint8_t fru, uint8_t snr_num, uint8_t *event_data) { return PAL_EOK; } int __attribute__((weak)) pal_oem_unified_sel_handler(uint8_t fru, uint8_t general_info, uint8_t *sel) { return PAL_EOK; } /* * A Function to parse common SEL message, a helper funciton * for pal_parse_sel. * * Note that this function __CANNOT__ be overriden. * To add board specific routine, please override pal_parse_sel. */ bool pal_parse_sel_helper(uint8_t fru, uint8_t *sel, char *error_log) { bool parsed = true; uint8_t snr_type = sel[10]; uint8_t snr_num = sel[11]; uint8_t *event_data = &sel[10]; uint8_t *ed = &event_data[3]; char temp_log[512] = {0}; uint8_t temp; uint8_t sen_type = event_data[0]; uint8_t chn_num, dimm_num; uint8_t idx; /*Used by decoding ME event*/ char *nm_capability_status[2] = {"Not Available", "Available"}; char *nm_domain_name[6] = {"Entire Platform", "CPU Subsystem", "Memory Subsystem", "HW Protection", "High Power I/O subsystem", "Unknown"}; char *nm_err_type[17] = {"Unknown", "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", "Extended Telemetry Device Reading Failure", "Outlet Temperature Reading Failure", "Volumetric Airflow Reading Failure", "Policy Misconfiguration", "Power Sensor Reading Failure", "Inlet Temperature Reading Failure", "Host Communication Error", "Real-time Clock Synchronization Failure", "Platform Shutdown Initiated by Intel NM Policy", "Unknown"}; char *nm_health_type[4] = {"Unknown", "Unknown", "SensorIntelNM", "Unknown"}; const char *thres_event_name[16] = {[0] = "Lower Non-critical", [2] = "Lower Critical", [4] = "Lower Non-recoverable", [7] = "Upper Non-critical", [9] = "Upper Critical", [11] = "Upper Non-recoverable"}; strcpy(error_log, ""); switch (snr_type) { case OS_BOOT: // OS_BOOT used by OS switch (ed[0] & 0xF) { case 0x07: strcat(error_log, "Base OS/Hypervisor Installation started"); break; case 0x08: strcat(error_log, "Base OS/Hypervisor Installation completed"); break; case 0x09: strcat(error_log, "Base OS/Hypervisor Installation aborted"); break; case 0x0A: strcat(error_log, "Base OS/Hypervisor Installation failed"); break; default: strcat(error_log, "Unknown"); parsed = false; break; } return parsed; } switch(snr_num) { case SYSTEM_EVENT: if (ed[0] == 0xE5) { strcat(error_log, "Cause of Time change - "); if (ed[2] == 0x00) strcat(error_log, "NTP"); else if (ed[2] == 0x01) strcat(error_log, "Host RTL"); else if (ed[2] == 0x02) strcat(error_log, "Set SEL time cmd "); else if (ed[2] == 0x03) strcat(error_log, "Set SEL time UTC offset cmd"); else strcat(error_log, "Unknown"); if (ed[1] == 0x00) strcat(error_log, " - First Time"); else if(ed[1] == 0x80) strcat(error_log, " - Second Time"); } break; case THERM_THRESH_EVT: if (ed[0] == 0x1) strcat(error_log, "Limit Exceeded"); else strcat(error_log, "Unknown"); break; case CRITICAL_IRQ: if (ed[0] == 0x0) strcat(error_log, "NMI / Diagnostic Interrupt"); else if (ed[0] == 0x03) strcat(error_log, "Software NMI"); else strcat(error_log, "Unknown"); sprintf(temp_log, "CRITICAL_IRQ, %s,FRU:%u", error_log, fru); pal_add_cri_sel(temp_log); break; case POST_ERROR: if ((ed[0] & 0x0F) == 0x0) strcat(error_log, "System Firmware Error"); else strcat(error_log, "Unknown"); if (((ed[0] >> 6) & 0x03) == 0x3) { // TODO: Need to implement IPMI spec based Post Code strcat(error_log, ", IPMI Post Code"); } else if (((ed[0] >> 6) & 0x03) == 0x2) { sprintf(temp_log, ", OEM Post Code 0x%02X%02X", ed[2], ed[1]); strcat(error_log, temp_log); switch ((ed[2] << 8) | ed[1]) { case 0xA105: sprintf(temp_log, ", BMC Failed (No Response)"); strcat(error_log, temp_log); break; case 0xA106: sprintf(temp_log, ", BMC Failed (Self Test Fail)"); strcat(error_log, temp_log); break; case 0xA10A: sprintf(temp_log, ", System Firmware Corruption Detected"); strcat(error_log, temp_log); break; case 0xA10B: sprintf(temp_log, ", TPM Self-Test FAIL Detected"); strcat(error_log, temp_log); break; default: break; } } break; case MACHINE_CHK_ERR: if ((ed[0] & 0x0F) == 0x0B) { strcat(error_log, "Uncorrectable"); sprintf(temp_log, "MACHINE_CHK_ERR, %s bank Number %d,FRU:%u", error_log, ed[1], fru); pal_add_cri_sel(temp_log); } else if ((ed[0] & 0x0F) == 0x0C) { strcat(error_log, "Correctable"); sprintf(temp_log, "MACHINE_CHK_ERR, %s bank Number %d,FRU:%u", error_log, ed[1], fru); pal_add_cri_sel(temp_log); } else { strcat(error_log, "Unknown"); sprintf(temp_log, "MACHINE_CHK_ERR, %s bank Number %d,FRU:%u", error_log, ed[1], fru); pal_add_cri_sel(temp_log); } sprintf(temp_log, ", Machine Check bank Number %d ", ed[1]); strcat(error_log, temp_log); sprintf(temp_log, ", CPU %d, Core %d ", ed[2] >> 5, ed[2] & 0x1F); strcat(error_log, temp_log); break; case PCIE_ERR: if ((ed[0] & 0xF) == 0x4) { sprintf(error_log, "PCI PERR (Bus %02X / Dev %02X / Fun %02X)", ed[2], ed[1] >> 3, ed[1] & 0x7); } else if ((ed[0] & 0xF) == 0x5) { sprintf(error_log, "PCI SERR (Bus %02X / Dev %02X / Fun %02X)", ed[2], ed[1] >> 3, ed[1] & 0x7); } else if ((ed[0] & 0xF) == 0x7) { sprintf(error_log, "Correctable (Bus %02X / Dev %02X / Fun %02X)", ed[2], ed[1] >> 3, ed[1] & 0x7); } else if ((ed[0] & 0xF) == 0x8) { sprintf(error_log, "Uncorrectable (Bus %02X / Dev %02X / Fun %02X)", ed[2], ed[1] >> 3, ed[1] & 0x7); } else if ((ed[0] & 0xF) == 0xA) { sprintf(error_log, "Bus Fatal (Bus %02X / Dev %02X / Fun %02X)", ed[2], ed[1] >> 3, ed[1] & 0x7); } else if ((ed[0] & 0xF) == 0xD) { unsigned int vendor_id = (unsigned int)ed[1] << 8 | (unsigned int)ed[2]; sprintf(error_log, "Vendor ID: 0x%4x", vendor_id); } else if ((ed[0] & 0xF) == 0xE) { unsigned int device_id = (unsigned int)ed[1] << 8 | (unsigned int)ed[2]; sprintf(error_log, "Device ID: 0x%4x", device_id); } else if ((ed[0] & 0xF) == 0xF) { sprintf(error_log, "Error ID from downstream: 0x%2x 0x%2x", ed[1], ed[2]); } else { strcat(error_log, "Unknown"); } sprintf(temp_log, "PCI_ERR %s,FRU:%u", error_log, fru); pal_add_cri_sel(temp_log); break; case IIO_ERR: if ((ed[0] & 0xF) == 0) { sprintf(temp_log, "CPU %d, Error ID 0x%X", (ed[2] & 0xE0) >> 5, ed[1]); strcat(error_log, temp_log); temp = ed[2] & 0xF; if (temp == 0x0) strcat(error_log, " - IRP0"); else if (temp == 0x1) strcat(error_log, " - IRP1"); else if (temp == 0x2) strcat(error_log, " - IIO-Core"); else if (temp == 0x3) strcat(error_log, " - VT-d"); else if (temp == 0x4) strcat(error_log, " - Intel Quick Data"); else if (temp == 0x5) strcat(error_log, " - Misc"); else if (temp == 0x6) strcat(error_log, " - DMA"); else if (temp == 0x7) strcat(error_log, " - ITC"); else if (temp == 0x8) strcat(error_log, " - OTC"); else if (temp == 0x9) strcat(error_log, " - CI"); else strcat(error_log, " - Reserved"); } else strcat(error_log, "Unknown"); sprintf(temp_log, "IIO_ERR %s,FRU:%u", error_log, fru); pal_add_cri_sel(temp_log); break; case MEMORY_ECC_ERR: case MEMORY_ERR_LOG_DIS: if (snr_num == MEMORY_ECC_ERR) { // SEL from MEMORY_ECC_ERR Sensor if ((ed[0] & 0x0F) == 0x0) { if (sen_type == 0x0C) { strcat(error_log, "Correctable"); sprintf(temp_log, "DIMM%02X ECC err,FRU:%u", ed[2], fru); pal_add_cri_sel(temp_log); } else if (sen_type == 0x10) strcat(error_log, "Correctable ECC error Logging Disabled"); } else if ((ed[0] & 0x0F) == 0x1) { strcat(error_log, "Uncorrectable"); sprintf(temp_log, "DIMM%02X UECC err,FRU:%u", ed[2], fru); pal_add_cri_sel(temp_log); } else if ((ed[0] & 0x0F) == 0x5) strcat(error_log, "Correctable ECC error Logging Limit Reached"); else strcat(error_log, "Unknown"); } else if (snr_num == MEMORY_ERR_LOG_DIS) { // SEL from MEMORY_ERR_LOG_DIS Sensor if ((ed[0] & 0x0F) == 0x0) strcat(error_log, "Correctable Memory Error Logging Disabled"); else strcat(error_log, "Unknown"); } // Common routine for both MEM_ECC_ERR and MEMORY_ERR_LOG_DIS sprintf(temp_log, " (DIMM %02X)", ed[2]); strcat(error_log, temp_log); sprintf(temp_log, " Logical Rank %d", ed[1] & 0x03); strcat(error_log, temp_log); // DIMM number (ed[2]): // Bit[7:5]: Socket number (Range: 0-7) // Bit[4:2]: Channel number (Range: 0-7) // Bit[1:0]: DIMM number (Range: 0-3) if (((ed[1] & 0xC) >> 2) == 0x0) { /* All Info Valid */ chn_num = (ed[2] & 0x1C) >> 2; dimm_num = ed[2] & 0x3; /* If critical SEL logging is available, do it */ if (sen_type == 0x0C) { if ((ed[0] & 0x0F) == 0x0) { sprintf(temp_log, "DIMM%c%d ECC err,FRU:%u", 'A'+chn_num, dimm_num, fru); pal_add_cri_sel(temp_log); } else if ((ed[0] & 0x0F) == 0x1) { sprintf(temp_log, "DIMM%c%d UECC err,FRU:%u", 'A'+chn_num, dimm_num, fru); pal_add_cri_sel(temp_log); } } /* Then continue parse the error into a string. */ /* All Info Valid */ sprintf(temp_log, " (CPU# %d, CHN# %d, DIMM# %d)", (ed[2] & 0xE0) >> 5, (ed[2] & 0x18) >> 3, ed[2] & 0x7); } else if (((ed[1] & 0xC) >> 2) == 0x1) { /* DIMM info not valid */ sprintf(temp_log, " (CPU# %d, CHN# %d)", (ed[2] & 0xE0) >> 5, (ed[2] & 0x18) >> 3); } else if (((ed[1] & 0xC) >> 2) == 0x2) { /* CHN info not valid */ sprintf(temp_log, " (CPU# %d, DIMM# %d)", (ed[2] & 0xE0) >> 5, ed[2] & 0x7); } else if (((ed[1] & 0xC) >> 2) == 0x3) { /* CPU info not valid */ sprintf(temp_log, " (CHN# %d, DIMM# %d)", (ed[2] & 0x18) >> 3, ed[2] & 0x7); } strcat(error_log, temp_log); break; case PWR_ERR: if (ed[0] == 0x1) { strcat(error_log, "SYS_PWROK failure"); /* Also try logging to Critial log file, if available */ sprintf(temp_log, "SYS_PWROK failure,FRU:%u", fru); pal_add_cri_sel(temp_log); } else if (ed[0] == 0x2) { strcat(error_log, "PCH_PWROK failure"); /* Also try logging to Critial log file, if available */ sprintf(temp_log, "PCH_PWROK failure,FRU:%u", fru); pal_add_cri_sel(temp_log); } else strcat(error_log, "Unknown"); break; case CATERR_A: case CATERR_B: if (ed[0] == 0x0) { strcat(error_log, "IERR/CATERR"); /* Also try logging to Critial log file, if available */ sprintf(temp_log, "IERR,FRU:%u", fru); pal_add_cri_sel(temp_log); } else if (ed[0] == 0xB) { strcat(error_log, "MCERR/CATERR"); /* Also try logging to Critial log file, if available */ sprintf(temp_log, "MCERR,FRU:%u", fru); pal_add_cri_sel(temp_log); } else if (ed[0] == 0xD){ strcat(error_log, "MCERR/RMCA"); /* Also try logging to Critial log file, if available */ sprintf(temp_log, "RMCA,FRU:%u", fru); pal_add_cri_sel(temp_log); } else strcat(error_log, "Unknown"); break; case MSMI: if (ed[0] == 0x0) strcat(error_log, "IERR/MSMI"); else if (ed[0] == 0xB) strcat(error_log, "MCERR/MSMI"); else strcat(error_log, "Unknown"); break; case CPU_DIMM_HOT: if ((ed[0] << 16 | ed[1] << 8 | ed[2]) == 0x01FFFF) strcat(error_log, "SOC MEMHOT"); else strcat(error_log, "Unknown"); sprintf(temp_log, "CPU_DIMM_HOT %s,FRU:%u", error_log, fru); pal_add_cri_sel(temp_log); break; case SOFTWARE_NMI: if ((ed[0] << 16 | ed[1] << 8 | ed[2]) == 0x03FFFF) strcat(error_log, "Software NMI"); else strcat(error_log, "Unknown SW NMI"); break; case ME_POWER_STATE: switch (ed[0]) { case 0: sprintf(error_log, "RUNNING"); break; case 2: sprintf(error_log, "POWER_OFF"); break; default: sprintf(error_log, "Unknown[%d]", ed[0]); break; } break; case SPS_FW_HEALTH: if ((ed[0] & 0x0F) == 0x00) { switch (ed[1]) { case 0x00: strcat(error_log, "Recovery GPIO forced"); return 1; case 0x01: strcat(error_log, "Image execution failed"); return 1; case 0x02: strcat(error_log, "Flash erase error"); return 1; case 0x03: strcat(error_log, "Flash state information"); return 1; case 0x04: strcat(error_log, "Internal error"); return 1; case 0x05: strcat(error_log, "BMC did not respond"); return 1; case 0x06: strcat(error_log, "Direct Flash update"); return 1; case 0x07: strcat(error_log, "Manufacturing error"); return 1; case 0x08: strcat(error_log, "Automatic Restore to Factory Presets"); return 1; case 0x09: strcat(error_log, "Firmware Exception"); return 1; case 0x0A: strcat(error_log, "Flash Wear-Out Protection Warning"); return 1; case 0x0D: strcat(error_log, "DMI interface error"); return 1; case 0x0E: strcat(error_log, "MCTP interface error"); return 1; case 0x0F: strcat(error_log, "Auto-configuration finished"); return 1; case 0x10: strcat(error_log, "Unsupported Segment Defined Feature"); return 1; case 0x12: strcat(error_log, "CPU Debug Capability Disabled"); return 1; case 0x13: strcat(error_log, "UMA operation error"); return 1; //0x14 and 0x15 are reserved case 0x16: strcat(error_log, "Intel PTT Health"); return 1; case 0x17: strcat(error_log, "Intel Boot Guard Health"); return 1; case 0x18: strcat(error_log, "Restricted mode information"); return 1; case 0x19: strcat(error_log, "MultiPCH mode misconfiguration"); return 1; case 0x1A: strcat(error_log, "Flash Descriptor Region Verification Error"); return 1; default: strcat(error_log, "Unknown"); break; } } else if ((ed[0] & 0x0F) == 0x01) { strcat(error_log, "SMBus link failure"); return 1; } else { strcat(error_log, "Unknown"); } break; /*NM4.0 #550710, Revision 1.95, and turn to p.155*/ case NM_EXCEPTION_A: if (ed[0] == 0xA8) { strcat(error_log, "Policy Correction Time Exceeded"); return 1; } else strcat(error_log, "Unknown"); break; case PCH_THERM_THRESHOLD: idx = ed[0] & 0x0f; sprintf(temp_log, "%s, curr_val: %d C, thresh_val: %d C", thres_event_name[idx] == NULL ? "Unknown" : thres_event_name[idx],ed[1],ed[2]); strcat(error_log, temp_log); break; case NM_HEALTH: { uint8_t health_type_index = (ed[0] & 0xf); uint8_t domain_index = (ed[1] & 0xf); uint8_t err_type_index = ((ed[1] >> 4) & 0xf); sprintf(error_log, "%s,Domain:%s,ErrType:%s,Err:0x%x", nm_health_type[health_type_index], nm_domain_name[domain_index], nm_err_type[err_type_index], ed[2]); } return 1; break; case NM_CAPABILITIES: if (ed[0] & 0x7)//BIT1=policy, BIT2=monitoring, BIT3=pwr limit and the others are reserved { int capability_index = 0; char *policy_capability = NULL; char *monitoring_capability = NULL; char *pwr_limit_capability = NULL; capability_index = BIT(ed[0], 0); policy_capability = nm_capability_status[ capability_index ]; capability_index = BIT(ed[0], 1); monitoring_capability = nm_capability_status[ capability_index ]; capability_index = BIT(ed[0], 2); pwr_limit_capability = nm_capability_status[ capability_index ]; sprintf(error_log, "PolicyInterface:%s,Monitoring:%s,PowerLimit:%s", policy_capability, monitoring_capability, pwr_limit_capability); } else { strcat(error_log, "Unknown"); } return 1; break; case NM_THRESHOLD: { uint8_t threshold_number = (ed[0] & 0x3); uint8_t domain_index = (ed[1] & 0xf); uint8_t policy_id = ed[2]; uint8_t policy_event_index = BIT(ed[0], 3); char *policy_event[2] = {"Threshold Exceeded", "Policy Correction Time Exceeded"}; sprintf(error_log, "Threshold Number:%d-%s,Domain:%s,PolicyID:0x%x", threshold_number, policy_event[policy_event_index], nm_domain_name[domain_index], policy_id); } return 1; break; case CPU0_THERM_STATUS: case CPU1_THERM_STATUS: case CPU2_THERM_STATUS: case CPU3_THERM_STATUS: if (ed[0] == 0x00) strcat(error_log, "CPU Critical Temperature"); else if (ed[0] == 0x01) strcat(error_log, "PROCHOT#"); else if (ed[0] == 0x02) strcat(error_log, "TCC Activation"); else strcat(error_log, "Unknown"); break; case PWR_THRESH_EVT: if (ed[0] == 0x00) strcat(error_log, "Limit Not Exceeded"); else if (ed[0] == 0x01) strcat(error_log, "Limit Exceeded"); else strcat(error_log, "Unknown"); break; case HPR_WARNING: if (ed[2] == 0x01) { if (ed[1] == 0xFF) strcat(temp_log, "Infinite Time"); else sprintf(temp_log, "%d minutes",ed[1]); strcat(error_log, temp_log); } else { strcat(error_log, "Unknown"); } break; default: sprintf(error_log, "Unknown"); parsed = false; break; } if (((event_data[2] & 0x80) >> 7) == 0) { sprintf(temp_log, " Assertion"); strcat(error_log, temp_log); } else { sprintf(temp_log, " Deassertion"); strcat(error_log, temp_log); } return parsed; } int __attribute__((weak)) pal_parse_sel(uint8_t fru, uint8_t *sel, char *error_log) { // // If a platform needs to process a specific type of SEL message // differently from what the common code does, // this function can be overriden to do such unique handling // instead of calling the common SEL parsing logic (pal_parse_sel_helper.) // // This default handler will not perform any special handling, and will // just call the default handler (pal_parse_sel_helper) for every type of // SEL msessages. // pal_parse_sel_helper(fru, sel, error_log); return 0; } // By default, pal_add_cri_sel will do the best effort to // log critical messages to default log file. // Some platform has already overriden this function with // empty function (do not log anything) void __attribute__((weak)) pal_add_cri_sel(char *str) { syslog(LOG_LOCAL0 | LOG_ERR, "%s", str); } int __attribute__((weak)) pal_set_sensor_health(uint8_t fru, uint8_t value) { return PAL_EOK; } int __attribute__((weak)) pal_get_fru_health(uint8_t fru, uint8_t *value) { return PAL_EOK; } int __attribute__((weak)) pal_get_fan_name(uint8_t num, char *name) { return PAL_EOK; } int __attribute__((weak)) pal_get_fan_speed(uint8_t fan, int *rpm) { return PAL_EOK; } int __attribute__((weak)) pal_set_fan_speed(uint8_t fan, uint8_t pwm) { return PAL_EOK; } int __attribute__((weak)) pal_get_pwm_value(uint8_t fan_num, uint8_t *value) { return PAL_EOK; } bool __attribute__((weak)) pal_is_fan_prsnt(uint8_t fan) { return true; } int __attribute__((weak)) pal_fan_dead_handle(int fan_num) { return PAL_EOK; } int __attribute__((weak)) pal_fan_recovered_handle(int fan_num) { return PAL_EOK; } void __attribute__((weak)) pal_inform_bic_mode(uint8_t fru, uint8_t mode) { return; } void __attribute__((weak)) pal_update_ts_sled(void) { return; } int __attribute__((weak)) pal_handle_dcmi(uint8_t fru, uint8_t *tbuf, uint8_t tlen, uint8_t *rbuf, uint8_t *rlen) { return PAL_EOK; } int __attribute__((weak)) pal_is_fru_ready(uint8_t fru, uint8_t *status) { return PAL_EOK; } int __attribute__((weak)) pal_is_slot_server(uint8_t fru) { return PAL_EOK; } int __attribute__((weak)) pal_is_slot_support_update(uint8_t fru) { return pal_is_slot_server(fru); } int __attribute__((weak)) pal_self_tray_location(uint8_t *value) { return PAL_EOK; } void __attribute__((weak)) pal_log_clear(char *fru) { return; } // GUID based on RFC4122 format @ https://tools.ietf.org/html/rfc4122 void pal_populate_guid(char *guid, char *str) { unsigned int secs; unsigned int usecs; struct timeval tv; uint8_t count; uint8_t lsb, msb; int i, r; // Populate time gettimeofday(&tv, NULL); secs = tv.tv_sec; usecs = tv.tv_usec; guid[0] = usecs & 0xFF; guid[1] = (usecs >> 8) & 0xFF; guid[2] = (usecs >> 16) & 0xFF; guid[3] = (usecs >> 24) & 0xFF; guid[4] = secs & 0xFF; guid[5] = (secs >> 8) & 0xFF; guid[6] = (secs >> 16) & 0xFF; guid[7] = (secs >> 24) & 0x0F; // Populate version guid[7] |= 0x10; // Populate clock seq with randmom number //getrandom(&guid[8], 2, 0); srand(time(NULL)); //memcpy(&guid[8], rand(), 2); r = rand(); guid[8] = r & 0xFF; guid[9] = (r>>8) & 0xFF; // Use string to populate 6 bytes unique // e.g. LSP62100035 => 'S' 'P' 0x62 0x10 0x00 0x35 count = 0; for (i = strlen(str)-1; i >= 0; i--) { if (count == 6) { break; } // If alphabet use the character as is if (isalpha(str[i])) { guid[15-count] = str[i]; count++; continue; } // If it is 0-9, use two numbers as BCD lsb = str[i] - '0'; if (i > 0) { i--; if (isalpha(str[i])) { i++; msb = 0; } else { msb = str[i] - '0'; } } else { msb = 0; } guid[15-count] = (msb << 4) | lsb; count++; } // zero the remaining bytes, if any if (count != 6) { memset(&guid[10], 0, 6-count); } } int __attribute__((weak)) pal_get_dev_guid(uint8_t fru, char *guid) { return PAL_EOK; } int __attribute__((weak)) pal_set_dev_guid(uint8_t fru, char *guid) { return PAL_EOK; } int __attribute__((weak)) pal_get_plat_sku_id(void) { return PAL_EOK; } int __attribute__((weak)) pal_is_test_board(void) { //Non Test Board:0 return 0; } int __attribute__((weak)) pal_get_fw_info(uint8_t fru, unsigned char target, unsigned char* res, unsigned char* res_len) { return PAL_EOK; } void __attribute__((weak)) pal_i2c_crash_assert_handle(int i2c_bus_num) { return; } void __attribute__((weak)) pal_i2c_crash_deassert_handle(int i2c_bus_num) { return; } int __attribute__((weak)) pal_is_cplddump_ongoing(uint8_t fru) { return PAL_EOK; } bool __attribute__((weak)) pal_is_cplddump_ongoing_system(void) { return PAL_EOK; } int __attribute__((weak)) pal_is_crashdump_ongoing(uint8_t fru) { char fname[128]; char value[MAX_VALUE_LEN] = {0}; struct timespec ts; int ret; //if pid file not exist, return false sprintf(fname, "/var/run/autodump%d.pid", fru); if ( access(fname, F_OK) != 0 ) { return 0; } //check the crashdump file in /tmp/cache_store/fru$1_crashdump sprintf(fname, "fru%d_crashdump", fru); ret = kv_get(fname, value, NULL, 0); if (ret < 0) { return 0; } clock_gettime(CLOCK_MONOTONIC, &ts); if (strtoul(value, NULL, 10) > ts.tv_sec) { return 1; } //over the threshold time, return false return 0; /* false */ } bool __attribute__((weak)) pal_is_crashdump_ongoing_system(void) { //Base on fru number to check if autodump is onging. uint8_t max_slot_num = 0; int i; pal_get_num_slots(&max_slot_num); for(i = 1; i <= max_slot_num; i++) //fru start from 1 { int fruid = pal_slotid_to_fruid(i); if ( 1 == pal_is_crashdump_ongoing(fruid) ) { return true; } } return false; } int __attribute__((weak)) pal_open_fw_update_flag(void) { return -1; } int __attribute__((weak)) pal_remove_fw_update_flag(void) { return -1; } int __attribute__((weak)) pal_get_fw_update_flag(void) { return 0; } int __attribute__((weak)) pal_set_machine_configuration(uint8_t slot, uint8_t *req_data, uint8_t req_len, uint8_t *res_data, uint8_t *res_len) { return PAL_EOK; } int __attribute__((weak)) pal_handle_string_sel(char *log, uint8_t log_len) { return PAL_EOK; } int __attribute__((weak)) pal_set_adr_trigger(uint8_t slot, bool trigger) { return PAL_ENOTSUP; } int __attribute__((weak)) pal_flock_flag_retry(int fd, unsigned int flag) { int ret = 0; int retry_count = 0; ret = flock(fd, flag); while (ret && (retry_count < 3)) { retry_count++; msleep(100); ret = flock(fd, flag); } if (ret) { return -1; } return 0; } int __attribute__((weak)) pal_flock_retry(int fd) { int ret = 0; int retry_count = 0; ret = flock(fd, LOCK_EX | LOCK_NB); while (ret && (retry_count < 3)) { retry_count++; msleep(100); ret = flock(fd, LOCK_EX | LOCK_NB); } if (ret) { return -1; } return 0; } int __attribute__((weak)) pal_unflock_retry(int fd) { int ret = 0; int retry_count = 0; ret = flock(fd, LOCK_UN); while (ret && (retry_count < 3)) { retry_count++; msleep(100); ret = flock(fd, LOCK_UN); } if (ret) { return -1; } return 0; } int __attribute__((weak)) pal_slotid_to_fruid(int slotid) { // This function is for mapping to fruid from slotid // If the platform's slotid is different with fruid, need to rewrite // this function in project layer. return slotid; } int __attribute__((weak)) pal_devnum_to_fruid(int devnum) { // This function is for mapping to fruid from devnum // If the platform's devnum is different with fruid, need to rewrite // this function in project layer. return devnum; } int __attribute__((weak)) pal_channel_to_bus(int channel) { // This function is for mapping to bus from channel // If the platform's channel is different with bus, need to rewrite // this function in project layer. return channel; } int __attribute__((weak)) pal_set_fw_update_ongoing(uint8_t fruid, uint16_t tmout) { char key[64] = {0}; char value[64] = {0}; struct timespec ts; sprintf(key, "fru%d_fwupd", fruid); clock_gettime(CLOCK_MONOTONIC, &ts); ts.tv_sec += tmout; sprintf(value, "%ld", ts.tv_sec); if (kv_set(key, value, 0, 0) < 0) { return -1; } return 0; } bool __attribute__((weak)) pal_is_fw_update_ongoing(uint8_t fruid) { char key[MAX_KEY_LEN]; char value[MAX_VALUE_LEN] = {0}; int ret; struct timespec ts; sprintf(key, "fru%d_fwupd", fruid); ret = kv_get(key, value, NULL, 0); if (ret < 0) { return false; } clock_gettime(CLOCK_MONOTONIC, &ts); if (strtoul(value, NULL, 10) > ts.tv_sec) return true; return false; } bool __attribute__((weak)) pal_is_fw_update_ongoing_system(void) { //Base on fru number to sum up if fw update is onging. uint8_t max_slot_num = 0; int i; pal_get_num_slots(&max_slot_num); for(i = 0; i <= max_slot_num; i++) { // 0 is reserved for BMC update int fruid = pal_slotid_to_fruid(i); if (pal_is_fw_update_ongoing(fruid) == true) //if any slot is true, then we can return true return true; } return false; } bool __attribute__((weak)) pal_sled_cycle_prepare(void) { char key[MAX_KEY_LEN] = "blk_fwupd"; char value[MAX_VALUE_LEN] = {0}; int ret; ret = kv_get(key, value, NULL, 0); if (ret < 0) { return false; } if ( atoi(value) > 0 ) return true; return false; } bool __attribute__((weak)) pal_can_change_power(uint8_t fru) { char fruname[32]; if (pal_get_fru_name(fru, fruname)) { sprintf(fruname, "fru%d", fru); } if (pal_is_fw_update_ongoing(fru)) { printf("FW update for %s is ongoing, block the power controlling.\n", fruname); return false; } if (pal_is_crashdump_ongoing(fru)) { printf("Crashdump for %s is ongoing, block the power controlling.\n", fruname); return false; } if (pal_is_cplddump_ongoing(fru)) { printf("CPLD dump for %s is ongoing, block the power controlling.\n", fruname); return false; } return true; } int __attribute__((weak)) run_command(const char* cmd) { int status = system(cmd); if (status == -1) { // system error or environment error return 127; } // WIFEXITED(status): cmd is executed complete or not. return true for success. // WEXITSTATUS(status): cmd exit code if (WIFEXITED(status) && (WEXITSTATUS(status) == 0)) return 0; else return -1; } int __attribute__((weak)) pal_get_restart_cause(uint8_t slot, uint8_t *restart_cause) { char key[MAX_KEY_LEN]; char value[MAX_VALUE_LEN] = {0}; unsigned int cause; sprintf(key, "fru%d_restart_cause", slot); if (kv_get(key, value, NULL, KV_FPERSIST)) { return -1; } if(sscanf(value, "%u", &cause) != 1) { return -1; } *restart_cause = cause; return 0; } int __attribute__((weak)) pal_set_restart_cause(uint8_t slot, uint8_t restart_cause) { char key[MAX_KEY_LEN]; char value[MAX_VALUE_LEN] = {0}; sprintf(key, "fru%d_restart_cause", slot); sprintf(value, "%d", restart_cause); if (kv_set(key, value, 0, KV_FPERSIST)) { return -1; } return 0; } int __attribute__((weak)) pal_get_nm_selftest_result(uint8_t fruid, uint8_t *data) { return PAL_ENOTSUP; } int __attribute__((weak)) pal_handle_oem_1s_intr(uint8_t slot, uint8_t *data) { return 0; } int __attribute__((weak)) pal_handle_oem_1s_asd_msg_in(uint8_t slot, uint8_t *data, uint8_t data_len) { return PAL_ENOTSUP; } int __attribute__((weak)) pal_handle_oem_1s_ras_dump_in(uint8_t slot, uint8_t *data, uint8_t data_len) { return PAL_ENOTSUP; } int __attribute__((weak)) pal_set_gpio_value(int gpio_num, uint8_t value) { char vpath[64] = {0}; char *val; FILE *fp = NULL; int rc = 0; int ret = 0; int retry_cnt = 5; int i = 0; sprintf(vpath, GPIO_VAL, gpio_num); val = (value == 0) ? "0": "1"; for (i = 0; i < retry_cnt; i++) { fp = fopen(vpath, "w"); if (fp == NULL) { syslog(LOG_ERR, "%s(): failed to open device %s (%s)", __func__, vpath, strerror(errno)); if (i == (retry_cnt - 1)) { return errno; } } else { break; } msleep(100); } for (i = 0; i < retry_cnt; i++) { ret = 0; rc = fputs(val, fp); if (rc < 0) { syslog(LOG_ERR, "failed to write device %s (%s)", vpath, strerror(errno)); if (i == (retry_cnt - 1)) { ret = errno; } } else { break; } msleep(100); } fclose(fp); return ret; } int __attribute__((weak)) pal_get_gpio_value(int gpio_num, uint8_t *value) { char vpath[64] = {0}; FILE *fp = NULL; int rc = 0; int ret = 0; int retry_cnt = 5; int i = 0; sprintf(vpath, GPIO_VAL, gpio_num); for (i = 0; i < retry_cnt; i++) { fp = fopen(vpath, "r"); if (fp == NULL) { syslog(LOG_ERR, "%s(): failed to open device %s (%s)", __func__, vpath, strerror(errno)); if (i == (retry_cnt - 1)) { return errno; } } else { break; } msleep(100); } for (i = 0; i < retry_cnt; i++) { int ival; ret = 0; rc = fscanf(fp, "%d", &ival); if (rc != 1) { syslog(LOG_ERR, "failed to read device %s (%s)", vpath, strerror(errno)); if (i == (retry_cnt - 1)) { ret = errno; } } else { *value = (uint8_t)ival; break; } msleep(100); } fclose(fp); return ret; } int __attribute__((weak)) pal_ipmb_processing(int bus, void *buf, uint16_t size) { return 0; } int __attribute__((weak)) pal_ipmb_finished(int bus, void *buf, uint16_t size) { return 0; } // Helper functions for some of PAL routines void __attribute__((weak)) msleep(int msec) { struct timespec req; req.tv_sec = 0; req.tv_nsec = msec * 1000 * 1000; while(nanosleep(&req, &req) == -1 && errno == EINTR) { continue; } } int __attribute__((weak)) pal_bypass_cmd(uint8_t slot, uint8_t *req_data, uint8_t req_len, uint8_t *res_data, uint8_t *res_len) { // Completion Code Invalid Command return 0xC1; } int __attribute__((weak)) pal_bypass_dev_card(uint8_t slot, uint8_t *req_data, uint8_t req_len, uint8_t *res_data, uint8_t *res_len) { // Completion Code Invalid Command return 0xC1; } void __attribute__((weak)) pal_set_def_restart_cause(uint8_t slot) { uint8_t cause; if (pal_get_restart_cause(slot, &cause)) { // If no restart cause is set, set the default to be // PWR_ON_PUSH_BUTTON since that is the most obvious cause // since BMC has just booted up and started the ipmid. pal_set_restart_cause(slot, RESTART_CAUSE_PWR_ON_PUSH_BUTTON); } } int __attribute__((weak)) pal_compare_fru_data(char *fru_out, char *fru_in, int cmp_size) { FILE *fru_in_fd=NULL; FILE *fru_out_fd=NULL; uint8_t *fru_in_arr=NULL; uint8_t *fru_out_arr=NULL; int ret=PAL_EOK; int size=0; int i; //get the size size=cmp_size * sizeof(uint8_t); //open the fru_in file fru_in_fd = fopen(fru_in, "rb"); if ( NULL == fru_in_fd ) { syslog(LOG_WARNING, "[%s] unable to open the file: %s", __func__, fru_in); ret=PAL_ENOTSUP; goto error_exit; } //open the fru_out file fru_out_fd = fopen(fru_out, "rb"); if ( NULL == fru_out_fd ) { syslog(LOG_WARNING, "[%s] unable to open the file: %s", __func__, fru_out); ret=PAL_ENOTSUP; goto error_exit; } //get the fru_in data fru_in_arr = (uint8_t*) malloc(size); ret = fread(fru_in_arr, sizeof(uint8_t), size, fru_in_fd); if ( ret != size ) { syslog(LOG_WARNING, "[%s] Get fru_in data fail", __func__); ret=PAL_ENOTSUP; goto error_exit; } #ifdef FRU_DEBUG syslog(LOG_WARNING,"[%s] Print Read_in", __func__); for ( i=0; i<size; i++ ) { syslog(LOG_WARNING, "[%s]ReadIn[%d]=%x", __func__, i, fru_in_arr[i]); } #endif //get the fru_out data fru_out_arr = (uint8_t*) malloc(size); ret=fread(fru_out_arr, sizeof(uint8_t), size, fru_out_fd); if ( ret != size ) { syslog(LOG_WARNING, "[%s] Get fru_out data fail", __func__); ret=PAL_ENOTSUP; goto error_exit; } #ifdef FRU_DEBUG syslog(LOG_WARNING,"[%s] Print Read_out", __func__); for ( i=0; i<size; i++ ) { syslog(LOG_WARNING, "[%s]ReadOut[%d]=%x", __func__, i, fru_out_arr[i]); } #endif for ( i=0; i<size; i++ ) { if ( fru_in_arr[i] != fru_out_arr[i] ) { printf("[%s]FRU Comparison Fail. Data Mismatch\n", __func__); syslog(LOG_WARNING, "[%s]FRU Comparison Fail. Data Mismatch", __func__); syslog(LOG_WARNING, "[%s]Index:%d In:%x Out:%x", __func__, i, fru_in_arr[i], fru_out_arr[i]); ret=PAL_ENOTSUP; goto error_exit; } } ret=PAL_EOK; error_exit: if ( NULL != fru_in_fd ) { fclose(fru_in_fd); } if ( NULL != fru_out_fd ) { fclose(fru_out_fd); } if ( NULL != fru_in_arr ) { free(fru_in_arr); } if ( NULL != fru_out_arr ) { free(fru_out_arr); } return ret; } void __attribute__((weak)) pal_get_me_name(uint8_t fru, char *target_name) { strcpy(target_name, "ME"); return; } int __attribute__((weak)) pal_set_tpm_physical_presence(uint8_t slot, uint8_t presence) { return PAL_ENOTSUP; } int __attribute__((weak)) pal_get_tpm_physical_presence(uint8_t slot) { return PAL_ENOTSUP; } int __attribute__((weak)) pal_create_TPMTimer(int fru) { return PAL_ENOTSUP; } int __attribute__((weak)) pal_force_update_bic_fw(uint8_t slot_id, uint8_t comp, char *path) { return -2; //means not support } void __attribute__((weak)) pal_specific_plat_fan_check(bool status) { return; } bool __attribute__((weak)) pal_get_pair_fru(uint8_t slot_id, uint8_t *pair_fru) { return false; } char * __attribute__((weak)) pal_get_pwn_list(void) { return pal_pwm_list; } char * __attribute__((weak)) pal_get_tach_list(void) { return pal_tach_list; } char * __attribute__((weak)) pal_get_fan_opt_list(void) { return pal_fan_opt_list; } int __attribute__((weak)) pal_get_pwm_cnt(void) { return pal_pwm_cnt; } int __attribute__((weak)) pal_get_tach_cnt(void) { return pal_tach_cnt; } int __attribute__((weak)) pal_get_fan_opt_cnt(void) { return pal_fan_opt_cnt; } int __attribute__((weak)) pal_set_fan_ctrl(char *ctrl_opt) { return -1; } int __attribute__((weak)) pal_set_time_sync(uint8_t *req_data, uint8_t req_len) { return PAL_ENOTSUP; } int __attribute__((weak)) pal_get_bmc_ipmb_slave_addr(uint16_t *slave_addr, uint8_t bus_id) { *slave_addr = BMC_SLAVE_ADDR; return 0; } int __attribute__((weak)) pal_is_mcu_ready(uint8_t bus) { return PAL_ENOTSUP; } int __attribute__((weak)) pal_wait_mcu_ready2update(uint8_t bus) { sleep(2); return 0; } int __attribute__((weak)) pal_set_sdr_update_flag(uint8_t slot, uint8_t update) { return 0; } int __attribute__((weak)) pal_get_sdr_update_flag(uint8_t slot) { return 0; } int __attribute__((weak)) pal_fw_update_prepare(uint8_t fru, const char *comp) { return 0; } int __attribute__((weak)) pal_fw_update_finished(uint8_t fru, const char *comp, int status) { return status; } bool __attribute__((weak)) pal_is_modify_sel_time(uint8_t *sel, int size) { return false; } int __attribute__((weak)) pal_update_sensor_reading_sdr (uint8_t fru) { return 0; } int __attribute__((weak)) pal_get_80port_page_record(uint8_t slot, uint8_t page_num, uint8_t *buf, size_t max_len, size_t *len) { return PAL_ENOTSUP; } int __attribute__((weak)) pal_set_usb_path (uint8_t slot, uint8_t endpoint) { return PAL_ENOTSUP; } int __attribute__((weak)) pal_display_4byte_post_code(uint8_t slot, uint32_t postcode_dw) { return 0; } void __attribute__((weak)) pal_get_eth_intf_name(char* intf_name) { snprintf(intf_name, 8, "eth0"); } int __attribute__((weak)) pal_get_host_system_mode(uint8_t *mode) { return PAL_ENOTSUP; } uint8_t __attribute__((weak)) pal_ipmb_get_sensor_val(uint8_t slot, uint8_t *req_data, uint8_t req_len, uint8_t *res_data, uint8_t *res_len) { *res_len = 0; return 0; } int __attribute__((weak)) pal_sensor_monitor_initial(void) { return 0; } int __attribute__((weak)) pal_sensor_thresh_init(void) { return 0; } int __attribute__((weak)) pal_set_host_system_mode(uint8_t mode) { return PAL_ENOTSUP; } int __attribute__((weak)) pal_is_pfr_active(void) { return PFR_NONE; } int __attribute__((weak)) pal_get_pfr_address(uint8_t fru, uint8_t *bus, uint8_t *addr, bool *bridged) { return -1; } int __attribute__((weak)) pal_get_pfr_update_address(uint8_t fru, uint8_t *bus, uint8_t *addr, bool *bridged) { return -1; } int __attribute__((weak)) pal_get_dev_card_sensor(uint8_t slot, uint8_t *req_data, uint8_t req_len, uint8_t *res_data, uint8_t *res_len) { return PAL_ENOTSUP; } int __attribute__((weak)) pal_set_bios_cap_fw_ver(uint8_t slot, uint8_t *req_data, uint8_t req_len, uint8_t *res_data, uint8_t *res_len) { return PAL_ENOTSUP; } int __attribute__((weak)) pal_is_sensor_valid(uint8_t fru, uint8_t snr_num) { return 0; } int __attribute__((weak)) pal_get_fw_ver(uint8_t slot, uint8_t *req_data, uint8_t *res_data, uint8_t *res_len) { return PAL_ENOTSUP; } bool __attribute__((weak)) pal_is_aggregate_snr_valid(uint8_t snr_num) { return true; } int __attribute__((weak)) pal_set_ioc_fw_recovery(uint8_t *ioc_recovery_setting, uint8_t req_len, uint8_t *res_data, uint8_t *res_len) { return CC_NOT_SUPP_IN_CURR_STATE; } int __attribute__((weak)) pal_get_ioc_fw_recovery(uint8_t ioc_recovery_component, uint8_t *res_data, uint8_t *res_len) { return CC_NOT_SUPP_IN_CURR_STATE; } int __attribute__((weak)) pal_setup_exp_uart_bridging(void) { return CC_NOT_SUPP_IN_CURR_STATE; } int __attribute__((weak)) pal_teardown_exp_uart_bridging(void) { return CC_NOT_SUPP_IN_CURR_STATE; } int __attribute__((weak)) pal_set_ioc_wwid(uint8_t *ioc_wwid, uint8_t req_len, uint8_t *res_data, uint8_t *res_len) { return CC_NOT_SUPP_IN_CURR_STATE; } int __attribute__((weak)) pal_get_ioc_wwid(uint8_t ioc_component, uint8_t *res_data, uint8_t *res_len) { return CC_NOT_SUPP_IN_CURR_STATE; } int __attribute__((weak)) pal_convert_sensor_reading(sdr_full_t *sdr, int in_value, float *out_value) { uint8_t m_lsb = 0, m_msb = 0; uint16_t m = 0; uint8_t b_lsb = 0, b_msb = 0; uint16_t b = 0; int8_t b_exp = 0, r_exp = 0; if (sdr == NULL || out_value == NULL) { syslog(LOG_ERR, "%s() Failed to convert sensor reading: input parameter is NULL", __func__); return -1; } m_lsb = sdr->m_val; m_msb = sdr->m_tolerance >> 6; m = (m_msb << 8) | m_lsb; b_lsb = sdr->b_val; b_msb = sdr->b_accuracy >> 6; b = (b_msb << 8) | b_lsb; // exponents are 2's complement 4-bit number b_exp = sdr->rb_exp & 0xF; if (b_exp > 7) { b_exp = (~b_exp + 1) & 0xF; b_exp = -b_exp; } r_exp = (sdr->rb_exp >> 4) & 0xF; if (r_exp > 7) { r_exp = (~r_exp + 1) & 0xF; r_exp = -r_exp; } *out_value = (float)(((m * in_value) + (b * pow(10, b_exp))) * (pow(10, r_exp))); return 0; } int __attribute__((weak)) pal_bic_self_test(void) { return PAL_ENOTSUP; } int __attribute__((weak)) pal_is_bic_ready(uint8_t fru, uint8_t *status) { return PAL_ENOTSUP; } bool __attribute__((weak)) pal_is_bic_heartbeat_ok(uint8_t fru) { return PAL_ENOTSUP; } int __attribute__((weak)) pal_bic_hw_reset(void) { return PAL_ENOTSUP; } int __attribute__((weak)) pal_get_server_12v_power(uint8_t fru_id, uint8_t *status) { return PAL_ENOTSUP; } int __attribute__((weak)) pal_handle_oem_1s_dev_power(uint8_t slot, uint8_t *req_data, uint8_t req_len, uint8_t *res_data, uint8_t *res_len) { return CC_NOT_SUPP_IN_CURR_STATE; } int __attribute__((weak)) pal_handle_fan_fru_checksum_sel(char *log, uint8_t log_len) { return PAL_ENOTSUP; } int __attribute__((weak)) pal_get_fru_slot(uint8_t fru, uint8_t *slot) { return PAL_ENOTSUP; } int __attribute__((weak)) pal_get_print_fru_name(const char **list) { return PAL_ENOTSUP; } int __attribute__((weak)) pal_get_root_fru(uint8_t fru, uint8_t *root) { return PAL_ENOTSUP; } int __attribute__((weak)) pal_handle_oem_1s_update_sdr(uint8_t slot) { return PAL_ENOTSUP; } static int append_list(char *dest, char *src, size_t size) { if (dest[0] == '\0') { if (strlen(src) >= size) { return PAL_ENOTREADY; } strncpy(dest, src, size); } else { if ((strlen(dest) + strlen(src) + 2) >= size) { return PAL_ENOTREADY; } strncat(dest, ", ", 2); strncat(dest, src, size); } return PAL_EOK; } int __attribute__((weak)) pal_get_fru_list_by_caps(unsigned int caps, char *list, size_t size){ int num_frus = pal_get_fru_count(); unsigned int fru_caps; list[0] = '\0'; for (int fru = 0; fru <= num_frus; fru++) { char name[64] = {0}; if (pal_get_fru_name(fru, name)) { continue; } if (pal_get_fru_capability(fru, &fru_caps)) { continue; } if ((caps & fru_caps) == caps) { int ret = append_list(list, name, size); if (ret) { return ret; } } } return PAL_EOK; } int __attribute__((weak)) pal_get_dev_list_by_caps(uint8_t fru, unsigned int caps, char *list, size_t size){ uint8_t num_devs, dev; unsigned int dev_caps; char fru_name[64] = {0}; if (pal_get_num_devs(fru, &num_devs)) { return PAL_ENOTREADY; } if (pal_get_fru_name(fru, fru_name)) { return PAL_ENOTREADY; } for (dev = 1; dev <= num_devs; dev++) { char name[128]; if (pal_get_dev_name(fru, dev, name)) { continue; } if (pal_get_dev_capability(fru, dev, &dev_caps)) { continue; } if ((caps & dev_caps) == caps) { int ret = append_list(list, name, size); if (ret) { return ret; } } } return PAL_EOK; } int __attribute__((weak)) pal_oem_bios_extra_setup(uint8_t slot, uint8_t *req_data, uint8_t req_len, uint8_t *res_data, uint8_t *res_len){ return CC_INVALID_CMD; } int __attribute__((weak)) pal_udbg_get_frame_total_num() { return 3; }