meta-facebook/meta-fby3/recipes-fby3/plat-libs/files/pal/pal.c (4,303 lines of code) (raw):

/* * * Copyright 2015-present Facebook. All Rights Reserved. * * This file contains code to support IPMI2.0 Specification available @ * http://www.intel.com/content/www/us/en/servers/ipmi/ipmi-specifications.html * * 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. */ #include <stdio.h> #include <stdint.h> #include <stdbool.h> #include <ctype.h> #include <errno.h> #include <syslog.h> #include <string.h> #include <unistd.h> #include <stddef.h> #include <time.h> #include <stdlib.h> #include <sys/time.h> #include <sys/types.h> #include <openbmc/kv.h> #include <openbmc/libgpio.h> #include <openbmc/obmc-i2c.h> #include <openbmc/ncsi.h> #include <openbmc/nl-wrapper.h> #include <sys/socket.h> #include <linux/netlink.h> #include <sys/un.h> #include "pal.h" #define PLATFORM_NAME "yosemitev3" #define LAST_KEY "last_key" #define OFFSET_SYS_GUID 0x17F0 #define OFFSET_DEV_GUID 0x1800 #define PFR_NICEXP_BUS 9 // NICEXP PFR #define PFR_BB_BUS 12 // Baseboard PFR #define PFR_MAILBOX_ADDR (0x70) #define NUM_SERVER_FRU 4 #define NUM_NIC_FRU 1 #define NUM_BMC_FRU 1 #define ERROR_ID_LOG_LEN 15 #define FAN_FAIL_RECORD_PATH "/tmp/cache_store/fan_fail_boost" const char pal_guid_fru_list[] = "slot1, slot2, slot3, slot4, bmc"; const char pal_dev_fru_list[] = "all, 1U, 2U, 1U-dev0, 1U-dev1, 1U-dev2, 1U-dev3, 2U-dev0, 2U-dev1, 2U-dev2, 2U-dev3, 2U-dev4, 2U-dev5, " \ "2U-dev6, 2U-dev7, 2U-dev8, 2U-dev9, 2U-dev10, 2U-dev11, 2U-dev12, 2U-dev13"; const char pal_dev_pwr_list[] = "all, 1U-dev0, 1U-dev1, 1U-dev2, 1U-dev3, 2U-dev0, 2U-dev1, 2U-dev2, 2U-dev3, 2U-dev4, 2U-dev5, " \ "2U-dev6, 2U-dev7, 2U-dev8, 2U-dev9, 2U-dev10, 2U-dev11, 2U-dev12, 2U-dev13, " \ "2U-dev0_1, 2U-dev2_3, 2U-dev4_5, 2U-dev6_7, 2U-dev8_9, 2U-dev10_11"; const char pal_dev_pwr_option_list[] = "status, off, on, cycle"; const char pal_m2_dual_list[] = ""; static char sel_error_record[NUM_SERVER_FRU] = {0}; const char pal_fru_list[] = "all, slot1, slot2, slot3, slot4, bmc, nic, slot1-2U-exp, slot1-2U-top, slot1-2U-bot"; #define SYSFW_VER "sysfw_ver_slot" #define SYSFW_VER_STR SYSFW_VER "%d" #define BOOR_ORDER_STR "slot%d_boot_order" #define SEL_ERROR_STR "slot%d_sel_error" #define SNR_HEALTH_STR "slot%d_sensor_health" #define GPIO_OCP_DEBUG_BMC_PRSNT_N "OCP_DEBUG_BMC_PRSNT_N" #define SLOT1_POSTCODE_OFFSET 0x02 #define SLOT2_POSTCODE_OFFSET 0x03 #define SLOT3_POSTCODE_OFFSET 0x04 #define SLOT4_POSTCODE_OFFSET 0x05 #define DEBUG_CARD_UART_MUX 0x06 #define BB_CPLD_IO_BASE_OFFSET 0x16 #define ENABLE_STR "enable" #define DISABLE_STR "disable" #define STATUS_STR "status" #define WAKEUP_STR "wakeup" #define SLEEP_STR "sleep" #define FAN_MODE_FILE "/tmp/cache_store/fan_mode" #define FAN_MODE_STR_LEN 8 // include the string terminal #define IPMI_GET_VER_FRU_NUM 5 #define IPMI_GET_VER_MAX_COMP 9 #define MAX_FW_VER_LEN 32 //include the string terminal #define MAX_COMPONENT_LEN 32 //include the string terminal #define MAX_PWR_LOCK_STR 32 #ifndef FRU_CAPABILITY_SENSOR_SLAVE #define FRU_CAPABILITY_SENSOR_SLAVE (1UL << 19) #endif #define BIC_READ_EEPROM_FAILED 0xE0 static int key_func_por_cfg(int event, void *arg); static int key_func_pwr_last_state(int event, void *arg); enum key_event { KEY_BEFORE_SET, KEY_AFTER_INI, }; enum sel_event_data_index { DATA_INDEX_0 = 3, DATA_INDEX_1 = 4, DATA_INDEX_2 = 5, }; struct pal_key_cfg { char *name; char *def_val; int (*function)(int, void*); } key_cfg[] = { /* name, default value, function */ {SYSFW_VER "1", "0", NULL}, {SYSFW_VER "2", "0", NULL}, {SYSFW_VER "3", "0", NULL}, {SYSFW_VER "4", "0", NULL}, {"pwr_server1_last_state", "on", key_func_pwr_last_state}, {"pwr_server2_last_state", "on", key_func_pwr_last_state}, {"pwr_server3_last_state", "on", key_func_pwr_last_state}, {"pwr_server4_last_state", "on", key_func_pwr_last_state}, {"timestamp_sled", "0", NULL}, {"slot1_por_cfg", "lps", key_func_por_cfg}, {"slot2_por_cfg", "lps", key_func_por_cfg}, {"slot3_por_cfg", "lps", key_func_por_cfg}, {"slot4_por_cfg", "lps", key_func_por_cfg}, {"slot1_boot_order", "0100090203ff", NULL}, {"slot2_boot_order", "0100090203ff", NULL}, {"slot3_boot_order", "0100090203ff", NULL}, {"slot4_boot_order", "0100090203ff", NULL}, {"slot1_cpu_ppin", "0", NULL}, {"slot2_cpu_ppin", "0", NULL}, {"slot3_cpu_ppin", "0", NULL}, {"slot4_cpu_ppin", "0", NULL}, {"fru1_restart_cause", "3", NULL}, {"fru2_restart_cause", "3", NULL}, {"fru3_restart_cause", "3", NULL}, {"fru4_restart_cause", "3", NULL}, {"slot1_sensor_health", "1", NULL}, {"slot2_sensor_health", "1", NULL}, {"slot3_sensor_health", "1", NULL}, {"slot4_sensor_health", "1", NULL}, {"slot1_sel_error", "1", NULL}, {"slot2_sel_error", "1", NULL}, {"slot3_sel_error", "1", NULL}, {"slot4_sel_error", "1", NULL}, {"ntp_server", "", NULL}, /* Add more Keys here */ {LAST_KEY, LAST_KEY, NULL} /* This is the last key of the list */ }; MAPTOSTRING root_port_common_mapping[] = { // NIC { 0xB2, 0, 0x4A, "Class 2", "NIC"}, // Class 2 NIC { 0x63, 3, 0x2D, "Class 1", "NIC"}, // Class 1 NIC // DL { 0x63, 2, 0x2C, "Num 0", "SB" }, // PVT switch Num 1 to 0 { 0x00, 0x1D, 0xFF, "Num 1", "SB"}, // PVT -> Remove // CWC/GPv3 root port { 0x15, 0, 0x1A, "CPU X16", "CWC/GPv3"}, //Port 0x1A { 0x63, 0, 0x2A, "CPU X8", "CWC/GPv3"}, //Port 0x2A // CWC/GPv3 Up Strem Ports { 0x16, 0, 0x1A, "USP X16", "CWC/GPv3"}, //Port 0x1A { 0x64, 0, 0x2A, "USP X8", "CWC/GPv3"}, //Port 0x2A // CWC TOP/BOT USBP0 { 0x17, 0, 0x1A, "USP0", "TOP"}, //Port 0x1A { 0x17, 1, 0x2A, "USP0", "BOT"}, //Port 0x2A // CWC TOP/BOT USBP1 { 0x65, 0, 0x1A, "USP1", "TOP"}, //Port 0x1A { 0x65, 1, 0x2A, "USP1", "BOT"}, //Port 0x2A }; MAPTOSTRING root_port_mapping[] = { { 0xB2, 3, 0x3D, "Num 0", "1OU"}, //Port 0x4D { 0xB2, 2, 0x3C, "Num 1", "1OU"}, //Port 0x4C { 0xB2, 1, 0x3B, "Num 2", "1OU"}, //Port 0x4B { 0xB2, 0, 0x3A, "Num 3", "1OU"}, //Port 0x4A { 0x15, 0, 0x1A, "Num 0", "2OU"}, //Port 0x1A { 0x15, 1, 0x1B, "Num 1", "2OU"}, //Port 0x1B { 0x63, 1, 0x2B, "Num 2", "2OU"}, //Port 0x2B { 0x63, 0, 0x2A, "Num 3", "2OU"}, //Port 0x2A { 0x15, 2, 0x1C, "Num 4", "2OU"}, //Port 0x1C { 0x15, 3, 0x1D, "Num 5", "2OU"}, //Port 0x1D }; // dual M2 for 4U MAPTOSTRING root_port_mapping_4u_dual_m2_gpv3[] = { // bus, device, port, silk screen, location // Down Stream Ports { 0x20, 0, 0x01, "Num 1", "BOT"}, { 0x20, 1, 0x02, "Num 3", "BOT"}, { 0x20, 2, 0x03, "Num 5", "BOT"}, { 0x20, 3, 0x04, "Num 7", "BOT"}, { 0x6C, 0, 0x05, "Num 9", "BOT"}, { 0x6C, 1, 0x06, "Num 11", "BOT"}, { 0x20, 4, 0x07, "E1S 0", "BOT"}, { 0x6C, 2, 0x08, "E1S 1", "BOT"}, { 0x1F, 0, 0x09, "PESW", "BOT"}, { 0x6B, 0, 0x0A, "PESW", "BOT"}, { 0x19, 0, 0x01, "Num 1", "TOP"}, { 0x19, 1, 0x02, "Num 3", "TOP"}, { 0x19, 2, 0x03, "Num 5", "TOP"}, { 0x19, 3, 0x04, "Num 7", "TOP"}, { 0x67, 0, 0x05, "Num 9", "TOP"}, { 0x67, 1, 0x06, "Num 11", "TOP"}, { 0x19, 4, 0x07, "E1S 0", "TOP"}, { 0x67, 2, 0x08, "E1S 1", "TOP"}, { 0x18, 0, 0x09, "PESW", "TOP"}, { 0x66, 0, 0x0A, "PESW", "TOP"}, // End devices { 0x21, 0, 0x01, "Num 1", "BOT"}, { 0x22, 0, 0x02, "Num 3", "BOT"}, { 0x23, 0, 0x03, "Num 5", "BOT"}, { 0x24, 0, 0x04, "Num 7", "BOT"}, { 0x6D, 0, 0x05, "Num 9", "BOT"}, { 0x6E, 0, 0x06, "Num 11", "BOT"}, { 0x25, 0, 0x07, "E1S 0", "BOT"}, { 0x6F, 0, 0x08, "E1S 1", "BOT"}, { 0x1A, 0, 0x01, "Num 1", "TOP"}, { 0x1B, 0, 0x02, "Num 3", "TOP"}, { 0x1C, 0, 0x03, "Num 5", "TOP"}, { 0x1D, 0, 0x04, "Num 7", "TOP"}, { 0x68, 0, 0x05, "Num 9", "TOP"}, { 0x69, 0, 0x06, "Num 11", "TOP"}, { 0x1E, 0, 0x07, "E1S 0", "TOP"}, { 0x6A, 0, 0x08, "E1S 1", "TOP"}, }; // singel M2 for 4U MAPTOSTRING root_port_mapping_4u_sgl_m2_gpv3[] = { // bus, device, port, silk screen, location // Down Stream Ports { 0x24, 0, 0x01, "Num 0", "BOT"}, { 0x24, 1, 0x02, "Num 1", "BOT"}, { 0x24, 2, 0x03, "Num 2", "BOT"}, { 0x24, 3, 0x04, "Num 3", "BOT"}, { 0x24, 4, 0x05, "Num 4", "BOT"}, { 0x24, 5, 0x06, "Num 5", "BOT"}, { 0x24, 6, 0x07, "Num 6", "BOT"}, { 0x24, 7, 0x08, "Num 7", "BOT"}, { 0x6E, 0, 0x09, "Num 8", "BOT"}, { 0x6E, 1, 0x0A, "Num 9", "BOT"}, { 0x6E, 2, 0x0B, "Num 10", "BOT"}, { 0x6E, 3, 0x0C, "Num 11", "BOT"}, { 0x24, 8, 0x0D, "E1S 0", "BOT"}, { 0x6E, 4, 0x0E, "E1S 1", "BOT"}, { 0x23, 0, 0x0F, "PESW", "BOT"}, { 0x6D, 0, 0x10, "PESW", "BOT"}, { 0x19, 0, 0x01, "Num 0", "TOP"}, { 0x19, 1, 0x02, "Num 1", "TOP"}, { 0x19, 2, 0x03, "Num 2", "TOP"}, { 0x19, 3, 0x04, "Num 3", "TOP"}, { 0x19, 4, 0x05, "Num 4", "TOP"}, { 0x19, 5, 0x06, "Num 5", "TOP"}, { 0x19, 6, 0x07, "Num 6", "TOP"}, { 0x19, 7, 0x08, "Num 7", "TOP"}, { 0x67, 0, 0x09, "Num 8", "TOP"}, { 0x67, 1, 0x0A, "Num 9", "TOP"}, { 0x67, 2, 0x0B, "Num 10", "TOP"}, { 0x67, 3, 0x0C, "Num 11", "TOP"}, { 0x19, 8, 0x0D, "E1S 0", "TOP"}, { 0x67, 4, 0x0E, "E1S 1", "TOP"}, { 0x18, 0, 0x0F, "PESW", "TOP"}, { 0x66, 0, 0x10, "PESW", "TOP"}, // End devices { 0x25, 0, 0x01, "Num 0", "BOT"}, { 0x26, 0, 0x02, "Num 1", "BOT"}, { 0x27, 0, 0x03, "Num 2", "BOT"}, { 0x28, 0, 0x04, "Num 3", "BOT"}, { 0x29, 0, 0x05, "Num 4", "BOT"}, { 0x2A, 0, 0x06, "Num 5", "BOT"}, { 0x2B, 0, 0x07, "Num 6", "BOT"}, { 0x2C, 0, 0x08, "Num 7", "BOT"}, { 0x6F, 0, 0x09, "Num 8", "BOT"}, { 0x70, 0, 0x0A, "Num 9", "BOT"}, { 0x71, 0, 0x0B, "Num 10", "BOT"}, { 0x72, 0, 0x0C, "Num 11", "BOT"}, { 0x2d, 0, 0x0D, "E1S 0", "BOT"}, { 0x73, 0, 0x0E, "E1S 1", "BOT"}, { 0x1A, 0, 0x01, "Num 0", "TOP"}, { 0x1B, 0, 0x02, "Num 1", "TOP"}, { 0x1C, 0, 0x03, "Num 2", "TOP"}, { 0x1D, 0, 0x04, "Num 3", "TOP"}, { 0x1E, 0, 0x05, "Num 4", "TOP"}, { 0x1F, 0, 0x06, "Num 5", "TOP"}, { 0x20, 0, 0x07, "Num 6", "TOP"}, { 0x21, 0, 0x08, "Num 7", "TOP"}, { 0x68, 0, 0x09, "Num 8", "TOP"}, { 0x69, 0, 0x0A, "Num 9", "TOP"}, { 0x6A, 0, 0x0B, "Num 10", "TOP"}, { 0x6B, 0, 0x0C, "Num 11", "TOP"}, { 0x22, 0, 0x0D, "E1S 0", "TOP"}, { 0x6C, 0, 0x0E, "E1S 1", "TOP"}, }; // dual M2 for 2U MAPTOSTRING root_port_mapping_2u_dual_m2_gpv3[] = { // bus, device, port, silk screen, location // Down Stream Ports { 0x17, 0, 0x01, "Num 1", "2OU"}, { 0x17, 1, 0x02, "Num 3", "2OU"}, { 0x17, 2, 0x03, "Num 5", "2OU"}, { 0x17, 3, 0x04, "Num 7", "2OU"}, { 0x65, 0, 0x05, "Num 9", "2OU"}, { 0x65, 1, 0x06, "Num 11", "2OU"}, { 0x17, 4, 0x07, "E1S 0", "2OU"}, { 0x65, 2, 0x08, "E1S 1", "2OU"}, // End devices { 0x18, 0, 0x01, "Num 1", "2OU"}, { 0x19, 0, 0x02, "Num 3", "2OU"}, { 0x1A, 0, 0x03, "Num 5", "2OU"}, { 0x1B, 0, 0x04, "Num 7", "2OU"}, { 0x66, 0, 0x05, "Num 9", "2OU"}, { 0x67, 0, 0x06, "Num 11", "2OU"}, { 0x1C, 0, 0x07, "E1S 0", "2OU"}, { 0x68, 0, 0x08, "E1S 1", "2OU"}, }; // single M2 for 2U MAPTOSTRING root_port_mapping_2u_sgl_m2_gpv3[] = { // bus, device, port, silk screen, location // Down Stream Ports { 0x17, 0, 0x01, "Num 0", "2OU"}, { 0x17, 1, 0x02, "Num 1", "2OU"}, { 0x17, 2, 0x03, "Num 2", "2OU"}, { 0x17, 3, 0x04, "Num 3", "2OU"}, { 0x17, 4, 0x05, "Num 4", "2OU"}, { 0x17, 5, 0x06, "Num 5", "2OU"}, { 0x17, 6, 0x07, "Num 6", "2OU"}, { 0x17, 7, 0x08, "Num 7", "2OU"}, { 0x65, 0, 0x09, "Num 8", "2OU"}, { 0x65, 1, 0x0A, "Num 9", "2OU"}, { 0x65, 2, 0x0B, "Num 10", "2OU"}, { 0x65, 3, 0x0C, "Num 11", "2OU"}, { 0x17, 8, 0x0D, "E1S 0", "2OU"}, { 0x65, 4, 0x0E, "E1S 1", "2OU"}, // End devices { 0x18, 0, 0x01, "Num 0", "2OU"}, { 0x19, 0, 0x02, "Num 1", "2OU"}, { 0x1A, 0, 0x03, "Num 2", "2OU"}, { 0x1B, 0, 0x04, "Num 3", "2OU"}, { 0x1C, 0, 0x05, "Num 4", "2OU"}, { 0x1D, 0, 0x06, "Num 5", "2OU"}, { 0x1E, 0, 0x07, "Num 6", "2OU"}, { 0x1F, 0, 0x08, "Num 7", "2OU"}, { 0x66, 0, 0x09, "Num 8", "2OU"}, { 0x67, 0, 0x0A, "Num 9", "2OU"}, { 0x68, 0, 0x0B, "Num 10", "2OU"}, { 0x69, 0, 0x0C, "Num 11", "2OU"}, { 0x20, 0, 0x0D, "E1S 0", "2OU"}, { 0x6A, 0, 0x0E, "E1S 1", "2OU"}, }; MAPTOSTRING root_port_mapping_e1s[] = { // bus, device, port, silk screen, location { 0xB2, 0, 0x3A, "Num 0", "1OU"}, { 0xB2, 1, 0x3B, "Num 1", "1OU"}, { 0xB2, 2, 0x3C, "Num 2", "1OU"}, { 0xB2, 3, 0x3D, "Num 3", "1OU"}, { 0x63, 0, 0x2A, "Num 0", "2OU"}, { 0x63, 1, 0x2B, "Num 1", "2OU"}, { 0x15, 3, 0x1D, "Num 2", "2OU"}, { 0x15, 2, 0x1C, "Num 3", "2OU"}, { 0x15, 1, 0x1B, "Num 4", "2OU"}, { 0x15, 0, 0x1A, "Num 5", "2OU"}, }; PCIE_ERR_DECODE pcie_err_tab[] = { {0x00, "Receiver Error"}, {0x01, "Bad TLP"}, {0x02, "Bad DLLP"}, {0x03, "Replay Time-out"}, {0x04, "Replay Rollover"}, {0x05, "Advisory Non-Fatal"}, {0x06, "Corrected Internal Error"}, {0x07, "Header Log Overflow"}, {0x20, "Data Link Protocol Error"}, {0x21, "Surprise Down Error"}, {0x22, "Poisoned TLP"}, {0x23, "Flow Control Protocol Error"}, {0x24, "Completion Timeout"}, {0x25, "Completer Abort"}, {0x26, "Unexpected Completion"}, {0x27, "Receiver Buffer Overflow"}, {0x28, "Malformed TLP"}, {0x29, "ECRC Error"}, {0x2A, "Unsupported Request"}, {0x2B, "ACS Violation"}, {0x2C, "Uncorrectable Internal Error"}, {0x2D, "MC Blocked TLP"}, {0x2E, "AtomicOp Egress Blocked"}, {0x2F, "TLP Prefix Blocked Error"}, {0x30, "Poisoned TLP Egress Blocked"}, {0x50, "Received ERR_COR Message"}, {0x51, "Received ERR_NONFATAL Message"}, {0x52, "Received ERR_FATAL Message"}, {0x59, "LER was triggered by ERR_NONFATAL"}, {0x5A, "LER was triggered by ERR_FATAL"}, {0xA0, "PERR (non-AER)"}, {0xA1, "SERR (non-AER)"}, {0xFF, "None"} }; err_t minor_auth_error[] = { /*MAJOR_ERROR_BMC_AUTH_FAILED or MAJOR_ERROR_PCH_AUTH_FAILED */ {0x01, "MINOR_ERROR_AUTH_ACTIVE"}, {0x02, "MINOR_ERROR_AUTH_RECOVERY"}, {0x03, "MINOR_ERROR_AUTH_ACTIVE_AND_RECOVERY"}, {0x04, "MINOR_ERROR_AUTH_ALL_REGIONS"}, }; err_t minor_update_error[] = { /* MAJOR_ERROR_PCH_UPDATE_FAIELD or MAJOR_ERROR_BMC_UPDATE_FAIELD */ {0x01, "MINOR_ERROR_INVALID_UPDATE_INTENT"}, {0x02, "MINOR_ERROR_FW_UPDATE_INVALID_SVN"}, {0x03, "MINOR_ERROR_FW_UPDATE_AUTH_FAILED"}, {0x04, "MINOR_ERROR_FW_UPDATE_EXCEEDED_MAX_FAILED_ATTEMPTS"}, {0x05, "MINOR_ERROR_FW_UPDATE_ACTIVE_UPDATE_NOT_ALLOWED"}, /* MAJOR_ERROR_CPLD_UPDATE_FAIELD */ {0x06, "MINOR_ERROR_CPLD_UPDATE_INVALID_SVN"}, {0x07, "MINOR_ERROR_CPLD_UPDATE_AUTH_FAILED"}, {0x08, "MINOR_ERROR_CPLD_UPDATE_EXCEEDED_MAX_FAILED_ATTEMPTS"}, }; size_t minor_auth_size = sizeof(minor_auth_error)/sizeof(err_t); size_t minor_update_size = sizeof(minor_update_error)/sizeof(err_t); static int pal_key_index(char *key) { int i; i = 0; while(strcmp(key_cfg[i].name, LAST_KEY)) { // If Key is valid, return success if (!strcmp(key, key_cfg[i].name)) return i; i++; } #ifdef DEBUG syslog(LOG_WARNING, "pal_key_index: invalid key - %s", key); #endif return -1; } static int key_func_pwr_last_state(int event, void *arg) { if (event == KEY_BEFORE_SET) { if (strcmp((char *)arg, "on") && strcmp((char *)arg, "off")) return -1; } return 0; } static int key_func_por_cfg(int event, void *arg) { if (event == KEY_BEFORE_SET) { if (strcmp((char *)arg, "lps") && strcmp((char *)arg, "on") && strcmp((char *)arg, "off")) return -1; } return 0; } int pal_get_key_value(char *key, char *value) { int index; // Check is key is defined and valid if ((index = pal_key_index(key)) < 0) return -1; return kv_get(key, value, NULL, KV_FPERSIST); } int pal_set_key_value(char *key, char *value) { int index, ret; // Check is key is defined and valid if ((index = pal_key_index(key)) < 0) return -1; if (key_cfg[index].function) { ret = key_cfg[index].function(KEY_BEFORE_SET, value); if (ret < 0) return ret; } return kv_set(key, value, 0, KV_FPERSIST); } void pal_dump_key_value(void) { int ret; int i = 0; char value[MAX_VALUE_LEN] = {0x0}; while (strcmp(key_cfg[i].name, LAST_KEY)) { printf("%s:", key_cfg[i].name); if ((ret = kv_get(key_cfg[i].name, value, NULL, KV_FPERSIST)) < 0) { printf("\n"); } else { printf("%s\n", value); } i++; memset(value, 0, MAX_VALUE_LEN); } } int pal_set_def_key_value() { int i; //char key[MAX_KEY_LEN] = {0}; for(i = 0; strcmp(key_cfg[i].name, LAST_KEY) != 0; i++) { if (kv_set(key_cfg[i].name, key_cfg[i].def_val, 0, KV_FCREATE | KV_FPERSIST)) { #ifdef DEBUG syslog(LOG_WARNING, "pal_set_def_key_value: kv_set failed."); #endif } if (key_cfg[i].function) { key_cfg[i].function(KEY_AFTER_INI, key_cfg[i].name); } } return 0; } int pal_get_boot_order(uint8_t slot_id, uint8_t *req_data, uint8_t *boot, uint8_t *res_len) { int i = 0, j = 0; int ret = PAL_EOK; char key[MAX_KEY_LEN] = {0}; char str[MAX_VALUE_LEN] = {0}; char tstr[4] = {0}; *res_len = 0; sprintf(key, BOOR_ORDER_STR, slot_id); ret = pal_get_key_value(key, str); if ( ret < 0 ) { *res_len = 0; goto error_exit; } for (i = 0; i < 2*SIZE_BOOT_ORDER; i += 2) { sprintf(tstr, "%c%c\n", str[i], str[i+1]); boot[j++] = strtol(tstr, NULL, 16); } *res_len = SIZE_BOOT_ORDER; error_exit: return ret; } int pal_set_boot_order(uint8_t slot_id, uint8_t *boot, uint8_t *res_data, uint8_t *res_len) { int i = 0; int j = 0; int network_dev = 0; int ret = PAL_EOK; char key[MAX_KEY_LEN] = {0}; char str[MAX_VALUE_LEN] = {0}; char tstr[10] = {0}; enum { BOOT_DEVICE_IPV4 = 0x1, BOOT_DEVICE_IPV6 = 0x9, BOOT_DEVICE_RSVD = 0xff, }; *res_len = 0; for (i = 0; i < SIZE_BOOT_ORDER; i++) { if ( (i > 0) && (boot[i] != BOOT_DEVICE_RSVD) ) { // byte[0] is boot mode, byte[1:5] are boot order for (j = i+1; j < SIZE_BOOT_ORDER; j++) { //not allow having the same boot devcie in the boot order if ( boot[i] == boot[j] ) { syslog(LOG_WARNING, "Not allow having the same boot devcie in the boot order"); ret = CC_INVALID_PARAM; goto error_exit; } } if ((boot[i] == BOOT_DEVICE_IPV4) || (boot[i] == BOOT_DEVICE_IPV6)) { network_dev++; } } snprintf(tstr, 3, "%02x", boot[i]); #pragma GCC diagnostic push // avoid the following compililatin error // error: '__builtin___strncat_chk' output may be truncated copying 3 bytes from a string of length 9 [-Werror=stringop-truncation] // // per https://stackoverflow.com/questions/50198319/gcc-8-wstringop-truncation-what-is-the-good-practice // this warning was was added in gcc8 // // here we do want to truncate the string #pragma GCC diagnostic ignored "-Wstringop-truncation" strncat(str, tstr, 3); #pragma GCC diagnostic pop } //not allow having more than 1 network boot device in the boot order if ( network_dev > 1 ) { syslog(LOG_WARNING, "Not allow having more than 1 network boot device in the boot order"); ret = CC_INVALID_PARAM; goto error_exit; } sprintf(key, BOOR_ORDER_STR, slot_id); ret = pal_set_key_value(key, str); error_exit: return ret; } int pal_set_ppin_info(uint8_t slot, uint8_t *req_data, uint8_t req_len, uint8_t *res_data, uint8_t *res_len) { char key[MAX_KEY_LEN]; char str[MAX_VALUE_LEN] = {0}; char tstr[8]; int i, comp_code = CC_UNSPECIFIED_ERROR; *res_len = 0; for (i = 0; i < SIZE_CPU_PPIN; i++) { sprintf(tstr, "%02x", req_data[i]); strcat(str, tstr); } sprintf(key, "slot%u_cpu_ppin", slot); if (!pal_set_key_value(key, str)) { comp_code = CC_SUCCESS; } return comp_code; } int pal_get_80port_record(uint8_t slot_id, uint8_t *res_data, size_t max_len, size_t *res_len) { int ret; uint8_t status; uint8_t len; ret = fby3_common_check_slot_id(slot_id); if (ret < 0 ) { ret = PAL_ENOTSUP; goto error_exit; } ret = pal_is_fru_prsnt(slot_id, &status); if ( ret < 0 || status == 0 ) { ret = PAL_ENOTREADY; goto error_exit; } ret = pal_get_server_12v_power(slot_id, &status); if(ret < 0 || SERVER_12V_OFF == status) { ret = PAL_ENOTREADY; goto error_exit; } // Send command to get 80 port record from Bridge IC ret = bic_get_80port_record(slot_id, res_data, &len, NONE_INTF); if (ret == 0) *res_len = (size_t)len; error_exit: return ret; } int pal_set_fw_update_ongoing(uint8_t fruid, uint16_t tmout) { static uint8_t bmc_location = 0; static bool is_called = false; uint8_t slot = fruid; // get the location if ( (bmc_location == 0) && (fby3_common_get_bmc_location(&bmc_location) < 0) ) { syslog(LOG_WARNING, "%s() Cannot get the location of BMC", __func__); return PAL_ENOTSUP; } if ( is_called == true ) return PAL_EOK; // postprocess function // the destructor in fw-util(system.cpp) will call set_update_ongoing twice // add the flag to avoid running it again if ( tmout == 0 ) { sleep(3); is_called = true; } if (pal_is_cwc() == PAL_EOK) { pal_get_fru_slot(fruid, &slot); } // set fw_update_ongoing flag if ( _set_fw_update_ongoing(slot, tmout) < 0 ) { printf("Failed to set fw update ongoing\n"); return PAL_ENOTSUP; } // preprocess function if ( tmout > 0 ) { // when fw_update_ongoing is set, need to wait for a while // make sure all daemons pending by pal_is_fw_update_ongoing if (pal_is_cwc() == PAL_EOK) { sleep(15); } else { sleep(5); } } // set pwr_lock_flag to prevent unexpected power control if ( (bmc_location == NIC_BMC) && \ (bic_set_crit_act_flag((tmout > 0)?SEL_ASSERT:SEL_DEASSERT) < 0) ) { printf("Failed to set power lock, dir_type = %s\n", (tmout > 0)?"ASSERT":"DEASSERT"); return PAL_ENOTSUP; } return PAL_EOK; } bool pal_get_crit_act_status(int fd) { #define SB_CPLD_PWR_LOCK_REGISTER 0x10 int ret = PAL_EOK; uint8_t tbuf = SB_CPLD_PWR_LOCK_REGISTER; uint8_t rbuf = 0x0; uint8_t tlen = 1; uint8_t rlen = 1; uint8_t retry = MAX_READ_RETRY; do { ret = i2c_rdwr_msg_transfer(fd, CPLD_ADDRESS, &tbuf, tlen, &rbuf, rlen); if ( ret < 0 ) msleep(100); else break; } while( retry-- > 0 ); if ( ret < 0 ) { syslog(LOG_WARNING, "%s() Failed to do I2C Rd/Wr, something went wrong?", __func__); rbuf = 1; // If something went wrong, don't lock the power or users can't run sled-cycle } return (rbuf == 0); // rbuf == 0 means power lock flag is asserted; } // for class 2 only bool pal_is_fan_manual_mode(uint8_t slot_id) { char value[MAX_VALUE_LEN] = {0}; int ret = kv_get("fan_manual", value, NULL, 0); if (ret < 0) { // return false because there is no critical activity in progress if (errno == ENOENT) { return false; } syslog(LOG_WARNING, "%s() Cannot get fan_manual", __func__); return true; } return (strncmp(value, "1", 1) == 0)?true:false; } bool pal_is_fw_update_ongoing(uint8_t fruid) { uint8_t slot = fruid; if (pal_is_cwc() == PAL_EOK) { pal_get_fru_slot(fruid, &slot); } return bic_is_fw_update_ongoing(slot); } int pal_set_sysfw_ver(uint8_t slot, uint8_t *ver) { int i; char key[MAX_KEY_LEN] = {0}; char str[MAX_VALUE_LEN] = {0}; char tstr[10] = {0}; sprintf(key, SYSFW_VER_STR, (int) slot); for (i = 0; i < SIZE_SYSFW_VER; i++) { sprintf(tstr, "%02x", ver[i]); strcat(str, tstr); } return pal_set_key_value(key, str); } void pal_update_ts_sled() { char key[MAX_KEY_LEN] = {0}; char tstr[MAX_VALUE_LEN] = {0}; struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); sprintf(tstr, "%ld", ts.tv_sec); sprintf(key, "timestamp_sled"); pal_set_key_value(key, tstr); } int pal_get_platform_name(char *name) { strcpy(name, PLATFORM_NAME); return PAL_EOK; } int pal_get_num_slots(uint8_t *num) { *num = MAX_NODES; return 0; } int pal_get_fru_list(char *list) { strcpy(list, pal_fru_list); return PAL_EOK; } int pal_get_dev_list(uint8_t fru, char *list) { strcpy(list, pal_dev_fru_list); return 0; } int pal_get_fru_capability(uint8_t fru, unsigned int *caps) { int ret = 0; switch (fru) { case FRU_ALL: *caps = FRU_CAPABILITY_SENSOR_HISTORY | FRU_CAPABILITY_SENSOR_READ; break; case FRU_SLOT1: case FRU_SLOT2: case FRU_SLOT3: case FRU_SLOT4: *caps = FRU_CAPABILITY_FRUID_ALL | FRU_CAPABILITY_SENSOR_ALL | FRU_CAPABILITY_SERVER | FRU_CAPABILITY_POWER_ALL | FRU_CAPABILITY_POWER_12V_ALL | FRU_CAPABILITY_HAS_DEVICE; break; case FRU_BMC: *caps = FRU_CAPABILITY_FRUID_ALL | FRU_CAPABILITY_SENSOR_ALL | FRU_CAPABILITY_MANAGEMENT_CONTROLLER; break; case FRU_NIC: *caps = FRU_CAPABILITY_FRUID_READ | FRU_CAPABILITY_SENSOR_ALL | FRU_CAPABILITY_NETWORK_CARD; break; case FRU_NICEXP: *caps = FRU_CAPABILITY_FRUID_ALL | FRU_CAPABILITY_SENSOR_READ; break; case FRU_BB: *caps = FRU_CAPABILITY_FRUID_ALL | FRU_CAPABILITY_SENSOR_READ; break; case FRU_2U: case FRU_2U_SLOT3: *caps = 0; break; case FRU_CWC: if (pal_is_cwc() == PAL_EOK) { *caps = FRU_CAPABILITY_FRUID_ALL | FRU_CAPABILITY_SENSOR_ALL | FRU_CAPABILITY_POWER_ALL; } else { *caps = 0; } break; case FRU_2U_TOP: case FRU_2U_BOT: if (pal_is_cwc() == PAL_EOK) { *caps = FRU_CAPABILITY_FRUID_ALL | FRU_CAPABILITY_HAS_DEVICE | FRU_CAPABILITY_SENSOR_READ | FRU_CAPABILITY_SENSOR_THRESHOLD_UPDATE | FRU_CAPABILITY_POWER_ALL; } else { *caps = 0; } break; default: ret = -1; break; } return ret; } int pal_get_dev_capability(uint8_t fru, uint8_t dev, unsigned int *caps) { if (pal_is_cwc() == PAL_EOK) { if (fru != FRU_SLOT1 && fru != FRU_2U_TOP && fru != FRU_2U_BOT) { return -1; } } else if (fru < FRU_SLOT1 || fru > FRU_SLOT4) { return -1; } if (dev >= DEV_ID0_1OU && dev <= DEV_ID13_2OU) { *caps = FRU_CAPABILITY_FRUID_ALL | FRU_CAPABILITY_SENSOR_ALL | (FRU_CAPABILITY_POWER_ALL & (~FRU_CAPABILITY_POWER_RESET)); } else if (dev >= BOARD_1OU && dev <= BOARD_2OU) { *caps = FRU_CAPABILITY_FRUID_ALL | FRU_CAPABILITY_SENSOR_ALL; } else if (dev >= BOARD_2OU_TOP && dev <= BOARD_2OU_CWC) { if (pal_is_cwc() == PAL_EOK) { *caps = FRU_CAPABILITY_FRUID_ALL | FRU_CAPABILITY_SENSOR_ALL; } else { *caps = 0; } } else { *caps = 0; } return 0; } int pal_get_board_id(uint8_t slot, uint8_t *req_data, uint8_t req_len, uint8_t *res_data, uint8_t *res_len) { int ret; uint8_t *data = res_data; uint8_t bmc_location = 0; //the value of bmc_location is board id. *res_len = 0; ret = fby3_common_get_bmc_location(&bmc_location); if ( ret < 0 ) { syslog(LOG_WARNING, "%s() Cannot get the location of BMC", __func__); return CC_UNSPECIFIED_ERROR; } *data++ = bmc_location; if ( (bmc_location == BB_BMC) || (bmc_location == DVT_BB_BMC) ) { uint8_t bb_rev = 0x00; ret = fby3_common_get_bb_board_rev(&bb_rev); if (ret) { *data++ = 0x00; //board rev id } else { *data++ = bb_rev; //board rev id } } else { // Config C can not get rev id form NIC EXP CPLD so far *data++ = 0x00; //board rev id } *data++ = slot; //slot id *data++ = 0x00; //slot type. server = 0x00 *res_len = data - res_data; return CC_SUCCESS; } int pal_get_slot_index(unsigned char payload_id) { uint8_t bmc_location = 0; uint8_t slot_index = 0; uint8_t tbuf[16] = {0}; uint8_t rbuf[16] = {0}; uint8_t tlen = 0; uint8_t rlen = 0; int ret = -1; ret = fby3_common_get_bmc_location(&bmc_location); if ( ret < 0 ) { syslog(LOG_WARNING, "%s() Cannot get the location of BMC", __func__); return payload_id; } if ( bmc_location == NIC_BMC ) { ret = bic_ipmb_send(payload_id, NETFN_OEM_REQ, 0xF0, tbuf, tlen, rbuf, &rlen, BB_BIC_INTF); if (ret) { return payload_id; } else { slot_index = rbuf[0]; return slot_index; } } else { return payload_id; } } int pal_is_fru_prsnt(uint8_t fru, uint8_t *status) { int ret = PAL_EOK; int val = 0; uint8_t bmc_location = 0, board_type = 0; ret = fby3_common_get_bmc_location(&bmc_location); if ( ret < 0 ) { syslog(LOG_WARNING, "%s() Cannot get the location of BMC", __func__); return ret; } if ( bmc_location == NIC_BMC ) { if (fby3_common_get_2ou_board_type(FRU_SLOT1, &board_type) < 0) { syslog(LOG_WARNING, "Failed to get slot1 2ou board type\n"); } } switch (fru) { case FRU_SLOT1: case FRU_SLOT2: case FRU_SLOT3: case FRU_SLOT4: if ( (bmc_location == BB_BMC) || (bmc_location == DVT_BB_BMC) ) { ret = fby3_common_is_fru_prsnt(fru, status); } else { if ( fru == FRU_SLOT1 ) { *status = 1; } else { *status = 0; } } break; case FRU_BB: *status = 1; break; case FRU_NICEXP: *status = (bmc_location == NIC_BMC)?1:0; break; case FRU_NIC: *status = 1; break; case FRU_BMC: *status = 1; break; case FRU_2U: if (board_type == GPV3_MCHP_BOARD || board_type == GPV3_BRCM_BOARD) { *status = 1; } else { *status = 0; } break; case FRU_CWC: if (board_type == CWC_MCHP_BOARD) { *status = 1; } else { *status = 0; } break; case FRU_2U_TOP: case FRU_2U_BOT: if (board_type == CWC_MCHP_BOARD) { if ((val = bic_is_2u_top_bot_prsnt(FRU_SLOT1)) > 0) { if ((fru == FRU_2U_TOP && (val & PRESENT_2U_TOP)) || (fru == FRU_2U_BOT && (val & PRESENT_2U_BOT))) { *status = 1; } else { *status = 0; } } else { *status = 0; } } else { *status = 0; } break; case FRU_2U_SLOT3: *status = 0; break; default: *status = 0; syslog(LOG_WARNING, "%s() wrong fru id 0x%02x", __func__, fru); ret = PAL_ENOTSUP; } return ret; } int pal_get_fru_id(char *str, uint8_t *fru) { int ret = 0; ret = fby3_common_get_fru_id(str, fru); if ( ret < 0 ) { syslog(LOG_WARNING, "%s() wrong fru %s", __func__, str); return -1; } return ret; } int pal_get_fruid_name(uint8_t fru, char *name) { return fby3_get_fruid_name(fru, name); } int pal_get_fru_name(uint8_t fru, char *name) { int ret = 0; uint8_t bmc_location = 0; ret = fby3_common_get_bmc_location(&bmc_location); if ( ret < 0 ) { syslog(LOG_WARNING, "%s() Cannot get the location of BMC", __func__); return ret; } switch(fru) { case FRU_ALL: sprintf(name, "all"); break; case FRU_SLOT1: sprintf(name, "slot1"); break; case FRU_SLOT2: sprintf(name, "slot2"); break; case FRU_SLOT3: sprintf(name, "slot3"); break; case FRU_SLOT4: sprintf(name, "slot4"); break; case FRU_BMC: sprintf(name, "bmc"); break; case FRU_NIC: sprintf(name, "nic"); break; case FRU_BB: sprintf(name, "bb"); break; case FRU_NICEXP: sprintf(name, "nicexp"); break; case FRU_2U: sprintf(name, "slot1-2U"); break; case FRU_CWC: sprintf(name, "slot1-2U-exp"); break; case FRU_2U_TOP: sprintf(name, "slot1-2U-top"); break; case FRU_2U_BOT: sprintf(name, "slot1-2U-bot"); break; case FRU_2U_SLOT3: sprintf(name, "slot3-2U"); break; case FRU_AGGREGATE: ret = PAL_EOK; //it's the virtual FRU. break; default: syslog(LOG_WARNING, "%s() unknown fruid %d", __func__, fru); ret = PAL_ENOTSUP; } return ret; } int pal_get_fruid_eeprom_path(uint8_t fru, char *path) { int ret = 0; uint8_t bmc_location = 0; uint8_t fru_bus = 0; ret = fby3_common_get_bmc_location(&bmc_location); if ( ret < 0 ) { syslog(LOG_WARNING, "%s() Cannot get the location of BMC", __func__); return ret; } switch(fru) { case FRU_BMC: if ( (bmc_location == BB_BMC) || (bmc_location == DVT_BB_BMC) ) { fru_bus = CLASS1_FRU_BUS; } else { fru_bus = CLASS2_FRU_BUS; } sprintf(path, EEPROM_PATH, fru_bus, BMC_FRU_ADDR); break; case FRU_BB: if ( bmc_location == NIC_BMC ) { //The FRU of baseboard is owned by BIC on class 2. //And so, there is no eeprom path. ret = PAL_ENOTSUP; } else { sprintf(path, EEPROM_PATH, CLASS1_FRU_BUS, BB_FRU_ADDR); } break; case FRU_NICEXP: sprintf(path, EEPROM_PATH, CLASS2_FRU_BUS, NICEXP_FRU_ADDR); break; case FRU_NIC: sprintf(path, EEPROM_PATH, NIC_FRU_BUS, NIC_FRU_ADDR); break; default: ret = PAL_ENOTSUP; } return ret; } int pal_get_fruid_path(uint8_t fru, char *path) { char fname[16] = {0}; int ret = 0; uint8_t bmc_location = 0; ret = fby3_common_get_bmc_location(&bmc_location); if ( ret < 0 ) { syslog(LOG_WARNING, "%s() Cannot get the location of BMC", __func__); return ret; } switch(fru) { case FRU_SLOT1: sprintf(fname, "slot1"); break; case FRU_SLOT2: sprintf(fname, "slot2"); break; case FRU_SLOT3: sprintf(fname, "slot3"); break; case FRU_SLOT4: sprintf(fname, "slot4"); break; case FRU_BMC: sprintf(fname, "bmc"); break; case FRU_NIC: sprintf(fname, "nic"); break; case FRU_BB: sprintf(fname, "bb"); break; case FRU_NICEXP: sprintf(fname, "nicexp"); break; case FRU_CWC: sprintf(fname, "2U-cwc"); break; case FRU_2U_TOP: sprintf(fname, "2U-top"); break; case FRU_2U_BOT: sprintf(fname, "2U-bot"); break; default: syslog(LOG_WARNING, "%s() unknown fruid %d", __func__, fru); ret = PAL_ENOTSUP; } if ( ret != PAL_ENOTSUP ) { sprintf(path, "/tmp/fruid_%s.bin", fname); } return ret; } int pal_fruid_write(uint8_t fru, char *path) { if (fru == FRU_NIC) { syslog(LOG_WARNING, "%s() nic is not supported", __func__); return PAL_ENOTSUP; } else if (fru == FRU_BB) { return bic_write_fruid(FRU_SLOT1, 0, path, BB_BIC_INTF); } else if (fru == FRU_CWC) { return bic_write_fruid(FRU_SLOT1, 0, path, REXP_BIC_INTF); } else if (fru == FRU_2U_TOP) { return bic_write_fruid(FRU_SLOT1, 0, path, RREXP_BIC_INTF1); } else if (fru == FRU_2U_BOT) { return bic_write_fruid(FRU_SLOT1, 0, path, RREXP_BIC_INTF2); } return bic_write_fruid(fru, 0, path, NONE_INTF); } int pal_dev_fruid_write(uint8_t fru, uint8_t dev_id, char *path) { int ret = PAL_ENOTSUP; uint8_t config_status = 0; uint8_t bmc_location = 0; uint8_t type_2ou = UNKNOWN_BOARD; uint8_t slot = (fru == FRU_2U_TOP || fru == FRU_2U_BOT) ? FRU_SLOT1 : fru; ret = fby3_common_get_bmc_location(&bmc_location); if ( ret < 0 ) { printf("%s() Couldn't get the location of BMC\n", __func__); return ret; } ret = bic_is_m2_exp_prsnt(slot); if ( ret < 0 ) { printf("%s() Couldn't get the status of 1OU/2OU\n", __func__); return ret; } config_status = (uint8_t) ret; if ( (dev_id == BOARD_1OU) && ((config_status & PRESENT_1OU) == PRESENT_1OU) && (bmc_location != NIC_BMC) ) { // 1U return bic_write_fruid(fru, 0, path, FEXP_BIC_INTF); } else if ( (config_status & PRESENT_2OU) == PRESENT_2OU ) { if ( fby3_common_get_2ou_board_type(slot, &type_2ou) < 0 ) { syslog(LOG_WARNING, "%s() Failed to get 2OU board type\n", __func__); } if ( dev_id == BOARD_2OU && type_2ou == DP_RISER_BOARD ) { return bic_write_fruid(fru, 1, path, NONE_INTF); } else if ( dev_id == BOARD_2OU && type_2ou != CWC_MCHP_BOARD ) { return bic_write_fruid(fru, 0, path, REXP_BIC_INTF); } else if ( dev_id >= DEV_ID0_2OU && dev_id <= DEV_ID11_2OU ) { // BMC shouldn't have the access to write the FRU that belongs to the vendor since we don't know the writing rules // We only have the read access if ( type_2ou != GPV3_MCHP_BOARD && type_2ou != CWC_MCHP_BOARD ) { return bic_write_fruid(fru, dev_id - DEV_ID0_2OU + 1, path, REXP_BIC_INTF); } printf("The device doesn't support the function\n"); } else { printf("The illegal dev%d is detected!\n", dev_id); } // if we reach here, it means something went wrong // normally, we should return in the previous statements ret = PAL_ENOTSUP; } else { printf("%s is not present!\n", (dev_id == BOARD_1OU)?"1OU":"2OU"); return PAL_ENOTSUP; } return ret; } int pal_is_bmc_por(void) { FILE *fp; int por = 0; fp = fopen("/tmp/ast_por", "r"); if (fp != NULL) { if (fscanf(fp, "%d", &por) != 1) { por = 0; } fclose(fp); } return (por)?1:0; } int pal_get_sysfw_ver(uint8_t slot, uint8_t *ver) { int i; int j = 0; int ret = 0; char key[MAX_KEY_LEN] = {0}; char str[MAX_VALUE_LEN] = {0}; char tstr[4] = {0}; sprintf(key, SYSFW_VER_STR, (int) slot); ret = pal_get_key_value(key, str); if (ret) { syslog(LOG_WARNING, "%s() Failed to run pal_get_key_value. key:%s", __func__, key); ret = PAL_ENOTSUP; goto error_exit; } for (i = 0; i < 2*SIZE_SYSFW_VER; i += 2) { sprintf(tstr, "%c%c\n", str[i], str[i+1]); ver[j++] = strtol(tstr, NULL, 16); } error_exit: return ret; } int pal_is_fru_ready(uint8_t fru, uint8_t *status) { int ret = PAL_EOK; uint8_t bmc_location = 0; uint8_t status_12v = 1; ret = fby3_common_get_bmc_location(&bmc_location); if ( ret < 0 ) { syslog(LOG_WARNING, "%s() Cannot get the location of BMC", __func__); return ret; } switch (fru) { case FRU_SLOT1: case FRU_SLOT2: case FRU_SLOT3: case FRU_SLOT4: case FRU_2U: case FRU_CWC: case FRU_2U_TOP: case FRU_2U_BOT: case FRU_2U_SLOT3: if (fru == FRU_2U ) { fru = FRU_SLOT1; } else if (fru == FRU_2U_SLOT3) { fru = FRU_SLOT3; } ret = pal_get_server_12v_power(fru, &status_12v); if(ret < 0 || status_12v == SERVER_12V_OFF) { *status = 0; } else { *status = 1; } break; case FRU_BB: *status = 1; break; case FRU_NICEXP: *status = (bmc_location == NIC_BMC)?1:0; break; case FRU_NIC: *status = 1; break; case FRU_BMC: *status = 1; break; default: ret = PAL_ENOTSUP; *status = 0; syslog(LOG_WARNING, "%s() wrong fru id 0x%02x", __func__, fru); break; } return ret; } // GUID for System and Device static int pal_get_guid(uint16_t offset, char *guid) { char path[128] = {0}; int fd; uint8_t bmc_location = 0; uint8_t fru_bus = 0; ssize_t bytes_rd; errno = 0; if ( fby3_common_get_bmc_location(&bmc_location) < 0 ) { syslog(LOG_ERR, "%s() Cannot get the location of BMC", __func__); return -1; } if ( (bmc_location == BB_BMC) || (bmc_location == DVT_BB_BMC) ) { fru_bus = CLASS1_FRU_BUS; } else { fru_bus = CLASS2_FRU_BUS; } snprintf(path, sizeof(path), EEPROM_PATH, fru_bus, BB_FRU_ADDR); // check for file presence if (access(path, F_OK)) { syslog(LOG_ERR, "%s() unable to access %s: %s", __func__, path, strerror(errno)); return errno; } fd = open(path, O_RDONLY); if (fd < 0) { syslog(LOG_ERR, "%s() unable to open %s: %s", __func__, path, strerror(errno)); return errno; } lseek(fd, offset, SEEK_SET); bytes_rd = read(fd, guid, GUID_SIZE); if (bytes_rd != GUID_SIZE) { syslog(LOG_ERR, "%s() read from %s failed: %s", __func__, path, strerror(errno)); } if (fd > 0 ) { close(fd); } return errno; } static int pal_set_guid(uint16_t offset, char *guid) { char path[128] = {0}; int fd; uint8_t bmc_location = 0; uint8_t fru_bus = 0; ssize_t bytes_wr; errno = 0; if ( fby3_common_get_bmc_location(&bmc_location) < 0 ) { syslog(LOG_ERR, "%s() Cannot get the location of BMC", __func__); return -1; } if ( (bmc_location == BB_BMC) || (bmc_location == DVT_BB_BMC) ) { fru_bus = CLASS1_FRU_BUS; } else { fru_bus = CLASS2_FRU_BUS; } snprintf(path, sizeof(path), EEPROM_PATH, fru_bus, BB_FRU_ADDR); // check for file presence if (access(path, F_OK)) { syslog(LOG_ERR, "%s() unable to open %s: %s", __func__, path, strerror(errno)); return errno; } fd = open(path, O_WRONLY); if (fd < 0) { syslog(LOG_ERR, "%s() read from %s failed: %s", __func__, path, strerror(errno)); return errno; } lseek(fd, offset, SEEK_SET); bytes_wr = write(fd, guid, GUID_SIZE); if (bytes_wr != GUID_SIZE) { syslog(LOG_ERR, "%s() write to %s failed: %s", __func__, path, strerror(errno)); } close(fd); return errno; } int pal_get_sys_guid(uint8_t fru, char *guid) { if (fru == FRU_SLOT1 || fru == FRU_SLOT2 || fru == FRU_SLOT3 || fru == FRU_SLOT4) { return bic_get_sys_guid(fru, (uint8_t *)guid); } else { return -1; } } int pal_set_sys_guid(uint8_t fru, char *str) { char guid[GUID_SIZE] = {0}; if (fru == FRU_SLOT1 || fru == FRU_SLOT2 || fru == FRU_SLOT3 || fru == FRU_SLOT4) { pal_populate_guid(guid, str); return bic_set_sys_guid(fru, (uint8_t *)guid); } else { return -1; } } int pal_get_dev_guid(uint8_t fru, char *guid) { return pal_get_guid(OFFSET_DEV_GUID, guid); } int pal_set_dev_guid(uint8_t fru, char *str) { char guid[GUID_SIZE] = {0}; pal_populate_guid(guid, str); if (fru == FRU_BMC) { return pal_set_guid(OFFSET_DEV_GUID, guid); } else { return -1; } } bool pal_is_fw_update_ongoing_system(void) { uint8_t i; for (i = 1; i <= MAX_NUM_FRUS; i++) { if (pal_is_fw_update_ongoing(i) == true) return true; } return false; } /* DP Riser bifurcation table ------------------------------------------------- | P3 P2 P1 P0 | Speed ------------------------------------------------- Retimer 1x16 | 0 1 0 0 | x16 (0x08) Retimer 2x8 | 0 0 0 1 | x8 (0x09) Retimer 4x4 | 0 0 0 0 | x4 (0x0A) Others Cards | 1 X X X | x16 (0x08) */ static int pal_get_dp_pcie_config(uint8_t slot_id, uint8_t *pcie_config) { const uint8_t dp_pcie_card_mask = 0x08; uint8_t dp_pcie_conf; if (bic_get_dp_pcie_config(slot_id, &dp_pcie_conf)) { syslog(LOG_ERR, "%s() Cannot get DP PCIE configuration\n", __func__); return -1; } syslog(LOG_INFO, "%s() DP PCIE config: %u\n", __func__, dp_pcie_conf); if (dp_pcie_conf & dp_pcie_card_mask) { // PCIE Card (*pcie_config) = CONFIG_D_DP_X16; } else { // Retimer Card switch(dp_pcie_conf) { case DP_RETIMER_X16: (*pcie_config) = CONFIG_D_DP_X16; break; case DP_RETIMER_X8: (*pcie_config) = CONFIG_D_DP_X8; break; case DP_RETIMER_X4: (*pcie_config) = CONFIG_D_DP_X4; break; default: syslog(LOG_ERR, "%s() Unable to get correct DP PCIE configuration\n", __func__); return -1; } } return 0; } static int pal_get_e1s_pcie_config(uint8_t slot_id, uint8_t *pcie_config) { int retry = 0; int ret = 0; int ssd_count = 0; int i2cfd = -1; uint8_t bus = 0; uint8_t tbuf[2] = {0x05}; uint8_t rbuf[2] = {0}; ret = fby3_common_get_bus_id(slot_id); if ( ret < 0 ) { syslog(LOG_WARNING, "%s() Cannot get the bus with fru%d", __func__, slot_id); return -1; } bus = (uint8_t)ret + 4; i2cfd = i2c_cdev_slave_open(bus, CPLD_ADDRESS >> 1, I2C_SLAVE_FORCE_CLAIM); if ( i2cfd < 0 ) { syslog(LOG_WARNING, "%s() Failed to open bus %d. Err: %s", __func__, bus, strerror(errno)); return -1; } while (retry < 3) { ret = i2c_rdwr_msg_transfer(i2cfd, CPLD_ADDRESS, tbuf, 1, rbuf, 1); if (ret == 0) break; retry++; } if ( ret < 0 ) { syslog(LOG_WARNING, "%s() Failed to do i2c_rdwr_msg_transfer", __func__); return -1; } if ( i2cfd > 0 ) close(i2cfd); for(int i=1; i<=4; i++) { if ( (rbuf[0] & (0x1<<i)) == 0 ) { ssd_count++; } } syslog(LOG_WARNING, "%s() ssd_count: %d", __func__, ssd_count); if (ssd_count >= 2) { *pcie_config = CONFIG_B_E1S_T3; } else { *pcie_config = CONFIG_B_E1S_T10; } return 0; } int pal_get_m2_config(uint8_t fru, uint8_t *config) { uint8_t tbuf[8] = {0x9c, 0x9c, 0x00, 0x00}; uint8_t rbuf[8] = {0}; uint8_t tlen = 4; uint8_t rlen = 0; uint8_t intf = 0; int ret = -1; switch (fru) { case FRU_2U: case FRU_CWC: intf = REXP_BIC_INTF; break; case FRU_2U_TOP: intf = RREXP_BIC_INTF1; break; case FRU_2U_BOT: intf = RREXP_BIC_INTF2; break; default: return -1; } ret = bic_ipmb_send(FRU_SLOT1, NETFN_OEM_1S_REQ, 0x66, tbuf, tlen, rbuf, &rlen, intf); if (ret == 0 && rlen == 4) { if (rbuf[3] == 0x08) { *config = CONFIG_C_CWC_SINGLE; } else if (rbuf[3] == 0x04) { *config = CONFIG_C_CWC_DUAL; } else { return -1; } } return ret; } int pal_get_poss_pcie_config(uint8_t slot, uint8_t *req_data, uint8_t req_len, uint8_t *res_data, uint8_t *res_len) { uint8_t pcie_conf = 0xff; uint8_t *data = res_data; int ret = 0, config_status = 0; uint8_t bmc_location = 0; uint8_t type_1ou = 0; uint8_t type_2ou = UNKNOWN_BOARD; ret = fby3_common_get_bmc_location(&bmc_location); if (ret < 0) { syslog(LOG_ERR, "%s() Cannot get the location of BMC", __func__); return -1; } config_status = bic_is_m2_exp_prsnt(slot); if ( (config_status & PRESENT_2OU) == PRESENT_2OU ) { //check if GPv3 is installed if ( fby3_common_get_2ou_board_type(slot, &type_2ou) < 0 ) { syslog(LOG_WARNING, "%s() Failed to get 2OU board type\n", __func__); } } if ( (bmc_location == BB_BMC) || (bmc_location == DVT_BB_BMC) ) { if ( type_2ou == GPV3_MCHP_BOARD || type_2ou == GPV3_BRCM_BOARD ) { pcie_conf = CONFIG_D_GPV3; } else if (type_2ou == DP_RISER_BOARD) { if (pal_get_dp_pcie_config(slot, &pcie_conf)) { // Unable to get correct DP PCIE configuration pcie_conf = CONFIG_UNKNOWN; } syslog(LOG_INFO, "%s() pcie_conf = %u\n", __func__, pcie_conf); } else if (config_status == 0) { pcie_conf = CONFIG_A; } else if (config_status == 1) { bic_get_1ou_type(slot, &type_1ou); if (type_1ou == EDSFF_1U) { if (pal_get_e1s_pcie_config(slot, &pcie_conf)) { // Unable to get correct PCIE configuration pcie_conf = CONFIG_B_E1S_T10; } syslog(LOG_INFO, "%s() pcie_conf = %02X\n", __func__, pcie_conf); } else { pcie_conf = CONFIG_B; } } else if (config_status == 3) { pcie_conf = CONFIG_D; } else { pcie_conf = CONFIG_B; } } else { if ( type_2ou == GPV3_MCHP_BOARD || type_2ou == GPV3_BRCM_BOARD ) { pcie_conf = CONFIG_C_GPV3; } else if ( type_2ou == CWC_MCHP_BOARD ) { if (pal_get_m2_config(FRU_2U_TOP, &pcie_conf) != 0) { pcie_conf = CONFIG_C_CWC_SINGLE; syslog(LOG_WARNING, "%s() fail to get pcie_conf, set default value = %02X\n", __func__, pcie_conf); } } else { pcie_conf = CONFIG_C; } } *data++ = pcie_conf; *res_len = data - res_data; return ret; } int pal_is_slot_server(uint8_t fru) { if ( SERVER_TYPE_DL == fby3_common_get_slot_type(fru) ) { return 1; } return 0; } int pal_is_cmd_valid(uint8_t *data) { uint8_t bus_num = ((data[0] & 0x7E) >> 1); //extend bit[7:1] for bus ID; uint8_t address = data[1]; // protect slot1,2,3,4 BIC if ( address == 0x40 && bus_num >= 0 && bus_num <= 3) { return -1; } return PAL_EOK; } static int pal_get_custom_event_sensor_name(uint8_t fru, uint8_t sensor_num, char *name) { int ret = PAL_EOK; uint8_t board_type = 0; switch(fru) { case FRU_SLOT1: case FRU_SLOT2: case FRU_SLOT3: case FRU_SLOT4: switch(sensor_num) { case BIC_SENSOR_VRHOT: sprintf(name, "VR_HOT"); break; case BIC_SENSOR_SYSTEM_STATUS: sprintf(name, "SYSTEM_STATUS"); break; case ME_SENSOR_SMART_CLST: sprintf(name, "SmaRT&CLST"); break; case BIC_SENSOR_PROC_FAIL: sprintf(name, "PROC_FAIL"); break; case BIC_SENSOR_SSD_HOT_PLUG: if (fby3_common_get_2ou_board_type(fru, &board_type) < 0) { syslog(LOG_ERR, "%s() Cannot get board_type", __func__); board_type = M2_BOARD; } if (board_type == E1S_BOARD) { snprintf(name, MAX_SNR_NAME, "E1S_NOT_PRESENT"); } else { snprintf(name, MAX_SNR_NAME, "SSD_HOT_PLUG"); } break; case BB_BIC_SENSOR_POWER_DETECT: sprintf(name, "POWER_DETECT"); break; case BB_BIC_SENSOR_BUTTON_DETECT: sprintf(name, "BUTTON_DETECT"); break; default: sprintf(name, "Unknown"); ret = PAL_ENOTSUP; break; } break; default: sprintf(name, "Unknown"); ret = PAL_ENOTSUP; break; } return ret; } int 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]; switch (snr_type) { // If SNR_TYPE is OS_BOOT, sensor name is OS case OS_BOOT: // OS_BOOT used by OS sprintf(name, "OS"); return PAL_EOK; default: if ( pal_get_custom_event_sensor_name(fru, snr_num, name) == PAL_EOK ) { return PAL_EOK; } } // Otherwise, translate it based on snr_num return pal_get_x86_event_sensor_name(fru, snr_num, name); } static int pal_parse_proc_fail(uint8_t fru, uint8_t *event_data, char *error_log) { enum { FRB3 = 0x04, }; switch(event_data[0]) { case FRB3: strcat(error_log, "FRB3, "); break; default: strcat(error_log, "Undefined data, "); break; } return PAL_EOK; } static int pal_parse_smart_clst_event(uint8_t fru, uint8_t *event_data, char *error_log) { enum { /* 00h - transition to OK 01h - transition to noncritical from OK 02h - transition to critical from less severe 03h - transition to unrecoverable from less severe 04h - transition to noncritical from more severe 05h - transition to critical from unrecoverable 06h - transition to unrecoverable 07h - monitor 08h - informational*/ TRANS_TO_OK = 0x00, TRANS_TO_NON_CRIT_FROM_OK = 0x01, TRANS_TO_CRIT_FROM_LESS_SEVERE = 0x02, TRANS_TO_UNR_FROM_LESS_SEVERE = 0x03, TRANS_TO_NCR_FROM_MORE_SEVERE = 0x04, TRANS_TO_CRIT_FROM_UNR = 0x05, TRANS_TO_UNR = 0x06, MONITOR = 0x07, INFORMATIONAL = 0x08, /* 0h – State Deasserted (throttling released) 1h – State Asserted (throttling enforced) */ THROTTLING_RELEASED = 0x00, THROTTLING_ENFORCED = 0x01, }; uint8_t code = (event_data[0] & 0x1); uint8_t severity = (event_data[1] >> 4) & 0x0f; const uint8_t ME_FW_ASSERTION[3] = {0x61, 0x2F, 0x00}; //612F00h is a special case. it just displays the ME FW assertion. //handle the special case if ( memcmp(event_data, (uint8_t *)&ME_FW_ASSERTION, 3) == 0 ) { strcat(error_log, "Management Engine FW"); return PAL_EOK; } switch(code) { case THROTTLING_RELEASED: strcat(error_log, "Throttling released, "); break; case THROTTLING_ENFORCED: strcat(error_log, "Throttling enforced, "); break; default: strcat(error_log, "Undefined data, "); break; } switch (severity) { case TRANS_TO_OK: strcat(error_log, "Transition to OK"); break; case TRANS_TO_NON_CRIT_FROM_OK: strcat(error_log, "Transition to noncritical from OK"); break; case TRANS_TO_CRIT_FROM_LESS_SEVERE: strcat(error_log, "Transition to critical from less severe"); break; case TRANS_TO_UNR_FROM_LESS_SEVERE: strcat(error_log, "Transition to unrecoverable from less severe"); break; case TRANS_TO_NCR_FROM_MORE_SEVERE: strcat(error_log, "Transition to noncritical from more severe"); break; case TRANS_TO_CRIT_FROM_UNR: strcat(error_log, "Transition to critical from unrecoverable"); break; case TRANS_TO_UNR: strcat(error_log, "Transition to unrecoverable"); break; case MONITOR: strcat(error_log, "Monitor"); break; case INFORMATIONAL: strcat(error_log, "Informational"); break; default: strcat(error_log, "Undefined severity"); break; } return PAL_EOK; } static int pal_parse_vr_event(uint8_t fru, uint8_t *event_data, char *error_log) { enum { VCCIN_VRHOT = 0x00, VCCIO_VRHOT = 0x01, DIMM_ABC_VRHOT = 0x02, DIMM_DEF_VRHOT = 0x03, }; uint8_t event = event_data[0]; switch (event) { case VCCIN_VRHOT: strcat(error_log, "CPU VCCIN VR HOT Warning"); break; case VCCIO_VRHOT: strcat(error_log, "CPU VCCIO VR HOT Warning"); break; case DIMM_ABC_VRHOT: strcat(error_log, "DIMM ABC Memory VR HOT Warning"); break; case DIMM_DEF_VRHOT: strcat(error_log, "DIMM DEF Memory VR HOT Warning"); break; default: strcat(error_log, "Undefined VR event"); break; } return PAL_EOK; } uint8_t pal_get_gpv3_cfg() { char value[MAX_VALUE_LEN] = {0}; int ret = PAL_ENOTSUP; static uint8_t cfg = 0; if ( cfg == 0 ) { ret = kv_get("gpv3_cfg", value, NULL, 0); if ( ret < 0 ) { syslog(LOG_WARNING, "Failed to get gpv3_cfg\n"); } else cfg = atoi(value); } // return 0 by default return cfg; } static void pal_sel_root_port_mapping_tbl(uint8_t fru, uint8_t *bmc_location, MAPTOSTRING **tbl, uint8_t *cnt) { enum { GPV3_84CH_DUAL = 0x4, GPV3_100CH_DUAL = 0x6, }; uint8_t board_1u = M2_BOARD; uint8_t board_2u = M2_BOARD; uint8_t config_status = CONFIG_UNKNOWN; int ret = 0; size_t tbl_size = 0; do { ret = fby3_common_get_bmc_location(bmc_location); if ( ret < 0 ) { syslog(LOG_WARNING, "%s() Cannot get the location of BMC\n", __func__); break; } ret = bic_is_m2_exp_prsnt(fru); if ( ret < 0 ) { syslog(LOG_WARNING, "%s() Cannot get bic_is_m2_exp_prsnt\n", __func__); break; } else config_status = (uint8_t)ret; // For Config C and D, there are EDSFF_1U, E1S_BOARD and GPv3 architecture // BMC should select the corresponding table. // For Config B and A, root_port_mapping should be selected. // only check it when 1OU is present if ( *bmc_location != NIC_BMC && ((config_status & PRESENT_1OU) == PRESENT_1OU) ) { ret = bic_get_1ou_type(fru, &board_1u); if (ret < 0) { syslog(LOG_ERR, "%s() Cannot get 1ou_board_type\n", __func__); break; } } // only check it when 2OU is present if ( ((config_status & PRESENT_2OU) == PRESENT_2OU) ) { ret = fby3_common_get_2ou_board_type(fru, &board_2u); if (ret < 0) { syslog(LOG_ERR, "%s() Cannot get 2ou_board_type\n", __func__); break; } // get the GPv3 config and provide the corresponding table if ( board_2u == GPV3_MCHP_BOARD || board_2u == CWC_MCHP_BOARD ) { // re-use it config_status = pal_get_gpv3_cfg(); } } } while(0); if ( ret < 0 ) { syslog(LOG_ERR, "%s() Use the default root_port_mapping\n", __func__); board_1u = M2_BOARD; //make sure the default is used board_2u = M2_BOARD; } if ( board_1u == EDSFF_1U || board_2u == E1S_BOARD ) { // case 1/2OU E1S *tbl = root_port_mapping_e1s; tbl_size = sizeof(root_port_mapping_e1s); } else if ( (board_2u == GPV3_MCHP_BOARD || board_2u == GPV3_BRCM_BOARD)) { // case Config C and Config D GPv3 if ( config_status == GPV3_84CH_DUAL || config_status == GPV3_100CH_DUAL ) { *tbl = root_port_mapping_2u_dual_m2_gpv3; tbl_size = sizeof(root_port_mapping_2u_dual_m2_gpv3); } else { // single by default *tbl = root_port_mapping_2u_sgl_m2_gpv3; tbl_size = sizeof(root_port_mapping_2u_sgl_m2_gpv3); } } else if ( board_2u == CWC_MCHP_BOARD ) { if ( config_status == GPV3_84CH_DUAL ||config_status == GPV3_100CH_DUAL ) { *tbl = root_port_mapping_4u_dual_m2_gpv3; tbl_size = sizeof(root_port_mapping_4u_dual_m2_gpv3); } else { // single by default *tbl = root_port_mapping_4u_sgl_m2_gpv3; tbl_size = sizeof(root_port_mapping_4u_sgl_m2_gpv3); } } else { *tbl = root_port_mapping; tbl_size = sizeof(root_port_mapping); } *cnt = tbl_size / sizeof(MAPTOSTRING); return; } static void pal_search_pcie_err(uint8_t err1_id, uint8_t err2_id, char **err1_desc, char **err2_desc) { int i = 0; int size = (sizeof(pcie_err_tab)/sizeof(PCIE_ERR_DECODE)); for ( i = 0; i < size; i++ ) { if ( err2_id == pcie_err_tab[i].err_id ) { *err2_desc = malloc(strlen(pcie_err_tab[i].err_descr)+ERROR_ID_LOG_LEN+2); sprintf(*err2_desc, ", ErrID2: 0x%02X(%s)",err2_id, pcie_err_tab[i].err_descr); continue; } else if ( err1_id == pcie_err_tab[i].err_id ) { *err1_desc = malloc(strlen(pcie_err_tab[i].err_descr)+ERROR_ID_LOG_LEN+2); sprintf(*err1_desc, ", ErrID1: 0x%02X(%s)",err1_id, pcie_err_tab[i].err_descr); continue; } if ( *err1_desc != NULL && *err2_desc != NULL ) { break; } } if (*err2_desc == NULL) { *err2_desc = malloc(ERROR_ID_LOG_LEN); sprintf(*err2_desc,", ErrID2: 0x%02X", err2_id); } if (*err1_desc == NULL) { *err1_desc = malloc(ERROR_ID_LOG_LEN); sprintf(*err1_desc,", ErrID1: 0x%02X", err1_id); } return; } static bool pal_search_pcie_dev(MAPTOSTRING *tbl, int size, uint8_t bmc_location, uint8_t dev, uint8_t bus, char **sil, char **location) { int i = 0; for ( i = 0; i < size; i++ ) { // check bus and dev are match if ( (bus == tbl[i].bus_value) && \ (dev == tbl[i].dev_value) ) { *location = tbl[i].location; // 1OU is not expected on class 2, skip if ( !strcmp(*location, "1OU") && bmc_location == NIC_BMC ) { continue; } *sil = tbl[i].silk_screen; return true; } } return false; } static void pal_get_pcie_err_string(uint8_t fru, uint8_t *pdata, char **sil, char **location, char **err1_str, char **err2_str) { enum { DMI_DEV = 0x00, DMI_BUS = 0x00, DMI_FUN = 0x00, }; uint8_t bmc_location = 0; uint8_t dev = pdata[0] >> 3; uint8_t fun = pdata[0] & 0x7; uint8_t bus = pdata[1]; uint8_t err1_id = pdata[5]; uint8_t err2_id = pdata[4]; uint8_t size = 0; MAPTOSTRING *mapping_table = NULL; // DMI case bus = 0, dev = 0, fun = 0 if ( dev == DMI_DEV && bus == DMI_BUS && fun == DMI_FUN ) { *location = "SB"; *sil = "DMI"; } else { // get the table first pal_sel_root_port_mapping_tbl(fru, &bmc_location, &mapping_table, &size); // search for the device table first if ( pal_search_pcie_dev(mapping_table, size, bmc_location, dev, bus, sil, location) == false ) { // if dev is not found in the device table, search for the common table size = sizeof(root_port_common_mapping)/sizeof(MAPTOSTRING); pal_search_pcie_dev(root_port_common_mapping, size, bmc_location, dev, bus, sil, location); } } // parse err pal_search_pcie_err(err1_id, err2_id, err1_str, err2_str); return; } static void pal_get_m2vpp_str_name(uint8_t fru, uint8_t comp, uint8_t root_port, char *error_log) { int i = 0; uint8_t size = 0; uint8_t bmc_location = 0; MAPTOSTRING *mapping_table = NULL; // select root port mapping tbl first pal_sel_root_port_mapping_tbl(fru, &bmc_location, &mapping_table, &size); for ( i = 0 ; i < size; i++ ) { if ( mapping_table[i].root_port == root_port ) { char *silk_screen = mapping_table[i].silk_screen; char *location = mapping_table[i].location; snprintf(error_log, 256, "%s/%s ", location, silk_screen); return; } } if ( i == size ) { snprintf(error_log, 256, "Undefined M2 RootPort %X ", root_port); } return; } static const char* pal_get_board_name(uint8_t comp) { const char *comp_str[8] = {"ServerBoard", "1OU", "2OU", "SPE", "GPv3", "CWC", "TOP GPv3", "BOT GPv3"}; const uint8_t comp_size = ARRAY_SIZE(comp_str); if ( comp < comp_size ) { return comp_str[comp]; } return "Undefined board"; } static const char* pal_get_cwc_dev_str(uint8_t dev) { const char *dev_str[5] = {"P5V", "P3V3_STBY", "P3V3", "P1V8", "P0V84"}; const uint8_t dev_size = ARRAY_SIZE(dev_str); if ( dev < dev_size ) { return dev_str[dev]; } return "Undefined device"; } static void pal_get_m2_str_name(uint8_t event, uint8_t comp, uint8_t device_num, char *error_log) { if ((event == 0x0c || event == 0x15) && comp == 5) { snprintf(error_log, 256, "%s/%s ", pal_get_board_name(comp), pal_get_cwc_dev_str(device_num)); } else { snprintf(error_log, 256, "%s/Num %d ", pal_get_board_name(comp), device_num); } return; } static void pal_get_2ou_pesw_str_name(uint8_t board_id, char *board_name_str) { snprintf(board_name_str, 256, "%s ", pal_get_board_name(board_id)); return; } static void pal_get_2ou_vr_str_name(uint8_t comp, uint8_t vr_num, char *error_log) { const char *vr_list_str[5] = {"P3V3_STBY1", "P3V3_STBY2", "P3V3_STBY3", "P1V8", "PESW VR"}; const char *cwc_vr_list[] = {"PESW VR"}; const char *board = pal_get_board_name(comp); const uint8_t vr_list_size = ARRAY_SIZE(vr_list_str); const uint8_t cwc_vr_list_size = ARRAY_SIZE(cwc_vr_list); if (strcmp(board, "CWC") == 0) { snprintf(error_log, 256, "%s/%s ", board, (vr_num < cwc_vr_list_size)?cwc_vr_list[vr_num]:"Undefined VR"); } else { snprintf(error_log, 256, "%s/%s ", board, (vr_num < vr_list_size)?vr_list_str[vr_num]:"Undefined VR"); } return; } static void pal_get_gpv3_not_present_str_name(uint8_t comp, uint8_t gpv3_name, char *error_log) { const char *gpv3_present_list_str[5] = {"TOP_GPv3_PRESENT1", "TOP_GPv3_PRESENT2", "BOT_GPv3_PRESENT1", "BOT_GPv3_PRESENT2"}; const uint8_t gpv3_present_list_size = ARRAY_SIZE(gpv3_present_list_str); snprintf(error_log, 256, "%s/%s ", pal_get_board_name(comp), (gpv3_name < gpv3_present_list_size)?gpv3_present_list_str[gpv3_name]:"Undefined GPv3"); return; } static void pal_get_pesw_config_str_name(uint8_t board_id, uint8_t pesw_config, char *error_log) { const char *pesw_config_list_str[8] = {"2U GPv3 SINGLE M.2", "2U GPv3 DUAL M.2", "4U CWC", "4U TOP GPv3 DUAL M.2", "4U BOT GPv3 DUAL M.2", "4U TOP GPv3 SINGLE M.2", "4U BOT GPv3 SINGLE M.2","GPv3_HALF_BW_M.2"}; const uint8_t pesw_config_list_size = ARRAY_SIZE(pesw_config_list_str); if (pesw_config == BIC_READ_EEPROM_FAILED ) { snprintf(error_log, 256, "%s/%s ", pal_get_board_name(board_id),"Read EEprom Failed"); } else { snprintf(error_log, 256, "%s ", (pesw_config < pesw_config_list_size)?pesw_config_list_str[pesw_config]:"Undefined" ); } return; } static void pal_get_tlp_timeout_str_name(uint8_t board_id, uint8_t pesw_port_id, char *error_log) { const char *single_gpv3_pesw_port_list_str[16] = {"GPv3 USP0", "Dev0", "Dev1", "Dev2", "Dev3", "Dev4", "Dev5", "Dev6", "Dev7", \ "E1.S 0", "GPv3 USP1", "Dev8", "Dev9", "Dev10", "Dev11", "E1.S 1"}; const char *dual_gpv3_pesw_port_list_str[10] = {"GPv3 USP0", "Dev0_1", "Dev2_3", "Dev4_5", "Dev6_7", "E1.S 0", "GPv3 USP1", "Dev8_9", \ "Dev10_11", "E1.S 1"}; const char *cwc_pesw_port_list_str[6] = {"CWC USP0", "TOP GPv3 USP0", "BOT GPv3 USP0", "CWC USP1", "TOP GPv3 USP1", "BOT GPv3 USP1"}; const uint8_t single_gpv3_pesw_port_list_size = ARRAY_SIZE(single_gpv3_pesw_port_list_str); const uint8_t dual_gpv3_pesw_port_list_size = ARRAY_SIZE(dual_gpv3_pesw_port_list_str); const uint8_t cwc_pesw_port_list_size = ARRAY_SIZE(cwc_pesw_port_list_str); enum { GPv3 = 0x04, CWC = 0x05, TOP_GPv3 = 0x06, BOT_GPv3 = 0x07, }; uint8_t pcie_config = 0xff; switch(board_id) { case GPv3: if (pal_get_m2_config(FRU_2U, &pcie_config) != 0) { return; } break; case TOP_GPv3: if (pal_get_m2_config(FRU_2U_TOP, &pcie_config) != 0) { return; } break; case BOT_GPv3: if (pal_get_m2_config(FRU_2U_BOT, &pcie_config) != 0) { return; } break; case CWC: snprintf(error_log, MAX_ERR_LOG_SIZE, "%s/%s ", pal_get_board_name(board_id), \ (pesw_port_id < cwc_pesw_port_list_size)?cwc_pesw_port_list_str[pesw_port_id]:"Undefined"); return; default: syslog(LOG_WARNING, "%s() Undefined board id:%u",__func__, board_id); return; } switch(pcie_config) { case CONFIG_C_CWC_SINGLE: snprintf(error_log, MAX_ERR_LOG_SIZE, "%s/%s ", pal_get_board_name(board_id), \ (pesw_port_id < single_gpv3_pesw_port_list_size)?single_gpv3_pesw_port_list_str[pesw_port_id]:"Undefined"); return; case CONFIG_C_CWC_DUAL: snprintf(error_log, MAX_ERR_LOG_SIZE, "%s/%s ", pal_get_board_name(board_id), \ (pesw_port_id < dual_gpv3_pesw_port_list_size)?dual_gpv3_pesw_port_list_str[pesw_port_id]:"Undefined"); return; default: return; } return; } static int pal_parse_sys_sts_event(uint8_t fru, uint8_t *sel, char *error_log) { enum { SYS_THERM_TRIP = 0x00, SYS_FIVR_FAULT = 0x01, SYS_SURGE_CURR = 0x02, SYS_PCH_PROCHOT = 0x03, SYS_UV_DETECT = 0x04, SYS_OC_DETECT = 0x05, SYS_OCP_FAULT_WARN = 0x06, SYS_FW_TRIGGER = 0x07, SYS_HSC_FAULT = 0x08, SYS_RSVD = 0x09, SYS_VR_WDT_TIMEOUT = 0x0A, SYS_M2_VPP = 0x0B, SYS_M2_PGOOD = 0x0C, SYS_VCCIO_FAULT = 0x0D, SYS_SMI_STUCK_LOW = 0x0E, SYS_OV_DETECT = 0x0F, SYS_M2_OCP_DETECT = 0x10, SYS_SLOT_PRSNT = 0x11, SYS_PESW_ERR = 0x12, SYS_2OU_VR_FAULT = 0x13, SYS_GPV3_NOT_PRESENT = 0x14, SYS_PWRGOOD_TIMEOUT = 0x15, SYS_DP_X8_PWR_FAULT = 0x16, SYS_DP_X16_PWR_FAULT = 0x17, SYS_PESW_CONFIG = 0x18, SYS_TLP_TIMEOUT = 0x19, E1S_1OU_M2_PRESENT = 0x80, E1S_1OU_HSC_PWR_ALERT = 0x82, }; uint8_t event_dir = sel[12] & 0x80; uint8_t *event_data = &sel[13]; uint8_t event = event_data[0]; char prsnt_str[32] = {0}; char log_msg[MAX_ERR_LOG_SIZE] = {0}; uint8_t type_2ou = UNKNOWN_BOARD; char cri_sel[128]; switch (event) { case SYS_THERM_TRIP: strcat(error_log, "System thermal trip"); sprintf(cri_sel, "%s - %s", error_log, ((event_dir & 0x80) == 0)?"Assert":"Deassert" ); pal_add_cri_sel(cri_sel); break; case SYS_FIVR_FAULT: strcat(error_log, "System FIVR fault"); break; case SYS_SURGE_CURR: strcat(error_log, "Surge Current Warning"); break; case SYS_PCH_PROCHOT: strcat(error_log, "PCH prochot"); break; case SYS_UV_DETECT: strcat(error_log, "Under Voltage Warning"); sprintf(cri_sel, "CPU FPH by UV - %s",((event_dir & 0x80) == 0)?"Assert":"Deassert" ); pal_add_cri_sel(cri_sel); break; case SYS_OC_DETECT: strcat(error_log, "OC Warning"); sprintf(cri_sel, "CPU FPH by OC - %s",((event_dir & 0x80) == 0)?"Assert":"Deassert" ); pal_add_cri_sel(cri_sel); break; case SYS_OCP_FAULT_WARN: strcat(error_log, "OCP Fault Warning"); sprintf(cri_sel, "CPU FPH by OCP Fault - %s",((event_dir & 0x80) == 0)?"Assert":"Deassert" ); pal_add_cri_sel(cri_sel); break; case SYS_FW_TRIGGER: strcat(error_log, "Firmware"); break; case SYS_HSC_FAULT: strcat(error_log, "HSC fault"); break; case SYS_VR_WDT_TIMEOUT: strcat(error_log, "VR WDT"); break; case SYS_M2_VPP: pal_get_m2vpp_str_name(fru, event_data[1], event_data[2], error_log); strcat(error_log, "VPP Power Control"); break; case SYS_M2_PGOOD: pal_get_m2_str_name(event, event_data[1], event_data[2], error_log); strcat(error_log, "Power Good Fault"); break; case SYS_VCCIO_FAULT: strcat(error_log, "VCCIO fault"); break; case SYS_SMI_STUCK_LOW: strcat(error_log, "SMI stuck low over 90s"); break; case SYS_OV_DETECT: strcat(error_log, "VCCIO Over Voltage Fault"); break; case SYS_M2_OCP_DETECT: pal_get_m2_str_name(event, event_data[1], event_data[2], error_log); strcat(error_log, "INA233 Alert"); break; case SYS_SLOT_PRSNT: snprintf(prsnt_str, sizeof(prsnt_str), "Slot%d present", event_data[1]); strcat(error_log, prsnt_str); break; case SYS_PESW_ERR: pal_get_2ou_pesw_str_name(event_data[1], error_log); strcat(error_log, "2OU PESW error"); break; case SYS_2OU_VR_FAULT: pal_get_2ou_vr_str_name(event_data[1], event_data[2], error_log); strcat(error_log, "2OU VR fault"); break; case SYS_GPV3_NOT_PRESENT: pal_get_gpv3_not_present_str_name(event_data[1], event_data[2], error_log); strcat(error_log, "GPv3 Board Not Present Warning"); break; case SYS_PWRGOOD_TIMEOUT: pal_get_m2_str_name(event, event_data[1], event_data[2], error_log); strcat(error_log, "Power Good Time Out"); break; case SYS_DP_X8_PWR_FAULT: fby3_common_get_2ou_board_type(fru, &type_2ou); if (type_2ou == M2_BOARD) { strcat(error_log, "M.2 Board Power Fault"); } else if (type_2ou == E1S_BOARD) { strcat(error_log, "Sierra Point Board Power Fault"); } else if ((type_2ou == GPV3_MCHP_BOARD) || (type_2ou == GPV3_BRCM_BOARD)) { strcat(error_log, "GPv3 Board Power Fault"); } else if (type_2ou == DP_RISER_BOARD) { strcat(error_log, "DP x8 Riser Power Fault"); } else if (type_2ou == CWC_MCHP_BOARD) { strcat(error_log, "CWC Board Power Fault"); } else { strcat(error_log, "Unknown 2OU Board Power Fault"); } break; case SYS_DP_X16_PWR_FAULT: strcat(error_log, "DP x16 Riser Power Fault"); break; case SYS_PESW_CONFIG: pal_get_pesw_config_str_name(event_data[1], event_data[2], error_log); strcat(error_log, "PESW Config Setting"); break; case SYS_TLP_TIMEOUT: pal_get_tlp_timeout_str_name(event_data[1], event_data[2], error_log); strcat(error_log, "TLP Credit Time Out"); break; case E1S_1OU_HSC_PWR_ALERT: strcat(error_log, "E1S 1OU HSC Power"); break; case E1S_1OU_M2_PRESENT: snprintf(log_msg, sizeof(log_msg), "E1S 1OU M.2 dev%d present", event_data[2]); strcat(error_log, log_msg); break; default: strcat(error_log, "Undefined system event"); break; } return PAL_EOK; } static int pal_parse_ssd_hot_plug_event(uint8_t fru, uint8_t *event_data, char *error_log) { enum { SSD0 = 0x00, SSD1 = 0x01, SSD2 = 0x02, SSD3 = 0x03, SSD4 = 0x04, SSD5 = 0x05, }; uint8_t event = event_data[0]; switch (event) { case SSD0: strcat(error_log, "SSD0"); break; case SSD1: strcat(error_log, "SSD1"); break; case SSD2: strcat(error_log, "SSD2"); break; case SSD3: strcat(error_log, "SSD3"); break; case SSD4: strcat(error_log, "SSD4"); break; case SSD5: strcat(error_log, "SSD5"); break; default: strcat(error_log, "Undefined hot plug event"); break; } return PAL_EOK; } static int pal_parse_pwr_detect_event(uint8_t fru, uint8_t *event_data, char *error_log) { enum { SLED_CYCLE = 0x00, SLOT = 0x01, }; enum { CYCLE_12V = 0x00, ON_12V = 0x01, OFF_12V = 0x02, HOST_RESET = 0x03, }; switch (event_data[0]) { case SLED_CYCLE: strcat(error_log, "SLED_CYCLE by BB BIC"); break; case SLOT: strcat(error_log, "SERVER "); switch (event_data[1]) { case CYCLE_12V: strcat(error_log, "12V CYCLE by BB BIC"); break; case ON_12V: strcat(error_log, "12V ON by BB BIC"); break; case OFF_12V: strcat(error_log, "12V OFF by BB BIC"); break; case HOST_RESET: strcat(error_log, "HOST RESET by LCD DEBUG CARD"); break; default: strcat(error_log, "Undefined Baseboard BIC event"); break; } break; default: strcat(error_log, "Undefined Baseboard BIC event"); break; } return PAL_EOK; } static int pal_parse_button_detect_event(uint8_t fru, uint8_t *event_data, char *error_log) { enum { ADAPTER_BUTTON_BMC_CO_N_R = 0x01, AC_ON_OFF_BTN_SLOT1_N = 0x02, AC_ON_OFF_BTN_SLOT3_N = 0x03, }; switch (event_data[0]) { case ADAPTER_BUTTON_BMC_CO_N_R: strcat(error_log, "ADAPTER_BUTTON_BMC_CO_N_R"); break; case AC_ON_OFF_BTN_SLOT1_N: strcat(error_log, "AC_ON_OFF_BTN_SLOT1_N"); break; case AC_ON_OFF_BTN_SLOT3_N: strcat(error_log, "AC_ON_OFF_BTN_SLOT3_N"); break; default: strcat(error_log, "Undefined Baseboard BIC event"); break; } return PAL_EOK; } int pal_parse_sel(uint8_t fru, uint8_t *sel, char *error_log) { enum { EVENT_TYPE_NOTIF = 0x77, /*IPMI-Table 42-1, Event/Reading Type Code Ranges - OEM specific*/ }; uint8_t snr_num = sel[11]; uint8_t event_dir = sel[12] & 0x80; uint8_t event_type = sel[12] & 0x7f; uint8_t *event_data = &sel[13]; bool unknown_snr = false; error_log[0] = '\0'; switch (snr_num) { case BIC_SENSOR_VRHOT: pal_parse_vr_event(fru, event_data, error_log); break; case BIC_SENSOR_SYSTEM_STATUS: pal_parse_sys_sts_event(fru, sel, error_log); break; case ME_SENSOR_SMART_CLST: pal_parse_smart_clst_event(fru, event_data, error_log); break; case BIC_SENSOR_PROC_FAIL: pal_parse_proc_fail(fru, event_data, error_log); break; case BIC_SENSOR_SSD_HOT_PLUG: pal_parse_ssd_hot_plug_event(fru, event_data, error_log); break; case BB_BIC_SENSOR_POWER_DETECT: pal_parse_pwr_detect_event(fru, event_data, error_log); break; case BB_BIC_SENSOR_BUTTON_DETECT: pal_parse_button_detect_event(fru, event_data, error_log); break; default: unknown_snr = true; break; } if ( unknown_snr == false ) { if ( event_type == EVENT_TYPE_NOTIF ) { strcat(error_log, " Triggered"); } else { strcat(error_log, ((event_dir & 0x80) == 0)?" Assertion":" Deassertion"); } } else { pal_parse_sel_helper(fru, sel, error_log); } return PAL_EOK; } int pal_parse_oem_unified_sel(uint8_t fru, uint8_t *sel, char *error_log) { #define ERROR_LOG_LEN 256 uint8_t general_info = (uint8_t) sel[3]; uint8_t error_type = general_info & 0x0f; uint8_t plat = 0; char temp_log[128] = {0}; error_log[0] = '\0'; char *sil = "NA"; char *location = "NA"; char *err1_descript = NULL, *err2_descript = NULL; switch (error_type) { case UNIFIED_PCIE_ERR: plat = (general_info & 0x10) >> 4; if (plat == 0) { //x86 pal_get_pcie_err_string(fru, &sel[10], &sil, &location, &err1_descript, &err2_descript); snprintf(error_log, ERROR_LOG_LEN, "GeneralInfo: x86/PCIeErr(0x%02X), Bus %02X/Dev %02X/Fun %02X, %s/%s," "TotalErrID1Cnt: 0x%04X", general_info, sel[11], sel[10] >> 3, sel[10] & 0x7, location, sil, ((sel[13]<<8)|sel[12])); if (err2_descript != NULL) { strcat(error_log,err2_descript); free(err2_descript); } if (err1_descript != NULL) { strcat(error_log,err1_descript); free(err1_descript); } } else { snprintf(error_log, ERROR_LOG_LEN, "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, "PCIe Error ,FRU:%u", fru); pal_add_cri_sel(temp_log); return PAL_EOK; } pal_parse_oem_unified_sel_common(fru, sel, error_log); return PAL_EOK; } int pal_oem_unified_sel_handler(uint8_t fru, uint8_t general_info, uint8_t *sel) { char key[MAX_KEY_LEN] = {0}; snprintf(key, MAX_KEY_LEN, SEL_ERROR_STR, fru); sel_error_record[fru-1]++; return pal_set_key_value(key, "0"); } void pal_log_clear(char *fru) { char key[MAX_KEY_LEN] = {0}; uint8_t fru_cnt = 0; int i = 0; if ( strncmp(fru, "slot", 4) == 0 ) { fru_cnt = fru[4] - 0x30; i = fru_cnt; } else if ( strcmp(fru, "all") == 0 ) { fru_cnt = 4; i = 1; } for ( ; ((i <= fru_cnt) && (i != 0)); i++ ) { snprintf(key, MAX_KEY_LEN, SEL_ERROR_STR, i); pal_set_key_value(key, "1"); snprintf(key, MAX_KEY_LEN, SNR_HEALTH_STR, i); pal_set_key_value(key, "1"); sel_error_record[i-1] = 0; } } int pal_is_debug_card_prsnt(uint8_t *status) { int ret = -1; uint8_t bmc_location = 0; int retry = 0; ret = fby3_common_get_bmc_location(&bmc_location); if ( ret < 0 ) { syslog(LOG_WARNING, "%s() Cannot get the location of BMC", __func__); return -1; } if(bmc_location == NIC_BMC) { // when updating firmware, front-paneld should pend to avoid the invalid access if ( pal_is_fw_update_ongoing(FRU_SLOT1) == true || \ bic_is_crit_act_ongoing(FRU_SLOT1) == true ) return PAL_ENOTSUP; uint8_t tbuf[3] = {0x9c, 0x9c, 0x00}; uint8_t rbuf[16] = {0x00}; uint8_t tlen = 3; uint8_t rlen = 1; while (retry < 3) { ret = bic_ipmb_send(FRU_SLOT1, NETFN_OEM_1S_REQ, BIC_CMD_OEM_GET_DBG_PRSNT, tbuf, tlen, rbuf, &rlen, BB_BIC_INTF); if (ret == 0) { break; } retry++; } if (ret != 0) { return -1; } if(rbuf[3] == 0x0) { *status = 1; } else { *status = 0; } } else { gpio_value_t value; gpio_desc_t *gpio = gpio_open_by_shadow(GPIO_OCP_DEBUG_BMC_PRSNT_N); if (!gpio) { return -1; } ret = gpio_get_value(gpio, &value); gpio_close(gpio); if (ret != 0) { return -1; } if (value == 0x0) { *status = 1; } else { *status = 0; } } return 0; } int pal_set_uart_IO_sts(uint8_t slot_id, uint8_t io_sts) { const uint8_t UART_POS_BMC = 0x00; const uint8_t MAX_RETRY = 3; int i2cfd = -1; int ret = PAL_EOK; int retry = MAX_RETRY; int st_idx = slot_id, end_idx = slot_id; uint8_t tbuf[5] = {0x00}; uint8_t rbuf[1] = {0x00}; uint8_t tlen = 2; uint8_t rlen = 0; uint8_t bmc_location = 0; //the value of bmc_location is board id. uint8_t index = 0; ret = fby3_common_get_bmc_location(&bmc_location); if ( ret < 0 ) { syslog(LOG_WARNING, "%s() Cannot get the location of BMC", __func__); return -1; } if (bmc_location == NIC_BMC) { uint8_t bus = 0; //class 2 might have slot1 or slot3 if(bic_get_mb_index(&index) != 0) { return -1; } if(slot_id == UART_POS_BMC) { index = index == FRU_SLOT3 ? FRU_SLOT3 : FRU_SLOT1; } tbuf[0] = (bus << 1) + 1; tbuf[1] = CPLD_ADDRESS; tbuf[2] = 0x00; //read 0 byte tbuf[3] = BB_CPLD_IO_BASE_OFFSET + index; tbuf[4] = io_sts; tlen = 5; rlen = 0; ret = bic_ipmb_send(FRU_SLOT1, NETFN_APP_REQ, CMD_APP_MASTER_WRITE_READ, tbuf, tlen, rbuf, &rlen, BB_BIC_INTF); if (ret != 0) { syslog(LOG_WARNING, "Failed to update IO sts. reg:%02X, data: %02X\n", tbuf[3], tbuf[1]); return ret; } } else { i2cfd = i2c_cdev_slave_open(BB_CPLD_BUS, CPLD_ADDRESS >> 1, I2C_SLAVE_FORCE_CLAIM); if ( i2cfd < 0 ) { syslog(LOG_WARNING, "Failed to open bus 12\n"); return i2cfd; } // adjust the st_idx and end_idx, we need to reset all reg values // when uart_pos is at BMC position if ( slot_id == UART_POS_BMC ) { st_idx = FRU_SLOT1; end_idx = FRU_SLOT4; } do { tbuf[0] = BB_CPLD_IO_BASE_OFFSET + st_idx; //get the corresponding reg tbuf[1] = io_sts; // data to be written ret = i2c_rdwr_msg_transfer(i2cfd, CPLD_ADDRESS, tbuf, tlen, NULL, 0); if ( ret < 0 ) { retry--; } else { st_idx++; //move on retry = MAX_RETRY; //reset it } } while ( retry > 0 && st_idx <= end_idx ); if ( retry == 0 ) { syslog(LOG_WARNING, "Failed to update IO sts after performed 3 time attempts. reg:%02X, data: %02X\n", tbuf[0], tbuf[1]); } if ( i2cfd > 0 ) close(i2cfd); } return ret; } int pal_get_uart_select_from_kv(uint8_t *pos) { char value[MAX_VALUE_LEN] = {0}; uint8_t loc; int ret = -1; ret = kv_get("debug_card_uart_select", value, NULL, 0); if (!ret) { loc = atoi(value); *pos = loc; } return ret; } int pal_get_uart_select_from_cpld(uint8_t *uart_select) { int fd = 0; int retry = 3; int ret = -1; uint8_t tbuf[3] = {0x00}; uint8_t rbuf[4] = {0x00}; uint8_t tlen = 0; uint8_t rlen = 0; uint8_t bmc_location = 0; //the value of bmc_location is board id. ret = fby3_common_get_bmc_location(&bmc_location); if ( ret < 0 ) { syslog(LOG_WARNING, "%s() Cannot get the location of BMC", __func__); return -1; } if(bmc_location == NIC_BMC) { tbuf[0] = 0x9c; tbuf[1] = 0x9c; tbuf[2] = 0x00; tlen = 3; rlen = 1; retry = 0; while (retry < 3) { ret = bic_ipmb_send(FRU_SLOT1, NETFN_OEM_1S_REQ, BIC_CMD_OEM_GET_DBG_UART, tbuf, tlen, rbuf, &rlen, BB_BIC_INTF); if (ret == 0) { break; } retry++; } if (ret != 0) { return -1; } if((rbuf[3] == 0) || (rbuf[3] == 1) || (rbuf[3] == 4)) rbuf[0] = 0; else if((rbuf[3] == 2) || (rbuf[3] == 3) || (rbuf[3] == 5) || (rbuf[3] == 6)) rbuf[0] = 1; else return -1; } else { fd = open("/dev/i2c-12", O_RDWR); if (fd < 0) { syslog(LOG_WARNING, "Failed to open bus 12"); return -1; } tbuf[0] = DEBUG_CARD_UART_MUX; tlen = 1; rlen = 1; while (retry-- > 0) { ret = i2c_rdwr_msg_transfer(fd, CPLD_ADDRESS, tbuf, tlen, rbuf, rlen); if (ret == 0) { break; } } if (fd > 0) { close(fd); } if (ret < 0) { return -1; } } *uart_select = rbuf[0]; return 0; } int pal_post_display(uint8_t uart_select, uint8_t postcode) { int fd = 0; int retry = 3; int ret = -1; uint8_t tlen = 0; uint8_t rlen = 0; uint8_t tbuf[5] = {0x00}; uint8_t rbuf[1] = {0x00}; uint8_t offset = 0; uint8_t bmc_location = 0; //the value of bmc_location is board id. uint8_t index = 0; ret = fby3_common_get_bmc_location(&bmc_location); if ( ret < 0 ) { syslog(LOG_WARNING, "%s() Cannot get the location of BMC", __func__); return -1; } if(bmc_location == NIC_BMC) { uint8_t bus = 0; if(bic_get_mb_index(&index) !=0) return -1; if((uart_select == FRU_SLOT1) && (index == FRU_SLOT3)) offset = SLOT3_POSTCODE_OFFSET; else offset = SLOT1_POSTCODE_OFFSET; tbuf[0] = (bus << 1) + 1; tbuf[1] = CPLD_ADDRESS; tbuf[2] = 0x00; tbuf[3] = offset; // offset 00 tbuf[4] = postcode; tlen = 5; rlen = 0; ret = bic_ipmb_send(FRU_SLOT1, NETFN_APP_REQ, CMD_APP_MASTER_WRITE_READ, tbuf, tlen, rbuf, &rlen, BB_BIC_INTF); if (ret != 0) { return -1; } } else { fd = open("/dev/i2c-12", O_RDWR); if (fd < 0) { syslog(LOG_WARNING, "Failed to open bus 12"); return -1; } switch (uart_select) { case 1: offset = SLOT1_POSTCODE_OFFSET; break; case 2: offset = SLOT2_POSTCODE_OFFSET; break; case 3: offset = SLOT3_POSTCODE_OFFSET; break; case 4: offset = SLOT4_POSTCODE_OFFSET; break; } tbuf[0] = offset; tbuf[1] = postcode; tlen = 2; rlen = 0; do { ret = i2c_rdwr_msg_transfer(fd, CPLD_ADDRESS, tbuf, tlen, rbuf, rlen); } while (ret < 0 && retry-- > 0); if (fd > 0) { close(fd); } } return ret; } // Handle the received post code, display it on debug card int pal_post_handle(uint8_t slot, uint8_t postcode) { uint8_t prsnt = 0; uint8_t uart_select = 0; int ret = -1; // Check for debug card presence ret = pal_is_debug_card_prsnt(&prsnt); if (ret) { return ret; } // No debug card present, return if (prsnt == 0) { return 0; } // Get the UART SELECT from kv, avoid large access CPLD in a short time ret = pal_get_uart_select_from_kv(&uart_select); if (ret) { return ret; } // If the give server is not selected, return if (uart_select != slot) { return 0; } // Display the post code in the debug card ret = pal_post_display(uart_select, postcode); return ret; } static int pal_store_crashdump(uint8_t fru, bool ierr) { uint8_t status; if (!pal_get_server_power(fru, &status) && !status) { syslog(LOG_WARNING, "%s() fru %u is OFF", __func__, fru); return PAL_ENOTSUP; } return fby3_common_crashdump(fru, ierr, false); } static int pal_bic_sel_handler(uint8_t fru, uint8_t snr_num, uint8_t *event_data) { int ret = PAL_EOK; bool is_cri_sel = false; enum { //event_data[3] SLOT = 0x01, }; enum { //event_data[4] HOST_RESET = 0x03, }; switch (snr_num) { case CATERR_B: is_cri_sel = true; pal_store_crashdump(fru, (event_data[3] == 0x00)); // 00h:IERR, 0Bh:MCERR break; case CPU_DIMM_HOT: case PWR_ERR: is_cri_sel = true; break; case BIC_SENSOR_SYSTEM_STATUS: switch(event_data[3]) { // it's not the fault event, filter it // or the amber LED will blink case 0x80: //E1S_1OU_M2_PRESENT case 0x11: //SYS_SLOT_PRSNT case 0x0B: //SYS_M2_VPP case 0x07: //SYS_FW_TRIGGER break; default: is_cri_sel = true; break; } if (event_data[3] == 0x11) { // when another blade insert/remove, start/stop fscd ret = system("/etc/init.d/setup-fan.sh reload &"); if (ret != 0) { syslog(LOG_WARNING, "%s() can not reload setup-fan.sh", __func__); return -1; } } break; case BB_BIC_SENSOR_POWER_DETECT: switch(event_data[3]) { case SLOT: switch(event_data[4]) { case HOST_RESET: //host reset from LCD debug card if (pal_can_change_power(FRU_SLOT1)) { ret = pal_set_server_power(FRU_SLOT1, SERVER_POWER_RESET); if (ret < 0) { syslog(LOG_WARNING, "power_util: pal_set_rst_btn failed for" " fru %u", FRU_SLOT1); } else { syslog(LOG_CRIT, "SERVER_POWER_RESET successful for FRU: %d", FRU_SLOT1); pal_set_restart_cause(FRU_SLOT1, RESTART_CAUSE_RESET_PUSH_BUTTON); } } else { syslog(LOG_WARNING, "Server power can not be reset for FRU: %d", FRU_SLOT1); } break; default: break; } break; default: break; } break; } if ( is_cri_sel == true ) { char key[MAX_KEY_LEN] = {0}; if ( (event_data[2] & 0x80) == 0 ) sel_error_record[fru-1]++; else sel_error_record[fru-1]--; snprintf(key, MAX_KEY_LEN, SEL_ERROR_STR, fru); pal_set_key_value(key, (sel_error_record[fru-1] > 0)?"0":"1"); // 0: Assertion, 1: Deassertion } return PAL_EOK; } int pal_sel_handler(uint8_t fru, uint8_t snr_num, uint8_t *event_data) { int ret = PAL_EOK; switch(fru) { case FRU_SLOT1: case FRU_SLOT2: case FRU_SLOT3: case FRU_SLOT4: ret = pal_bic_sel_handler(fru, snr_num, event_data); break; default: ret = PAL_ENOTSUP; break; } return ret; } int pal_get_dev_id(char *str, uint8_t *dev) { return fby3_common_dev_id(str, dev); } int pal_get_num_devs(uint8_t slot, uint8_t *num) { if (fby3_common_check_slot_id(slot) == 0) { *num = MAX_NUM_DEVS - 1; } else if (pal_is_cwc() == PAL_EOK && (slot == FRU_2U_TOP || slot == FRU_2U_BOT)) { return fby3_common_exp_get_num_devs(slot, num); } else { *num = 0; } return 0; } int pal_get_dev_fruid_name(uint8_t fru, uint8_t dev, char *name) { char temp[64] = {0}; char dev_name[32] = {0}; int ret = pal_get_fruid_name(fru, name); if (ret < 0) { return ret; } switch(fru) { case FRU_SLOT1: case FRU_SLOT2: case FRU_SLOT3: case FRU_SLOT4: fby3_common_dev_name(dev, dev_name); break; case FRU_2U_TOP: case FRU_2U_BOT: fby3_common_exp_dev_name(dev, dev_name); break; default: return -1; } snprintf(temp, sizeof(temp), "%s %s", name, dev_name); strcpy(name, temp); return 0; } int pal_get_dev_name(uint8_t fru, uint8_t dev, char *name) { switch(fru) { case FRU_SLOT1: case FRU_SLOT2: case FRU_SLOT3: case FRU_SLOT4: fby3_common_dev_name(dev, name); break; case FRU_2U_TOP: case FRU_2U_BOT: if (pal_is_cwc() == PAL_EOK) { fby3_common_exp_dev_name(dev, name); } else { return -1; } break; default: return -1; } return 0; } int pal_get_dev_fruid_path(uint8_t fru, uint8_t dev_id, char *path) { return fby3_get_fruid_path(fru, dev_id, path); } int pal_handle_dcmi(uint8_t fru, uint8_t *request, uint8_t req_len, uint8_t *response, uint8_t *rlen) { int ret; uint8_t rbuf[256] = {0x00}, len = 0; ret = bic_me_xmit(fru, request, req_len, rbuf, &len); if (ret || (len < 1)) { return -1; } if (rbuf[0] != 0x00) { return -1; } *rlen = len - 1; memcpy(response, &rbuf[1], *rlen); return 0; } // only for class 2 static int pal_init_fan_mode(uint8_t ctrl_mode) { #define FAN_MANUAL 3 #define FAN_AUTO 6 int ret = PAL_ENOTSUP; uint8_t low_time = 0; // assign low_time if ( AUTO_MODE == ctrl_mode ) low_time = FAN_AUTO; else if ( MANUAL_MODE == ctrl_mode ) low_time = FAN_MANUAL; else { printf("it's not supported, ctrl_mode = %02X\n", ctrl_mode); return ret; } // set crit_act bit and then sleep ret = bic_set_crit_act_flag(SEL_ASSERT); if ( ret < 0 ) { // if we cant notify the other BMC, force to run the mode // because it's just a notification syslog(LOG_WARNING, "Failed to assert crit_act bit"); } else { printf("Setup fan mode control...\n"); // if we want to do something before sleeping, put here sleep (low_time); } // recover the flag if ( ret == PAL_EOK ) { ret = bic_set_crit_act_flag(SEL_DEASSERT); if ( ret < 0 ) { syslog(LOG_WARNING, "Failed to deassert crit_act bit"); } sleep(2); // need to wait for gpiod to be ready } return ret; } int pal_set_fan_ctrl (char *ctrl_opt) { FILE* fp = NULL; uint8_t bmc_location = 0; uint8_t ctrl_mode, status; int ret = 0; char cmd[64] = {0}; char buf[32]; ret = fby3_common_get_bmc_location(&bmc_location); if ( ret < 0 ) { syslog(LOG_WARNING, "%s() Cannot get the location of BMC", __func__); return ret; } // get the option if (!strcmp(ctrl_opt, ENABLE_STR)) ctrl_mode = AUTO_MODE; else if (!strcmp(ctrl_opt, DISABLE_STR)) ctrl_mode = MANUAL_MODE; else if (!strcmp(ctrl_opt, STATUS_STR)) ctrl_mode = GET_FAN_MODE; else if (!strcmp(ctrl_opt, WAKEUP_STR)) ctrl_mode = WAKEUP_MODE; else if (!strcmp(ctrl_opt, SLEEP_STR)) ctrl_mode = SLEEP_MODE; else { syslog(LOG_WARNING, "%s() it's not supported, ctrl_opt=%s\n", __func__, ctrl_opt); return -1; } // assign the command if needed switch (ctrl_mode) { case AUTO_MODE: case WAKEUP_MODE: snprintf(cmd, sizeof(cmd), "sv start fscd > /dev/null 2>&1"); break; case MANUAL_MODE: case SLEEP_MODE: snprintf(cmd, sizeof(cmd), "sv force-stop fscd > /dev/null 2>&1"); break; } // special fan case for class 2 if (bmc_location == NIC_BMC) { // use WAKEUP_MODE/SLEEP_MODE to skip the above code, adjust it back // so we can use the original logic to start fscd if ( ctrl_mode == WAKEUP_MODE || ctrl_mode == SLEEP_MODE ) { ctrl_mode = (ctrl_mode == WAKEUP_MODE)?AUTO_MODE:MANUAL_MODE; } else { // notify the other BMC except for getting fan mode if ( (pal_is_cwc() != PAL_EOK) && (ctrl_mode != GET_FAN_MODE) && (pal_init_fan_mode(ctrl_mode) < 0) ) { syslog(LOG_WARNING, "%s() Failed to call pal_init_fan_mode. ctrl_mode=%02X", __func__, ctrl_mode); return -1; } // get/set/ fan mode if ( bic_set_fan_auto_mode(ctrl_mode, &status) < 0 ) { syslog(LOG_WARNING, "%s() Failed to call bic_set_fan_auto_mode. ctrl_mode=%02X", __func__, ctrl_mode); return -1; } else { // set the flag by itself, so it can handle requests from the other BMC kv_set("fan_manual", (ctrl_mode == AUTO_MODE)?"0":"1", 0, 0); } } } if (ctrl_mode == GET_FAN_MODE) { if (bmc_location == NIC_BMC) { if (status == AUTO_MODE) { printf("Auto Mode: Normal\n"); } else if (status == MANUAL_MODE) { printf("Auto Mode: Manual\n"); } else { printf("Auto Mode: Unknown\n"); } } else { snprintf(cmd, sizeof(cmd), "fan-util --get | grep \"Fan Mode:\" | cut -d: -f2-"); if((fp = popen(cmd, "r")) == NULL) { printf("Auto Mode: Unknown\n"); return -1; } if(fgets(buf, sizeof(buf), fp) != NULL) { printf("Auto Mode:%s",buf); } if(fp != NULL) pclose(fp); } } else { // AUTO_MODE or MANUAL_MODE if(ctrl_mode == AUTO_MODE) { if (system(cmd) != 0) return -1; } else if (ctrl_mode == MANUAL_MODE){ if (system(cmd) != 0) { // Although sv force-stop sends kill (-9) signal after timeout, // it still returns an error code. // we will check status here to ensure that fscd has stopped completely. syslog(LOG_WARNING, "%s() force-stop timeout", __func__); snprintf(cmd, sizeof(cmd), "sv status fscd 2>/dev/null | cut -d: -f1"); if((fp = popen(cmd, "r")) == NULL) { syslog(LOG_WARNING, "%s() popen failed, cmd: %s", __func__, cmd); ret = -1; } else if(fgets(buf, sizeof(buf), fp) == NULL) { syslog(LOG_WARNING, "%s() read popen failed, cmd: %s", __func__, cmd); ret = -1; } else if(strncmp(buf, "down", 4) != 0) { syslog(LOG_WARNING, "%s() failed to terminate fscd", __func__); ret = -1; } if(fp != NULL) pclose(fp); if(ret != 0) return ret; } } } return ret; } int pal_get_pfr_address(uint8_t fru, uint8_t *bus, uint8_t *addr, bool *bridged) { int ret; uint8_t bmc_location = 0; if ((ret = fby3_common_get_bmc_location(&bmc_location))) { syslog(LOG_WARNING, "%s() Cannot get the location of BMC", __func__); return ret; } switch (fru) { case FRU_BMC: *bus = (bmc_location == NIC_BMC) ? PFR_NICEXP_BUS : PFR_BB_BUS; *addr = PFR_MAILBOX_ADDR; *bridged = false; break; case FRU_SLOT1: case FRU_SLOT2: case FRU_SLOT3: case FRU_SLOT4: if ((bmc_location == NIC_BMC) && (fru != FRU_SLOT1)) { ret = -1; break; } if ((ret = fby3_common_get_bus_id(fru)) < 0) { syslog(LOG_WARNING, "%s() get bus failed, fru %d\n", __func__, fru); break; } *bus = ret + 4; // I2C_4 ~ I2C_7 *addr = PFR_MAILBOX_ADDR; *bridged = false; ret = 0; break; default: ret = -1; break; } return ret; } int pal_is_pfr_active(void) { int pfr_active = PFR_NONE; int ifd, retry = 3; uint8_t tbuf[8], rbuf[8]; char dev_i2c[16]; uint8_t bus, addr; bool bridged; if (pal_get_pfr_address(FRU_BMC, &bus, &addr, &bridged)) { return pfr_active; } sprintf(dev_i2c, "/dev/i2c-%d", bus); ifd = open(dev_i2c, O_RDWR); if (ifd < 0) { return pfr_active; } tbuf[0] = 0x0A; do { if (!i2c_rdwr_msg_transfer(ifd, addr, tbuf, 1, rbuf, 1)) { pfr_active = (rbuf[0] & 0x20) ? PFR_ACTIVE : PFR_UNPROVISIONED; break; } #ifdef DEBUG syslog(LOG_WARNING, "i2c%u xfer failed, cmd: %02x", 4, tbuf[0]); #endif if (--retry > 0) msleep(20); } while (retry > 0); close(ifd); return pfr_active; } int pal_is_slot_pfr_active(uint8_t fru) { int pfr_active = PFR_NONE; int ifd, retry = 3; uint8_t tbuf[8], rbuf[8]; uint8_t bus, addr; bool bridged; if (pal_get_pfr_address(fru, &bus, &addr, &bridged)) { return pfr_active; } ifd = i2c_cdev_slave_open(bus, addr >> 1, I2C_SLAVE_FORCE_CLAIM); if (ifd < 0) { return pfr_active; } tbuf[0] = 0x0A; do { if (!i2c_rdwr_msg_transfer(ifd, addr, tbuf, 1, rbuf, 1)) { pfr_active = (rbuf[0] & 0x20) ? PFR_ACTIVE : PFR_UNPROVISIONED; break; } #ifdef DEBUG syslog(LOG_WARNING, "i2c%u xfer failed, cmd: %02x", 4, tbuf[0]); #endif if (--retry > 0) msleep(20); } while (retry > 0); close(ifd); return pfr_active; } int pal_fw_update_finished(uint8_t fru, const char *comp, int status) { int ret = 0; int ifd, retry = 3; uint8_t buf[16]; uint8_t rbuf[16]; char dev_i2c[16]; uint8_t bus, addr; bool bridged; if (pal_get_pfr_address(FRU_BMC, &bus, &addr, &bridged)) { return -1; } ret = status; if (ret == 0) { sprintf(dev_i2c, "/dev/i2c-%d", bus); ifd = open(dev_i2c, O_RDWR); if (ifd < 0) { return -1; } buf[0] = 0x13; // BMC update intent if (!strcmp(comp, "bmc")) { buf[1] = UPDATE_BMC_ACTIVE; buf[1] |= UPDATE_AT_RESET; } else if (!strcmp(comp, "pfr_cpld")) { buf[1] = UPDATE_CPLD_ACTIVE; } else { close(ifd); return -1; } sync(); printf("sending update intent to CPLD...\n"); fflush(stdout); sleep(1); do { ret = i2c_rdwr_msg_transfer(ifd, addr, buf, 2, rbuf, 1); if (ret) { syslog(LOG_WARNING, "i2c%u xfer failed, cmd: %02x", addr, buf[0]); if (--retry > 0) { msleep(100); } } } while (ret && retry > 0); buf[1] |= rbuf[0]; do { ret = i2c_rdwr_msg_transfer(ifd, addr, buf, 2, NULL, 0); if (ret) { syslog(LOG_WARNING, "i2c%u xfer failed, cmd: %02x %02x", addr, buf[0], buf[1]); if (--retry > 0) { msleep(100); } } } while (ret && retry > 0); close(ifd); } return ret; } int pal_get_pfr_update_address(uint8_t fru, uint8_t *bus, uint8_t *addr, bool *bridged) { int ret; uint8_t bmc_location = 0; ret = fby3_common_get_bmc_location(&bmc_location); if (ret < 0) { syslog(LOG_ERR, "%s() Cannot get the location of BMC", __func__); } switch (fru) { case FRU_BB: case FRU_BMC: *bus = (bmc_location == NIC_BMC) ? PFR_NICEXP_BUS : PFR_BB_BUS; *addr = CPLD_UPDATE_ADDR; *bridged = false; break; case FRU_SLOT1: case FRU_SLOT2: case FRU_SLOT3: case FRU_SLOT4: if ((bmc_location == NIC_BMC) && (fru != FRU_SLOT1)) { ret = -1; break; } if ((ret = fby3_common_get_bus_id(fru)) < 0) { syslog(LOG_WARNING, "%s() get bus failed, fru %d\n", __func__, fru); break; } *bus = ret + 4; // I2C_4 ~ I2C_7 *addr = CPLD_UPDATE_ADDR; *bridged = false; ret = 0; break; default: ret = -1; break; } return ret; } // OEM Command "CMD_OEM_BYPASS_CMD" 0x34 int pal_bypass_cmd(uint8_t slot, uint8_t *req_data, uint8_t req_len, uint8_t *res_data, uint8_t *res_len){ int ret; int completion_code = CC_UNSPECIFIED_ERROR; uint8_t netfn, cmd, select; uint8_t tlen, rlen; uint8_t tbuf[256] = {0x00}; uint8_t rbuf[256] = {0x00}; uint8_t status; NCSI_NL_MSG_T *msg = NULL; NCSI_NL_RSP_T *rsp = NULL; uint8_t channel = 0; uint8_t netdev = 0; uint8_t netenable = 0; char sendcmd[128] = {0}; int i; *res_len = 0; if (slot < FRU_SLOT1 || slot > FRU_SLOT4) { return CC_PARAM_OUT_OF_RANGE; } ret = pal_is_fru_prsnt(slot, &status); if (ret < 0) { return -1; } if (status == 0) { return CC_UNSPECIFIED_ERROR; } ret = pal_get_server_12v_power(slot, &status); if(ret < 0 || status == SERVER_12V_OFF) { return CC_NOT_SUPP_IN_CURR_STATE; } if(!pal_is_slot_server(slot)) { return CC_UNSPECIFIED_ERROR; } select = req_data[0]; switch (select) { case BYPASS_BIC: tlen = req_len - 6; // payload_id, netfn, cmd, data[0] (select), data[1] (bypass netfn), data[2] (bypass cmd) if (tlen < 0) { completion_code = CC_INVALID_LENGTH; break; } netfn = req_data[1]; cmd = req_data[2]; // Bypass command to Bridge IC if (tlen != 0) { ret = bic_ipmb_wrapper(slot, netfn, cmd, &req_data[3], tlen, res_data, res_len); } else { ret = bic_ipmb_wrapper(slot, netfn, cmd, NULL, 0, res_data, res_len); } if (0 == ret) { completion_code = CC_SUCCESS; } break; case BYPASS_ME: tlen = req_len - 6; // payload_id, netfn, cmd, data[0] (select), data[1] (bypass netfn), data[2] (bypass cmd) if (tlen < 0) { completion_code = CC_INVALID_LENGTH; break; } netfn = req_data[1]; cmd = req_data[2]; tlen += 2; memcpy(tbuf, &req_data[1], tlen); tbuf[0] = tbuf[0] << 2; // Bypass command to ME ret = bic_me_xmit(slot, tbuf, tlen, rbuf, &rlen); if (0 == ret) { completion_code = rbuf[0]; memcpy(&res_data[0], &rbuf[1], (rlen - 1)); *res_len = rlen - 1; } break; case BYPASS_NCSI: tlen = req_len - 7; // payload_id, netfn, cmd, data[0] (select), netdev, channel, cmd if (tlen < 0) { completion_code = CC_INVALID_LENGTH; break; } netdev = req_data[1]; channel = req_data[2]; cmd = req_data[3]; msg = calloc(1, sizeof(NCSI_NL_MSG_T)); if (!msg) { syslog(LOG_ERR, "%s Error: failed msg buffer allocation", __func__); break; } memset(msg, 0, sizeof(NCSI_NL_MSG_T)); sprintf(msg->dev_name, "eth%d", netdev); msg->channel_id = channel; msg->cmd = cmd; msg->payload_length = tlen; for (i=0; i<msg->payload_length; i++) { msg->msg_payload[i] = req_data[4+i]; } //send_nl_msg_libnl rsp = send_nl_msg_libnl(msg); if (rsp) { memcpy(&res_data[0], &rsp->msg_payload[0], rsp->hdr.payload_length); *res_len = rsp->hdr.payload_length; completion_code = CC_SUCCESS; } else { completion_code = CC_UNSPECIFIED_ERROR; } free(msg); if (rsp) free(rsp); break; case BYPASS_NETWORK: tlen = req_len - 6; // payload_id, netfn, cmd, data[0] (select), netdev, netenable if (tlen != 0) { completion_code = CC_INVALID_LENGTH; break; } netdev = req_data[1]; netenable = req_data[2]; if (netenable) { if (netenable > 1) { completion_code = CC_INVALID_PARAM; break; } sprintf(sendcmd, "ifup eth%d", netdev); } else { sprintf(sendcmd, "ifdown eth%d", netdev); } ret = system(sendcmd); completion_code = CC_SUCCESS; break; default: return completion_code; } return completion_code; } int pal_check_pfr_mailbox(uint8_t fru) { int ret = 0, i2cfd = 0, retry=0, index = 0; uint8_t tbuf[1] = {0}, rbuf[1] = {0}; uint8_t tlen = 1, rlen = 1; uint8_t major_err = 0, minor_err = 0; char *major_str = "NA", *minor_str = "NA"; char fru_str[32] = {0}; uint8_t bus, addr; bool bridged; if (pal_get_pfr_address(fru, &bus, &addr, &bridged)) { syslog(LOG_WARNING, "%s() Failed to do pal_get_pfr_address(), FRU%d", __func__, fru); return -1; } i2cfd = i2c_cdev_slave_open(bus, addr >> 1, I2C_SLAVE_FORCE_CLAIM); if ( i2cfd < 0 ) { syslog(LOG_WARNING, "%s() Failed to open bus %d. Err: %s", __func__, bus, strerror(errno)); return -1; } tbuf[0] = MAJOR_ERR_OFFSET; tlen = 1; retry = 0; while (retry < MAX_READ_RETRY) { ret = i2c_rdwr_msg_transfer(i2cfd, addr, tbuf, tlen, rbuf, rlen); if ( ret < 0 ) { retry++; sleep(1); } else { major_err = rbuf[0]; break; } } if (retry == MAX_READ_RETRY) { syslog(LOG_WARNING, "%s() Failed to do i2c_rdwr_msg_transfer, tlen=%d", __func__, tlen); } tbuf[0] = MINOR_ERR_OFFSET; tlen = 1; retry = 0; while (retry < MAX_READ_RETRY) { ret = i2c_rdwr_msg_transfer(i2cfd, addr, tbuf, tlen, rbuf, rlen); if ( ret < 0 ) { retry++; sleep(1); } else { minor_err = rbuf[0]; break; } } if ( i2cfd > 0 ) close(i2cfd); if ( (major_err != 0) || (minor_err != 0) ) { if ( major_err == MAJOR_ERROR_PCH_AUTH_FAILED ) { major_str = "MAJOR_ERROR_BMC_AUTH_FAILED"; for (index = 0; index < minor_auth_size; index++) { if (minor_err == minor_auth_error[index].err_id) { minor_str = minor_auth_error[index].err_des; break; } } } else if ( major_err == MAJOR_ERROR_PCH_AUTH_FAILED ) { major_str = "MAJOR_ERROR_PCH_AUTH_FAILED"; for (index = 0; index < minor_auth_size; index++) { if (minor_err == minor_auth_error[index].err_id) { minor_str = minor_auth_error[index].err_des; break; } } } else if ( major_err == MAJOR_ERROR_UPDATE_FROM_PCH_FAILED ) { major_str = "MAJOR_ERROR_UPDATE_FROM_PCH_FAILED"; for (index = 0; index < minor_update_size; index++) { if (minor_err == minor_update_error[index].err_id) { minor_str = minor_update_error[index].err_des; break; } } } else if ( major_err == MAJOR_ERROR_UPDATE_FROM_BMC_FAILED ) { major_str = "MAJOR_ERROR_UPDATE_FROM_BMC_FAILED"; for (index = 0; index < minor_update_size; index++) { if (minor_err == minor_update_error[index].err_id) { minor_str = minor_update_error[index].err_des; break; } } } else { major_str = "unknown major error"; } switch (fru) { case FRU_BMC: snprintf(fru_str, sizeof(fru_str), "BMC"); break; case FRU_SLOT1: case FRU_SLOT2: case FRU_SLOT3: case FRU_SLOT4: snprintf(fru_str, sizeof(fru_str), "FRU: %d", fru); break; default: break; } syslog(LOG_CRIT, "%s, PFR - Major error: %s (0x%02X), Minor error: %s (0x%02X)", fru_str, major_str, major_err, minor_str, minor_err); return -1; } return 0; } int pal_parse_oem_sel(uint8_t fru, uint8_t *sel, char *error_log) { uint8_t mfg_id[] = {0x9c, 0x9c, 0x00}; char temp_log[MAX_ERR_LOG_SIZE]; error_log[0] = '\0'; // Record Type: 0xC0 (OEM) if ((sel[2] == 0xC0) && !memcmp(&sel[7], mfg_id, sizeof(mfg_id))) { snprintf(temp_log, MAX_ERR_LOG_SIZE, "%s: Can not control SSD%d alert LED", sel[10] ? "Assert" : "Deassert", sel[11]); strcat(error_log, temp_log); } return 0; } int set_pfr_i2c_filter(uint8_t slot_id, uint8_t value) { int ret; uint8_t tbuf[2] = {0}; uint8_t tlen = 2; char path[128]; int i2cfd = 0, retry=0; snprintf(path, sizeof(path), "/dev/i2c-%d", (slot_id + SLOT_BUS_BASE)); i2cfd = open(path, O_RDWR); if ( i2cfd < 0 ) { syslog(LOG_WARNING, "%s() Failed to open %s", __func__, path); return -1; } retry = 0; tbuf[0] = PFR_I2C_FILTER_OFFSET; tbuf[1] = value; while (retry < RETRY_TIME) { ret = i2c_rdwr_msg_transfer(i2cfd, CPLD_ADDRESS, tbuf, tlen, NULL, 0); if ( ret < 0 ) { retry++; msleep(100); } else { break; } } if ( i2cfd > 0 ) close(i2cfd); if ( retry == RETRY_TIME ) return -1; return 0; } int pal_check_sled_mgmt_cbl_id(uint8_t slot_id, uint8_t *cbl_val, bool log_evnt, uint8_t bmc_location) { enum { SLOT1_CBL = 0x03, SLOT2_CBL = 0x02, SLOT3_CBL = 0x01, SLOT4_CBL = 0x00, }; enum { SLOT1_ID0_DETECT_BMC_N = 33, SLOT1_ID1_DETECT_BMC_N = 34, SLOT3_ID0_DETECT_BMC_N = 37, SLOT3_ID1_DETECT_BMC_N = 38, }; const uint8_t mapping_tbl[4] = {SLOT1_CBL, SLOT2_CBL, SLOT3_CBL, SLOT4_CBL}; const char *gpio_mgmt_cbl_tbl[] = {"SLOT%d_ID1_DETECT_BMC_N", "SLOT%d_ID0_DETECT_BMC_N"}; const int num_of_mgmt_pins = ARRAY_SIZE(gpio_mgmt_cbl_tbl); int i = 0; int ret = 0; char dev[32] = {0}; uint8_t val = 0; gpio_value_t gval; uint8_t gpio_vals = 0; bic_gpio_t gpio = {0}; int i2cfd = 0; uint8_t bus = 0; uint8_t tbuf[1] = {0x06}; uint8_t rbuf[1] = {0}; uint8_t tlen = 1; uint8_t rlen = 1; uint8_t cpld_slot_cbl_val = 0; uint8_t slot_id_tmp = slot_id; if ( bmc_location == BB_BMC ) { // EVT BB_BMC HW not support cable management // just return present to skip checking cbl_val[0] = STATUS_PRSNT; return 0; } else if ( bmc_location == DVT_BB_BMC ) { //read GPIO vals for ( i = 0; i < num_of_mgmt_pins; i++ ) { snprintf(dev, sizeof(dev), gpio_mgmt_cbl_tbl[i], slot_id); if ( (gval = gpio_get_value_by_shadow(dev)) == GPIO_VALUE_INVALID ) { syslog(LOG_WARNING, "%s() Failed to read %s", __func__, dev); } val = (uint8_t)gval; gpio_vals |= (val << i); } } else { //NIC EXP //a bus starts from 4 ret = fby3_common_get_bus_id(slot_id) + 4; if ( ret < 0 ) { syslog(LOG_WARNING, "%s() Cannot get the bus with fru%d", __func__, slot_id); return -1; } bus = (uint8_t)ret; i2cfd = i2c_cdev_slave_open(bus, CPLD_ADDRESS >> 1, I2C_SLAVE_FORCE_CLAIM); if ( i2cfd < 0 ) { syslog(LOG_WARNING, "%s() Failed to open bus %d. Err: %s", __func__, bus, strerror(errno)); return -1; } //read 06h from SB CPLD ret = i2c_rdwr_msg_transfer(i2cfd, CPLD_ADDRESS, tbuf, tlen, rbuf, rlen); if ( i2cfd > 0 ) close(i2cfd); if ( ret < 0 ) { syslog(LOG_WARNING, "%s() Failed to do i2c_rdwr_msg_transfer, tlen=%d", __func__, tlen); return -1; } cpld_slot_cbl_val = rbuf[0]; //read GPIO from BB BIC ret = bic_get_gpio(slot_id, &gpio, BB_BIC_INTF); if ( ret < 0 ) { printf("%s() bic_get_gpio returns %d\n", __func__, ret); return ret; } if (cpld_slot_cbl_val == SLOT1_CBL) { val = BIT_VALUE(gpio, SLOT1_ID1_DETECT_BMC_N); gpio_vals |= (val << 0); val = BIT_VALUE(gpio, SLOT1_ID0_DETECT_BMC_N); gpio_vals |= (val << 1); } else { val = BIT_VALUE(gpio, SLOT3_ID1_DETECT_BMC_N); gpio_vals |= (val << 0); val = BIT_VALUE(gpio, SLOT3_ID0_DETECT_BMC_N); gpio_vals |= (val << 1); slot_id_tmp = 3; } } bool vals_match = (bmc_location == DVT_BB_BMC) ? (gpio_vals == mapping_tbl[slot_id-1]):(gpio_vals == cpld_slot_cbl_val); if (vals_match == false) { for ( i = 0; i < (sizeof(mapping_tbl)/sizeof(uint8_t)); i++ ) { if(mapping_tbl[i] == gpio_vals) { break; } } if (log_evnt == true) { syslog(LOG_CRIT, "Abnormal - slot%d instead of slot%d", slot_id_tmp, (i+1)); } } if ( cbl_val != NULL ) { cbl_val[0] = (vals_match == false)?STATUS_ABNORMAL:STATUS_PRSNT; if (cbl_val[0] == STATUS_ABNORMAL) { cbl_val[1] = slot_id_tmp << 4 | (i+1); } else { cbl_val[1] = 0x00; } } return ret; } int 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) { int i2cfd = 0, ret = 0; uint8_t status; uint8_t bus; uint8_t retry = 0; uint32_t ver_reg = BIOS_CAP_STAG_MAILBOX; uint8_t tbuf[18] = {0}; uint8_t tlen = BIOS_CAP_VER_LEN; ret = fby3_common_check_slot_id(slot); if (ret < 0 ) { ret = PAL_ENOTSUP; goto error_exit; } ret = pal_is_fru_prsnt(slot, &status); if ( ret < 0 || status == 0 ) { ret = PAL_ENOTREADY; goto error_exit; } ret = fby3_common_get_bus_id(slot) + 4; if ( ret < 0 ) { syslog(LOG_WARNING, "%s() Cannot get the bus with fru%d", __func__, slot); goto error_exit; } bus = (uint8_t)ret; i2cfd = i2c_cdev_slave_open(bus, CPLD_INTENT_CTRL_ADDR >> 1, I2C_SLAVE_FORCE_CLAIM); if ( i2cfd < 0) { printf("Failed to open bus %d. Err: %s\n", bus, strerror(errno)); goto error_exit; } memcpy(tbuf, (uint8_t *)&ver_reg, 1); memcpy(&tbuf[1], req_data, tlen); tlen = tlen + 1; while (retry < MAX_READ_RETRY) { ret = i2c_rdwr_msg_transfer(i2cfd, CPLD_INTENT_CTRL_ADDR, tbuf, tlen, NULL, 0); if ( ret < 0 ) { retry++; sleep(1); } else { break; } } if (retry == MAX_READ_RETRY) { syslog(LOG_WARNING, "%s() Failed to do i2c_rdwr_msg_transfer, tlen=%d", __func__, tlen); } error_exit: if ( i2cfd > 0 ) close(i2cfd); *res_len = 0; return ret; } static int pal_get_cpld_ver(uint8_t fru, uint8_t* data_buf, uint8_t* data_len) { int ret = 0; const uint8_t cpld_addr = 0x80; uint8_t tbuf[4] = {0x00, 0x20, 0x00, 0x28}; uint8_t rbuf[4] = {0x00}; uint8_t tlen = 4; uint8_t rlen = 4; uint8_t i2c_bus = 0; int i2cfd = 0; switch (fru){ case FRU_SLOT1: case FRU_SLOT2: case FRU_SLOT3: case FRU_SLOT4: i2c_bus = fby3_common_get_bus_id(fru) + 4; break; case FRU_BB: i2c_bus = 12; break; default: return -1; } ret = i2c_cdev_slave_open(i2c_bus, cpld_addr >> 1, I2C_SLAVE_FORCE_CLAIM); if (ret < 0) { syslog(LOG_WARNING, "Failed to open bus 12"); return -1; } i2cfd = ret; ret = i2c_rdwr_msg_transfer(i2cfd, cpld_addr, tbuf, tlen, rbuf, rlen); if ( i2cfd > 0 ) close(i2cfd); if (ret < 0) { syslog(LOG_WARNING, "%s() Failed to do i2c_rdwr_msg_transfer to slave@0x%02X on bus %d", __func__, cpld_addr, i2c_bus); return -1; } memcpy(data_buf, rbuf, rlen); if (data_len != NULL) { *data_len = rlen; } return 0; } int pal_get_bb_fw_info(unsigned char target, char* ver_str) { char key[MAX_KEY_LEN] = {0}; char value[MAX_VALUE_LEN] = {0}; if (target == FW_CPLD) { uint8_t data_buf[4] = {0}; uint8_t data_len; sprintf(key, "bb_cpld_ver"); // kv cache exist if (kv_get(key, value, NULL, 0) == 0) { memcpy(ver_str, value, 8); return 0; } // get version by i2c if (pal_get_cpld_ver(FRU_BB, data_buf, &data_len) < 0) { return -1; } // write cache sprintf(value, "%02X%02X%02X%02X", data_buf[3], data_buf[2], data_buf[1], data_buf[0]); kv_set(key, value, 8, 0); memcpy(ver_str, value, 8); return 0; } // unsupported target return -1; } int pal_get_fw_info(uint8_t fru, unsigned char target, unsigned char* res, unsigned char* res_len) { uint8_t bmc_location = 0; uint8_t config_status; int ret = PAL_ENOTSUP; uint8_t tmp_cpld_swap[4] = {0}; uint8_t type_2ou = UNKNOWN_BOARD; ret = fby3_common_get_bmc_location(&bmc_location); if (ret < 0) { syslog(LOG_ERR, "%s() Cannot get the location of BMC", __func__); goto error_exit; } if (target == FW_CPLD) { ret = pal_get_cpld_ver(fru, res, res_len); if (ret < 0) { goto error_exit; } } else if(target == FW_BIOS) { ret = pal_get_sysfw_ver(fru, res); if ( ret < 0 ) { syslog(LOG_WARNING, "%s() Failed to get sysfw ver", __func__); goto error_exit; } } else if(target == FW_VR) { // TODO goto not_support; } else { switch(target) { case FW_1OU_BIC: case FW_1OU_BIC_BOOTLOADER: case FW_1OU_CPLD: ret = (pal_is_fw_update_ongoing(fru) == false) ? bic_is_m2_exp_prsnt(fru):bic_is_m2_exp_prsnt_cache(fru); if (ret < 0) { syslog(LOG_WARNING, "%s() Failed to get 1ou & 2ou present status", __func__); goto error_exit; } config_status = (uint8_t) ret; if (!((bmc_location == BB_BMC || bmc_location == DVT_BB_BMC) && ((config_status & PRESENT_1OU) == PRESENT_1OU))) { goto not_support; } break; case FW_2OU_BIC: case FW_2OU_BIC_BOOTLOADER: case FW_2OU_CPLD: ret = (pal_is_fw_update_ongoing(fru) == false) ? bic_is_m2_exp_prsnt(fru):bic_is_m2_exp_prsnt_cache(fru); if (ret < 0) { syslog(LOG_WARNING, "%s() Failed to get 1ou & 2ou present status", __func__); goto error_exit; } config_status = (uint8_t) ret; if ( fby3_common_get_2ou_board_type(fru, &type_2ou) < 0 ) { syslog(LOG_WARNING, "%s() Failed to get 2OU board type\n", __func__); } if (!((config_status & PRESENT_2OU) == PRESENT_2OU)) { goto not_support; } else if (type_2ou == DP_RISER_BOARD) { goto not_support; } break; case FW_BB_BIC: case FW_BB_BIC_BOOTLOADER: case FW_BB_CPLD: if(bmc_location != NIC_BMC) { goto not_support; } break; case FW_BIOS_CAPSULE: case FW_CPLD_CAPSULE: case FW_BIOS_RCVY_CAPSULE: case FW_CPLD_RCVY_CAPSULE: // TODO goto not_support; default: if (target >= FW_COMPONENT_LAST_ID) goto not_support; break; } ret = bic_get_fw_ver(fru, target, res); if (ret != BIC_STATUS_SUCCESS) { syslog(LOG_WARNING, "%s() bic_get_fw_ver returns %d\n", __func__, ret); goto error_exit; } } switch(target) { case FW_CPLD: case FW_1OU_CPLD: case FW_2OU_CPLD: case FW_BB_CPLD: tmp_cpld_swap[0] = res[3]; tmp_cpld_swap[1] = res[2]; tmp_cpld_swap[2] = res[1]; tmp_cpld_swap[3] = res[0]; memcpy(res, tmp_cpld_swap, 4); *res_len = 4; break; case FW_ME: *res_len = 5; break; case FW_BIC: case FW_1OU_BIC: case FW_2OU_BIC: case FW_BB_BIC: case FW_BIC_BOOTLOADER: case FW_1OU_BIC_BOOTLOADER: case FW_2OU_BIC_BOOTLOADER: case FW_BB_BIC_BOOTLOADER: *res_len = 2; break; case FW_BIOS: *res_len = 16; break; default: goto not_support; } return PAL_EOK; not_support: return PAL_ENOTSUP; error_exit: return ret; } int pal_set_nic_perst(uint8_t fru, uint8_t val) { int i2cfd = 0; int ret = 0; char path[32] = {0}; uint8_t bmc_location = 0; uint8_t bus = 0; uint8_t tbuf[2] = {NIC_CARD_PERST_CTRL, val}; uint8_t tlen = 2; ret = fby3_common_get_bmc_location(&bmc_location); if ( ret < 0 ) { syslog(LOG_WARNING, "%s() Cannot get the location of BMC", __func__); goto error_exit; } if ( bmc_location == BB_BMC || bmc_location == DVT_BB_BMC ) { return 0; } bus= (uint8_t)NIC_CPLD_BUS; snprintf(path, sizeof(path), "/dev/i2c-%d", bus); i2cfd = open(path, O_RDWR); if ( i2cfd < 0 ) { syslog(LOG_WARNING, "%s() Failed to open %s", __func__, path); goto error_exit; } ret = i2c_rdwr_msg_transfer(i2cfd, CPLD_ADDRESS, tbuf, tlen, NULL, 0); if ( ret < 0 ) { syslog(LOG_WARNING, "%s() Failed to do i2c_rdwr_msg_transfer, tlen=%d", __func__, tlen); goto error_exit; } error_exit: if ( i2cfd > 0 ) { close(i2cfd); } return ret; } static const char *sock_path_asd_bic[MAX_NODES+1] = { "", SOCK_PATH_ASD_BIC "_1", SOCK_PATH_ASD_BIC "_2", SOCK_PATH_ASD_BIC "_3", SOCK_PATH_ASD_BIC "_4" }; static const char *sock_path_jtag_msg[MAX_NODES+1] = { "", SOCK_PATH_JTAG_MSG "_1", SOCK_PATH_JTAG_MSG "_2", SOCK_PATH_JTAG_MSG "_3", SOCK_PATH_JTAG_MSG "_4" }; int pal_handle_oem_1s_intr(uint8_t slot, uint8_t *data) { int sock; int err; struct sockaddr_un server; if (access(sock_path_asd_bic[slot], F_OK) == -1) { // SOCK_PATH_ASD_BIC doesn't exist, means ASD daemon for this // slot is not running, exit return 0; } sock = socket(AF_UNIX, SOCK_STREAM, 0); if (sock < 0) { err = errno; syslog(LOG_ERR, "%s failed open socket (errno=%d)", __FUNCTION__, err); return -1; } server.sun_family = AF_UNIX; strcpy(server.sun_path, sock_path_asd_bic[slot]); if (connect(sock, (struct sockaddr *) &server, sizeof(struct sockaddr_un)) < 0) { err = errno; close(sock); syslog(LOG_ERR, "%s failed connecting stream socket (errno=%d), %s", __FUNCTION__, err, server.sun_path); return -1; } if (write(sock, data, 2) < 0) { err = errno; syslog(LOG_ERR, "%s error writing on stream sockets (errno=%d)", __FUNCTION__, err); } close(sock); return 0; } int pal_handle_oem_1s_asd_msg_in(uint8_t slot, uint8_t *data, uint8_t data_len) { int sock; int err; struct sockaddr_un server; if (access(sock_path_jtag_msg[slot], F_OK) == -1) { // SOCK_PATH_JTAG_MSG doesn't exist, means ASD daemon for this // slot is not running, exit return 0; } sock = socket(AF_UNIX, SOCK_STREAM, 0); if (sock < 0) { err = errno; syslog(LOG_ERR, "%s failed open socket (errno=%d)", __FUNCTION__, err); return -1; } server.sun_family = AF_UNIX; strcpy(server.sun_path, sock_path_jtag_msg[slot]); if (connect(sock, (struct sockaddr *)&server, sizeof(struct sockaddr_un)) < 0) { err = errno; close(sock); syslog(LOG_ERR, "%s failed connecting stream socket (errno=%d), %s", __FUNCTION__, err, server.sun_path); return -1; } if (write(sock, data, data_len) < 0) { err = errno; syslog(LOG_ERR, "%s error writing on stream sockets (errno=%d)", __FUNCTION__, err); } close(sock); return 0; } // It's called by fpc-util and front-paneld int pal_sb_set_amber_led(uint8_t fru, bool led_on, uint8_t led_mode) { int ret = 0; int i2cfd = -1; uint8_t bus = 0; ret = fby3_common_get_bus_id(fru); if ( ret < 0 ) { printf("%s() Couldn't get the bus id of fru%d\n", __func__, fru); goto err_exit; } bus = (uint8_t)ret + 4; i2cfd = i2c_cdev_slave_open(bus, CPLD_ADDRESS >> 1, I2C_SLAVE_FORCE_CLAIM); if ( i2cfd < 0 ) { printf("%s() Couldn't open i2c bus%d, err: %s\n", __func__, bus, strerror(errno)); goto err_exit; } uint8_t tbuf[2] = {0x0, (led_on == true)?0x01:0x00}; if ( led_mode == LED_LOCATE_MODE ) { /* LOCATE_MODE */ // 0x0f 01h: off // 00h: on tbuf[0] = 0x0f; tbuf[1] = (led_on == true)?0x01:0x00; } else if ( led_mode == LED_CRIT_PWR_OFF_MODE || led_mode == LED_CRIT_PWR_ON_MODE ) { /* CRIT_MODE */ // 0x12 02h: 900ms_on/100ms_off // 01h: 900ms_off/100ms_on // 00h: off tbuf[0] = 0x12; tbuf[1] = (led_on == false)?0x00:(led_mode == LED_CRIT_PWR_OFF_MODE)?0x01:0x02; } else { syslog(LOG_WARNING, "%s() fru:%d, led_on:%d, led_mode:%d\n", __func__, fru, led_on, led_mode); } ret = i2c_rdwr_msg_transfer(i2cfd, CPLD_ADDRESS, tbuf, 2, NULL, 0); if ( ret < 0 ) { printf("%s() Couldn't write data to addr %02X, err: %s\n", __func__, CPLD_ADDRESS, strerror(errno)); } err_exit: if ( i2cfd > 0 ) close(i2cfd); return ret; } // IPMI chassis identification LED command // ipmitool chassis identify [force|0] // force: turn on LED indefinitely // 0: turn off LED int pal_set_slot_led(uint8_t slot, uint8_t *req_data, uint8_t req_len, uint8_t *res_data, uint8_t *res_len) { int rsp_cc = CC_UNSPECIFIED_ERROR; uint8_t *data = req_data; *res_len = 0; /* There are 2 option bytes for Chassis Identify Command * Byte 1 : Identify Interval in seconds. (Not support, OpenBMC only support turn off action) * 00h = Turn off Identify * Byte 2 : Force Identify On * BIT0 : 1b = Turn on Identify indefinitely. This overrides the values in byte 1. * 0b = Identify state driven according to byte 1. */ if ( 5 == req_len ) { if ( GETBIT(*(data+1), 0) ) { //turn on rsp_cc = pal_sb_set_amber_led(slot, true, LED_LOCATE_MODE); } else if ( 0 == *data ) { //turn off rsp_cc = pal_sb_set_amber_led(slot, false, LED_LOCATE_MODE); } else { rsp_cc = CC_INVALID_PARAM; } } else if ( 4 == req_len ) { if (0 == *data) { //turn off rsp_cc = pal_sb_set_amber_led(slot, false, LED_LOCATE_MODE); } else { rsp_cc = CC_INVALID_PARAM; } } if ( rsp_cc < 0 ) rsp_cc = CC_UNSPECIFIED_ERROR; return rsp_cc; } int pal_get_dev_info(uint8_t slot_id, uint8_t dev_id, uint8_t *nvme_ready, uint8_t *status, uint8_t *type) { return bic_get_dev_info(slot_id, dev_id, nvme_ready, status, type); } int pal_check_slot_cpu_present(uint8_t slot_id) { int ret = 0; bic_gpio_t gpio = {0}; ret = bic_get_gpio(slot_id, &gpio, NONE_INTF); if ( ret < 0 ) { printf("%s() bic_get_gpio returns %d\n", __func__, ret); return ret; } if (BIT_VALUE(gpio, FM_CPU_SKTOCC_LVT3_N)) { syslog(LOG_CRIT, "FRU: %d, CPU absence", slot_id); } else { syslog(LOG_CRIT, "FRU: %d, CPU presence", slot_id); } return ret; } int pal_get_sensor_util_timeout(uint8_t fru) { switch (fru) { case FRU_SLOT1: case FRU_SLOT2: case FRU_SLOT3: case FRU_SLOT4: case FRU_2U: case FRU_CWC: case FRU_2U_TOP: case FRU_2U_BOT: return 10; case FRU_BMC: return 15; case FRU_NIC: default: return 4; } } // IPMI OEM Command // netfn: NETFN_OEM_1S_REQ (0x38) // command code: CMD_OEM_1S_GET_SYS_FW_VER (0x40) int pal_get_fw_ver(uint8_t slot, uint8_t *req_data, uint8_t *res_data, uint8_t *res_len) { int ret = 0; uint8_t type_2ou = 0; uint8_t fru = 0; uint8_t comp = 0; FILE* fp = NULL; char buf[MAX_FW_VER_LEN] = {0}; // To keep the format consistent with fw-util, get version from fw-util directly. static const char* cmd_table[IPMI_GET_VER_FRU_NUM][IPMI_GET_VER_MAX_COMP] = { // BMC { "/usr/bin/fw-util bmc --version bmc | grep 'Version:' | awk '{print $NF}'", "/usr/bin/fw-util bmc --version rom | grep 'Version:' | awk '{print $NF}'", "/usr/bin/fw-util bmc --version cpld | awk '{print $NF}'", "/usr/bin/fw-util bmc --version fscd | awk '{print $NF}'", "/usr/bin/fw-util bmc --version tpm | awk '{print $NF}'", NULL, NULL, NULL, NULL }, // NIC { "/usr/bin/fw-util nic --version | awk '{print $NF}'", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }, // Base board { "/usr/bin/fw-util slot1 --version bb_bic | awk '{print $NF}'", "/usr/bin/fw-util slot1 --version bb_bicbl | awk '{print $NF}'", "/usr/bin/fw-util slot1 --version bb_cpld | awk '{print $NF}'", NULL, NULL, NULL, NULL, NULL, NULL }, // Server board { "/usr/bin/fw-util slot1 --version bic | awk '{print $NF}'", "/usr/bin/fw-util slot1 --version bicbl | awk '{print $NF}'", "/usr/bin/fw-util slot1 --version bios | awk '{print $NF}'", "/usr/bin/fw-util slot1 --version cpld | awk '{print $NF}'", "/usr/bin/fw-util slot1 --version me | awk '{print $NF}'", "/usr/bin/fw-util slot1 --version vr | grep 'VCCIN_VSA' | awk '{print $5}' | cut -c -8", "/usr/bin/fw-util slot1 --version vr | grep 'VCCIO' | awk '{print $5}' | cut -c -8", "/usr/bin/fw-util slot1 --version vr | grep 'VDDQ_ABC' | awk '{print $5}' | cut -c -8", "/usr/bin/fw-util slot1 --version vr | grep 'VDDQ_DEF' | awk '{print $5}' | cut -c -8" }, // 2OU { "/usr/bin/fw-util slot1 --version 2ou_bic | awk '{print $NF}'", "/usr/bin/fw-util slot1 --version 2ou_bicbl | awk '{print $NF}'", NULL, NULL, NULL, NULL, NULL, NULL, NULL } }; *res_len = 0; if (req_data == NULL) { syslog(LOG_ERR, "%s(): IPMI request failed due to NULL parameter: *req_data", __func__); return CC_INVALID_PARAM; } if (res_data == NULL) { syslog(LOG_ERR, "%s(): IPMI request failed due to NULL parameter: *res_data", __func__); return CC_INVALID_PARAM; } if (res_len == NULL) { syslog(LOG_ERR, "%s(): IPMI request failed due to NULL parameter: *res_len", __func__); return CC_INVALID_PARAM; } ret = fby3_common_get_2ou_board_type(slot, &type_2ou); if (ret < 0) { syslog(LOG_ERR, "%s(): Not support CMD_OEM_1S_GET_SYS_FW_VER IPMI command due to get 2ou board type failed", __func__); return CC_UNSPECIFIED_ERROR; } if (type_2ou != E1S_BOARD) { syslog(LOG_ERR, "%s(): CMD_OEM_1S_GET_SYS_FW_VER IPMI command only support by Sierra Point system", __func__); return CC_NOT_SUPP_IN_CURR_STATE; } fru = ((GET_FW_VER_REQ*)req_data)->fru; comp = ((GET_FW_VER_REQ*)req_data)->component; if ((fru >= IPMI_GET_VER_FRU_NUM) || (comp >= IPMI_GET_VER_MAX_COMP) || (cmd_table[fru][comp] == NULL)) { syslog(LOG_ERR, "%s(): wrong FRU or component, fru = %x, comp = %x", __func__, fru, comp); return CC_PARAM_OUT_OF_RANGE; } if((fp = popen(cmd_table[fru][comp], "r")) == NULL) { syslog(LOG_ERR, "%s(): fail to send command: %s, errno: %s", __func__, cmd_table[fru][comp], strerror(errno)); return CC_UNSPECIFIED_ERROR; } memset(buf, 0, sizeof(buf)); if(fgets(buf, sizeof(buf), fp) != NULL) { *res_len = strlen(buf); strncpy((char*)res_data, buf, MAX_FW_VER_LEN); } if (fp != NULL) { pclose(fp); } return CC_SUCCESS; } int pal_gpv3_mux_select(uint8_t slot_id, uint8_t dev_id) { if ( slot_id == FRU_2U_TOP ) { if ( bic_mux_select(FRU_SLOT1, get_gpv3_bus_number(dev_id), dev_id, RREXP_BIC_INTF1) < 0 ) { printf("* Failed to select MUX from top GPV3\n"); return BIC_STATUS_FAILURE; } } else if ( slot_id == FRU_2U_BOT ) { if ( bic_mux_select(FRU_SLOT1, get_gpv3_bus_number(dev_id), dev_id, RREXP_BIC_INTF2) < 0 ) { printf("* Failed to select MUX from bot GPV3\n"); return BIC_STATUS_FAILURE; } } else { if ( bic_mux_select(slot_id, get_gpv3_bus_number(dev_id), dev_id, REXP_BIC_INTF) < 0 ) { printf("* Failed to select MUX\n"); return BIC_STATUS_FAILURE; } } return BIC_STATUS_SUCCESS; } bool pal_is_aggregate_snr_valid(uint8_t snr_num) { char sys_conf[MAX_VALUE_LEN] = {0}; switch(snr_num) { // In type 8 system, if one fan fail, show NA in airflow reading. case AGGREGATE_SENSOR_SYSTEM_AIRFLOW: memset(sys_conf, 0, sizeof(sys_conf)); if (kv_get("sled_system_conf", sys_conf, NULL, KV_FPERSIST) < 0) { syslog(LOG_WARNING, "%s() Failed to read sled_system_conf", __func__); return true; } if (strcmp(sys_conf, "Type_8") != 0) { return true; } if (access(FAN_FAIL_RECORD_PATH, F_OK) == 0) { return false; } break; default: return true; } return true; } int pal_dp_hba_fan_table_check(void) { //DP only slot1 uint8_t slot = FRU_SLOT1; int ret = 0, config_status = 0; uint8_t bmc_location = 0; uint8_t type_2ou = UNKNOWN_BOARD; uint8_t tbuf[16] = {0xb8, 0x40, 0x57, 0x01 ,0x00 ,0x30 ,0x06 ,0x05 ,0x61 ,0x00 ,0x00 ,0x00 ,0x60 ,0x01}; uint8_t rbuf[10] = {0x00}; uint8_t tlen = 14; uint8_t rlen = 10; uint16_t read_vid = 0x0, read_did = 0x0; char cmd[64] = {0}; ret = fby3_common_get_bmc_location(&bmc_location); if (ret < 0) { syslog(LOG_ERR, "%s() Cannot get the location of BMC", __func__); return -1; } config_status = bic_is_m2_exp_prsnt(slot); if ( (config_status & PRESENT_2OU) == PRESENT_2OU ) { //check if GPv3 is installed if ( fby3_common_get_2ou_board_type(slot, &type_2ou) < 0 ) { syslog(LOG_WARNING, "%s() Failed to get 2OU board type\n", __func__); } } if ( (bmc_location == BB_BMC) || (bmc_location == DVT_BB_BMC) ) { if (type_2ou == DP_RISER_BOARD) { ret = bic_me_xmit(slot, tbuf, tlen, rbuf, &rlen); if (ret == 0) { read_vid = rbuf[6] << 8 | rbuf[5]; read_did = rbuf[8] << 8 | rbuf[7];; if (((read_vid == HBA_M_VID) && (read_did == HBA_M_DID)) || ((read_vid == HBA_B_VID) && (read_did == HBA_B_DID))) { snprintf(cmd, sizeof(cmd), "ln -sf %s %s", DP_HBA_FAN_TBL_PATH, DEFAULT_FSC_CFG_PATH); ret = system(cmd); if (ret != 0) { syslog(LOG_WARNING, "%s() can not import DP-HBA fan table", __func__); return ret; } ret = system("/usr/bin/sv restart fscd"); if (ret != 0) { syslog(LOG_WARNING, "%s() can not restart fscd", __func__); return ret; } ret = kv_set("sled_system_conf", "Type_DPB", 0, KV_FPERSIST); if (ret < 0) { syslog(LOG_WARNING, "%s() Failed to set sled_system_conf\n", __func__); } ret = system("/usr/bin/sv restart sensord"); if (ret != 0) { syslog(LOG_WARNING, "%s() can not restart sensord", __func__); return ret; } } } } } return ret; } int pal_is_cwc(void) { static uint8_t bmc_location = UNKNOWN_BOARD; static uint8_t board_type = UNKNOWN_BOARD; if (board_type == UNKNOWN_BOARD) { if (fby3_common_get_bmc_location(&bmc_location) < 0) { syslog(LOG_ERR, "%s() Cannot get the location of BMC", __func__); return PAL_ENOTSUP; } if ( bmc_location == NIC_BMC ) { if (fby3_common_get_2ou_board_type(FRU_SLOT1, &board_type) < 0) { syslog(LOG_WARNING, "%s() Failed to get 2OU board type\n", __func__); return PAL_ENOTSUP; } } } return board_type == CWC_MCHP_BOARD ? PAL_EOK : PAL_ENOTSUP; } int pal_get_asd_sw_status(uint8_t fru) { int intf = 0, slot = 0; bic_gpio_t gpio = {0}; switch (fru) { case FRU_2U_TOP: intf = RREXP_BIC_INTF1; slot = FRU_SLOT1; break; case FRU_2U_BOT: intf = RREXP_BIC_INTF2; slot = FRU_SLOT1; break; default: return 0; } if (bic_get_gpio(slot, &gpio, intf) == 0) { if (gpio.gpio[3] & 0x01) { return 1; } } return 0; } int pal_is_exp(void) { return pal_is_cwc(); } int pal_get_fru_slot(uint8_t fru, uint8_t *slot) { switch (fru) { case FRU_2U: case FRU_CWC: case FRU_2U_TOP: case FRU_2U_BOT: *slot = FRU_SLOT1; break; case FRU_2U_SLOT3: *slot = FRU_SLOT3; break; default: *slot = fru; break; } return PAL_EOK; } int pal_get_root_fru(uint8_t fru, uint8_t *root) { return pal_get_fru_slot(fru, root); } int pal_get_2ou_board_type(uint8_t fru, uint8_t *type_2ou) { int ret = 0; uint8_t bmc_location = 0; uint8_t slot = 0; ret = fby3_common_get_bmc_location(&bmc_location); if ( ret < 0 ) { syslog(LOG_WARNING, "%s() Cannot get the location of BMC\n", __func__); return ret; } if ( bmc_location == NIC_BMC ) { ret = pal_get_fru_slot(fru, &slot); if ( ret < 0 ) { syslog(LOG_WARNING, "%s() Failed to get slot of fru\n",__func__); return ret; } ret = fby3_common_get_2ou_board_type(slot, type_2ou); if ( ret < 0 ) { syslog(LOG_WARNING, "%s() Failed to get 2ou board type\n",__func__); return ret; } } else { *type_2ou = UNKNOWN_BOARD; return ret; } return ret; } int pal_is_sensor_num_exceed(uint8_t sensor_num) { if (sensor_num > MAX_SENSOR_NUM) { syslog(LOG_CRIT, "Amount of sensors is more than Maximum value"); return PAL_ENOTSUP; } else { return PAL_EOK; } return PAL_EOK; } int pal_is_pesw_power_on(uint8_t fru, uint8_t *status) { enum { GP3_GPIO_PWRGD_P0V84 = 43, GP3_GPIO_PWRGD_P1V8 = 46, CWC_GPIO_PWRGD_P0V84 = 47, CWC_GPIO_PWRGD_P1V8 = 48, }; int ret = 0; uint8_t slot = 0; uint8_t intf = 0; bic_gpio_t gpio = {0}; ret = pal_get_fru_slot(fru, &slot); if ( ret < 0 ) { syslog(LOG_WARNING, "%s() Failed to get slot of fru\n",__func__); return ret; } switch (fru) { case FRU_CWC: intf = REXP_BIC_INTF; break; case FRU_2U_TOP: intf = RREXP_BIC_INTF1; break; case FRU_2U_BOT: intf = RREXP_BIC_INTF2; break; default: return -1; } ret = bic_get_gpio(slot, &gpio, intf); if ( ret < 0 ) { printf("%s() bic_get_gpio returns %d\n", __func__, ret); return ret; } switch (fru) { case FRU_CWC: if (BIT_VALUE(gpio, CWC_GPIO_PWRGD_P0V84) == VALUE_HIGH && BIT_VALUE(gpio, CWC_GPIO_PWRGD_P1V8) == VALUE_HIGH) { *status = 1; } else { *status = 0; } break; case FRU_2U_TOP: case FRU_2U_BOT: if (BIT_VALUE(gpio, GP3_GPIO_PWRGD_P0V84) == VALUE_HIGH && BIT_VALUE(gpio, GP3_GPIO_PWRGD_P1V8) == VALUE_HIGH) { *status = 1; } else { *status = 0; } break; default: return -1; } return ret; }