meta-facebook/meta-fbtp/recipes-fbtp/plat-libs/files/pal/pal.c (6,035 lines of code) (raw):
/*
*
* Copyright 2015-present Facebook. All Rights Reserved.
*
* This file contains code to support IPMI2.0 Specificaton 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 <fcntl.h>
#include <errno.h>
#include <syslog.h>
#include <sys/mman.h>
#include <string.h>
#include <ctype.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/time.h>
#include "pal.h"
#include "pal_sensors.h"
#include <openbmc/misc-utils.h>
#include <openbmc/vr.h>
#include <openbmc/obmc-i2c.h>
#include <openbmc/obmc-sensors.h>
#include <sys/stat.h>
#include <openbmc/libgpio.h>
#include <openbmc/kv.h>
#include <openbmc/sensor-correction.h>
#define BIT(value, index) ((value >> index) & 1)
#define FBTP_PLATFORM_NAME "fbtp"
#define LAST_KEY "last_key"
#define FBTP_MAX_NUM_SLOTS 1
#define PAGE_SIZE 0x1000
#define AST_SCU_BASE 0x1e6e2000
#define PIN_CTRL1_OFFSET 0x80
#define PIN_CTRL2_OFFSET 0x84
#define RST_STS_OFFSET 0x3c
#define AST_LPC_BASE 0x1e789000
#define HICRA_OFFSET 0x9C
#define HICRA_MASK_UART1 0x70000
#define HICRA_MASK_UART2 0x380000
#define HICRA_MASK_UART3 0x1C00000
#define UART1_TO_UART3 0x5
#define UART2_TO_UART3 0x6
#define UART3_TO_UART1 0x5
#define UART3_TO_UART2 0x4
#define DEBUG_TO_UART1 0x0
#define UART1_TXD (1 << 22)
#define UART2_TXD (1 << 30)
#define UART3_TXD (1 << 22)
#define UART4_TXD (1 << 30)
#define DELAY_GRACEFUL_SHUTDOWN 1
#define DELAY_POWER_OFF 6
#define DELAY_POWER_CYCLE 10
#define CRASHDUMP_BIN "/usr/local/bin/dump.sh"
#define CRASHDUMP_FILE "/mnt/data/crashdump_"
#define LARGEST_DEVICE_NAME 120
#define EEPROM_RISER "/sys/bus/i2c/devices/1-0050/eeprom"
#define EEPROM_RETIMER "/sys/bus/i2c/devices/3-0054/eeprom"
#define MAX_SENSOR_NUM 0xFF
#define ALL_BYTES 0xFF
#define LAST_REC_ID 0xFFFF
#define RISER_BUS_ID 0x1
#define OFFSET_SYS_GUID 0x17F0
#define OFFSET_DEV_GUID 0x1800
#define FRU_EEPROM "/sys/bus/i2c/devices/6-0054/eeprom"
#define READING_NA -2
#define READING_SKIP 1
#define NIC_MAX_TEMP 125
#define NIC_MIN_TEMP 0
#define MAX_READ_RETRY 10
#define CPLD_BUS_ID 0x6
#define CPLD_ADDR 0xA0
#define BIOS_VER_REGION_SIZE (4*1024*1024)
#define BIOS_ERASE_PKT_SIZE (64*1024)
#define NUM_SERVER_FRU 1
#define NUM_NIC_FRU 1
#define NUM_BMC_FRU 1
// If (Vin-Vout) is larger than this diff threshold, that means HSC has problems
#define HSC_FAULT_DIFF_THRES (0.3)
const char pal_fru_list[] = "all, mb, nic, riser_slot2, riser_slot3, riser_slot4";
const char pal_server_list[] = "mb";
size_t pal_pwm_cnt = 2;
size_t pal_tach_cnt = 2;
const char pal_pwm_list[] = "0, 1";
const char pal_tach_list[] = "0, 1";
static uint8_t g_plat_id = 0x0;
static uint8_t postcodes_last[256] = {0};
enum key_event {
KEY_BEFORE_SET,
KEY_AFTER_INI,
};
struct pal_key_cfg {
char *name;
char *def_val;
int (*function)(int, void*);
} key_cfg[] = {
/* name, default value, function */
{"pwr_server_last_state", "on", NULL},
{"sysfw_ver_server", "0", NULL},
{"identify_sled", "off", NULL},
{"timestamp_sled", "0", NULL},
{"server_por_cfg", "lps", NULL},
{"server_sensor_health", "1", NULL},
{"nic_sensor_health", "1", NULL},
{"server_sel_error", "1", NULL},
{"server_boot_order", "0100090203ff", NULL},
{"ntp_server", "", NULL},
/* Add more Keys here */
{LAST_KEY, LAST_KEY, NULL} /* This is the last key of the list */
};
//control mux based on the bus and channel
int
pal_control_mux_to_target_ch(uint8_t channel, uint8_t bus, uint8_t mux_addr)
{
int ret;
int fd;
char fn[32];
uint8_t retry;
uint8_t tbuf[16] = {0};
uint8_t rbuf[16] = {0};
snprintf(fn, sizeof(fn), "/dev/i2c-%d", bus);
fd = open(fn, O_RDWR);
if (fd < 0)
{
syslog(LOG_WARNING,"[%s]Cannot open bus %d", __func__, bus);
ret = PAL_ENOTSUP;
goto error_exit;
}
if (channel < 4)
{
tbuf[0] = 0x04 + channel;
}
else
{
tbuf[0] = 0x00; // close all channels
}
retry = MAX_READ_RETRY;
while ( retry > 0 )
{
ret = i2c_rdwr_msg_transfer(fd, mux_addr, tbuf, 1, rbuf, 0);
if ( PAL_EOK == ret )
{
break;
}
msleep(50);
retry--;
}
if ( ret < 0 )
{
syslog(LOG_WARNING,"[%s] Cannot switch the mux on bus %d", __func__, bus);
goto error_exit;
}
error_exit:
if ( fd > 0 )
{
close(fd);
}
return ret;
}
static int
pal_control_mux(int fd, uint8_t addr, uint8_t channel) {
uint8_t tcount = 1, rcount = 0;
uint8_t tbuf[16] = {0};
uint8_t rbuf[16] = {0};
// PCA9544A
if (channel < 4)
tbuf[0] = 0x04 + channel;
else
tbuf[0] = 0x00; // close all channels
return i2c_rdwr_msg_transfer(fd, addr, tbuf, tcount, rbuf, rcount);
}
static int
pal_control_switch(int fd, uint8_t addr, uint8_t channel) {
uint8_t tcount = 1, rcount = 0;
uint8_t tbuf[16] = {0};
uint8_t rbuf[16] = {0};
// PCA9846
if (channel < 4)
tbuf[0] = 0x01 << channel;
else
tbuf[0] = 0x00; // close all channels
return i2c_rdwr_msg_transfer(fd, addr, tbuf, tcount, rbuf, rcount);
}
// Shared Memory data accrossing processes
struct mux_shm {
pthread_mutex_t mutex;
pthread_cond_t unlock, free;
int locked;
int using_num;
time_t expiration;
uint8_t chan, ipmb_chan;
};
// Data in each process
struct mux {
pthread_once_t init;
void (*init_func)(void);
int bus_fd, addr, wait_time;
struct mux_shm *shm;
};
static void init_mux_data_riser_mux(void);
struct mux riser_mux = {
.init = PTHREAD_ONCE_INIT,
.init_func = init_mux_data_riser_mux,
.bus_fd = -1,
.addr = 0xe2,
.wait_time = 3,
.shm = NULL,
};
static void init_mux_data_riser_mux(void) {
int fd;
struct stat st;
pthread_mutexattr_t mutex_attr;
pthread_condattr_t cond_attr;
char path[128];
uint8_t slot_cfg;
fd = shm_open("/mux_data_riser_mux", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
flock(fd, LOCK_EX);
fstat(fd, &st);
if (ftruncate(fd, sizeof(struct mux_shm)) != 0) {
syslog(LOG_ERR, "Setting size of SHM failed!\n");
}
riser_mux.shm = (struct mux_shm *)mmap(NULL, sizeof(struct mux_shm),
PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
// Initialize shared memory
if (st.st_size < sizeof(struct mux_shm)) {
pthread_mutexattr_init(&mutex_attr);
pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutexattr_setpshared(&mutex_attr, PTHREAD_PROCESS_SHARED);
pthread_mutexattr_setrobust(&mutex_attr, PTHREAD_MUTEX_ROBUST);
pthread_mutex_init(&riser_mux.shm->mutex, &mutex_attr);
pthread_condattr_init(&cond_attr);
pthread_condattr_setpshared(&cond_attr, PTHREAD_PROCESS_SHARED);
pthread_cond_init(&riser_mux.shm->unlock, &cond_attr);
pthread_cond_init(&riser_mux.shm->free, &cond_attr);
riser_mux.shm->locked = 0;
riser_mux.shm->using_num = 0;
riser_mux.shm->expiration = 0;
riser_mux.shm->chan = 0xff;
if (pal_get_slot_cfg_id(&slot_cfg) < 0)
slot_cfg = SLOT_CFG_EMPTY;
// default channel to top slot
if(slot_cfg == SLOT_CFG_SS_3x8)
riser_mux.shm->ipmb_chan = 2;
else
riser_mux.shm->ipmb_chan = 1;
}
flock(fd, LOCK_UN);
close(fd);
snprintf(path, sizeof(path), "/dev/i2c-%d", RISER_BUS_ID);
riser_mux.bus_fd = open(path, O_RDWR);
if (riser_mux.bus_fd < 0) {
syslog(LOG_ERR, "Cannot open %s\n", path);
}
}
static struct mux_shm *mux_get_shm(struct mux *mux) {
pthread_once(&(mux->init), mux->init_func);
return mux->shm;
}
static void shm_lock(struct mux_shm *shm)
{
int rc = pthread_mutex_lock(&shm->mutex);
if (rc == EOWNERDEAD) {
syslog(LOG_WARNING, "Trying to recover riser mutex due to dead-owner\n");
rc = pthread_mutex_consistent(&shm->mutex);
if (rc != 0) {
syslog(LOG_ERR, "Failed to recover riser mutex after dead-owner: %s\n", strerror(rc));
} else {
// Switch to defaults.
shm->locked = 0;
shm->using_num = 0;
shm->expiration = 0;
shm->chan = 0xff;
syslog(LOG_ERR, "Successfully recovered riser mutex after a dead-owner");
// Let any other "expired" user's lease expire.
sleep(1);
}
} else if (rc != 0) {
syslog(LOG_ERR, "Failed to lock riser mux: %s\n", strerror(rc));
}
}
static void shm_unlock(struct mux_shm *shm)
{
pthread_mutex_unlock(&shm->mutex);
}
/*
* Release the mux
*/
static int mux_release (struct mux *mux)
{
struct mux_shm *shm = mux_get_shm(mux);
int ret = 0;
uint8_t old_chan;
shm_lock(shm);
old_chan = shm->chan;
if (shm->chan != shm->ipmb_chan) {
ret = pal_control_mux(mux->bus_fd, mux->addr, shm->ipmb_chan);
}
shm->chan = shm->ipmb_chan;
shm_unlock(shm);
//send online command out side of mutex
if(old_chan != shm->ipmb_chan) {
if(pal_is_BBV_prsnt())
notify_BBV_ipmb_offline_online(1,0);
}
shm_lock(shm);
shm->locked = 0;
pthread_cond_broadcast(&shm->unlock);
shm_unlock(shm);
return ret;
}
/*
* Request to use the mux on the channel
*/
static int mux_using (struct mux *mux)
{
struct mux_shm *shm = mux_get_shm(mux);
int ret = -1;
struct timespec to;
clock_gettime(CLOCK_REALTIME, &to);
to.tv_sec += mux->wait_time;
shm_lock(shm);
if (shm->locked == 1 && time(NULL) > shm->expiration) {
mux_release(mux);
}
while(1) {
if (shm->chan == shm->ipmb_chan) {
ret = 0;
break;
}
ret = pthread_cond_timedwait(&shm->unlock, &shm->mutex, &to);
if (ret == ETIMEDOUT) {
syslog(LOG_WARNING, "%s wait unlock timeout\n", __func__);
break;
}
}
shm->using_num++;
shm_unlock(shm);
return ret;
}
/*
* Notify that using finished
*/
static int mux_finish (struct mux *mux)
{
struct mux_shm *shm = mux_get_shm(mux);
shm_lock(shm);
if (shm->using_num > 0)
shm->using_num--;
pthread_cond_broadcast(&shm->free);
shm_unlock(shm);
return 0;
}
/*
* Request to lock the mux on the channel, doesn't allow other to use
* Return 0 on success, other on failure
*/
static int mux_lock (struct mux *mux, int chan, int lease_time)
{
struct mux_shm *shm = mux_get_shm(mux);
int ret = -1;
struct timespec to;
clock_gettime(CLOCK_REALTIME, &to);
to.tv_sec += mux->wait_time;
shm_lock(shm);
if (shm->locked == 1 && time(NULL) > shm->expiration) {
mux_release(mux);
}
// Announce to lock this resource
while(1) {
if (shm->locked == 0) {
shm->expiration = time(NULL) + lease_time;
shm->locked = 1;
shm_unlock(shm);
//send offline command out side of mutex
if(shm->ipmb_chan != chan) {
if(pal_is_BBV_prsnt())
notify_BBV_ipmb_offline_online(0,mux->wait_time);
}
shm_lock(shm);
shm->chan = chan;
ret = 0;
break;
}
ret = pthread_cond_timedwait(&shm->unlock, &shm->mutex, &to);
if (ret == ETIMEDOUT) {
ret = -ETIMEDOUT;
syslog(LOG_WARNING, "%s wait unlock timeout\n", __func__);
break;
}
}
// Wait for all ipmb transaction finished before switch channel
if (ret == 0 && shm->ipmb_chan != chan) {
clock_gettime(CLOCK_REALTIME, &to);
to.tv_sec += mux->wait_time;
shm->expiration += mux->wait_time;
while (1) {
if (shm->using_num == 0) {
break;
}
ret = pthread_cond_timedwait(&shm->free, &shm->mutex, &to);
if (ret == ETIMEDOUT) {
syslog(LOG_WARNING, "%s wait free timeout\n", __func__);
break;
}
}
// switch MUX no matter bus free or time-out
ret = pal_control_mux(mux->bus_fd, mux->addr, chan);
if (ret != 0) {
// unlock if failed
pal_control_mux(mux->bus_fd, mux->addr, shm->ipmb_chan);
shm->chan = shm->ipmb_chan;
shm->locked = 0;
pthread_cond_broadcast(&shm->unlock);
}
}
shm_unlock(shm);
return ret;
}
int pal_ipmb_processing(int bus, void *buf, uint16_t size)
{
if (bus == RISER_BUS_ID)
return mux_using(&riser_mux);
return 0;
}
int pal_ipmb_finished(int bus, void *buf, uint16_t size)
{
if (bus == RISER_BUS_ID)
return mux_finish(&riser_mux);
return 0;
}
int
notify_BBV_ipmb_offline_online(uint8_t on_off, int off_sec) {
int rlen = 0;
rlen = ipmb_send(
RISER_BUS_ID,
0x2c,
NETFN_OEM_REQ << 2,
CMD_OEM_SET_IPMB_OFFONLINE,
0x4C,
0x1C,
0x00,
on_off,
off_sec & 0xff,
off_sec >> 8);
if ( rlen < 0 )
{
#ifdef DEBUG
syslog(LOG_DEBUG, "%s(%d): Zero bytes received\n", __func__, __LINE__);
#endif
return -1;
}
else
{
if (ipmb_rxb()->cc == 0) {
return 0;
} else {
syslog(LOG_DEBUG, "%s(%d): fail com_code:%x \n", __func__, __LINE__,ipmb_rxb()->cc);
return -1;
}
}
}
// List of MB sensors to be monitored
const uint8_t mb_sensor_list[] = {
MB_SENSOR_INLET_TEMP,
MB_SENSOR_OUTLET_TEMP,
MB_SENSOR_INLET_REMOTE_TEMP,
MB_SENSOR_OUTLET_REMOTE_TEMP,
MB_SENSOR_FAN0_TACH,
MB_SENSOR_FAN1_TACH,
MB_SENSOR_P3V3,
MB_SENSOR_P5V,
MB_SENSOR_P12V,
MB_SENSOR_P1V05,
MB_SENSOR_PVNN_PCH_STBY,
MB_SENSOR_P3V3_STBY,
MB_SENSOR_P5V_STBY,
MB_SENSOR_P3V_BAT,
MB_SENSOR_HSC_IN_VOLT,
MB_SENSOR_HSC_OUT_CURR,
MB_SENSOR_HSC_TEMP,
MB_SENSOR_HSC_IN_POWER,
MB_SENSOR_CPU0_TEMP,
MB_SENSOR_CPU0_TJMAX,
MB_SENSOR_CPU0_PKG_POWER,
MB_SENSOR_CPU0_THERM_MARGIN,
MB_SENSOR_CPU1_TEMP,
MB_SENSOR_CPU1_TJMAX,
MB_SENSOR_CPU1_PKG_POWER,
MB_SENSOR_CPU1_THERM_MARGIN,
MB_SENSOR_PCH_TEMP,
MB_SENSOR_CPU0_DIMM_GRPA_TEMP,
MB_SENSOR_CPU0_DIMM_GRPB_TEMP,
MB_SENSOR_CPU1_DIMM_GRPC_TEMP,
MB_SENSOR_CPU1_DIMM_GRPD_TEMP,
MB_SENSOR_VR_CPU0_VCCIN_TEMP,
MB_SENSOR_VR_CPU0_VCCIN_CURR,
MB_SENSOR_VR_CPU0_VCCIN_VOLT,
MB_SENSOR_VR_CPU0_VCCIN_POWER,
MB_SENSOR_VR_CPU0_VSA_TEMP,
MB_SENSOR_VR_CPU0_VSA_CURR,
MB_SENSOR_VR_CPU0_VSA_VOLT,
MB_SENSOR_VR_CPU0_VSA_POWER,
MB_SENSOR_VR_CPU0_VCCIO_TEMP,
MB_SENSOR_VR_CPU0_VCCIO_CURR,
MB_SENSOR_VR_CPU0_VCCIO_VOLT,
MB_SENSOR_VR_CPU0_VCCIO_POWER,
MB_SENSOR_VR_CPU0_VDDQ_GRPA_TEMP,
MB_SENSOR_VR_CPU0_VDDQ_GRPA_CURR,
MB_SENSOR_VR_CPU0_VDDQ_GRPA_VOLT,
MB_SENSOR_VR_CPU0_VDDQ_GRPA_POWER,
MB_SENSOR_VR_CPU0_VDDQ_GRPB_TEMP,
MB_SENSOR_VR_CPU0_VDDQ_GRPB_CURR,
MB_SENSOR_VR_CPU0_VDDQ_GRPB_VOLT,
MB_SENSOR_VR_CPU0_VDDQ_GRPB_POWER,
MB_SENSOR_VR_CPU1_VCCIN_TEMP,
MB_SENSOR_VR_CPU1_VCCIN_CURR,
MB_SENSOR_VR_CPU1_VCCIN_VOLT,
MB_SENSOR_VR_CPU1_VCCIN_POWER,
MB_SENSOR_VR_CPU1_VSA_TEMP,
MB_SENSOR_VR_CPU1_VSA_CURR,
MB_SENSOR_VR_CPU1_VSA_VOLT,
MB_SENSOR_VR_CPU1_VSA_POWER,
MB_SENSOR_VR_CPU1_VCCIO_TEMP,
MB_SENSOR_VR_CPU1_VCCIO_CURR,
MB_SENSOR_VR_CPU1_VCCIO_VOLT,
MB_SENSOR_VR_CPU1_VCCIO_POWER,
MB_SENSOR_VR_CPU1_VDDQ_GRPC_TEMP,
MB_SENSOR_VR_CPU1_VDDQ_GRPC_CURR,
MB_SENSOR_VR_CPU1_VDDQ_GRPC_VOLT,
MB_SENSOR_VR_CPU1_VDDQ_GRPC_POWER,
MB_SENSOR_VR_CPU1_VDDQ_GRPD_TEMP,
MB_SENSOR_VR_CPU1_VDDQ_GRPD_CURR,
MB_SENSOR_VR_CPU1_VDDQ_GRPD_VOLT,
MB_SENSOR_VR_CPU1_VDDQ_GRPD_POWER,
MB_SENSOR_VR_PCH_PVNN_TEMP,
MB_SENSOR_VR_PCH_PVNN_CURR,
MB_SENSOR_VR_PCH_PVNN_VOLT,
MB_SENSOR_VR_PCH_PVNN_POWER,
MB_SENSOR_VR_PCH_P1V05_TEMP,
MB_SENSOR_VR_PCH_P1V05_CURR,
MB_SENSOR_VR_PCH_P1V05_VOLT,
MB_SENSOR_VR_PCH_P1V05_POWER,
MB_SENSOR_CONN_P12V_INA230_VOL,
MB_SENSOR_CONN_P12V_INA230_CURR,
MB_SENSOR_CONN_P12V_INA230_PWR,
MB_SENSOR_HOST_BOOT_TEMP,
};
// List of NIC sensors to be monitored
const uint8_t nic_sensor_list[] = {
MEZZ_SENSOR_TEMP,
};
// List of MB discrete sensors to be monitored
const uint8_t mb_discrete_sensor_list[] = {
MB_SENSOR_POWER_FAIL,
MB_SENSOR_MEMORY_LOOP_FAIL,
MB_SENSOR_PROCESSOR_FAIL,
MB_SENSOR_HSC_VDELTA,
MB_SENSOR_VR_STATUS,
};
const uint8_t riser_slot2_sensor_list[] = {
MB_SENSOR_C2_AVA_FTEMP,
MB_SENSOR_C2_AVA_RTEMP,
MB_SENSOR_C2_NVME_CTEMP,
MB_SENSOR_C2_1_NVME_CTEMP,
MB_SENSOR_C2_2_NVME_CTEMP,
MB_SENSOR_C2_3_NVME_CTEMP,
MB_SENSOR_C2_4_NVME_CTEMP,
MB_SENSOR_C2_P12V_INA230_VOL,
MB_SENSOR_C2_P12V_INA230_CURR,
MB_SENSOR_C2_P12V_INA230_PWR,
};
const uint8_t riser_slot3_sensor_list[] = {
MB_SENSOR_C3_AVA_FTEMP,
MB_SENSOR_C3_AVA_RTEMP,
MB_SENSOR_C3_NVME_CTEMP,
MB_SENSOR_C3_1_NVME_CTEMP,
MB_SENSOR_C3_2_NVME_CTEMP,
MB_SENSOR_C3_3_NVME_CTEMP,
MB_SENSOR_C3_4_NVME_CTEMP,
MB_SENSOR_C3_P12V_INA230_VOL,
MB_SENSOR_C3_P12V_INA230_CURR,
MB_SENSOR_C3_P12V_INA230_PWR,
};
const uint8_t riser_slot4_sensor_list[] = {
MB_SENSOR_C4_AVA_FTEMP,
MB_SENSOR_C4_AVA_RTEMP,
MB_SENSOR_C4_NVME_CTEMP,
MB_SENSOR_C4_1_NVME_CTEMP,
MB_SENSOR_C4_2_NVME_CTEMP,
MB_SENSOR_C4_3_NVME_CTEMP,
MB_SENSOR_C4_4_NVME_CTEMP,
MB_SENSOR_C4_P12V_INA230_VOL,
MB_SENSOR_C4_P12V_INA230_CURR,
MB_SENSOR_C4_P12V_INA230_PWR,
};
float mb_sensor_threshold[MAX_SENSOR_NUM + 1][MAX_SENSOR_THRESHOLD + 1] = {0};
float nic_sensor_threshold[MAX_SENSOR_NUM + 1][MAX_SENSOR_THRESHOLD + 1] = {0};
float riser_slot2_sensor_threshold[MAX_SENSOR_NUM + 1][MAX_SENSOR_THRESHOLD + 1] = {0};
float riser_slot3_sensor_threshold[MAX_SENSOR_NUM + 1][MAX_SENSOR_THRESHOLD + 1] = {0};
float riser_slot4_sensor_threshold[MAX_SENSOR_NUM + 1][MAX_SENSOR_THRESHOLD + 1] = {0};
size_t mb_sensor_cnt = sizeof(mb_sensor_list)/sizeof(uint8_t);
size_t nic_sensor_cnt = sizeof(nic_sensor_list)/sizeof(uint8_t);
size_t mb_discrete_sensor_cnt = sizeof(mb_discrete_sensor_list)/sizeof(uint8_t);
size_t riser_slot2_sensor_cnt = sizeof(riser_slot2_sensor_list)/sizeof(uint8_t);
size_t riser_slot3_sensor_cnt = sizeof(riser_slot3_sensor_list)/sizeof(uint8_t);
size_t riser_slot4_sensor_cnt = sizeof(riser_slot4_sensor_list)/sizeof(uint8_t);
char g_sys_guid[GUID_SIZE] = {0};
char g_dev_guid[GUID_SIZE] = {0};
static uint8_t g_board_rev_id = BOARD_REV_EVT;
static uint8_t g_vr_cpu0_vddq_abc;
static uint8_t g_vr_cpu0_vddq_def;
static uint8_t g_vr_cpu1_vddq_ghj;
static uint8_t g_vr_cpu1_vddq_klm;
static char *dimm_label_SS_DVT[12] = {
"A0", "A1", "A2", "B0", "B1", "B2", "C0", "C1", "C2", "D0", "D1", "D2"};
static char *dimm_label_SS_PVT[12] = {
"A0", "A1", "A2", "A3", "A4", "A5", "B0", "B1", "B2", "B3", "B4", "B5"};
static char *dimm_label_DS_DVT[24] = {
"A0", "A3", "A1", "A4", "A2", "A5", "B0", "B3", "B1", "B4", "B2", "B5", \
"C0", "C3", "C1", "C4", "C2", "C5", "D0", "D3", "D1", "D4", "D2", "D5"};
static char *dimm_label_DS_PVT[24] = {
"A0", "C0", "A1", "C1", "A2", "C2", "A3", "C3", "A4", "C4", "A5", "C5", \
"B0", "D0", "B1", "D1", "B2", "D2", "B3", "D3", "B4", "D4", "B5", "D5", };
struct dimm_map {
unsigned char index;
char *label;
};
static bool is_cpu_socket_occupy(unsigned int cpu_id);
static void _print_sensor_discrete_log(uint8_t fru, uint8_t snr_num, char *snr_name,
uint8_t val, char *event);
static void apply_inlet_correction(float *value) {
int i;
static int rpm[2] = {0};
static bool rpm_valid[2] = {false, false};
static bool inited = false;
float avg_rpm = 0;
uint8_t cnt = 0;
// Get PWM value
for (i = 0; i < 2; i ++) {
if (pal_get_fan_speed(i, &rpm[i]) == 0 || rpm_valid[i] == true) {
rpm_valid[i] = true;
avg_rpm += (float)rpm[i];
cnt++;
}
}
if (cnt) {
avg_rpm = avg_rpm / (float)cnt;
if (!inited) {
inited = true;
sensor_correction_init("/etc/sensor-correction-conf.json");
}
sensor_correction_apply(FRU_MB, MB_SENSOR_INLET_REMOTE_TEMP, avg_rpm, value);
}
}
static void
init_board_sensors(void) {
pal_get_board_rev_id(&g_board_rev_id);
if (g_board_rev_id == BOARD_REV_POWERON ||
g_board_rev_id == BOARD_REV_EVT ) {
g_vr_cpu0_vddq_abc = VR_CPU0_VDDQ_ABC_EVT;
g_vr_cpu0_vddq_def = VR_CPU0_VDDQ_DEF_EVT;
g_vr_cpu1_vddq_ghj = VR_CPU1_VDDQ_GHJ_EVT;
g_vr_cpu1_vddq_klm = VR_CPU1_VDDQ_KLM_EVT;
} else {
g_vr_cpu0_vddq_abc = VR_CPU0_VDDQ_ABC;
g_vr_cpu0_vddq_def = VR_CPU0_VDDQ_DEF;
g_vr_cpu1_vddq_ghj = VR_CPU1_VDDQ_GHJ;
g_vr_cpu1_vddq_klm = VR_CPU1_VDDQ_KLM;
}
}
//Dynamic change CPU Temp threshold
static void
dyn_sensor_thresh_array_init() {
static bool init_cpu0 = false;
static bool init_cpu1 = false;
static bool init_done = false;
char key[MAX_KEY_LEN] = {0};
char str[MAX_VALUE_LEN] = {0};
// Return if both cpu thresholds are initialized
if (init_done) {
return;
}
// Checkd if cpu0 threshold needs to be initialized
if (init_cpu0) {
goto dyn_cpu1_init;
}
sprintf(key, "mb_sensor%d", MB_SENSOR_CPU0_TJMAX);
if( kv_get(key,str,NULL,0) >= 0 && (float) (strtof(str, NULL) - 2) > 0) {
mb_sensor_threshold[MB_SENSOR_CPU0_TEMP][UCR_THRESH] = (float) (strtof(str, NULL) - 2);
init_cpu0 = true;
}else{
mb_sensor_threshold[MB_SENSOR_CPU0_TEMP][UCR_THRESH] = 91;
}
// Check if cpu1 threshold needs to be initialized
dyn_cpu1_init:
if (init_cpu1) {
goto dyn_thresh_exit;
}
sprintf(key, "mb_sensor%d", MB_SENSOR_CPU1_TJMAX);
if( kv_get(key,str,NULL,0) >= 0 && (float) (strtof(str, NULL) - 2) > 0 ) {
mb_sensor_threshold[MB_SENSOR_CPU1_TEMP][UCR_THRESH] = (float) (strtof(str, NULL) - 2);
init_cpu1 = true;
}else{
mb_sensor_threshold[MB_SENSOR_CPU1_TEMP][UCR_THRESH] = 91;
}
// Mark init complete only if both thresholds are initialized
dyn_thresh_exit:
if (init_cpu0 && init_cpu1) {
init_done = true;
}
}
static void
sensor_thresh_array_init() {
static bool init_done = false;
dyn_sensor_thresh_array_init();
if (init_done)
return;
mb_sensor_threshold[MB_SENSOR_OUTLET_TEMP][UCR_THRESH] = 100;
mb_sensor_threshold[MB_SENSOR_INLET_REMOTE_TEMP][UCR_THRESH] = 40;
mb_sensor_threshold[MB_SENSOR_OUTLET_REMOTE_TEMP][UCR_THRESH] = 90;
// Assign UCT based on the system is Single Side or Double Side
if (!(pal_get_platform_id(&g_plat_id)) && !(g_plat_id & PLAT_ID_SKU_MASK)) {
// Single side 10k RPM fans.
mb_sensor_threshold[MB_SENSOR_FAN0_TACH][UNC_THRESH] = 8500;
mb_sensor_threshold[MB_SENSOR_FAN1_TACH][UNC_THRESH] = 8500;
mb_sensor_threshold[MB_SENSOR_FAN0_TACH][UCR_THRESH] = 11500;
mb_sensor_threshold[MB_SENSOR_FAN1_TACH][UCR_THRESH] = 11500;
} else {
// Double side 15k RPM fans.
mb_sensor_threshold[MB_SENSOR_FAN0_TACH][UNC_THRESH] = 13500;
mb_sensor_threshold[MB_SENSOR_FAN1_TACH][UNC_THRESH] = 13500;
mb_sensor_threshold[MB_SENSOR_FAN0_TACH][UCR_THRESH] = 17000;
mb_sensor_threshold[MB_SENSOR_FAN1_TACH][UCR_THRESH] = 17000;
}
mb_sensor_threshold[MB_SENSOR_FAN0_TACH][LCR_THRESH] = 500;
mb_sensor_threshold[MB_SENSOR_FAN1_TACH][LCR_THRESH] = 500;
mb_sensor_threshold[MB_SENSOR_P3V3][UCR_THRESH] = 3.621;
mb_sensor_threshold[MB_SENSOR_P3V3][LCR_THRESH] = 2.975;
mb_sensor_threshold[MB_SENSOR_P5V][UCR_THRESH] = 5.486;
mb_sensor_threshold[MB_SENSOR_P5V][LCR_THRESH] = 4.524;
mb_sensor_threshold[MB_SENSOR_P12V][UCR_THRESH] = 13.23;
mb_sensor_threshold[MB_SENSOR_P12V][LCR_THRESH] = 10.773;
mb_sensor_threshold[MB_SENSOR_P1V05][UCR_THRESH] = 1.15;
mb_sensor_threshold[MB_SENSOR_P1V05][LCR_THRESH] = 0.94;
mb_sensor_threshold[MB_SENSOR_PVNN_PCH_STBY][UCR_THRESH] = 1.1;
mb_sensor_threshold[MB_SENSOR_PVNN_PCH_STBY][LCR_THRESH] = 0.76;
mb_sensor_threshold[MB_SENSOR_P3V3_STBY][UCR_THRESH] = 3.621;
mb_sensor_threshold[MB_SENSOR_P3V3_STBY][LCR_THRESH] = 2.975;
mb_sensor_threshold[MB_SENSOR_P5V_STBY][UCR_THRESH] = 5.486;
mb_sensor_threshold[MB_SENSOR_P5V_STBY][LCR_THRESH] = 4.524;
mb_sensor_threshold[MB_SENSOR_P3V_BAT][UCR_THRESH] = 3.738;
mb_sensor_threshold[MB_SENSOR_P3V_BAT][LCR_THRESH] = 2.73;
mb_sensor_threshold[MB_SENSOR_HSC_IN_VOLT][UCR_THRESH] = 13.2;
mb_sensor_threshold[MB_SENSOR_HSC_IN_VOLT][LCR_THRESH] = 10.8;
mb_sensor_threshold[MB_SENSOR_HSC_OUT_CURR][UCR_THRESH] = 52.8;
mb_sensor_threshold[MB_SENSOR_HSC_IN_POWER][UCR_THRESH] = 792.0;
mb_sensor_threshold[MB_SENSOR_PCH_TEMP][UCR_THRESH] = 82;
mb_sensor_threshold[MB_SENSOR_CPU0_DIMM_GRPA_TEMP][UCR_THRESH] = 81;
mb_sensor_threshold[MB_SENSOR_CPU0_DIMM_GRPB_TEMP][UCR_THRESH] = 81;
mb_sensor_threshold[MB_SENSOR_CPU1_DIMM_GRPC_TEMP][UCR_THRESH] = 81;
mb_sensor_threshold[MB_SENSOR_CPU1_DIMM_GRPD_TEMP][UCR_THRESH] = 81;
mb_sensor_threshold[MB_SENSOR_VR_CPU0_VCCIN_TEMP][UCR_THRESH] = 95;
mb_sensor_threshold[MB_SENSOR_VR_CPU0_VCCIN_CURR][UCR_THRESH] = 235;
mb_sensor_threshold[MB_SENSOR_VR_CPU0_VCCIN_POWER][UCR_THRESH] = 414;
mb_sensor_threshold[MB_SENSOR_VR_CPU0_VCCIN_VOLT][LCR_THRESH] = 1.45;
mb_sensor_threshold[MB_SENSOR_VR_CPU0_VCCIN_VOLT][UCR_THRESH] = 2.05;
mb_sensor_threshold[MB_SENSOR_VR_CPU0_VSA_TEMP][UCR_THRESH] = 95;
mb_sensor_threshold[MB_SENSOR_VR_CPU0_VSA_CURR][UCR_THRESH] = 20;
mb_sensor_threshold[MB_SENSOR_VR_CPU0_VSA_POWER][UCR_THRESH] = 25;
mb_sensor_threshold[MB_SENSOR_VR_CPU0_VSA_VOLT][LCR_THRESH] = 0.45;
mb_sensor_threshold[MB_SENSOR_VR_CPU0_VSA_VOLT][UCR_THRESH] = 1.2;
mb_sensor_threshold[MB_SENSOR_VR_CPU0_VCCIO_TEMP][UCR_THRESH] = 95;
mb_sensor_threshold[MB_SENSOR_VR_CPU0_VCCIO_CURR][UCR_THRESH] = 24;
mb_sensor_threshold[MB_SENSOR_VR_CPU0_VCCIO_POWER][UCR_THRESH] = 32;
mb_sensor_threshold[MB_SENSOR_VR_CPU0_VCCIO_VOLT][LCR_THRESH] = 0.8;
mb_sensor_threshold[MB_SENSOR_VR_CPU0_VCCIO_VOLT][UCR_THRESH] = 1.2;
mb_sensor_threshold[MB_SENSOR_VR_CPU0_VDDQ_GRPA_TEMP][UCR_THRESH] = 95;
if (!(pal_get_platform_id(&g_plat_id)) && !(g_plat_id & PLAT_ID_SKU_MASK)) {
mb_sensor_threshold[MB_SENSOR_VR_CPU0_VDDQ_GRPA_CURR][UCR_THRESH] = 40;
mb_sensor_threshold[MB_SENSOR_VR_CPU0_VDDQ_GRPA_POWER][UCR_THRESH] = 66;
} else {
mb_sensor_threshold[MB_SENSOR_VR_CPU0_VDDQ_GRPA_CURR][UCR_THRESH] = 95;
mb_sensor_threshold[MB_SENSOR_VR_CPU0_VDDQ_GRPA_POWER][UCR_THRESH] = 115;
}
mb_sensor_threshold[MB_SENSOR_VR_CPU0_VDDQ_GRPA_VOLT][LCR_THRESH] = 1.08;
mb_sensor_threshold[MB_SENSOR_VR_CPU0_VDDQ_GRPA_VOLT][UCR_THRESH] = 1.32;
mb_sensor_threshold[MB_SENSOR_VR_CPU0_VDDQ_GRPB_TEMP][UCR_THRESH] = 95;
if (!(pal_get_platform_id(&g_plat_id)) && !(g_plat_id & PLAT_ID_SKU_MASK)) {
mb_sensor_threshold[MB_SENSOR_VR_CPU0_VDDQ_GRPB_CURR][UCR_THRESH] = 40;
mb_sensor_threshold[MB_SENSOR_VR_CPU0_VDDQ_GRPB_POWER][UCR_THRESH] = 66;
} else {
mb_sensor_threshold[MB_SENSOR_VR_CPU0_VDDQ_GRPB_CURR][UCR_THRESH] = 95;
mb_sensor_threshold[MB_SENSOR_VR_CPU0_VDDQ_GRPB_POWER][UCR_THRESH] = 115;
}
mb_sensor_threshold[MB_SENSOR_VR_CPU0_VDDQ_GRPB_VOLT][LCR_THRESH] = 1.08;
mb_sensor_threshold[MB_SENSOR_VR_CPU0_VDDQ_GRPB_VOLT][UCR_THRESH] = 1.32;
mb_sensor_threshold[MB_SENSOR_VR_CPU1_VCCIN_TEMP][UCR_THRESH] = 95;
mb_sensor_threshold[MB_SENSOR_VR_CPU1_VCCIN_CURR][UCR_THRESH] = 235;
mb_sensor_threshold[MB_SENSOR_VR_CPU1_VCCIN_POWER][UCR_THRESH] = 420;
mb_sensor_threshold[MB_SENSOR_VR_CPU1_VCCIN_VOLT][LCR_THRESH] = 1.45;
mb_sensor_threshold[MB_SENSOR_VR_CPU1_VCCIN_VOLT][UCR_THRESH] = 2.05;
mb_sensor_threshold[MB_SENSOR_VR_CPU1_VSA_TEMP][UCR_THRESH] = 95;
mb_sensor_threshold[MB_SENSOR_VR_CPU1_VSA_CURR][UCR_THRESH] = 20;
mb_sensor_threshold[MB_SENSOR_VR_CPU1_VSA_POWER][UCR_THRESH] = 25;
mb_sensor_threshold[MB_SENSOR_VR_CPU1_VSA_VOLT][LCR_THRESH] = 0.45;
mb_sensor_threshold[MB_SENSOR_VR_CPU1_VSA_VOLT][UCR_THRESH] = 1.2;
mb_sensor_threshold[MB_SENSOR_VR_CPU1_VCCIO_TEMP][UCR_THRESH] = 95;
mb_sensor_threshold[MB_SENSOR_VR_CPU1_VCCIO_CURR][UCR_THRESH] = 24;
mb_sensor_threshold[MB_SENSOR_VR_CPU1_VCCIO_POWER][UCR_THRESH] = 32;
mb_sensor_threshold[MB_SENSOR_VR_CPU1_VCCIO_VOLT][LCR_THRESH] = 0.8;
mb_sensor_threshold[MB_SENSOR_VR_CPU1_VCCIO_VOLT][UCR_THRESH] = 1.2;
mb_sensor_threshold[MB_SENSOR_VR_CPU1_VDDQ_GRPC_TEMP][UCR_THRESH] = 95;
if (!(pal_get_platform_id(&g_plat_id)) && !(g_plat_id & PLAT_ID_SKU_MASK)) {
mb_sensor_threshold[MB_SENSOR_VR_CPU1_VDDQ_GRPC_CURR][UCR_THRESH] = 40;
mb_sensor_threshold[MB_SENSOR_VR_CPU1_VDDQ_GRPC_POWER][UCR_THRESH] = 66;
} else {
mb_sensor_threshold[MB_SENSOR_VR_CPU1_VDDQ_GRPC_CURR][UCR_THRESH] = 95;
mb_sensor_threshold[MB_SENSOR_VR_CPU1_VDDQ_GRPC_POWER][UCR_THRESH] = 115;
}
mb_sensor_threshold[MB_SENSOR_VR_CPU1_VDDQ_GRPC_VOLT][LCR_THRESH] = 1.08;
mb_sensor_threshold[MB_SENSOR_VR_CPU1_VDDQ_GRPC_VOLT][UCR_THRESH] = 1.32;
mb_sensor_threshold[MB_SENSOR_VR_CPU1_VDDQ_GRPD_TEMP][UCR_THRESH] = 95;
if (!(pal_get_platform_id(&g_plat_id)) && !(g_plat_id & PLAT_ID_SKU_MASK)) {
mb_sensor_threshold[MB_SENSOR_VR_CPU1_VDDQ_GRPD_CURR][UCR_THRESH] = 40;
mb_sensor_threshold[MB_SENSOR_VR_CPU1_VDDQ_GRPD_POWER][UCR_THRESH] = 66;
} else {
mb_sensor_threshold[MB_SENSOR_VR_CPU1_VDDQ_GRPD_CURR][UCR_THRESH] = 95;
mb_sensor_threshold[MB_SENSOR_VR_CPU1_VDDQ_GRPD_POWER][UCR_THRESH] = 115;
}
mb_sensor_threshold[MB_SENSOR_VR_CPU1_VDDQ_GRPD_VOLT][LCR_THRESH] = 1.08;
mb_sensor_threshold[MB_SENSOR_VR_CPU1_VDDQ_GRPD_VOLT][UCR_THRESH] = 1.32;
mb_sensor_threshold[MB_SENSOR_VR_PCH_PVNN_TEMP][UCR_THRESH] = 95;
mb_sensor_threshold[MB_SENSOR_VR_PCH_PVNN_CURR][UCR_THRESH] = 23;
mb_sensor_threshold[MB_SENSOR_VR_PCH_PVNN_POWER][UCR_THRESH] = 28;
mb_sensor_threshold[MB_SENSOR_VR_PCH_PVNN_VOLT][LCR_THRESH] = 0.76;
mb_sensor_threshold[MB_SENSOR_VR_PCH_PVNN_VOLT][UCR_THRESH] = 1.1;
mb_sensor_threshold[MB_SENSOR_VR_PCH_P1V05_TEMP][UCR_THRESH] = 95;
mb_sensor_threshold[MB_SENSOR_VR_PCH_P1V05_CURR][UCR_THRESH] = 19;
mb_sensor_threshold[MB_SENSOR_VR_PCH_P1V05_POWER][UCR_THRESH] = 26;
mb_sensor_threshold[MB_SENSOR_VR_PCH_P1V05_VOLT][LCR_THRESH] = 0.94;
mb_sensor_threshold[MB_SENSOR_VR_PCH_P1V05_VOLT][UCR_THRESH] = 1.15;
// Set when required
// mb_sensor_threshold[MB_SENSOR_HOST_BOOT_TEMP][UCR_THRESH] = 100;
riser_slot2_sensor_threshold[MB_SENSOR_C2_NVME_CTEMP][UCR_THRESH] = 75;
riser_slot3_sensor_threshold[MB_SENSOR_C3_NVME_CTEMP][UCR_THRESH] = 75;
riser_slot4_sensor_threshold[MB_SENSOR_C4_NVME_CTEMP][UCR_THRESH] = 75;
riser_slot2_sensor_threshold[MB_SENSOR_C2_AVA_FTEMP][UCR_THRESH] = 60;
riser_slot2_sensor_threshold[MB_SENSOR_C2_AVA_RTEMP][UCR_THRESH] = 80;
riser_slot2_sensor_threshold[MB_SENSOR_C2_1_NVME_CTEMP][UCR_THRESH] = 75;
riser_slot2_sensor_threshold[MB_SENSOR_C2_2_NVME_CTEMP][UCR_THRESH] = 75;
riser_slot2_sensor_threshold[MB_SENSOR_C2_3_NVME_CTEMP][UCR_THRESH] = 75;
riser_slot2_sensor_threshold[MB_SENSOR_C2_4_NVME_CTEMP][UCR_THRESH] = 75;
riser_slot3_sensor_threshold[MB_SENSOR_C3_AVA_FTEMP][UCR_THRESH] = 60;
riser_slot3_sensor_threshold[MB_SENSOR_C3_AVA_RTEMP][UCR_THRESH] = 80;
riser_slot3_sensor_threshold[MB_SENSOR_C3_1_NVME_CTEMP][UCR_THRESH] = 75;
riser_slot3_sensor_threshold[MB_SENSOR_C3_2_NVME_CTEMP][UCR_THRESH] = 75;
riser_slot3_sensor_threshold[MB_SENSOR_C3_3_NVME_CTEMP][UCR_THRESH] = 75;
riser_slot3_sensor_threshold[MB_SENSOR_C3_4_NVME_CTEMP][UCR_THRESH] = 75;
riser_slot4_sensor_threshold[MB_SENSOR_C4_AVA_FTEMP][UCR_THRESH] = 60;
riser_slot4_sensor_threshold[MB_SENSOR_C4_AVA_RTEMP][UCR_THRESH] = 80;
riser_slot4_sensor_threshold[MB_SENSOR_C4_1_NVME_CTEMP][UCR_THRESH] = 75;
riser_slot4_sensor_threshold[MB_SENSOR_C4_2_NVME_CTEMP][UCR_THRESH] = 75;
riser_slot4_sensor_threshold[MB_SENSOR_C4_3_NVME_CTEMP][UCR_THRESH] = 75;
riser_slot4_sensor_threshold[MB_SENSOR_C4_4_NVME_CTEMP][UCR_THRESH] = 75;
riser_slot2_sensor_threshold[MB_SENSOR_C2_P12V_INA230_VOL][UCR_THRESH] = 12.96;
riser_slot2_sensor_threshold[MB_SENSOR_C2_P12V_INA230_VOL][LCR_THRESH] = 11.04;
riser_slot2_sensor_threshold[MB_SENSOR_C2_P12V_INA230_CURR][UCR_THRESH] = 5.5;
riser_slot2_sensor_threshold[MB_SENSOR_C2_P12V_INA230_PWR][UCR_THRESH] = 75;
riser_slot3_sensor_threshold[MB_SENSOR_C3_P12V_INA230_VOL][UCR_THRESH] = 12.96;
riser_slot3_sensor_threshold[MB_SENSOR_C3_P12V_INA230_VOL][LCR_THRESH] = 11.04;
riser_slot3_sensor_threshold[MB_SENSOR_C3_P12V_INA230_CURR][UCR_THRESH] = 5.5;
riser_slot3_sensor_threshold[MB_SENSOR_C3_P12V_INA230_PWR][UCR_THRESH] = 75;
riser_slot4_sensor_threshold[MB_SENSOR_C4_P12V_INA230_VOL][UCR_THRESH] = 12.96;
riser_slot4_sensor_threshold[MB_SENSOR_C4_P12V_INA230_VOL][LCR_THRESH] = 11.04;
riser_slot4_sensor_threshold[MB_SENSOR_C4_P12V_INA230_CURR][UCR_THRESH] = 5.5;
riser_slot4_sensor_threshold[MB_SENSOR_C4_P12V_INA230_PWR][UCR_THRESH] = 75;
mb_sensor_threshold[MB_SENSOR_CONN_P12V_INA230_VOL][UCR_THRESH] = 12.96;
mb_sensor_threshold[MB_SENSOR_CONN_P12V_INA230_VOL][LCR_THRESH] = 11.04;
mb_sensor_threshold[MB_SENSOR_CONN_P12V_INA230_CURR][UCR_THRESH] = 20;
mb_sensor_threshold[MB_SENSOR_CONN_P12V_INA230_PWR][UCR_THRESH] = 250;
nic_sensor_threshold[MEZZ_SENSOR_TEMP][UCR_THRESH] = 95;
init_board_sensors();
init_done = true;
}
void
turn_off_p12v_stby(char* cause) {
syslog(LOG_CRIT, "Turn off P12V_STBY because of %s\n", cause);
sync();
sleep(1);
if (system("i2cset -y 7 0x45 0x01 0 &> /dev/null") != 0) {
syslog(LOG_CRIT, "turn off HSC output failed\n");
}
return;
}
static int
read_outlet_temp(float *value) {
int ret = sensors_read("tmp421-i2c-6-4f", "MB_OUTLET_TEMP", (float *)value);
// check the return value
if ( ret < 0 ) {
return READING_NA;
}
// if we get the reading, check the reading is greater than or equal to its threshold
if ( (*value >= mb_sensor_threshold[MB_SENSOR_OUTLET_TEMP][UCR_THRESH]) ) {
syslog(LOG_CRIT, "MB_OUTLET_TEMP sensor is over the threshold, turn off P12V_STBY\n");
turn_off_p12v_stby("MB_OUTLET_TEMP");
}
return ret;
}
static int
read_nic_temp(float *value)
{
static unsigned int retry = 0;
int ret = sensors_read("tmp421-i2c-8-1f", "MEZZ_SENSOR_TEMP", value);
// Workaround: handle when NICs wrongly report higher temperatures
if (ret || ( *value > NIC_MAX_TEMP ) || ( *value < NIC_MIN_TEMP )) {
ret = READING_NA;
} else {
retry = 0;
}
if (ret == READING_NA && ++retry <= 3)
ret = READING_SKIP;
return ret;
}
static int
read_fan_value(const char *fan, float *value)
{
int ret = sensors_read_fan(fan, value);
if (ret || *value < 500 || *value > mb_sensor_threshold[MB_SENSOR_FAN0_TACH][UCR_THRESH]) {
sleep(2);
ret = sensors_read_fan(fan, value);
}
return ret;
}
int
check_vr_ov_ot_status(float *value) {
uint8_t vr_addr_list[] = {VR_CPU0_VCCIN, VR_CPU0_VSA, VR_CPU0_VCCIO, VR_CPU0_VDDQ_ABC, VR_CPU0_VDDQ_DEF, \
VR_CPU1_VCCIN, VR_CPU1_VSA, VR_CPU1_VCCIO, VR_CPU1_VDDQ_GHJ, VR_CPU1_VDDQ_KLM, VR_PCH_PVNN};
char *vr_name_list[] = {"VR_CPU0_VCCIN", "VR_CPU0_VSA", "VR_CPU0_VCCIO", "VR_CPU0_VDDQ_ABC", "VR_CPU0_VDDQ_DEF", \
"VR_CPU1_VCCIN", "VR_CPU1_VSA", "VR_CPU1_VCCIO", "VR_CPU1_VDDQ_GHJ", "VR_CPU1_VDDQ_KLM", "VR_PCH_PVNN"};
size_t vr_list_size = sizeof(vr_addr_list);
int ret = 0;
*value = 0;
for ( int i = 0; i < vr_list_size; i++ ) {
ret = vr_read_ov_ot_status(vr_addr_list[i]);
if ( ret == VR_GET_OV_OC_OT ) {
turn_off_p12v_stby(vr_name_list[i]);
} else if ( ret < 0 ) {
syslog(LOG_WARNING, "%s(): failed to access vr status\n", __func__);
}
}
return PAL_EOK;
}
static int
read_hsc_vdelta_value(float *value) {
uint8_t bus_id = 0x4;
uint8_t rbuf[256] = {0x00};
uint8_t tlen = 0;
int rlen = 0;
float hsc_b = 0;
ipmb_req_t *req;
int ret = 0;
static int retry = 0;
uint8_t revision_id = 0;
uint8_t sku_id = 0;
uint8_t hsc_volt_reg[2] = {0x88, 0x8B}; //VIN, VOUT
float hsc_volt[2] = {0}; //VIN, VOUT
if (pal_get_platform_id(&sku_id) ||
pal_get_board_rev_id(&revision_id)) {
return -1;
}
req = ipmb_txb();
req->res_slave_addr = 0x2C; //ME's Slave Address
req->netfn_lun = NETFN_NM_REQ<<2;
req->cmd = CMD_NM_SEND_RAW_PMBUS;
req->data[0] = 0x57;
req->data[1] = 0x01;
req->data[2] = 0x00;
req->data[3] = 0x86;
if (revision_id < BOARD_REV_PVT) { //DVT
//HSC slave addr check for SS and DS
if ((sku_id & (1 << 4))) { // DS
req->data[4] = 0x8A;
}else{ //SS
req->data[4] = 0x22;
}
} else { //PVT and MP
//HSC slave addr is the same for SS and DS
req->data[4] = 0x8A;
}
req->data[5] = 0x00;
req->data[6] = 0x00;
req->data[7] = 0x01;
req->data[8] = 0x02;
tlen = 10 + MIN_IPMB_REQ_LEN; // Data Length + Others
ret = 0;
for ( int i = 0; i < 2; i++ ) {
req->data[9] = hsc_volt_reg[i];
rlen = ipmb_send_buf(bus_id, tlen);
if ( rlen > 0 ) {
memset(rbuf, 0, sizeof(rbuf));
memcpy(rbuf, ipmb_rxb(), rlen);
}
if ( rlen <= 0 || rbuf[6] != 0 ) {
syslog(LOG_WARNING, "something went wrong, rlen=%d, req->data[9]=%02X, comp_code=%02X\n", rlen, req->data[9], rbuf[6]);
ret = READING_NA;
} else if ( rbuf[6] == 0 ) {
hsc_volt[i] = ((float) (rbuf[11] << 8 | rbuf[10])*100-hsc_b )/(19599);
}
}
if ( ret != READING_NA ) {
*value = hsc_volt[0] - hsc_volt[1];
// Get HSC fault
if ( *value >= HSC_FAULT_DIFF_THRES ) {
if ( retry < 1 ) {
// Check HSC vdelta again
retry++;
} else {
// read ADC P12V for comparison
float p12v_adc = 0;
if ( sensors_read_adc("MB_P12V", &p12v_adc) < 0 ) {
syslog(LOG_CRIT, "Failed to get MB_P12V\n");
}
syslog(LOG_CRIT, "HSC vdelta(Vin(%0.2f)-Vout(%0.2f)) %0.2f >= %0.2f, MB_P12V: %0.2f, turn off P12V_STBY\n" \
, hsc_volt[0], hsc_volt[1], *value, HSC_FAULT_DIFF_THRES, p12v_adc);
turn_off_p12v_stby("HSC vdelta");
}
} else {
retry = 0;
}
} else {
syslog(LOG_INFO, "Couldn't calculate hsc_vdelta, ret= %d, vin=%0.2f vout=%0.2f\n", ret, hsc_volt[0], hsc_volt[1]);
}
return ret;
}
static int
read_hsc_current_value(float *value) {
uint8_t bus_id = 0x4; //TODO: ME's address 0x2c in FBTP
uint8_t rbuf[256] = {0x00};
uint8_t tlen = 0;
int rlen = 0;
float hsc_b = 20475;
float Rsence;
ipmb_req_t *req;
int ret = 0;
static int retry = 0;
uint8_t revision_id;
uint8_t sku_id;
if (pal_get_platform_id(&sku_id) ||
pal_get_board_rev_id(&revision_id)) {
return -1;
}
req = ipmb_txb();
req->res_slave_addr = 0x2C; //ME's Slave Address
req->netfn_lun = NETFN_NM_REQ<<2;
req->cmd = CMD_NM_SEND_RAW_PMBUS;
req->data[0] = 0x57;
req->data[1] = 0x01;
req->data[2] = 0x00;
req->data[3] = 0x86;
if (revision_id < BOARD_REV_PVT) { //DVT
//HSC slave addr check for SS and DS
if ((sku_id & (1 << 4))) { // DS
req->data[4] = 0x8A;
Rsence = 0.265;
}else{ //SS
req->data[4] = 0x22;
Rsence = 0.505;
}
} else { //PVT and MP
//HSC slave addr is the same for SS and DS
req->data[4] = 0x8A;
Rsence = 0.267;
}
req->data[5] = 0x00;
req->data[6] = 0x00;
req->data[7] = 0x01;
req->data[8] = 0x02;
req->data[9] = 0x8C;
tlen = 10 + MIN_IPMB_REQ_LEN; // Data Length + Others
// Invoke IPMB library handler
rlen = ipmb_send_buf(bus_id, tlen);
if (rlen > 0) {
memcpy(rbuf, ipmb_rxb(), rlen);
}
if (rlen <= 0) {
#ifdef DEBUG
syslog(LOG_DEBUG, "read_hsc_current_value: Zero bytes received\n");
#endif
ret = READING_NA;
}
if (rbuf[6] == 0)
{
*value = ((float) (rbuf[11] << 8 | rbuf[10])*10-hsc_b )/(800*Rsence);
retry = 0;
} else {
ret = READING_NA;
}
if (ret == READING_NA) {
retry++;
if (retry <= 3 )
ret = READING_SKIP;
}
return ret;
}
static int
read_hsc_temp_value(float *value) {
uint8_t bus_id = 0x4; //TODO: ME's address 0x2c in FBTP
uint8_t tbuf[256] = {0x00};
uint8_t rbuf[256] = {0x00};
uint8_t tlen = 0;
uint8_t rlen = 0;
float hsc_b = 31880;
float hsc_m = 42;
ipmb_req_t *req;
int ret = 0;
static int retry = 0;
uint8_t revision_id;
uint8_t sku_id;
if (pal_get_platform_id(&sku_id) ||
pal_get_board_rev_id(&revision_id)) {
return -1;
}
req = (ipmb_req_t*)tbuf;
req->res_slave_addr = 0x2C; //ME's Slave Address
req->netfn_lun = NETFN_NM_REQ<<2;
req->hdr_cksum = req->res_slave_addr + req->netfn_lun;
req->hdr_cksum = ZERO_CKSUM_CONST - req->hdr_cksum;
req->req_slave_addr = 0x20;
req->seq_lun = 0x00;
req->cmd = CMD_NM_SEND_RAW_PMBUS;
req->data[0] = 0x57;
req->data[1] = 0x01;
req->data[2] = 0x00;
req->data[3] = 0x86;
if (revision_id < BOARD_REV_PVT) { //DVT
//HSC slave addr check for SS and DS
if ((sku_id & (1 << 4))) { // DS
req->data[4] = 0x8A;
}else{ //SS
req->data[4] = 0x22;
}
} else { //PVT and MP
//HSC slave addr is the same for SS and DS
req->data[4] = 0x8A;
}
req->data[5] = 0x00;
req->data[6] = 0x00;
req->data[7] = 0x01;
req->data[8] = 0x02;
req->data[9] = 0x8D;
tlen = 16;
// Invoke IPMB library handler
lib_ipmb_handle(bus_id, tbuf, tlen+1, rbuf, &rlen);
if (rlen == 0) {
#ifdef DEBUG
syslog(LOG_DEBUG, "read_hsc_temp_value: Zero bytes received\n");
#endif
ret = READING_NA;
}
if (rbuf[6] == 0)
{
*value = ((float) (rbuf[11] << 8 | rbuf[10])*10-hsc_b )/(hsc_m);
retry = 0;
} else {
ret = READING_NA;
}
if (ret == READING_NA) {
retry++;
if (retry <= 3 )
ret = READING_SKIP;
}
return ret;
}
static int
read_sensor_reading_from_ME(uint8_t snr_num, float *value) {
uint8_t bus_id = 0x4; //TODO: ME's address 0x2c in FBTP
uint8_t tbuf[256] = {0x00};
uint8_t rbuf[256] = {0x00};
uint8_t tlen = 0;
uint8_t rlen = 0;
ipmb_req_t *req;
int ret = 0;
enum {
e_HSC_PIN,
e_HSC_VIN,
e_PCH_TEMP,
e_MAX,
};
static uint8_t retry[e_MAX] = {0};
req = (ipmb_req_t*)tbuf;
req->res_slave_addr = 0x2C; //ME's Slave Address
req->netfn_lun = NETFN_SENSOR_REQ<<2;
req->hdr_cksum = req->res_slave_addr + req->netfn_lun;
req->hdr_cksum = ZERO_CKSUM_CONST - req->hdr_cksum;
req->req_slave_addr = 0x20;
req->seq_lun = 0x00;
req->cmd = CMD_SENSOR_GET_SENSOR_READING;
req->data[0] = snr_num;
tlen = 7;
// Invoke IPMB library handler
lib_ipmb_handle(bus_id, tbuf, tlen+1, rbuf, &rlen);
if (rlen == 0) {
//ME no response
#ifdef DEBUG
syslog(LOG_DEBUG, "read HSC %x from_ME: Zero bytes received\n", snr_num);
#endif
ret = READING_NA;
} else {
if (rbuf[6] == 0)
{
if (rbuf[8] & 0x20) {
//not available
ret = READING_NA;
}
} else {
ret = READING_NA;
}
}
if(snr_num == MB_SENSOR_HSC_IN_POWER) {
if (!ret) {
*value = (((float) rbuf[7])*0x28 + 0 )/10 ;
retry[e_HSC_PIN] = 0;
} else {
retry[e_HSC_PIN]++;
if (retry[e_HSC_PIN] <= 3)
ret = READING_SKIP;
}
} else if(snr_num == MB_SENSOR_HSC_IN_VOLT) {
if (!ret) {
*value = (((float) rbuf[7])*0x02 + (0x5e*10) )/100 ;
retry[e_HSC_VIN] = 0;
} else {
retry[e_HSC_VIN]++;
if (retry[e_HSC_VIN] <= 3)
ret = READING_SKIP;
}
} else if(snr_num == MB_SENSOR_PCH_TEMP) {
if (!ret) {
*value = (float) rbuf[7];
retry[e_PCH_TEMP] = 0;
} else {
retry[e_PCH_TEMP]++;
if (retry[e_PCH_TEMP] <= 3)
ret = READING_SKIP;
}
}
return ret;
}
static int
read_cpu_temp(uint8_t snr_num, float *value) {
int ret = 0;
uint8_t bus_id = 0x4; //TODO: ME's address 0x2c in FBTP
uint8_t tbuf[256] = {0x00};
uint8_t rbuf1[256] = {0x00};
static uint8_t tjmax[2] = {0x00};
static uint8_t tjmax_flag[2] = {0};
uint8_t tlen = 0;
uint8_t rlen = 0;
ipmb_req_t *req;
char key[MAX_KEY_LEN] = {0};
char str[MAX_VALUE_LEN] = {0};
int cpu_index;
int16_t dts;
static uint8_t retry[2] = {0x00}; // CPU0 and CPU1
switch (snr_num) {
case MB_SENSOR_CPU0_TEMP:
cpu_index = 0;
break;
case MB_SENSOR_CPU1_TEMP:
cpu_index = 1;
break;
default:
return -1;
}
req = (ipmb_req_t*)tbuf;
req->res_slave_addr = 0x2C; //ME's Slave Address
req->netfn_lun = NETFN_NM_REQ<<2;
req->hdr_cksum = req->res_slave_addr + req->netfn_lun;
req->hdr_cksum = ZERO_CKSUM_CONST - req->hdr_cksum;
req->req_slave_addr = 0x20;
req->seq_lun = 0x00;
if( tjmax_flag[cpu_index] == 0 ) { // First time to get CPU0/CPU1 Tjmax reading
//Get CPU0/CPU1 Tjmax
req->cmd = CMD_NM_SEND_RAW_PECI;
req->data[0] = 0x57;
req->data[1] = 0x01;
req->data[2] = 0x00;
req->data[3] = 0x30 + cpu_index;
req->data[4] = 0x05;
req->data[5] = 0x05;
req->data[6] = 0xa1;
req->data[7] = 0x00;
req->data[8] = 0x10;
req->data[9] = 0x00;
req->data[10] = 0x00;
tlen = 17;
// Invoke IPMB library handler
lib_ipmb_handle(bus_id, tbuf, tlen+1, rbuf1, &rlen);
if (rlen == 0) {
//ME no response
#ifdef DEBUG
syslog(LOG_DEBUG, "%s(%d): Zero bytes received\n", __func__, __LINE__);
#endif
} else {
if (rbuf1[6] == 0)
{
// If PECI command successes and got a reasonable value
if ( (rbuf1[10] == 0x40) && rbuf1[13] > 50) {
tjmax[cpu_index] = rbuf1[13];
tjmax_flag[cpu_index] = 1;
}
}
}
}
//Updated CPU Tjmax cache
sprintf(key, "mb_sensor%d", (cpu_index?MB_SENSOR_CPU1_TJMAX:MB_SENSOR_CPU0_TJMAX));
if (tjmax_flag[cpu_index] != 0) {
sprintf(str, "%.2f",(float) tjmax[cpu_index]);
} else {
//ME no response or PECI command completion code error. Set "NA" in sensor cache.
strcpy(str, "NA");
}
kv_set(key, str, 0, 0);
// Get CPU temp if BMC got TjMax
ret = READING_NA;
if (tjmax_flag[cpu_index] != 0) {
rlen = 0;
memset( rbuf1,0x00,sizeof(rbuf1) );
//Get CPU Temp
req->cmd = CMD_NM_SEND_RAW_PECI;
req->data[0] = 0x57;
req->data[1] = 0x01;
req->data[2] = 0x00;
req->data[3] = 0x30 + cpu_index;
req->data[4] = 0x05;
req->data[5] = 0x05;
req->data[6] = 0xa1;
req->data[7] = 0x00;
req->data[8] = 0x02;
req->data[9] = 0xff;
req->data[10] = 0x00;
tlen = 17;
// Invoke IPMB library handler
lib_ipmb_handle(bus_id, tbuf, tlen+1, rbuf1, &rlen);
if (rlen == 0) {
//ME no response
#ifdef DEBUG
syslog(LOG_DEBUG, "%s(%d): Zero bytes received\n", __func__, __LINE__);
#endif
} else {
if (rbuf1[6] == 0) { // ME Completion Code
if ( (rbuf1[10] == 0x40) ) { // PECI Completion Code
dts = (rbuf1[11] | rbuf1[12] << 8);
// Intel Doc#554767 p.58: Reserved Values 0x8000~0x81ff
if (dts <= -32257) {
ret = READING_NA;
} else {
// 16-bit, 2s complement [15]Sign Bit;[14:6]Integer Value;[5:0]Fractional Value
*value = (float) (tjmax[0] + (dts >> 6));
ret = 0;
}
}
}
}
}
if (ret != 0) {
retry[cpu_index]++;
if (retry[cpu_index] <= 3) {
ret = READING_SKIP;
}
} else
retry[cpu_index] = 0;
//Updated CPU Thermal Margin cache
sprintf(key, "mb_sensor%d", (cpu_index?MB_SENSOR_CPU1_THERM_MARGIN:MB_SENSOR_CPU0_THERM_MARGIN));
switch (ret) {
case 0:
sprintf(str, "%.2f",(float) (dts >> 6));
kv_set(key, str, 0, 0);
break;
case READING_NA:
strcpy(str, "NA");
kv_set(key, str, 0, 0);
break;
case READING_SKIP:
default:
break;
}
return ret;
}
bool
pal_is_BIOS_completed(uint8_t fru)
{
gpio_desc_t *desc;
gpio_value_t value;
bool ret = false;
if ( FRU_MB != fru )
{
syslog(LOG_WARNING, "[%s]incorrect fru id: %d", __func__, fru);
return false;
}
desc = gpio_open_by_shadow("FM_BIOS_POST_CMPLT_N");
if (!desc)
return false;
if (gpio_get_value(desc, &value) == 0 && value == GPIO_VALUE_LOW)
ret = true;
gpio_close(desc);
return ret;
}
void
pal_is_dimm_present_check(uint8_t fru, bool *dimm_sts_list)
{
char key[MAX_KEY_LEN] = {0};
char value[MAX_VALUE_LEN] = {0};
int i;
int DIMM_SLOT_CNT = 12;//only SS
size_t ret;
//check dimm info from /mnt/data/sys_config/
for (i=0; i<DIMM_SLOT_CNT; i++)
{
sprintf(key, "sys_config/fru%d_dimm%d_location", fru, i);
if(kv_get(key, value, &ret, KV_FPERSIST) != 0 || ret < 4)
{
syslog(LOG_WARNING,"[%s]Cannot get dimm_slot%d present info", __func__, i);
return;
}
#ifdef FSC_DEBUG
syslog(LOG_WARNING,"[%s]0=%x 1=%x 2=%x 3=%x", __func__, value[0], value[1], value[2], value[3]);
#endif
if ( 0xff == value[0] )
{
dimm_sts_list[i] = false;
#ifdef FSC_DEBUG
syslog(LOG_WARNING,"[%s]dimm_slot%d is not present", __func__, i);
#endif
}
else
{
dimm_sts_list[i] = true;
#ifdef FSC_DEBUG
syslog(LOG_WARNING,"[%s]dimm_slot%d is present", __func__, i);
#endif
}
}
}
bool
pal_is_dimm_present(uint8_t sensor_num)
{
static bool is_check = false;
static bool dimm_sts_list[12] = {0};
int i = 0,j;
uint8_t fru = FRU_MB;
if ( false == pal_is_BIOS_completed(fru) )
{
return false;
}
if ( false == is_check )
{
is_check = true;
pal_is_dimm_present_check(fru, dimm_sts_list);
}
switch (sensor_num)
{
case MB_SENSOR_CPU0_DIMM_GRPA_TEMP:
i = 0;
break;
case MB_SENSOR_CPU0_DIMM_GRPB_TEMP:
i = 3;
break;
case MB_SENSOR_CPU1_DIMM_GRPC_TEMP:
i = 6;
break;
case MB_SENSOR_CPU1_DIMM_GRPD_TEMP:
i = 9;
break;
default:
syslog(LOG_WARNING, "[%s]Unknown sensor num: 0x%x", __func__, sensor_num);
break;
}
j = i + 3;
for ( ; i<j; i++ )
{
if ( true == dimm_sts_list[i] )
{
return true;
}
}
return false;
}
static int
read_dimm_temp(uint8_t snr_num, float *value) {
int ret = READING_NA;
uint8_t bus_id = 0x4; //TODO: ME's address 0x2c in FBTP
uint8_t tbuf[256] = {0x00};
uint8_t rbuf1[256] = {0x00};
uint8_t tlen = 0;
uint8_t rlen = 0;
ipmb_req_t *req;
int dimm_index, i;
int max = 0;
static uint8_t retry[4] = {0x00};
static int odm_id = -1;
uint8_t BoardInfo;
//Use FM_BOARD_SKU_ID0 to identify ODM to apply filter
if (odm_id == -1) {
ret = pal_get_platform_id(&BoardInfo);
if (ret == 0) {
odm_id = (int) (BoardInfo & 0x1);
//re-init the ret variable since the sensor reading(NA or value) is affected by it
//make sure the ret variable used correctly.
ret = READING_NA;
}
}
//show NA if BIOS has not completed POST.
if ( false == pal_is_BIOS_completed(FRU_MB) )
{
return ret;
}
switch (snr_num) {
case MB_SENSOR_CPU0_DIMM_GRPA_TEMP:
dimm_index = 0;
break;
case MB_SENSOR_CPU0_DIMM_GRPB_TEMP:
dimm_index = 1;
break;
case MB_SENSOR_CPU1_DIMM_GRPC_TEMP:
dimm_index = 2;
break;
case MB_SENSOR_CPU1_DIMM_GRPD_TEMP:
dimm_index = 3;
break;
default:
return -1;
}
req = (ipmb_req_t*)tbuf;
req->res_slave_addr = 0x2C; //ME's Slave Address
req->netfn_lun = NETFN_NM_REQ<<2;
req->hdr_cksum = req->res_slave_addr + req->netfn_lun;
req->hdr_cksum = ZERO_CKSUM_CONST - req->hdr_cksum;
req->req_slave_addr = 0x20;
req->seq_lun = 0x00;
for (i=0; i<3; i++) { // Get 3 channel for each DIMM group
//Get DIMM Temp per channel
req->cmd = CMD_NM_SEND_RAW_PECI;
req->data[0] = 0x57;
req->data[1] = 0x01;
req->data[2] = 0x00;
req->data[3] = 0x30 + (dimm_index / 2);
req->data[4] = 0x05;
req->data[5] = 0x05;
req->data[6] = 0xa1;
req->data[7] = 0x00;
req->data[8] = 0x0e;
req->data[9] = 0x00 + (dimm_index % 2 * 3) + i;
req->data[10] = 0x00;
tlen = 17;
// Invoke IPMB library handler
lib_ipmb_handle(bus_id, tbuf, tlen+1, rbuf1, &rlen);
if (rlen == 0) {
//ME no response
#ifdef DEBUG
syslog(LOG_DEBUG, "%s(%d): Zero bytes received\n", __func__, __LINE__);
#endif
} else {
if (rbuf1[6] == 0)
{
// If PECI command successes
if ( (rbuf1[10] == 0x40)) {
if (rbuf1[11] > max)
max = rbuf1[11];
if (rbuf1[12] > max)
max = rbuf1[11];
}
}
}
}
if (odm_id == 1) {
// Filter abnormal values: 0x0 and 0xFF
if (max != 0 && max != 0xFF)
ret = 0;
} else {
// Filter abnormal values: 0x0
if (max != 0)
ret = 0;
}
if (ret != 0) {
retry[dimm_index]++;
if (retry[dimm_index] <= 3) {
ret = READING_SKIP;
return ret;
}
} else
retry[dimm_index] = 0;
if (ret == 0) {
*value = (float)max;
}
return ret;
}
static int
read_cpu_package_power(uint8_t snr_num, float *value) {
int ret = READING_NA;
uint8_t bus_id = 0x4; //TODO: ME's address 0x2c in FBTP
uint8_t tbuf[256] = {0x00};
uint8_t rbuf1[256] = {0x00};
// Energy units: Intel Doc#554767, p37, 2^(-ENERGY UNIT) J, ENERGY UNIT defalut is 14
// Run Time units: Intel Doc#554767, p33, msec
// 2^(-14)*1000 = 0.06103515625
float unit = 0.06103515625f;
static uint32_t last_pkg_energy[2] = {0}, last_run_time[2] = {0};
uint32_t pkg_energy, run_time, diff_energy, diff_time;
uint8_t tlen = 0;
uint8_t rlen = 0;
ipmb_req_t *req;
int cpu_index;
static uint8_t retry[2] = {0x00}; // CPU0 and CPU1
switch (snr_num) {
case MB_SENSOR_CPU0_PKG_POWER:
cpu_index = 0;
break;
case MB_SENSOR_CPU1_PKG_POWER:
cpu_index = 1;
break;
default:
return -1;
}
req = (ipmb_req_t*)tbuf;
req->res_slave_addr = 0x2C; //ME's Slave Address
req->netfn_lun = NETFN_NM_REQ<<2;
req->hdr_cksum = req->res_slave_addr + req->netfn_lun;
req->hdr_cksum = ZERO_CKSUM_CONST - req->hdr_cksum;
req->req_slave_addr = 0x20;
req->seq_lun = 0x00;
// Get CPU package power and run time
rlen = 0;
memset( rbuf1,0x00,sizeof(rbuf1) );
//Read Accumulated Energy Pkg and Accumulated Run Time
req->cmd = CMD_NM_AGGREGATED_SEND_RAW_PECI;
req->data[0] = 0x57;
req->data[1] = 0x01;
req->data[2] = 0x00;
req->data[3] = 0x30 + cpu_index;
req->data[4] = 0x05;
req->data[5] = 0x05;
req->data[6] = 0xa1;
req->data[7] = 0x00;
req->data[8] = 0x03;
req->data[9] = 0xff;
req->data[10] = 0x00;
req->data[11] = 0x30 + cpu_index;
req->data[12] = 0x05;
req->data[13] = 0x05;
req->data[14] = 0xa1;
req->data[15] = 0x00;
req->data[16] = 0x1F;
req->data[17] = 0x00;
req->data[18] = 0x00;
tlen = 25;
// Invoke IPMB library handler
lib_ipmb_handle(bus_id, tbuf, tlen+1, rbuf1, &rlen);
if (rlen == 0) {
//ME no response
#ifdef DEBUG
syslog(LOG_DEBUG, "%s(%d): Zero bytes received\n", __func__, __LINE__);
#endif
goto error_exit;
} else {
if (rbuf1[6] == 0) { // ME Completion Code
if ( (rbuf1[10] == 0x00) && (rbuf1[11] == 0x40) && // 1st ME CC & PECI CC
(rbuf1[16] == 0x00) && (rbuf1[17] == 0x40) ){ // 2nd ME CC & PECI CC
pkg_energy = rbuf1[15];
pkg_energy = (pkg_energy << 8) | rbuf1[14];
pkg_energy = (pkg_energy << 8) | rbuf1[13];
pkg_energy = (pkg_energy << 8) | rbuf1[12];
run_time = rbuf1[21];
run_time = (run_time << 8) | rbuf1[20];
run_time = (run_time << 8) | rbuf1[19];
run_time = (run_time << 8) | rbuf1[18];
ret = 0;
}
}
}
// need at least 2 entries to calculate
if (last_pkg_energy[cpu_index] == 0 && last_run_time[cpu_index] == 0) {
if (ret == 0) {
last_pkg_energy[cpu_index] = pkg_energy;
last_run_time[cpu_index] = run_time;
}
ret = READING_NA;
}
if(!ret) {
if(pkg_energy >= last_pkg_energy[cpu_index])
diff_energy = pkg_energy - last_pkg_energy[cpu_index];
else
diff_energy = pkg_energy + (0xffffffff - last_pkg_energy[cpu_index] + 1);
last_pkg_energy[cpu_index] = pkg_energy;
if(run_time >= last_run_time[cpu_index])
diff_time = run_time - last_run_time[cpu_index];
else
diff_time = run_time + (0xffffffff - last_run_time[cpu_index] + 1);
last_run_time[cpu_index] = run_time;
if(diff_time == 0)
ret = READING_NA;
else
*value = ((float)diff_energy / (float)diff_time * unit);
}
error_exit:
if (ret != 0) {
retry[cpu_index]++;
if (retry[cpu_index] <= 3) {
ret = READING_SKIP;
return ret;
}
} else
retry[cpu_index] = 0;
return ret;
}
static int
read_ava_temp(uint8_t sensor_num, float *value) {
int fd = 0;
char fn[32];
int ret = READING_NA;;
static unsigned int retry[6] = {0};
uint8_t i_retry;
uint8_t tcount, rcount, slot_cfg, addr, mux_chan;
uint8_t tbuf[16] = {0};
uint8_t rbuf[16] = {0};
if (pal_get_slot_cfg_id(&slot_cfg) < 0)
slot_cfg = SLOT_CFG_EMPTY;
switch(sensor_num) {
case MB_SENSOR_C2_AVA_FTEMP:
i_retry = 0; break;
case MB_SENSOR_C2_AVA_RTEMP:
i_retry = 1; break;
case MB_SENSOR_C3_AVA_FTEMP:
i_retry = 2; break;
case MB_SENSOR_C3_AVA_RTEMP:
i_retry = 3; break;
case MB_SENSOR_C4_AVA_FTEMP:
i_retry = 4; break;
case MB_SENSOR_C4_AVA_RTEMP:
i_retry = 5; break;
default:
return READING_NA;
}
switch(sensor_num) {
case MB_SENSOR_C2_AVA_FTEMP:
case MB_SENSOR_C2_AVA_RTEMP:
if(slot_cfg == SLOT_CFG_EMPTY)
return READING_NA;
mux_chan = 0;
break;
case MB_SENSOR_C3_AVA_FTEMP:
case MB_SENSOR_C3_AVA_RTEMP:
if(slot_cfg == SLOT_CFG_EMPTY)
return READING_NA;
mux_chan = 1;
break;
case MB_SENSOR_C4_AVA_FTEMP:
case MB_SENSOR_C4_AVA_RTEMP:
if(slot_cfg != SLOT_CFG_SS_3x8)
return READING_NA;
mux_chan = 2;
break;
default:
return READING_NA;
}
if ( false == pal_is_ava_card(mux_chan) )
return READING_NA;
switch(sensor_num) {
case MB_SENSOR_C2_AVA_FTEMP:
case MB_SENSOR_C3_AVA_FTEMP:
case MB_SENSOR_C4_AVA_FTEMP:
addr = 0x92;
break;
case MB_SENSOR_C2_AVA_RTEMP:
case MB_SENSOR_C3_AVA_RTEMP:
case MB_SENSOR_C4_AVA_RTEMP:
addr = 0x90;
break;
default:
return READING_NA;
}
//try to control multiplexer to target channel and it will exit if it fail
ret = mux_lock(&riser_mux, mux_chan, 2);
if (ret < 0) {
ret = READING_NA;
goto error_exit;
}
snprintf(fn, sizeof(fn), "/dev/i2c-%d", RISER_BUS_ID);
fd = open(fn, O_RDWR);
if (fd < 0) {
ret = READING_NA;
goto release_mux_and_exit;
}
// Read 2 bytes from TMP75
tbuf[0] = 0x00;
tcount = 1;
rcount = 2;
ret = i2c_rdwr_msg_transfer(fd, addr, tbuf, tcount, rbuf, rcount);
if (ret < 0) {
ret = READING_NA;
goto release_mux_and_exit;
}
ret = 0;
retry[i_retry] = 0;
// rbuf:MSB, LSB; 12-bit value on Bit[15:4], unit: 0.0625
*value = (float)(signed char)rbuf[0];
//if the channel is locked, unlock it and then exit
release_mux_and_exit:
mux_release(&riser_mux);
//if the channel is busy, exit the function
error_exit:
if (fd > 0) {
close(fd);
}
if (ret == READING_NA && ++retry[i_retry] <= 3)
ret = READING_SKIP;
return ret;
}
static int
read_INA230 (uint8_t sensor_num, float *value, int pot) {
int fd = 0;
char fn[32];
int ret = READING_NA;;
static unsigned int retry[12] = {0};
uint8_t i_retry;
uint8_t slot_cfg, addr, mux_chan;
uint8_t tbuf[16] = {0};
uint8_t rbuf[16] = {0};
uint8_t BoardInfo;
static int odm_id = -1;
//Use FM_BOARD_SKU_ID0 to identify ODM to apply filter
if (odm_id == -1) {
ret = pal_get_platform_id(&BoardInfo);
if (ret == 0) {
odm_id = (int) (BoardInfo & 0x1);
}
}
if (pal_get_slot_cfg_id(&slot_cfg) < 0)
slot_cfg = SLOT_CFG_EMPTY;
switch(sensor_num) {
case MB_SENSOR_C2_P12V_INA230_VOL:
i_retry = 0; break;
case MB_SENSOR_C2_P12V_INA230_CURR:
i_retry = 1; break;
case MB_SENSOR_C2_P12V_INA230_PWR:
i_retry = 2; break;
case MB_SENSOR_C3_P12V_INA230_VOL:
i_retry = 3; break;
case MB_SENSOR_C3_P12V_INA230_CURR:
i_retry = 4; break;
case MB_SENSOR_C3_P12V_INA230_PWR:
i_retry = 5; break;
case MB_SENSOR_C4_P12V_INA230_VOL:
i_retry = 6; break;
case MB_SENSOR_C4_P12V_INA230_CURR:
i_retry = 7; break;
case MB_SENSOR_C4_P12V_INA230_PWR:
i_retry = 8; break;
case MB_SENSOR_CONN_P12V_INA230_VOL:
i_retry = 9; break;
case MB_SENSOR_CONN_P12V_INA230_CURR:
i_retry = 10; break;
case MB_SENSOR_CONN_P12V_INA230_PWR:
i_retry = 11; break;
}
switch(sensor_num) {
case MB_SENSOR_C2_P12V_INA230_VOL:
case MB_SENSOR_C2_P12V_INA230_CURR:
case MB_SENSOR_C2_P12V_INA230_PWR:
case MB_SENSOR_C3_P12V_INA230_VOL:
case MB_SENSOR_C3_P12V_INA230_CURR:
case MB_SENSOR_C3_P12V_INA230_PWR:
case MB_SENSOR_CONN_P12V_INA230_VOL:
case MB_SENSOR_CONN_P12V_INA230_CURR:
case MB_SENSOR_CONN_P12V_INA230_PWR:
if(slot_cfg == SLOT_CFG_EMPTY)
return READING_NA;
break;
case MB_SENSOR_C4_P12V_INA230_VOL:
case MB_SENSOR_C4_P12V_INA230_CURR:
case MB_SENSOR_C4_P12V_INA230_PWR:
if(slot_cfg != SLOT_CFG_SS_3x8)
return READING_NA;
break;
default:
return READING_NA;
}
//use channel 4
mux_chan = 0x3;
//try to control multiplexer to target channel and it will exit if it fail
ret = mux_lock(&riser_mux, mux_chan, 2);
if (ret < 0) {
ret = READING_NA;
goto error_exit;
}
snprintf(fn, sizeof(fn), "/dev/i2c-%d", RISER_BUS_ID);
fd = open(fn, O_RDWR);
if (fd < 0) {
ret = READING_NA;
goto release_mux_and_exit;
}
switch(sensor_num) {
case MB_SENSOR_C2_P12V_INA230_VOL:
case MB_SENSOR_C2_P12V_INA230_CURR:
case MB_SENSOR_C2_P12V_INA230_PWR:
addr = 0x80;
break;
case MB_SENSOR_C3_P12V_INA230_VOL:
case MB_SENSOR_C3_P12V_INA230_CURR:
case MB_SENSOR_C3_P12V_INA230_PWR:
addr = 0x82;
break;
case MB_SENSOR_C4_P12V_INA230_VOL:
case MB_SENSOR_C4_P12V_INA230_CURR:
case MB_SENSOR_C4_P12V_INA230_PWR:
addr = 0x88;
break;
case MB_SENSOR_CONN_P12V_INA230_VOL:
case MB_SENSOR_CONN_P12V_INA230_CURR:
case MB_SENSOR_CONN_P12V_INA230_PWR:
addr = 0x8A;
break;
default:
syslog(LOG_WARNING, "read_INA230: undefined sensor number") ;
break;
}
if (odm_id == 0) {
static unsigned int initialized[4] = {0};
// If Power On Time == 1, re-initialize INA230
if (pot == 1 && (i_retry % 3) == 0)
initialized[i_retry/3] = 0;
if (initialized[i_retry/3] == 0) {
//Set Configuration register
tbuf[0] = 0x00, tbuf[1] = 0x49; tbuf[2] = 0x27;
ret = i2c_rdwr_msg_transfer(fd, addr, tbuf, 3, rbuf, 0);
if (ret < 0) {
ret = READING_NA;
goto release_mux_and_exit;
}
//Set Calibration register
tbuf[0] = 0x05, tbuf[1] = 0x9; tbuf[2] = 0xd9;
ret = i2c_rdwr_msg_transfer(fd, addr, tbuf, 3, rbuf, 0);
if (ret < 0) {
ret = READING_NA;
goto release_mux_and_exit;
}
initialized[i_retry/3] = 1;
}
// Delay for 2 cycles and check INA230 init done
if(pot < 3 || initialized[i_retry/3] == 0){
ret = READING_NA;
goto release_mux_and_exit;
}
//Get registers data
switch(sensor_num) {
case MB_SENSOR_C2_P12V_INA230_VOL:
case MB_SENSOR_C3_P12V_INA230_VOL:
case MB_SENSOR_C4_P12V_INA230_VOL:
case MB_SENSOR_CONN_P12V_INA230_VOL:
tbuf[0] = 0x02;
break;
case MB_SENSOR_C2_P12V_INA230_CURR:
case MB_SENSOR_C3_P12V_INA230_CURR:
case MB_SENSOR_C4_P12V_INA230_CURR:
case MB_SENSOR_CONN_P12V_INA230_CURR:
tbuf[0] = 0x04;
break;
case MB_SENSOR_C2_P12V_INA230_PWR:
case MB_SENSOR_C3_P12V_INA230_PWR:
case MB_SENSOR_C4_P12V_INA230_PWR:
case MB_SENSOR_CONN_P12V_INA230_PWR:
tbuf[0] = 0x03;
break;
default:
syslog(LOG_WARNING, "read_INA230: undefined sensor number") ;
break;
}
tbuf[1] = 0x0; tbuf[2] = 0x0;
ret = i2c_rdwr_msg_transfer(fd, addr, tbuf, 1, rbuf, 2);
if (ret < 0) {
ret = READING_NA;
goto release_mux_and_exit;
}
int16_t temp;
switch(sensor_num) {
case MB_SENSOR_C2_P12V_INA230_VOL:
case MB_SENSOR_C3_P12V_INA230_VOL:
case MB_SENSOR_C4_P12V_INA230_VOL:
case MB_SENSOR_CONN_P12V_INA230_VOL:
*value = ((rbuf[1] + rbuf[0] *256) *0.00125) ;
break;
case MB_SENSOR_C2_P12V_INA230_CURR:
case MB_SENSOR_C3_P12V_INA230_CURR:
case MB_SENSOR_C4_P12V_INA230_CURR:
case MB_SENSOR_CONN_P12V_INA230_CURR:
temp = rbuf[0];
temp = (temp <<8) | rbuf[1];
//*value = (((int16_t)rbuf[0] << 8) | (int16_t)rbuf[1]) * 0.001;
*value = temp * 0.001;
if(*value < 0)
*value = 0;
break;
case MB_SENSOR_C2_P12V_INA230_PWR:
case MB_SENSOR_C3_P12V_INA230_PWR:
case MB_SENSOR_C4_P12V_INA230_PWR:
case MB_SENSOR_CONN_P12V_INA230_PWR:
*value = (rbuf[1] + rbuf[0] * 256)*0.025;
if(*value < 1)
*value = 0;
break;
default:
syslog(LOG_WARNING, "read_INA230: undefined sensor number") ;
break;
}
} else {
/*
*Rshunt - it is defined by the schematic. It will be 2m ohm in the fbtp
*/
const float Rshunt = 0.002; // 2m ohm
const uint8_t bus_volt_addr = 0x02; // bus voltage address
const uint8_t shunt_volt_addr = 0x01; // shunt voltage address
// Delay for 2 cycles and check INA230 init done
if( pot < 3 )
{
ret = READING_NA;
goto release_mux_and_exit;
}
memset(rbuf, 0, sizeof(rbuf));
memset(tbuf, 0, sizeof(tbuf));
switch(sensor_num)
{
case MB_SENSOR_C2_P12V_INA230_VOL:
case MB_SENSOR_C3_P12V_INA230_VOL:
case MB_SENSOR_C4_P12V_INA230_VOL:
case MB_SENSOR_CONN_P12V_INA230_VOL:
tbuf[0] = bus_volt_addr;
break;
case MB_SENSOR_C2_P12V_INA230_CURR:
case MB_SENSOR_C3_P12V_INA230_CURR:
case MB_SENSOR_C4_P12V_INA230_CURR:
case MB_SENSOR_CONN_P12V_INA230_CURR:
tbuf[0] = shunt_volt_addr;
break;
case MB_SENSOR_C2_P12V_INA230_PWR:
case MB_SENSOR_C3_P12V_INA230_PWR:
case MB_SENSOR_C4_P12V_INA230_PWR:
case MB_SENSOR_CONN_P12V_INA230_PWR:
tbuf[0] = shunt_volt_addr;
tbuf[1] = bus_volt_addr;
break;
default:
syslog(LOG_WARNING, "read_INA230: undefined sensor number") ;
break;
}
ret = i2c_rdwr_msg_transfer(fd, addr, tbuf, 1, rbuf, 2);
if (ret < 0)
{
ret = READING_NA;
goto release_mux_and_exit;
}
//get the additional data to calculate the power reading
if ( bus_volt_addr == tbuf[1] )
{
tbuf[0] = tbuf[1];
//use the rbuf[2] and rbuf[3] to store data
ret = i2c_rdwr_msg_transfer(fd, addr, tbuf, 1, &rbuf[2], 2);
if (ret < 0)
{
ret = READING_NA;
goto release_mux_and_exit;
}
}
switch(sensor_num)
{
case MB_SENSOR_C2_P12V_INA230_VOL:
case MB_SENSOR_C3_P12V_INA230_VOL:
case MB_SENSOR_C4_P12V_INA230_VOL:
case MB_SENSOR_CONN_P12V_INA230_VOL:
//calculate the bus voltage
*value = ((rbuf[1] + rbuf[0]*256) * 0.00125);
break;
case MB_SENSOR_C2_P12V_INA230_CURR:
case MB_SENSOR_C3_P12V_INA230_CURR:
case MB_SENSOR_C4_P12V_INA230_CURR:
case MB_SENSOR_CONN_P12V_INA230_CURR:
*value = 0;
//check the sign bit. If it is a negative value, show 0
if ( 1 != BIT(rbuf[0], 7) )
{
//calculate the shunt voltage
*value = ((rbuf[1] + rbuf[0]*256) * 0.0000025);
//use I = V / R to get the current
*value = (*value) / Rshunt;
}
break;
case MB_SENSOR_C2_P12V_INA230_PWR:
case MB_SENSOR_C3_P12V_INA230_PWR:
case MB_SENSOR_C4_P12V_INA230_PWR:
case MB_SENSOR_CONN_P12V_INA230_PWR:
{
float shunt_volt = 0;
float current = 0;
float bus_volt = ((rbuf[3] + rbuf[2]*256) * 0.00125);//use rbuf[2] and rbuf[3] to get the bus voltage
//check the sign bit. If it is a negative value, show 0
if ( 1 != BIT(rbuf[0], 7) )
{
//calculate the shunt voltage
shunt_volt = ((rbuf[1] + rbuf[0]*256) * 0.0000025);
//use I = V / R to get the current
current = shunt_volt / Rshunt;
}
//use P = V * I to get the power
*value = bus_volt * current;
}
break;
default:
syslog(LOG_WARNING, "read_INA230: undefined sensor number") ;
break;
}
}
ret = 0;
retry[i_retry] = 0;
//if the channel is locked, unlock it and then exit
release_mux_and_exit:
mux_release(&riser_mux);
//if the channel is busy, exit the function
error_exit:
if (fd > 0) {
close(fd);
}
if (ret == READING_NA && ++retry[i_retry] <= 3)
ret = READING_SKIP;
return ret;
}
static int
read_nvme_temp(uint8_t sensor_num, float *value) {
int fd = 0;
char fn[32];
int ret = READING_NA;
static unsigned int retry[15] = {0};
uint8_t i_retry;
uint8_t tcount, rcount, slot_cfg, addr = 0xd4, mux_chan;
uint8_t switch_chan, switch_addr=0xe6;
uint8_t tbuf[16] = {0};
uint8_t rbuf[16] = {0};
if (pal_get_slot_cfg_id(&slot_cfg) < 0)
slot_cfg = SLOT_CFG_EMPTY;
switch(sensor_num) {
case MB_SENSOR_C2_1_NVME_CTEMP:
i_retry = 0; break;
case MB_SENSOR_C2_2_NVME_CTEMP:
i_retry = 1; break;
case MB_SENSOR_C2_3_NVME_CTEMP:
i_retry = 2; break;
case MB_SENSOR_C2_4_NVME_CTEMP:
i_retry = 3; break;
case MB_SENSOR_C3_1_NVME_CTEMP:
i_retry = 4; break;
case MB_SENSOR_C3_2_NVME_CTEMP:
i_retry = 5; break;
case MB_SENSOR_C3_3_NVME_CTEMP:
i_retry = 6; break;
case MB_SENSOR_C3_4_NVME_CTEMP:
i_retry = 7; break;
case MB_SENSOR_C4_1_NVME_CTEMP:
i_retry = 8; break;
case MB_SENSOR_C4_2_NVME_CTEMP:
i_retry = 9; break;
case MB_SENSOR_C4_3_NVME_CTEMP:
i_retry = 10; break;
case MB_SENSOR_C4_4_NVME_CTEMP:
i_retry = 11; break;
case MB_SENSOR_C2_NVME_CTEMP:
i_retry = 12; break;
case MB_SENSOR_C3_NVME_CTEMP:
i_retry = 13; break;
case MB_SENSOR_C4_NVME_CTEMP:
i_retry = 14; break;
default:
return READING_NA;
}
switch(sensor_num) {
case MB_SENSOR_C2_NVME_CTEMP:
if(slot_cfg == SLOT_CFG_EMPTY || ( !pal_is_pcie_ssd_card(0) ))
return READING_NA;
mux_chan = 0;
break;
case MB_SENSOR_C2_1_NVME_CTEMP:
case MB_SENSOR_C2_2_NVME_CTEMP:
case MB_SENSOR_C2_3_NVME_CTEMP:
case MB_SENSOR_C2_4_NVME_CTEMP:
if(slot_cfg == SLOT_CFG_EMPTY || (!pal_is_ava_card(0)))
return READING_NA;
mux_chan = 0;
break;
case MB_SENSOR_C3_NVME_CTEMP:
if(slot_cfg == SLOT_CFG_EMPTY || ( !pal_is_pcie_ssd_card(1)))
return READING_NA;
mux_chan = 1;
break;
case MB_SENSOR_C3_1_NVME_CTEMP:
case MB_SENSOR_C3_2_NVME_CTEMP:
case MB_SENSOR_C3_3_NVME_CTEMP:
case MB_SENSOR_C3_4_NVME_CTEMP:
if(slot_cfg == SLOT_CFG_EMPTY || ( !pal_is_ava_card(1)))
return READING_NA;
mux_chan = 1;
break;
case MB_SENSOR_C4_NVME_CTEMP:
if(slot_cfg != SLOT_CFG_SS_3x8 || ( !pal_is_pcie_ssd_card(2)))
return READING_NA;
mux_chan = 2;
break;
case MB_SENSOR_C4_1_NVME_CTEMP:
case MB_SENSOR_C4_2_NVME_CTEMP:
case MB_SENSOR_C4_3_NVME_CTEMP:
case MB_SENSOR_C4_4_NVME_CTEMP:
if(slot_cfg != SLOT_CFG_SS_3x8 || ( !pal_is_ava_card(2)))
return READING_NA;
mux_chan = 2;
break;
default:
return READING_NA;
}
switch(sensor_num) {
case MB_SENSOR_C2_1_NVME_CTEMP:
case MB_SENSOR_C3_1_NVME_CTEMP:
case MB_SENSOR_C4_1_NVME_CTEMP:
switch_chan = 0;
break;
case MB_SENSOR_C2_2_NVME_CTEMP:
case MB_SENSOR_C3_2_NVME_CTEMP:
case MB_SENSOR_C4_2_NVME_CTEMP:
switch_chan = 1;
break;
case MB_SENSOR_C2_3_NVME_CTEMP:
case MB_SENSOR_C3_3_NVME_CTEMP:
case MB_SENSOR_C4_3_NVME_CTEMP:
switch_chan = 2;
break;
case MB_SENSOR_C2_4_NVME_CTEMP:
case MB_SENSOR_C3_4_NVME_CTEMP:
case MB_SENSOR_C4_4_NVME_CTEMP:
switch_chan = 3;
break;
case MB_SENSOR_C2_NVME_CTEMP:
case MB_SENSOR_C3_NVME_CTEMP:
case MB_SENSOR_C4_NVME_CTEMP:
switch_chan = 0xff; // no i2c switch
break;
default:
return READING_NA;
}
//try to control I2C multiplexer to target channel and it will exit if it fail
ret = mux_lock(&riser_mux, mux_chan, 2);
if (ret < 0) {
ret = READING_NA;
goto error_exit;
}
snprintf(fn, sizeof(fn), "/dev/i2c-%d", RISER_BUS_ID);
fd = open(fn, O_RDWR);
if (fd < 0) {
ret = READING_NA;
goto release_mux_and_exit;
}
if (switch_chan != 0xff) {
// control I2C switch to target channel if it has
ret = pal_control_switch(fd, switch_addr, switch_chan);
if (ret < 0) {
ret = READING_NA;
goto release_mux_and_exit;
}
}
// Read 8 bytes from NVMe
tbuf[0] = 0x00;
tcount = 1;
rcount = 8;
ret = i2c_rdwr_msg_transfer(fd, addr, tbuf, tcount, rbuf, rcount);
if (ret < 0) {
ret = READING_NA;
goto release_mux_and_exit;
}
ret = 0;
retry[i_retry] = 0;
// Cmd 0: length, SFLGS, SMART Warnings, CTemp, PDLU, Reserved, Reserved, PEC
*value = (float)(signed char)rbuf[3];
//if the channel is locked, unlock it and then exit
release_mux_and_exit:
mux_release(&riser_mux);
//if the channel is busy, exit the function
error_exit:
if (fd > 0) {
if (switch_chan != 0xff)
pal_control_switch(fd, switch_addr, 0xff); // close
close(fd);
}
if (ret == READING_NA && ++retry[i_retry] <= 3)
ret = READING_SKIP;
return ret;
}
//When the power is turned off, three states are 0.
enum
{
MAIN_STATE_PWR_OFF = 0x0,
CPU0_STATE_PWR_OFF = 0x0,
CPU1_STATE_PWR_OFF = 0x0,
};
//CPLD power status register define
enum {
MAIN_PWR_STS_REG = 0x00,
CPU0_PWR_STS_REG = 0x01,
CPU1_PWR_STS_REG = 0x02,
};
//CPLD power status register normal value after power on
enum {
MAIN_PWR_STS_VAL = 0x04, // MAIN_ON
CPU0_PWR_STS_VAL = 0x13, // CPUPWRGD
CPU1_PWR_STS_VAL = 0x13, // CPUPWRGD
};
static struct cpld_reg_desc {
unsigned char offset;
unsigned char bit;
char *name;
} cpld_power_seq[] = {
{ 0x07, 5, "PWRGD_PVNN_P1V05_PCH"},
{ 0x07, 4, "PWRGD_DSW_PWROK"},
{ 0x07, 3, "FM_SLP_SUS_N" },
{ 0x07, 2, "RST_RSMRST_N" },
{ 0x07, 1, "FM_SLPS4_N" },
{ 0x07, 0, "FM_SLPS3_N" },
{ 0x03, 7, "FM_CTNR_PS_ON" },
{ 0x0a, 6, "FM_P12V_MAIN_SW_EN" },
{ 0x03, 6, "PWRGD_P12V_MAIN" },
{ 0x0a, 7, "FM_PS_EN" },
{ 0x03, 5, "PWRGD_P5V" },
{ 0x0a, 5, "FM_P3V3_CPLD_EN" },
{ 0x03, 4, "PWRGD_P3V3" },
{ 0x0a, 4, "FM_PVPP_CPU0_EN" },
{ 0x03, 3, "PWRGD_PVPP_ABC" },
{ 0x03, 2, "PWRGD_PVPP_DEF" },
{ 0x0a, 3, "FM_PVPP_CPU1_EN" },
{ 0x03, 1, "PWRGD_PVPP_GHJ" },
{ 0x03, 0, "PWRGD_PVPP_KLM" },
{ 0x0a, 2, "FM_PVDDQ_ABC_EN" },
{ 0x0a, 1, "FM_PVDDQ_DEF_EN" },
{ 0x04, 7, "PWRGD_PVTT_CPU0" },
{ 0x0a, 0, "FM_PVDDQ_GHJ_EN" },
{ 0x0b, 7, "FM_PVDDQ_KLM_EN" },
{ 0x04, 6, "PWRGD_PVTT_CPU1" },
{ 0x0b, 2, "PWRGD_DRAMPWRGD" },
{ 0x0b, 6, "FM_PVCCIO_CPU0_EN" },
{ 0x04, 5, "PWRGD_PVCCIO_CPU0" },
{ 0x0b, 5, "FM_PVCCIO_CPU1_EN" },
{ 0x04, 4, "PWRGD_PVCCIO_CPU1" },
{ 0x0b, 4, "FM_PVCCIN_PVCCSA_CPU0_EN_LVC1" },
{ 0x04, 3, "PWRGD_PVCCIN_CPU0" },
{ 0x0b, 3, "FM_PVCCIN_PVCCSA_CPU1_EN_LVC1" },
{ 0x04, 2, "PWRGD_PVCCIN_CPU1" },
{ 0x04, 1, "PWRGD_PVSA_CPU0" },
{ 0x04, 0, "PWRGD_PVSA_CPU1" },
{ 0x0b, 1, "PWRGD_PCH_PWROK" },
{ 0x0b, 0, "PWRGD_CPU0_LVC3" },
{ 0x0c, 7, "PWRGD_CPU1_LVC3" },
{ 0x05, 7, "PWRGD_CPUPWRGD" },
{ 0x0c, 6, "PWRGD_SYS_PWROK" },
{ 0x05, 6, "RST_PLTRST_N" },
};
static int cpld_power_seq_num = (sizeof(cpld_power_seq)/sizeof(struct cpld_reg_desc));
static int get_CPLD_power_sts(uint8_t *reg)
{
int fd = 0;
char fn[32];
uint8_t tbuf[16] = {0};
int ret = PAL_ENOTSUP;
int i;
snprintf(fn, sizeof(fn), "/dev/i2c-%d", CPLD_BUS_ID);
fd = open(fn, O_RDWR);
if (fd < 0) {
syslog(LOG_WARNING, "[%s] Cannot open the i2c-%d", __func__, CPLD_BUS_ID);
ret = PAL_ENOTSUP;
goto exit;
}
// Get the data offset 0x00 to 0x0c
for(i = 0; i < 0x0d; i++) {
tbuf[0] = i;
ret = i2c_rdwr_msg_transfer(fd, CPLD_ADDR, tbuf, 1, ®[i], 1);
if (ret < 0) {
syslog(LOG_WARNING, "[%s] Cannot acces the i2c-%d dev: %x", __func__, CPLD_BUS_ID, CPLD_ADDR);
ret = PAL_ENOTSUP;
goto exit;
}
}
ret = PAL_EOK;
exit:
if (fd > 0)
{
close(fd);
}
return ret;
}
static bool is_slps4_deassert(void)
{
gpio_value_t value;
gpio_desc_t *desc = gpio_open_by_shadow("FM_SLPS4_N");
if (!desc)
return false;
if (gpio_get_value(desc, &value)) {
gpio_close(desc);
return false;
}
gpio_close(desc);
return value == GPIO_VALUE_HIGH ? true : false;
}
static int
read_CPLD_power_fail_sts (uint8_t fru, uint8_t sensor_num, float *value, int pot) {
static uint8_t power_fail = 0;
static uint8_t power_fail_log = 0;
int fd = 0;
char fn[32];
int ret = READING_NA, i;
uint8_t tbuf[16] = {0};
uint8_t data_chk, fail_offset;
unsigned char reg[16];
char sensor_name[32] = {0}, event_str[30] = {0};
// Check SLPS4 is high before start monitor CPLD power fail
if (!is_slps4_deassert()) {
// Reset
power_fail = 0;
power_fail_log = 0;
ret = 0;
goto exit;
}
// Already log
if (power_fail_log) {
ret = 0;
goto exit;
}
snprintf(fn, sizeof(fn), "/dev/i2c-%d", CPLD_BUS_ID);
fd = open(fn, O_RDWR);
if (fd < 0) {
syslog(LOG_WARNING, "[%s] Cannot open the i2c-%d", __func__, CPLD_BUS_ID);
ret = READING_NA;
goto exit;
}
// Check the status register 0 to 2
for(i=0;i<3;i++) {
switch(i) {
case MAIN_PWR_STS_REG :
data_chk = MAIN_PWR_STS_VAL;
break;
case CPU0_PWR_STS_REG :
data_chk = CPU0_PWR_STS_VAL;
break;
case CPU1_PWR_STS_REG :
data_chk = CPU1_PWR_STS_VAL;
break;
}
tbuf[0] = i;
ret = i2c_rdwr_msg_transfer(fd, CPLD_ADDR, tbuf, 1, ®[i], 1);
if (ret < 0) {
syslog(LOG_WARNING, "[%s] Cannot acces the i2c-%d dev: %x", __func__, CPLD_BUS_ID, CPLD_ADDR);
ret = READING_NA;
goto exit;
}
if ( reg[i] != data_chk ) {
fail_offset = i;
power_fail++;
break;
}
}
// All status regs are expected
if (i == 3) {
power_fail = 0;
}
// Check the status regs later, it might has not finished
if(power_fail <= 3) {
ret = 0;
*value = 0;
goto exit;
}
// Power failed, get the data offset 0x03 to 0x0c
for(i = 3; i < 0x0d; i++) {
tbuf[0] = i;
ret = i2c_rdwr_msg_transfer(fd, CPLD_ADDR, tbuf, 1, ®[i], 1);
if (ret < 0) {
ret = READING_NA;
goto exit;
}
}
// Check the power sequence one by one in order
for(i=0; i < cpld_power_seq_num; i++) {
if (!( reg[cpld_power_seq[i].offset] & (1 << cpld_power_seq[i].bit) )) {
break;
}
}
if (i == cpld_power_seq_num) {
sprintf(event_str, "Unknown power rail fails");
// keep the fail status reg offset(0~2)
} else {
sprintf(event_str, "%s power rail fails", cpld_power_seq[i].name);
fail_offset = cpld_power_seq[i].offset;
}
pal_get_sensor_name(fru, sensor_num, sensor_name);
_print_sensor_discrete_log(fru, sensor_num, sensor_name, fail_offset, event_str);
pal_add_cri_sel(event_str);
power_fail_log = 1;
ret = 0;
exit:
if (fd > 0) {
close(fd);
}
return ret;
}
void
pal_check_power_sts(void)
{
uint8_t fail_offset =0xff; //init to 0xff to identify the undefined error
uint8_t reg[16]={0};
char *sensor_name = "MB_POWER_FAIL";
const uint8_t sensor_num = MB_SENSOR_POWER_FAIL;
const uint8_t fru = FRU_MB;
//the main_state, cpu0_state, cpu1_state are 0 when the power is turned off normally
const uint8_t normal_power_off_sts[3]={MAIN_STATE_PWR_OFF, CPU0_STATE_PWR_OFF, CPU1_STATE_PWR_OFF};
char event_str[30] = {0};
int i;
int ret;
int bit_value = 0; //get the bit from the register
int power_faill_addr = -1;
sleep(1);//ensure the power data is updated
//get the power data when the slp4 falling
ret = get_CPLD_power_sts(reg);
if ( ret < 0 )
{
syslog(LOG_WARNING, "[%s] Cannot get the power status from CPLD", __func__);
return;
}
//if the power is turned off normally. the value of three machine states are 0
ret = memcmp(reg, normal_power_off_sts, sizeof(normal_power_off_sts));
if ( PAL_EOK == ret )
{
return;
}
// Check the power sequence one by one in order.
for ( i=0; i < cpld_power_seq_num; i++ )
{
bit_value = reg[cpld_power_seq[i].offset] & (1 << cpld_power_seq[i].bit);
//record the fail index if the power fail occur
//0 means the power fail
if ( 0 == bit_value )
{
power_faill_addr = i;
sprintf(event_str, "%s power rail fails", cpld_power_seq[power_faill_addr].name);
fail_offset = cpld_power_seq[power_faill_addr].offset;
_print_sensor_discrete_log(fru, sensor_num, sensor_name, fail_offset, event_str);
pal_add_cri_sel(event_str);
}
}
//Unknnow error
if ( power_faill_addr < 0 )
{
sprintf(event_str, "%s power rail fails", "Unknown");
_print_sensor_discrete_log(fru, sensor_num, sensor_name, fail_offset, event_str);
pal_add_cri_sel(event_str);
}
}
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;
}
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);
}
static void
FORCE_ADR() {
char key[MAX_KEY_LEN] = {0};
char value[MAX_VALUE_LEN];
size_t len;
//char vpath[64] = {0};
sprintf(key, "%s", "mb_machine_config");
if (kv_get(key, value, &len, KV_FPERSIST) < 0 || len < 13) {
#ifdef DEBUG
syslog(LOG_WARNING, "FORCE_ADR: get mb_machine_config failed for fru %u", fru);
#endif
return;
}
if(value[12] == 0 || value[12] > 32)
return;
#if 0 /*disable the force ADR*/
{
gpio_desc_t *desc = gpio_open_by_shadow("FM_FORCE_ADR_N");
if (!desc)
return;
if (gpio_set_value(desc, GPIO_VALUE_HIGH))
goto bail;
if (gpio_set_value(desc, GPIO_VALUE_LOW))
goto bail;
msleep(10);
if (gpio_set_value(desc, GPIO_VALUE_HIGH))
goto bail;
bail:
gpio_close(desc);
}
#endif
}
// Power Button Override
int
pal_power_button_override(uint8_t fruid) {
int ret = -1;
gpio_desc_t *gpio = gpio_open_by_shadow("FM_BMC_PWRBTN_OUT_N");
if (!gpio) {
return -1;
}
if (gpio_set_value(gpio, GPIO_VALUE_HIGH)) {
goto bail;
}
if (gpio_set_value(gpio, GPIO_VALUE_LOW)) {
goto bail;
}
sleep(6);
if (gpio_set_value(gpio, GPIO_VALUE_HIGH)) {
goto bail;
}
ret = 0;
bail:
gpio_close(gpio);
return ret;
}
// Power On the server in a given slot
static int
server_power_on(void) {
int ret = -1;
gpio_desc_t *gpio = gpio_open_by_shadow("FM_BMC_PWRBTN_OUT_N");
if (!gpio) {
return -1;
}
if (gpio_set_value(gpio, GPIO_VALUE_HIGH)) {
goto bail;
}
if (gpio_set_value(gpio, GPIO_VALUE_LOW)) {
goto bail;
}
sleep(1);
if (gpio_set_value(gpio, GPIO_VALUE_HIGH)) {
goto bail;
}
sleep(2);
if (system("/usr/bin/sv restart fscd >> /dev/null") != 0) {
syslog(LOG_CRIT, "FSCD Restart failed\n");
goto bail;
}
ret = 0;
bail:
gpio_close(gpio);
return ret;
}
// Power Off the server in given slot
static int
server_power_off(bool gs_flag) {
int ret = -1;
gpio_desc_t *gpio = gpio_open_by_shadow("FM_BMC_PWRBTN_OUT_N");
if (!gpio) {
return -1;
}
if (system("/usr/bin/sv stop fscd >> /dev/null") != 0) {
syslog(LOG_CRIT, "FSCD Stop on server power-off failed\n");
// Still go ahead in power-off
}
if (!gs_flag)
FORCE_ADR();
if (gpio_set_value(gpio, GPIO_VALUE_HIGH)) {
goto bail;
}
sleep(1);
if (gpio_set_value(gpio, GPIO_VALUE_LOW)) {
goto bail;
}
if (gs_flag) {
sleep(DELAY_GRACEFUL_SHUTDOWN);
} else {
sleep(DELAY_POWER_OFF);
}
if (gpio_set_value(gpio, GPIO_VALUE_HIGH)) {
goto bail;
}
ret = 0;
bail:
gpio_close(gpio);
return ret;
}
// Debug Card's UART and BMC/SoL port share UART port and need to enable only one
static int
control_sol_txd(uint8_t fru) {
uint32_t lpc_fd;
uint32_t ctrl;
void *lpc_reg;
void *lpc_hicr;
lpc_fd = open("/dev/mem", O_RDWR | O_SYNC );
if (lpc_fd < 0) {
#ifdef DEBUG
syslog(LOG_WARNING, "control_sol_txd: open fails\n");
#endif
return -1;
}
lpc_reg = mmap(NULL, PAGE_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, lpc_fd,
AST_LPC_BASE);
lpc_hicr = (char*)lpc_reg + HICRA_OFFSET;
// Read HICRA register
ctrl = *(volatile uint32_t*) lpc_hicr;
// Clear bits for UART2 and UART3 routing
ctrl &= (~HICRA_MASK_UART2);
ctrl &= (~HICRA_MASK_UART3);
// Route UART2 to UART3 for SoL purpose
ctrl |= (UART2_TO_UART3 << 22);
// Route DEBUG to UART1 for TXD control
ctrl |= (UART3_TO_UART2 << 19);
*(volatile uint32_t*) lpc_hicr = ctrl;
munmap(lpc_reg, PAGE_SIZE);
close(lpc_fd);
return 0;
}
// Platform Abstraction Layer (PAL) Functions
int
pal_get_platform_name(char *name) {
strcpy(name, FBTP_PLATFORM_NAME);
return 0;
}
int
pal_get_num_slots(uint8_t *num) {
*num = FBTP_MAX_NUM_SLOTS;
return 0;
}
int
pal_is_fru_prsnt(uint8_t fru, uint8_t *status) {
uint8_t slot_cfg = 0;
char full_name[LARGEST_DEVICE_NAME + 1]={0};
FILE *fp;
*status = 0;
switch (fru) {
case FRU_MB:
*status = 1;
break;
case FRU_NIC:
snprintf(full_name, LARGEST_DEVICE_NAME, "%s", "/sys/bus/i2c/devices/8-001f/hwmon");
fp = fopen(full_name, "r");
if (!fp) {
return -1;
}
fclose(fp);
*status = 1;
break;
case FRU_RISER_SLOT2:
case FRU_RISER_SLOT3:
case FRU_RISER_SLOT4:
if (pal_get_slot_cfg_id(&slot_cfg) < 0)
return -1;
if (slot_cfg == SLOT_CFG_EMPTY)
return 0;
*status = 1;
break;
default:
return -1;
}
return 0;
}
int
pal_is_fru_ready(uint8_t fru, uint8_t *status) {
*status = 1;
return 0;
}
int
pal_is_slot_server(uint8_t fru) {
if (fru == FRU_MB)
return 1;
return 0;
}
int
pal_is_debug_card_prsnt(uint8_t *status) {
gpio_desc_t *desc = gpio_open_by_shadow("FM_POST_CARD_PRES_BMC_N");
gpio_value_t value;
int ret = -1;
if (!desc) {
return -1;
}
if (gpio_get_value(desc, &value) == 0) {
*status = value == GPIO_VALUE_LOW ? 1 : 0;
ret = 0;
}
gpio_close(desc);
return ret;
}
int
pal_get_server_power(uint8_t fru, uint8_t *status) {
gpio_desc_t *gpio;
gpio_value_t val;
int ret = -1;
if ( fru != FRU_MB)
return -1;
gpio = gpio_open_by_shadow("PWRGD_SYS_PWROK");
if (!gpio) {
return -1;
}
if (gpio_get_value(gpio, &val) == 0) {
ret = 0;
*status = val == GPIO_VALUE_LOW ? 0 : 1;
}
gpio_close(gpio);
return ret;
}
static bool
is_server_off(void) {
int ret;
uint8_t status;
ret = pal_get_server_power(FRU_MB, &status);
if (ret) {
return false;
}
if (status == SERVER_POWER_OFF) {
return true;
} else {
return false;
}
}
// Power Off, Power On, or Power Reset the server in given slot
int
pal_set_server_power(uint8_t fru, uint8_t cmd) {
uint8_t status;
bool gs_flag = false;
uint8_t ret;
if (pal_get_server_power(fru, &status) < 0) {
return -1;
}
switch(cmd) {
case SERVER_POWER_ON:
if (status == SERVER_POWER_ON)
return 1;
else
return server_power_on();
break;
case SERVER_POWER_OFF:
if (status == SERVER_POWER_OFF)
return 1;
else
return server_power_off(gs_flag);
break;
case SERVER_POWER_CYCLE:
if (status == SERVER_POWER_ON) {
if (server_power_off(gs_flag))
return -1;
sleep(DELAY_POWER_CYCLE);
return server_power_on();
} else if (status == SERVER_POWER_OFF) {
return (server_power_on());
}
break;
case SERVER_GRACEFUL_SHUTDOWN:
if (status == SERVER_POWER_OFF)
return 1;
gs_flag = true;
return server_power_off(gs_flag);
break;
case SERVER_POWER_RESET:
if (status == SERVER_POWER_ON) {
FORCE_ADR();
ret = pal_set_rst_btn(fru, 0);
if (ret < 0)
return ret;
msleep(100); //some server miss to detect a quick pulse, so delay 100ms between low high
ret = pal_set_rst_btn(fru, 1);
if (ret < 0)
return ret;
} else if (status == SERVER_POWER_OFF)
return -1;
break;
default:
return -1;
}
return 0;
}
int
pal_sled_cycle(void) {
// Send command to HSC power cycle
if (system("i2cset -y 7 0x45 0xd9 c &> /dev/null") != 0) {
syslog(LOG_CRIT, "SLED Cycle failed\n");
return -1;
}
return 0;
}
// Return the front panel's Reset Button status
int
pal_get_rst_btn(uint8_t *status) {
int ret = -1;
gpio_value_t value;
gpio_desc_t *desc = gpio_open_by_shadow("FM_THROTTLE_N");
if (!desc) {
return -1;
}
if (0 == gpio_get_value(desc, &value)) {
*status = value == GPIO_VALUE_HIGH ? 0 : 1;
ret = 0;
}
gpio_close(desc);
return ret;
}
// Update the Reset button input to the server at given slot
int
pal_set_rst_btn(uint8_t slot, uint8_t status) {
gpio_desc_t *desc;
int ret = -1;
if (slot != FRU_MB) {
return -1;
}
desc = gpio_open_by_shadow("RST_BMC_SYSRST_BTN_OUT_N");
if (!desc) {
return -1;
}
if (gpio_set_value(desc, status ? GPIO_VALUE_HIGH : GPIO_VALUE_LOW) == 0) {
ret = 0;
}
gpio_close(desc);
return ret;
}
// Update the LED for the given slot with the status
int
pal_set_sled_led(uint8_t fru, uint8_t status) {
int ret = -1;
gpio_desc_t *gpio = gpio_open_by_shadow("SERVER_POWER_LED");
if (!gpio) {
return -1;
}
//TODO: Need to check power LED control from CPLD
if (gpio_set_value(gpio, status ? GPIO_VALUE_HIGH : GPIO_VALUE_LOW) == 0) {
ret = 0;
}
gpio_close(gpio);
return ret;
}
// Update Heartbeet LED
int
pal_set_hb_led(uint8_t status) {
char cmd[64] = {0};
char *val;
if (status) {
val = "1";
} else {
val = "0";
}
sprintf(cmd, "devmem 0x1e6c0064 32 %s", val);
if (system(cmd) != 0) {
syslog(LOG_ERR, "Setting HB LED failed!\n");
return -1;
}
return 0;
}
// Update the Identification LED for the given fru with the status
int
pal_set_id_led(uint8_t fru, uint8_t status) {
return pal_set_sled_led(fru, status);
}
// Switch the UART mux to the given fru
int
pal_switch_uart_mux(uint8_t fru) {
return control_sol_txd(fru);
}
static int
check_postcodes(uint8_t fru_id, uint8_t sensor_num, float *value) {
static int log_asserted = 0;
const int loop_threshold = 3;
const int longest_loop_code = 4;
size_t len;
int i, check_from, check_until;
uint8_t buff[256];
uint8_t location, maj_err, min_err, loop_convention;
int ret = READING_NA, rc;
static unsigned int retry=0;
char sensor_name[32] = {0};
char str[32] = {0};
if (fru_id != 1) {
syslog(LOG_ERR, "Not Supported Operation for fru %d", fru_id);
goto error_exit;
}
if (is_server_off()) {
log_asserted = 0;
goto error_exit;
}
len = 0; // clear higher bits
rc = pal_get_80port_record(FRU_MB, buff, sizeof(buff), &len);
if (rc != PAL_EOK)
goto error_exit;
loop_convention = 0; // NO loop
check_from = len - (longest_loop_code * (loop_threshold) );
check_until = len - (longest_loop_code * (loop_threshold+1) );
// Check post code from last 12 to last 16 codes
for(i = check_from; i >= 0 && i >= check_until; i--) {
if (i > 0 && buff[i-1] == 0x00) {
// If previous code is 00h, find the 1st 00h.
continue;
}
// Check Loop Convention1, 0x00 -> DIMM Location -> Major Error Code - > Minor Error Code -> Loop
// Major shall not be 0x00, and it also shall not be 0xA0 ~ 0xDF
// DIMM Location and Minor might be 0x00, but they shall not be 0x00 at the same time.
// When Minor is 0x00, the DIMM location shall be 0xA0 ~ 0xDF
if (buff[i] == 0x00 &&
buff[i+4] == 0x00 &&
!memcmp(&buff[i], &buff[i+4], len - i - 4) ) {
// Check special minor 00h case
if (buff[i+1] == 0x00 &&
buff[i+2] >= 0xA0 &&
buff[i+2] <= 0xDF ) {
// This is minor 00h case, the 2nd 00h is starting 00h
i = i + 1;
}
// PostCode looping
loop_convention = 1;
location = buff[i+1];
maj_err = buff[i+2];
min_err = buff[i+3];
break;
}
// Check Loop Convention2, 0x00 -> Major Error Code -> Minor Error Code ->Loop
// Major and Minor shall not be 0x00 in this convention
else if (buff[i] == 0x00 &&
buff[i+3] == 0x00 &&
!memcmp(&buff[i], &buff[i+3], len - i - 3) ) {
// PostCode looping
loop_convention = 2;
location = 0x00;
maj_err = buff[i+1];
min_err = buff[i+2];
break;
}
}
if (loop_convention != 0) {
if (!log_asserted) {
pal_get_sensor_name(fru_id, sensor_num, sensor_name);
if (loop_convention == 1) { // Convention1
snprintf(str, sizeof(str), "Location:%02X Err:%02X %02X",location, maj_err, min_err);
_print_sensor_discrete_log(fru_id, sensor_num, sensor_name, 0x01, str);
snprintf(str, sizeof(str), "DIMM %02X initial fails",location);
pal_add_cri_sel(str);
//syslog(LOG_CRIT, "Memory training failure at %02X MajErr:%02X, MinErr:%02X", location, maj_err, min_err);
} else { // Convention2
snprintf(str, sizeof(str), "Location Unknown Err:%02X %02X", maj_err, min_err);
_print_sensor_discrete_log(fru_id, sensor_num, sensor_name, 0x01, str);
//syslog(LOG_CRIT, "Memory training failure MajErr:%02X, MinErr:%02X", maj_err, min_err);
snprintf(str, sizeof(str), "DIMM XX initial fails");
pal_add_cri_sel(str);
}
}
log_asserted = 1;
}
else
{
log_asserted = 0;
}
*value = (float)log_asserted;
ret = 0;
error_exit:
if ((ret == READING_NA) && (retry < MAX_READ_RETRY)){
ret = READING_SKIP;
retry++;
} else {
retry = 0;
}
return ret;
}
static int
check_frb3(uint8_t fru_id, uint8_t sensor_num, float *value) {
static unsigned int retry = 0;
static uint8_t frb3_fail = 0x10; // bit 4: FRB3 failure
static time_t rst_time = 0;
uint8_t postcodes[256] = {0};
struct stat file_stat;
int ret = READING_NA, rc;
size_t len = 0;
char sensor_name[32] = {0};
char error[32] = {0};
if (fru_id != 1) {
syslog(LOG_ERR, "Not Supported Operation for fru %d", fru_id);
return READING_NA;
}
if (stat("/tmp/rst_touch", &file_stat) == 0 && file_stat.st_mtime > rst_time) {
rst_time = file_stat.st_mtime;
// assume fail till we know it is not
frb3_fail = 0x10; // bit 4: FRB3 failure
retry = 0;
// cache current postcode buffer
if (stat("/tmp/DWR", &file_stat) != 0) {
memset(postcodes_last, 0, sizeof(postcodes_last));
pal_get_80port_record(FRU_MB, postcodes_last, sizeof(postcodes_last), &len);
}
}
if (frb3_fail) {
// KCS transaction
if (stat("/tmp/kcs_touch", &file_stat) == 0 && file_stat.st_mtime > rst_time)
frb3_fail = 0;
// Port 80 updated
memset(postcodes, 0, sizeof(postcodes));
rc = pal_get_80port_record(FRU_MB, postcodes, sizeof(postcodes), &len);
if (rc == PAL_EOK && memcmp(postcodes_last, postcodes, 256) != 0) {
frb3_fail = 0;
}
// BIOS POST COMPLT, in case BMC reboot when system idle in OS
if (pal_is_BIOS_completed(FRU_MB))
frb3_fail = 0;
}
if (frb3_fail)
retry++;
else
retry = 0;
if (retry == MAX_READ_RETRY) {
pal_get_sensor_name(fru_id, sensor_num, sensor_name);
snprintf(error, sizeof(error), "FRB3 failure");
_print_sensor_discrete_log(fru_id, sensor_num, sensor_name, frb3_fail, error);
}
*value = (float)frb3_fail;
ret = 0;
return ret;
}
int
pal_get_fru_list(char *list) {
strcpy(list, pal_fru_list);
return 0;
}
int
pal_get_fru_capability(uint8_t fru, unsigned int *caps)
{
int ret = 0;
switch (fru) {
case FRU_MB:
*caps = FRU_CAPABILITY_FRUID_ALL | FRU_CAPABILITY_SENSOR_ALL |
FRU_CAPABILITY_SERVER | FRU_CAPABILITY_MANAGEMENT_CONTROLLER |
FRU_CAPABILITY_POWER_ALL;
break;
case FRU_NIC:
*caps = FRU_CAPABILITY_FRUID_ALL | FRU_CAPABILITY_SENSOR_ALL |
FRU_CAPABILITY_NETWORK_CARD;
break;
case FRU_RISER_SLOT2:
case FRU_RISER_SLOT3:
case FRU_RISER_SLOT4:
*caps = FRU_CAPABILITY_FRUID_ALL | FRU_CAPABILITY_SENSOR_ALL;
break;
default:
ret = -1;
break;
}
return ret;
}
int
pal_get_fru_id(char *str, uint8_t *fru) {
if (!strcmp(str, "all")) {
*fru = FRU_ALL;
} else if (!strcmp(str, "mb")) {
*fru = FRU_MB;
} else if (!strcmp(str, "nic")) {
*fru = FRU_NIC;
} else if (!strcmp(str, "riser_slot2")) {
*fru = FRU_RISER_SLOT2;
} else if (!strcmp(str, "riser_slot3")) {
*fru = FRU_RISER_SLOT3;
} else if (!strcmp(str, "riser_slot4")) {
*fru = FRU_RISER_SLOT4;
} else if (!strncmp(str, "fru", 3)) {
*fru = atoi(&str[3]);
if (*fru <= FRU_NIC || *fru > MAX_NUM_FRUS)
return -1;
} else {
syslog(LOG_WARNING, "pal_get_fru_id: Wrong fru#%s", str);
return -1;
}
return 0;
}
int
pal_get_fru_name(uint8_t fru, char *name) {
switch(fru) {
case FRU_MB:
strcpy(name, "mb");
break;
case FRU_NIC:
strcpy(name, "nic");
break;
case FRU_RISER_SLOT2:
strcpy(name, "riser_slot2");
break;
case FRU_RISER_SLOT3:
strcpy(name, "riser_slot3");
break;
case FRU_RISER_SLOT4:
strcpy(name, "riser_slot4");
break;
default:
if (fru > MAX_NUM_FRUS)
return -1;
sprintf(name, "fru%d", fru);
break;
}
return 0;
}
int
pal_devnum_to_fruid(int devnum)
{
return FRU_MB;
}
int
pal_channel_to_bus(int channel)
{
switch (channel) {
case 0:
return 9; // USB (LCD Debug Board)
case 6:
return 4; // ME
case 9:
return 1; // Riser (Big Basin)
}
// Debug purpose, map to real bus number
if (channel & 0x80) {
return (channel & 0x7f);
}
return channel;
}
int
pal_get_fru_sdr_path(uint8_t fru, char *path) {
return -1;
}
int
pal_sensor_sdr_init(uint8_t fru, sensor_info_t *sinfo) {
return -1;
}
int
pal_get_fru_sensor_list(uint8_t fru, uint8_t **sensor_list, int *cnt) {
switch(fru) {
case FRU_MB:
*sensor_list = (uint8_t *) mb_sensor_list;
*cnt = mb_sensor_cnt;
break;
case FRU_NIC:
*sensor_list = (uint8_t *) nic_sensor_list;
*cnt = nic_sensor_cnt;
break;
case FRU_RISER_SLOT2:
*sensor_list = (uint8_t *) riser_slot2_sensor_list;
*cnt = riser_slot2_sensor_cnt;
break;
case FRU_RISER_SLOT3:
*sensor_list = (uint8_t *) riser_slot3_sensor_list;
*cnt = riser_slot3_sensor_cnt;
break;
case FRU_RISER_SLOT4:
*sensor_list = (uint8_t *) riser_slot4_sensor_list;
*cnt = riser_slot4_sensor_cnt;
break;
default:
if (fru > MAX_NUM_FRUS)
return -1;
// Nothing to read yet.
*sensor_list = NULL;
*cnt = 0;
}
return 0;
}
int
pal_fruid_write(uint8_t fru, char *path)
{
int fru_size = 0;
char command[128]={0};
char device_name[16]={0};
uint8_t bus = 0;
uint8_t device_addr = 0;
uint8_t device_type = 0;
uint8_t acutal_riser_slot = 0;
int ret=PAL_EOK;
FILE *fruid_fd;
fruid_fd = fopen(path, "rb");
if ( NULL == fruid_fd ) {
syslog(LOG_WARNING, "[%s] unable to open the file: %s", __func__, path);
return PAL_ENOTSUP;
}
fseek(fruid_fd, 0, SEEK_END);
fru_size = (uint32_t) ftell(fruid_fd);
fclose(fruid_fd);
printf("[%s]FRU Size: %d\n", __func__, fru_size);
switch (fru)
{
case FRU_RISER_SLOT2:
case FRU_RISER_SLOT3:
case FRU_RISER_SLOT4:
acutal_riser_slot = fru - FRU_RISER_SLOT2;//make the slot start from 0
if ( true == pal_is_ava_card( acutal_riser_slot ) )
{
device_type = FOUND_AVA_DEVICE;
device_addr = 0x50;
bus = RISER_BUS_ID;
sprintf(device_name, "24c64");
sprintf(command, "dd if=%s of=%s bs=%d count=1", path, EEPROM_RISER, fru_size);
}
else if ( true == pal_is_retimer_card( acutal_riser_slot ) )
{
device_type = FOUND_RETIMER_DEVICE;
device_addr = 0x55;
bus = 0x3;
sprintf(device_name, "24c02");
sprintf(command, "dd if=%s of=%s bs=%d count=1", path, EEPROM_RETIMER, fru_size);
}
else
{
//if there is no riser card, return
syslog(LOG_WARNING, "[%s] There is no fru on the riser slot %d ", __func__, fru);
return PAL_ENOTSUP;
}
break;
default:
//if there is an unknown device on the slot, return
syslog(LOG_WARNING, "[%s] Unknown device on the fru %d ", __func__, fru);
return PAL_ENOTSUP;
break;
}
switch (device_type)
{
case FOUND_AVA_DEVICE:
ret = mux_lock(&riser_mux, acutal_riser_slot, 5);
if ( PAL_EOK == ret )
{
pal_add_i2c_device(bus, device_name, device_addr);
if (system(command) != 0) {
syslog(LOG_WARNING, "%s failed\n", command);
}
//compare the in and out data
ret=pal_compare_fru_data((char*)EEPROM_RISER, path, fru_size);
if (ret < 0)
{
ret = PAL_ENOTSUP;
if (system("i2cdetect -y -q 1 > /tmp/AVA_FRU_FAIL.log") != 0) {
syslog(LOG_ERR, "Gathering I2C detect failure log failed\n");
}
syslog(LOG_ERR, "[%s] AVA FRU Write Fail", __func__);
}
pal_del_i2c_device(bus, device_addr);
mux_release(&riser_mux);
}
break;
case FOUND_RETIMER_DEVICE:
ret = pal_control_mux_to_target_ch(acutal_riser_slot, 0x3/*bus number*/, 0xe2/*mux address*/);
if ( PAL_EOK == ret )
{
pal_add_i2c_device(bus, device_name, device_addr);
if (system(command) != 0) {
syslog(LOG_ERR, "%s failed", command);
}
ret = pal_compare_fru_data((char*)EEPROM_RETIMER, path, fru_size);
if ( ret < 0 )
{
ret = PAL_ENOTSUP;
if (system("i2cdetect -y -q 3 > /tmp/RETIMER_FRU_FAIL.log") != 0) {
syslog(LOG_ERR, "Gathering I2C detect failure log failed");
}
syslog(LOG_ERR, "[%s] RETIMER FRU Write Fail", __func__);
}
pal_del_i2c_device(bus, device_addr);
}
ret = PAL_EOK;
break;
}
return ret;
}
int
pal_get_sensor_poll_interval(uint8_t fru, uint8_t sensor_num, uint32_t *value)
{
//default poll interval
*value = 2;
switch (fru)
{
case FRU_MB:
if ( MB_SENSOR_P3V_BAT == sensor_num )
{
*value = 3600;
}
break;
case FRU_NIC:
case FRU_RISER_SLOT2:
case FRU_RISER_SLOT3:
case FRU_RISER_SLOT4:
break;
}
return PAL_EOK;
}
static int
read_battery_status(float *value)
{
int ret = -1;
gpio_desc_t *gp_batt = gpio_open_by_shadow("FM_BATTERY_SENSE_EN_N");
if (!gp_batt) {
return -1;
}
if (gpio_set_value(gp_batt, GPIO_VALUE_LOW)) {
goto bail;
}
msleep(10);
ret = sensors_read_adc("MB_P3V_BAT", value);
gpio_set_value(gp_batt, GPIO_VALUE_HIGH);
bail:
gpio_close(gp_batt);
return ret;
}
int
pal_sensor_read_raw(uint8_t fru, uint8_t sensor_num, void *value) {
char key[MAX_KEY_LEN] = {0};
char str[MAX_VALUE_LEN] = {0};
char fru_name[32];
int ret;
static uint8_t poweron_10s_flag = 0;
bool server_off;
pal_get_fru_name(fru, fru_name);
sprintf(key, "%s_sensor%d", fru_name, sensor_num);
switch(fru) {
case FRU_MB:
case FRU_RISER_SLOT2:
case FRU_RISER_SLOT3:
case FRU_RISER_SLOT4:
server_off = is_server_off();
if (server_off) {
poweron_10s_flag = 0;
// Power is OFF, so only some of the sensors can be read
switch(sensor_num) {
// Temp. Sensors
case MB_SENSOR_INLET_TEMP:
ret = sensors_read("tmp421-i2c-6-4e", "MB_INLET_TEMP", (float *)value);
break;
case MB_SENSOR_OUTLET_TEMP:
ret = read_outlet_temp((float *)value);
break;
case MB_SENSOR_INLET_REMOTE_TEMP:
ret = sensors_read("tmp421-i2c-6-4e", "MB_INLET_REMOTE_TEMP", (float *)value);
if (!ret)
apply_inlet_correction((float *) value);
break;
case MB_SENSOR_OUTLET_REMOTE_TEMP:
ret = sensors_read("tmp421-i2c-6-4f", "MB_OUTLET_REMOTE_TEMP", (float *)value);
break;
case MB_SENSOR_P12V:
ret = sensors_read_adc("MB_P12V", (float *)value);
break;
case MB_SENSOR_P1V05:
ret = sensors_read_adc("MB_P1V05", (float *)value);
break;
case MB_SENSOR_PVNN_PCH_STBY:
ret = sensors_read_adc("MB_PVNN_PCH_STBY", (float *)value);
break;
case MB_SENSOR_P3V3_STBY:
ret = sensors_read_adc("MB_P3V3_STBY", (float *)value);
break;
case MB_SENSOR_P5V_STBY:
ret = sensors_read_adc("MB_P5V_STBY", (float *)value);
break;
case MB_SENSOR_P3V_BAT:
ret = read_battery_status((float *)value);
break;
// Hot Swap Controller
case MB_SENSOR_HSC_IN_VOLT:
ret = read_sensor_reading_from_ME(MB_SENSOR_HSC_IN_VOLT, (float*) value);
break;
case MB_SENSOR_HSC_OUT_CURR:
ret = read_hsc_current_value((float*) value);
break;
case MB_SENSOR_HSC_TEMP:
ret = read_hsc_temp_value((float*) value);
break;
case MB_SENSOR_HSC_IN_POWER:
ret = read_sensor_reading_from_ME(MB_SENSOR_HSC_IN_POWER, (float*) value);
break;
case MB_SENSOR_POWER_FAIL:
ret = read_CPLD_power_fail_sts (fru, sensor_num, (float*) value, poweron_10s_flag);
break;
case MB_SENSOR_HSC_VDELTA:
ret = read_hsc_vdelta_value((float*) value);
break;
case MB_SENSOR_VR_STATUS:
ret = check_vr_ov_ot_status((float*) value);
break;
default:
ret = READING_NA;
break;
}
} else {
if((poweron_10s_flag < 5) && ((sensor_num == MB_SENSOR_HSC_IN_VOLT) ||
(sensor_num == MB_SENSOR_HSC_OUT_CURR) || (sensor_num == MB_SENSOR_HSC_IN_POWER) ||
(sensor_num == MB_SENSOR_HSC_TEMP) ||
(sensor_num == MB_SENSOR_FAN0_TACH) || (sensor_num == MB_SENSOR_FAN1_TACH))) {
if(sensor_num == MB_SENSOR_HSC_IN_POWER){
poweron_10s_flag++;
}
ret = READING_NA;
break;
}
switch(sensor_num) {
// Temp. Sensors
case MB_SENSOR_INLET_TEMP:
ret = sensors_read("tmp421-i2c-6-4e", "MB_INLET_TEMP", (float *)value);
break;
case MB_SENSOR_OUTLET_TEMP:
ret = read_outlet_temp((float *)value);
break;
case MB_SENSOR_INLET_REMOTE_TEMP:
ret = sensors_read("tmp421-i2c-6-4e", "MB_INLET_REMOTE_TEMP", (float *)value);
if (!ret)
apply_inlet_correction((float *) value);
break;
case MB_SENSOR_OUTLET_REMOTE_TEMP:
ret = sensors_read("tmp421-i2c-6-4f", "MB_OUTLET_REMOTE_TEMP", (float *)value);
break;
// Fan Sensors
case MB_SENSOR_FAN0_TACH:
ret = read_fan_value("fan1", (float *)value);
break;
case MB_SENSOR_FAN1_TACH:
ret = read_fan_value("fan3", (float *)value);
break;
// Various Voltages
case MB_SENSOR_P3V3:
ret = sensors_read_adc("MB_P3V3", (float *)value);
break;
case MB_SENSOR_P5V:
ret = sensors_read_adc("MB_P5V", (float *)value);
break;
case MB_SENSOR_P12V:
ret = sensors_read_adc("MB_P12V", (float *)value);
break;
case MB_SENSOR_P1V05:
ret = sensors_read_adc("MB_P1V05", (float *)value);
break;
case MB_SENSOR_PVNN_PCH_STBY:
ret = sensors_read_adc("MB_PVNN_PCH_STBY", (float *)value);
break;
case MB_SENSOR_P3V3_STBY:
ret = sensors_read_adc("MB_P3V3_STBY", (float *)value);
break;
case MB_SENSOR_P5V_STBY:
ret = sensors_read_adc("MB_P5V_STBY", (float *)value);
break;
case MB_SENSOR_P3V_BAT:
ret = read_battery_status((float *)value);
break;
// Hot Swap Controller
case MB_SENSOR_HSC_IN_VOLT:
ret = read_sensor_reading_from_ME(MB_SENSOR_HSC_IN_VOLT, (float*) value);
break;
case MB_SENSOR_HSC_OUT_CURR:
ret = read_hsc_current_value((float*) value);
break;
case MB_SENSOR_HSC_TEMP:
ret = read_hsc_temp_value((float*) value);
break;
case MB_SENSOR_HSC_IN_POWER:
ret = read_sensor_reading_from_ME(MB_SENSOR_HSC_IN_POWER, (float*) value);
break;
//CPU, DIMM, PCH Temp
case MB_SENSOR_CPU0_TEMP:
case MB_SENSOR_CPU1_TEMP:
ret = read_cpu_temp(sensor_num, (float*) value);
break;
case MB_SENSOR_CPU0_DIMM_GRPA_TEMP:
case MB_SENSOR_CPU0_DIMM_GRPB_TEMP:
case MB_SENSOR_CPU1_DIMM_GRPC_TEMP:
case MB_SENSOR_CPU1_DIMM_GRPD_TEMP:
ret = read_dimm_temp(sensor_num, (float*) value);
break;
case MB_SENSOR_CPU0_PKG_POWER:
case MB_SENSOR_CPU1_PKG_POWER:
ret = read_cpu_package_power(sensor_num, (float*) value);
break;
case MB_SENSOR_PCH_TEMP:
ret = read_sensor_reading_from_ME(MB_SENSOR_PCH_TEMP, (float*) value);
break;
//VR Sensors
case MB_SENSOR_VR_CPU0_VCCIN_TEMP:
ret = vr_read_temp(VR_CPU0_VCCIN, VR_LOOP_PAGE_0, (float*) value);
break;
case MB_SENSOR_VR_CPU0_VCCIN_CURR:
ret = vr_read_curr(VR_CPU0_VCCIN, VR_LOOP_PAGE_0, (float*) value);
break;
case MB_SENSOR_VR_CPU0_VCCIN_VOLT:
ret = vr_read_volt(VR_CPU0_VCCIN, VR_LOOP_PAGE_0, (float*) value);
break;
case MB_SENSOR_VR_CPU0_VCCIN_POWER:
ret = vr_read_power(VR_CPU0_VCCIN, VR_LOOP_PAGE_0, (float*) value);
break;
case MB_SENSOR_VR_CPU0_VSA_TEMP:
ret = vr_read_temp(VR_CPU0_VSA, VR_LOOP_PAGE_1, (float*) value);
break;
case MB_SENSOR_VR_CPU0_VSA_CURR:
ret = vr_read_curr(VR_CPU0_VSA, VR_LOOP_PAGE_1, (float*) value);
break;
case MB_SENSOR_VR_CPU0_VSA_VOLT:
ret = vr_read_volt(VR_CPU0_VSA, VR_LOOP_PAGE_1, (float*) value);
break;
case MB_SENSOR_VR_CPU0_VSA_POWER:
ret = vr_read_power(VR_CPU0_VSA, VR_LOOP_PAGE_1, (float*) value);
break;
case MB_SENSOR_VR_CPU0_VCCIO_TEMP:
ret = vr_read_temp(VR_CPU0_VCCIO, VR_LOOP_PAGE_0, (float*) value);
break;
case MB_SENSOR_VR_CPU0_VCCIO_CURR:
ret = vr_read_curr(VR_CPU0_VCCIO, VR_LOOP_PAGE_0, (float*) value);
break;
case MB_SENSOR_VR_CPU0_VCCIO_VOLT:
ret = vr_read_volt(VR_CPU0_VCCIO, VR_LOOP_PAGE_0, (float*) value);
break;
case MB_SENSOR_VR_CPU0_VCCIO_POWER:
ret = vr_read_power(VR_CPU0_VCCIO, VR_LOOP_PAGE_0, (float*) value);
break;
case MB_SENSOR_VR_CPU0_VDDQ_GRPA_TEMP:
ret = vr_read_temp(g_vr_cpu0_vddq_abc, VR_LOOP_PAGE_0, (float*) value);
break;
case MB_SENSOR_VR_CPU0_VDDQ_GRPA_CURR:
ret = vr_read_curr(g_vr_cpu0_vddq_abc, VR_LOOP_PAGE_0, (float*) value);
break;
case MB_SENSOR_VR_CPU0_VDDQ_GRPA_VOLT:
ret = vr_read_volt(g_vr_cpu0_vddq_abc, VR_LOOP_PAGE_0, (float*) value);
break;
case MB_SENSOR_VR_CPU0_VDDQ_GRPA_POWER:
ret = vr_read_power(g_vr_cpu0_vddq_abc, VR_LOOP_PAGE_0, (float*) value);
break;
case MB_SENSOR_VR_CPU0_VDDQ_GRPB_TEMP:
ret = vr_read_temp(g_vr_cpu0_vddq_def, VR_LOOP_PAGE_0, (float*) value);
break;
case MB_SENSOR_VR_CPU0_VDDQ_GRPB_CURR:
ret = vr_read_curr(g_vr_cpu0_vddq_def, VR_LOOP_PAGE_0, (float*) value);
break;
case MB_SENSOR_VR_CPU0_VDDQ_GRPB_VOLT:
ret = vr_read_volt(g_vr_cpu0_vddq_def, VR_LOOP_PAGE_0, (float*) value);
break;
case MB_SENSOR_VR_CPU0_VDDQ_GRPB_POWER:
ret = vr_read_power(g_vr_cpu0_vddq_def, VR_LOOP_PAGE_0, (float*) value);
break;
case MB_SENSOR_VR_CPU1_VCCIN_TEMP:
if (is_cpu_socket_occupy(1))
ret = vr_read_temp(VR_CPU1_VCCIN, VR_LOOP_PAGE_0, (float*) value);
else
ret = READING_NA;
break;
case MB_SENSOR_VR_CPU1_VCCIN_CURR:
if (is_cpu_socket_occupy(1))
ret = vr_read_curr(VR_CPU1_VCCIN, VR_LOOP_PAGE_0, (float*) value);
else
ret = READING_NA;
break;
case MB_SENSOR_VR_CPU1_VCCIN_VOLT:
if (is_cpu_socket_occupy(1))
ret = vr_read_volt(VR_CPU1_VCCIN, VR_LOOP_PAGE_0, (float*) value);
else
ret = READING_NA;
break;
case MB_SENSOR_VR_CPU1_VCCIN_POWER:
if (is_cpu_socket_occupy(1))
ret = vr_read_power(VR_CPU1_VCCIN, VR_LOOP_PAGE_0, (float*) value);
else
ret = READING_NA;
break;
case MB_SENSOR_VR_CPU1_VSA_TEMP:
if (is_cpu_socket_occupy(1))
ret = vr_read_temp(VR_CPU1_VSA, VR_LOOP_PAGE_1, (float*) value);
else
ret = READING_NA;
break;
case MB_SENSOR_VR_CPU1_VSA_CURR:
if (is_cpu_socket_occupy(1))
ret = vr_read_curr(VR_CPU1_VSA, VR_LOOP_PAGE_1, (float*) value);
else
ret = READING_NA;
break;
case MB_SENSOR_VR_CPU1_VSA_VOLT:
if (is_cpu_socket_occupy(1))
ret = vr_read_volt(VR_CPU1_VSA, VR_LOOP_PAGE_1, (float*) value);
else
ret = READING_NA;
break;
case MB_SENSOR_VR_CPU1_VSA_POWER:
if (is_cpu_socket_occupy(1))
ret = vr_read_power(VR_CPU1_VSA, VR_LOOP_PAGE_1, (float*) value);
else
ret = READING_NA;
break;
case MB_SENSOR_VR_CPU1_VCCIO_TEMP:
if (is_cpu_socket_occupy(1))
ret = vr_read_temp(VR_CPU1_VCCIO, VR_LOOP_PAGE_0, (float*) value);
else
ret = READING_NA;
break;
case MB_SENSOR_VR_CPU1_VCCIO_CURR:
if (is_cpu_socket_occupy(1))
ret = vr_read_curr(VR_CPU1_VCCIO, VR_LOOP_PAGE_0, (float*) value);
else
ret = READING_NA;
break;
case MB_SENSOR_VR_CPU1_VCCIO_VOLT:
if (is_cpu_socket_occupy(1))
ret = vr_read_volt(VR_CPU1_VCCIO, VR_LOOP_PAGE_0, (float*) value);
else
ret = READING_NA;
break;
case MB_SENSOR_VR_CPU1_VCCIO_POWER:
if (is_cpu_socket_occupy(1))
ret = vr_read_power(VR_CPU1_VCCIO, VR_LOOP_PAGE_0, (float*) value);
else
ret = READING_NA;
break;
case MB_SENSOR_VR_CPU1_VDDQ_GRPC_TEMP:
if (is_cpu_socket_occupy(1))
ret = vr_read_temp(g_vr_cpu1_vddq_ghj, VR_LOOP_PAGE_0, (float*) value);
else
ret = READING_NA;
break;
case MB_SENSOR_VR_CPU1_VDDQ_GRPC_CURR:
if (is_cpu_socket_occupy(1))
ret = vr_read_curr(g_vr_cpu1_vddq_ghj, VR_LOOP_PAGE_0, (float*) value);
else
ret = READING_NA;
break;
case MB_SENSOR_VR_CPU1_VDDQ_GRPC_VOLT:
if (is_cpu_socket_occupy(1))
ret = vr_read_volt(g_vr_cpu1_vddq_ghj, VR_LOOP_PAGE_0, (float*) value);
else
ret = READING_NA;
break;
case MB_SENSOR_VR_CPU1_VDDQ_GRPC_POWER:
if (is_cpu_socket_occupy(1))
ret = vr_read_power(g_vr_cpu1_vddq_ghj, VR_LOOP_PAGE_0, (float*) value);
else
ret = READING_NA;
break;
case MB_SENSOR_VR_CPU1_VDDQ_GRPD_TEMP:
if (is_cpu_socket_occupy(1))
ret = vr_read_temp(g_vr_cpu1_vddq_klm, VR_LOOP_PAGE_0, (float*) value);
else
ret = READING_NA;
break;
case MB_SENSOR_VR_CPU1_VDDQ_GRPD_CURR:
if (is_cpu_socket_occupy(1))
ret = vr_read_curr(g_vr_cpu1_vddq_klm, VR_LOOP_PAGE_0, (float*) value);
else
ret = READING_NA;
break;
case MB_SENSOR_VR_CPU1_VDDQ_GRPD_VOLT:
if (is_cpu_socket_occupy(1))
ret = vr_read_volt(g_vr_cpu1_vddq_klm, VR_LOOP_PAGE_0, (float*) value);
else
ret = READING_NA;
break;
case MB_SENSOR_VR_CPU1_VDDQ_GRPD_POWER:
if (is_cpu_socket_occupy(1))
ret = vr_read_power(g_vr_cpu1_vddq_klm, VR_LOOP_PAGE_0, (float*) value);
else
ret = READING_NA;
break;
case MB_SENSOR_VR_PCH_PVNN_TEMP:
ret = vr_read_temp(VR_PCH_PVNN, VR_LOOP_PAGE_0, (float*) value);
break;
case MB_SENSOR_VR_PCH_PVNN_CURR:
ret = vr_read_curr(VR_PCH_PVNN, VR_LOOP_PAGE_0, (float*) value);
break;
case MB_SENSOR_VR_PCH_PVNN_VOLT:
ret = vr_read_volt(VR_PCH_PVNN, VR_LOOP_PAGE_0, (float*) value);
break;
case MB_SENSOR_VR_PCH_PVNN_POWER:
ret = vr_read_power(VR_PCH_PVNN, VR_LOOP_PAGE_0, (float*) value);
break;
case MB_SENSOR_VR_PCH_P1V05_TEMP:
ret = vr_read_temp(VR_PCH_P1V05, VR_LOOP_PAGE_1, (float*) value);
break;
case MB_SENSOR_VR_PCH_P1V05_CURR:
ret = vr_read_curr(VR_PCH_P1V05, VR_LOOP_PAGE_1, (float*) value);
break;
case MB_SENSOR_VR_PCH_P1V05_VOLT:
ret = vr_read_volt(VR_PCH_P1V05, VR_LOOP_PAGE_1, (float*) value);
break;
case MB_SENSOR_VR_PCH_P1V05_POWER:
ret = vr_read_power(VR_PCH_P1V05, VR_LOOP_PAGE_1, (float*) value);
break;
case MB_SENSOR_C2_AVA_FTEMP:
case MB_SENSOR_C2_AVA_RTEMP:
case MB_SENSOR_C3_AVA_FTEMP:
case MB_SENSOR_C3_AVA_RTEMP:
case MB_SENSOR_C4_AVA_FTEMP:
case MB_SENSOR_C4_AVA_RTEMP:
ret = read_ava_temp(sensor_num, (float*) value);
break;
case MB_SENSOR_C2_NVME_CTEMP:
case MB_SENSOR_C3_NVME_CTEMP:
case MB_SENSOR_C4_NVME_CTEMP:
case MB_SENSOR_C2_1_NVME_CTEMP:
case MB_SENSOR_C2_2_NVME_CTEMP:
case MB_SENSOR_C2_3_NVME_CTEMP:
case MB_SENSOR_C2_4_NVME_CTEMP:
case MB_SENSOR_C3_1_NVME_CTEMP:
case MB_SENSOR_C3_2_NVME_CTEMP:
case MB_SENSOR_C3_3_NVME_CTEMP:
case MB_SENSOR_C3_4_NVME_CTEMP:
case MB_SENSOR_C4_1_NVME_CTEMP:
case MB_SENSOR_C4_2_NVME_CTEMP:
case MB_SENSOR_C4_3_NVME_CTEMP:
case MB_SENSOR_C4_4_NVME_CTEMP:
ret = read_nvme_temp(sensor_num, (float*) value);
break;
case MB_SENSOR_C2_P12V_INA230_VOL:
case MB_SENSOR_C3_P12V_INA230_VOL:
case MB_SENSOR_C4_P12V_INA230_VOL:
case MB_SENSOR_CONN_P12V_INA230_VOL:
case MB_SENSOR_C2_P12V_INA230_CURR:
case MB_SENSOR_C3_P12V_INA230_CURR:
case MB_SENSOR_C4_P12V_INA230_CURR:
case MB_SENSOR_CONN_P12V_INA230_CURR:
case MB_SENSOR_C2_P12V_INA230_PWR:
case MB_SENSOR_C3_P12V_INA230_PWR:
case MB_SENSOR_C4_P12V_INA230_PWR:
case MB_SENSOR_CONN_P12V_INA230_PWR:
ret = read_INA230 (sensor_num, (float*) value, poweron_10s_flag);
break;
case MB_SENSOR_POWER_FAIL:
ret = read_CPLD_power_fail_sts (fru, sensor_num, (float*) value, poweron_10s_flag);
break;
case MB_SENSOR_MEMORY_LOOP_FAIL:
ret = check_postcodes(FRU_MB, sensor_num, (float*) value);
break;
case MB_SENSOR_PROCESSOR_FAIL:
ret = check_frb3(FRU_MB, sensor_num, (float*) value);
break;
case MB_SENSOR_HSC_VDELTA:
ret = read_hsc_vdelta_value((float*) value);
break;
default:
return -1;
}
}
if (is_server_off() != server_off) {
/* server power status changed while we were reading the sensor.
* this sensor is potentially NA. */
return pal_sensor_read_raw(fru, sensor_num, value);
}
break;
case FRU_NIC:
sprintf(key, "nic_sensor%d", sensor_num);
switch(sensor_num) {
case MEZZ_SENSOR_TEMP:
ret = read_nic_temp((float*) value);
break;
default:
return -1;
}
break;
default:
return -1;
}
if (ret) {
if (ret == READING_NA || ret == -1) {
strcpy(str, "NA");
} else {
return ret;
}
} else {
sprintf(str, "%.2f",*((float*)value));
}
if(kv_set(key, str, 0, 0) < 0) {
#ifdef DEBUG
syslog(LOG_WARNING, "pal_sensor_read_raw: cache_set key = %s, str = %s failed.", key, str);
#endif
return -1;
} else {
return ret;
}
return 0;
}
int
pal_sensor_threshold_flag(uint8_t fru, uint8_t snr_num, uint16_t *flag) {
return 0;
}
int
pal_get_sensor_threshold(uint8_t fru, uint8_t sensor_num, uint8_t thresh, void *value) {
float *val = (float*) value;
sensor_thresh_array_init();
switch(fru) {
case FRU_MB:
*val = mb_sensor_threshold[sensor_num][thresh];
break;
case FRU_NIC:
*val = nic_sensor_threshold[sensor_num][thresh];
break;
case FRU_RISER_SLOT2:
*val = riser_slot2_sensor_threshold[sensor_num][thresh];
break;
case FRU_RISER_SLOT3:
*val = riser_slot3_sensor_threshold[sensor_num][thresh];
break;
case FRU_RISER_SLOT4:
*val = riser_slot4_sensor_threshold[sensor_num][thresh];
break;
default:
return -1;
}
return 0;
}
int
pal_get_sensor_name(uint8_t fru, uint8_t sensor_num, char *name) {
switch(fru) {
case FRU_MB:
case FRU_RISER_SLOT2:
case FRU_RISER_SLOT3:
case FRU_RISER_SLOT4:
switch(sensor_num) {
case MB_SENSOR_INLET_TEMP:
sprintf(name, "MB_INLET_TEMP");
break;
case MB_SENSOR_OUTLET_TEMP:
sprintf(name, "MB_OUTLET_TEMP");
break;
case MB_SENSOR_INLET_REMOTE_TEMP:
sprintf(name, "MB_INLET_REMOTE_TEMP");
break;
case MB_SENSOR_OUTLET_REMOTE_TEMP:
sprintf(name, "MB_OUTLET_REMOTE_TEMP");
break;
case MB_SENSOR_FAN0_TACH:
sprintf(name, "MB_FAN0_TACH");
break;
case MB_SENSOR_FAN1_TACH:
sprintf(name, "MB_FAN1_TACH");
break;
case MB_SENSOR_P3V3:
sprintf(name, "MB_P3V3");
break;
case MB_SENSOR_P5V:
sprintf(name, "MB_P5V");
break;
case MB_SENSOR_P12V:
sprintf(name, "MB_P12V");
break;
case MB_SENSOR_P1V05:
sprintf(name, "MB_P1V05");
break;
case MB_SENSOR_PVNN_PCH_STBY:
sprintf(name, "MB_PVNN_PCH_STBY");
break;
case MB_SENSOR_P3V3_STBY:
sprintf(name, "MB_P3V3_STBY");
break;
case MB_SENSOR_P5V_STBY:
sprintf(name, "MB_P5V_STBY");
break;
case MB_SENSOR_P3V_BAT:
sprintf(name, "MB_P3V_BAT");
break;
case MB_SENSOR_HSC_IN_VOLT:
sprintf(name, "MB_HSC_IN_VOLT");
break;
case MB_SENSOR_HSC_OUT_CURR:
sprintf(name, "MB_HSC_OUT_CURR");
break;
case MB_SENSOR_HSC_TEMP:
sprintf(name, "MB_HSC_TEMP");
break;
case MB_SENSOR_HSC_IN_POWER:
sprintf(name, "MB_HSC_IN_POWER");
break;
case MB_SENSOR_CPU0_TEMP:
sprintf(name, "MB_CPU0_TEMP");
break;
case MB_SENSOR_CPU0_TJMAX:
sprintf(name, "MB_CPU0_TJMAX");
break;
case MB_SENSOR_CPU0_PKG_POWER:
sprintf(name, "MB_CPU0_PKG_POWER");
break;
case MB_SENSOR_CPU0_THERM_MARGIN:
sprintf(name, "MB_CPU0_THERM_MARGIN");
break;
case MB_SENSOR_CPU1_TEMP:
sprintf(name, "MB_CPU1_TEMP");
break;
case MB_SENSOR_CPU1_TJMAX:
sprintf(name, "MB_CPU1_TJMAX");
break;
case MB_SENSOR_CPU1_PKG_POWER:
sprintf(name, "MB_CPU1_PKG_POWER");
break;
case MB_SENSOR_CPU1_THERM_MARGIN:
sprintf(name, "MB_CPU1_THERM_MARGIN");
break;
case MB_SENSOR_PCH_TEMP:
sprintf(name, "MB_PCH_TEMP");
break;
case MB_SENSOR_CPU0_DIMM_GRPA_TEMP:
sprintf(name, "MB_CPU0_DIMM_GRPA_TEMP");
break;
case MB_SENSOR_CPU0_DIMM_GRPB_TEMP:
sprintf(name, "MB_CPU0_DIMM_GRPB_TEMP");
break;
case MB_SENSOR_CPU1_DIMM_GRPC_TEMP:
sprintf(name, "MB_CPU1_DIMM_GRPC_TEMP");
break;
case MB_SENSOR_CPU1_DIMM_GRPD_TEMP:
sprintf(name, "MB_CPU1_DIMM_GRPD_TEMP");
break;
case MB_SENSOR_VR_CPU0_VCCIN_TEMP:
sprintf(name, "MB_VR_CPU0_VCCIN_TEMP");
break;
case MB_SENSOR_VR_CPU0_VCCIN_CURR:
sprintf(name, "MB_VR_CPU0_VCCIN_CURR");
break;
case MB_SENSOR_VR_CPU0_VCCIN_VOLT:
sprintf(name, "MB_VR_CPU0_VCCIN_VOLT");
break;
case MB_SENSOR_VR_CPU0_VCCIN_POWER:
sprintf(name, "MB_VR_CPU0_VCCIN_POWER");
break;
case MB_SENSOR_VR_CPU0_VSA_TEMP:
sprintf(name, "MB_VR_CPU0_VSA_TEMP");
break;
case MB_SENSOR_VR_CPU0_VSA_CURR:
sprintf(name, "MB_VR_CPU0_VSA_CURR");
break;
case MB_SENSOR_VR_CPU0_VSA_VOLT:
sprintf(name, "MB_VR_CPU0_VSA_VOLT");
break;
case MB_SENSOR_VR_CPU0_VSA_POWER:
sprintf(name, "MB_VR_CPU0_VSA_POWER");
break;
case MB_SENSOR_VR_CPU0_VCCIO_TEMP:
sprintf(name, "MB_VR_CPU0_VCCIO_TEMP");
break;
case MB_SENSOR_VR_CPU0_VCCIO_CURR:
sprintf(name, "MB_VR_CPU0_VCCIO_CURR");
break;
case MB_SENSOR_VR_CPU0_VCCIO_VOLT:
sprintf(name, "MB_VR_CPU0_VCCIO_VOLT");
break;
case MB_SENSOR_VR_CPU0_VCCIO_POWER:
sprintf(name, "MB_VR_CPU0_VCCIO_POWER");
break;
case MB_SENSOR_VR_CPU0_VDDQ_GRPA_TEMP:
sprintf(name, "MB_VR_CPU0_VDDQ_GRPA_TEMP");
break;
case MB_SENSOR_VR_CPU0_VDDQ_GRPA_CURR:
sprintf(name, "MB_VR_CPU0_VDDQ_GRPA_CURR");
break;
case MB_SENSOR_VR_CPU0_VDDQ_GRPA_VOLT:
sprintf(name, "MB_VR_CPU0_VDDQ_GRPA_VOLT");
break;
case MB_SENSOR_VR_CPU0_VDDQ_GRPA_POWER:
sprintf(name, "MB_VR_CPU0_VDDQ_GRPA_POWER");
break;
case MB_SENSOR_VR_CPU0_VDDQ_GRPB_TEMP:
sprintf(name, "MB_VR_CPU0_VDDQ_GRPB_TEMP");
break;
case MB_SENSOR_VR_CPU0_VDDQ_GRPB_CURR:
sprintf(name, "MB_VR_CPU0_VDDQ_GRPB_CURR");
break;
case MB_SENSOR_VR_CPU0_VDDQ_GRPB_VOLT:
sprintf(name, "MB_VR_CPU0_VDDQ_GRPB_VOLT");
break;
case MB_SENSOR_VR_CPU0_VDDQ_GRPB_POWER:
sprintf(name, "MB_VR_CPU0_VDDQ_GRPB_POWER");
break;
case MB_SENSOR_VR_CPU1_VCCIN_TEMP:
sprintf(name, "MB_VR_CPU1_VCCIN_TEMP");
break;
case MB_SENSOR_VR_CPU1_VCCIN_CURR:
sprintf(name, "MB_VR_CPU1_VCCIN_CURR");
break;
case MB_SENSOR_VR_CPU1_VCCIN_VOLT:
sprintf(name, "MB_VR_CPU1_VCCIN_VOLT");
break;
case MB_SENSOR_VR_CPU1_VCCIN_POWER:
sprintf(name, "MB_VR_CPU1_VCCIN_POWER");
break;
case MB_SENSOR_VR_CPU1_VSA_TEMP:
sprintf(name, "MB_VR_CPU1_VSA_TEMP");
break;
case MB_SENSOR_VR_CPU1_VSA_CURR:
sprintf(name, "MB_VR_CPU1_VSA_CURR");
break;
case MB_SENSOR_VR_CPU1_VSA_VOLT:
sprintf(name, "MB_VR_CPU1_VSA_VOLT");
break;
case MB_SENSOR_VR_CPU1_VSA_POWER:
sprintf(name, "MB_VR_CPU1_VSA_POWER");
break;
case MB_SENSOR_VR_CPU1_VCCIO_TEMP:
sprintf(name, "MB_VR_CPU1_VCCIO_TEMP");
break;
case MB_SENSOR_VR_CPU1_VCCIO_CURR:
sprintf(name, "MB_VR_CPU1_VCCIO_CURR");
break;
case MB_SENSOR_VR_CPU1_VCCIO_VOLT:
sprintf(name, "MB_VR_CPU1_VCCIO_VOLT");
break;
case MB_SENSOR_VR_CPU1_VCCIO_POWER:
sprintf(name, "MB_VR_CPU1_VCCIO_POWER");
break;
case MB_SENSOR_VR_CPU1_VDDQ_GRPC_TEMP:
sprintf(name, "MB_VR_CPU1_VDDQ_GRPC_TEMP");
break;
case MB_SENSOR_VR_CPU1_VDDQ_GRPC_CURR:
sprintf(name, "MB_VR_CPU1_VDDQ_GRPC_CURR");
break;
case MB_SENSOR_VR_CPU1_VDDQ_GRPC_VOLT:
sprintf(name, "MB_VR_CPU1_VDDQ_GRPC_VOLT");
break;
case MB_SENSOR_VR_CPU1_VDDQ_GRPC_POWER:
sprintf(name, "MB_VR_CPU1_VDDQ_GRPC_POWER");
break;
case MB_SENSOR_VR_CPU1_VDDQ_GRPD_TEMP:
sprintf(name, "MB_VR_CPU1_VDDQ_GRPD_TEMP");
break;
case MB_SENSOR_VR_CPU1_VDDQ_GRPD_CURR:
sprintf(name, "MB_VR_CPU1_VDDQ_GRPD_CURR");
break;
case MB_SENSOR_VR_CPU1_VDDQ_GRPD_VOLT:
sprintf(name, "MB_VR_CPU1_VDDQ_GRPD_VOLT");
break;
case MB_SENSOR_VR_CPU1_VDDQ_GRPD_POWER:
sprintf(name, "MB_VR_CPU1_VDDQ_GRPD_POWER");
break;
case MB_SENSOR_VR_PCH_PVNN_TEMP:
sprintf(name, "MB_VR_PCH_PVNN_TEMP");
break;
case MB_SENSOR_VR_PCH_PVNN_CURR:
sprintf(name, "MB_VR_PCH_PVNN_CURR");
break;
case MB_SENSOR_VR_PCH_PVNN_VOLT:
sprintf(name, "MB_VR_PCH_PVNN_VOLT");
break;
case MB_SENSOR_VR_PCH_PVNN_POWER:
sprintf(name, "MB_VR_PCH_PVNN_POWER");
break;
case MB_SENSOR_VR_PCH_P1V05_TEMP:
sprintf(name, "MB_VR_PCH_P1V05_TEMP");
break;
case MB_SENSOR_VR_PCH_P1V05_CURR:
sprintf(name, "MB_VR_PCH_P1V05_CURR");
break;
case MB_SENSOR_VR_PCH_P1V05_VOLT:
sprintf(name, "MB_VR_PCH_P1V05_VOLT");
break;
case MB_SENSOR_VR_PCH_P1V05_POWER:
sprintf(name, "MB_VR_PCH_P1V05_POWER");
break;
case MB_SENSOR_HOST_BOOT_TEMP:
sprintf(name, "MB_HOST_BOOT_TEMP");
break;
case MB_SENSOR_C2_NVME_CTEMP:
sprintf(name, "MB_C2_NVME_CTEMP");
break;
case MB_SENSOR_C3_NVME_CTEMP:
sprintf(name, "MB_C3_NVME_CTEMP");
break;
case MB_SENSOR_C4_NVME_CTEMP:
sprintf(name, "MB_C4_NVME_CTEMP");
break;
case MB_SENSOR_C2_AVA_FTEMP:
sprintf(name, "MB_C2_AVA_FTEMP");
break;
case MB_SENSOR_C2_AVA_RTEMP:
sprintf(name, "MB_C2_AVA_RTEMP");
break;
case MB_SENSOR_C2_1_NVME_CTEMP:
sprintf(name, "MB_C2_0_NVME_CTEMP");
break;
case MB_SENSOR_C2_2_NVME_CTEMP:
sprintf(name, "MB_C2_1_NVME_CTEMP");
break;
case MB_SENSOR_C2_3_NVME_CTEMP:
sprintf(name, "MB_C2_2_NVME_CTEMP");
break;
case MB_SENSOR_C2_4_NVME_CTEMP:
sprintf(name, "MB_C2_3_NVME_CTEMP");
break;
case MB_SENSOR_C3_AVA_FTEMP:
sprintf(name, "MB_C3_AVA_FTEMP");
break;
case MB_SENSOR_C3_AVA_RTEMP:
sprintf(name, "MB_C3_AVA_RTEMP");
break;
case MB_SENSOR_C3_1_NVME_CTEMP:
sprintf(name, "MB_C3_0_NVME_CTEMP");
break;
case MB_SENSOR_C3_2_NVME_CTEMP:
sprintf(name, "MB_C3_1_NVME_CTEMP");
break;
case MB_SENSOR_C3_3_NVME_CTEMP:
sprintf(name, "MB_C3_2_NVME_CTEMP");
break;
case MB_SENSOR_C3_4_NVME_CTEMP:
sprintf(name, "MB_C3_3_NVME_CTEMP");
break;
case MB_SENSOR_C4_AVA_FTEMP:
sprintf(name, "MB_C4_AVA_FTEMP");
break;
case MB_SENSOR_C4_AVA_RTEMP:
sprintf(name, "MB_C4_AVA_RTEMP");
break;
case MB_SENSOR_C4_1_NVME_CTEMP:
sprintf(name, "MB_C4_0_NVME_CTEMP");
break;
case MB_SENSOR_C4_2_NVME_CTEMP:
sprintf(name, "MB_C4_1_NVME_CTEMP");
break;
case MB_SENSOR_C4_3_NVME_CTEMP:
sprintf(name, "MB_C4_2_NVME_CTEMP");
break;
case MB_SENSOR_C4_4_NVME_CTEMP:
sprintf(name, "MB_C4_3_NVME_CTEMP");
break;
case MB_SENSOR_C2_P12V_INA230_VOL:
sprintf(name, "MB_C2_P12V_INA230_VOL");
break;
case MB_SENSOR_C2_P12V_INA230_CURR:
sprintf(name, "MB_C2_P12V_INA230_CURR");
break;
case MB_SENSOR_C2_P12V_INA230_PWR:
sprintf(name, "MB_C2_P12V_INA230_PWR");
break;
case MB_SENSOR_C3_P12V_INA230_VOL:
sprintf(name, "MB_C3_P12V_INA230_VOL");
break;
case MB_SENSOR_C3_P12V_INA230_CURR:
sprintf(name, "MB_C3_P12V_INA230_CURR");
break;
case MB_SENSOR_C3_P12V_INA230_PWR:
sprintf(name, "MB_C3_P12V_INA230_PWR");
break;
case MB_SENSOR_C4_P12V_INA230_VOL:
sprintf(name, "MB_C4_P12V_INA230_VOL");
break;
case MB_SENSOR_C4_P12V_INA230_CURR:
sprintf(name, "MB_C4_P12V_INA230_CURR");
break;
case MB_SENSOR_C4_P12V_INA230_PWR:
sprintf(name, "MB_C4_P12V_INA230_PWR");
break;
case MB_SENSOR_CONN_P12V_INA230_VOL:
sprintf(name, "MB_CONN_P12V_INA230_VOL");
break;
case MB_SENSOR_CONN_P12V_INA230_CURR:
sprintf(name, "MB_CONN_P12V_INA230_CURR");
break;
case MB_SENSOR_CONN_P12V_INA230_PWR:
sprintf(name, "MB_CONN_P12V_INA230_PWR");
break;
case MB_SENSOR_POWER_FAIL:
sprintf(name, "MB_POWER_FAIL");
break;
case MB_SENSOR_MEMORY_LOOP_FAIL:
sprintf(name, "MB_MEMORY_LOOP_FAIL");
break;
case MB_SENSOR_PROCESSOR_FAIL:
sprintf(name, "MB_PROCESSOR_FAIL");
break;
default:
return -1;
}
break;
case FRU_NIC:
switch(sensor_num) {
case MEZZ_SENSOR_TEMP:
sprintf(name, "MEZZ_SENSOR_TEMP");
break;
default:
return -1;
}
break;
default:
return -1;
}
return 0;
}
int
pal_get_sensor_units(uint8_t fru, uint8_t sensor_num, char *units) {
switch(fru) {
case FRU_MB:
case FRU_RISER_SLOT2:
case FRU_RISER_SLOT3:
case FRU_RISER_SLOT4:
switch(sensor_num) {
case MB_SENSOR_INLET_TEMP:
case MB_SENSOR_OUTLET_TEMP:
case MB_SENSOR_INLET_REMOTE_TEMP:
case MB_SENSOR_OUTLET_REMOTE_TEMP:
case MB_SENSOR_CPU0_TEMP:
case MB_SENSOR_CPU0_TJMAX:
case MB_SENSOR_CPU0_THERM_MARGIN:
case MB_SENSOR_CPU1_TEMP:
case MB_SENSOR_CPU1_TJMAX:
case MB_SENSOR_CPU1_THERM_MARGIN:
case MB_SENSOR_PCH_TEMP:
case MB_SENSOR_CPU0_DIMM_GRPA_TEMP:
case MB_SENSOR_CPU0_DIMM_GRPB_TEMP:
case MB_SENSOR_CPU1_DIMM_GRPC_TEMP:
case MB_SENSOR_CPU1_DIMM_GRPD_TEMP:
case MB_SENSOR_VR_CPU0_VCCIN_TEMP:
case MB_SENSOR_VR_CPU0_VSA_TEMP:
case MB_SENSOR_VR_CPU0_VCCIO_TEMP:
case MB_SENSOR_VR_CPU0_VDDQ_GRPA_TEMP:
case MB_SENSOR_VR_CPU0_VDDQ_GRPB_TEMP:
case MB_SENSOR_VR_CPU1_VCCIN_TEMP:
case MB_SENSOR_VR_CPU1_VSA_TEMP:
case MB_SENSOR_VR_CPU1_VCCIO_TEMP:
case MB_SENSOR_VR_CPU1_VDDQ_GRPC_TEMP:
case MB_SENSOR_VR_CPU1_VDDQ_GRPD_TEMP:
case MB_SENSOR_VR_PCH_PVNN_TEMP:
case MB_SENSOR_VR_PCH_P1V05_TEMP:
case MB_SENSOR_HOST_BOOT_TEMP:
case MB_SENSOR_C2_NVME_CTEMP:
case MB_SENSOR_C3_NVME_CTEMP:
case MB_SENSOR_C4_NVME_CTEMP:
case MB_SENSOR_C2_AVA_FTEMP:
case MB_SENSOR_C2_AVA_RTEMP:
case MB_SENSOR_C2_1_NVME_CTEMP:
case MB_SENSOR_C2_2_NVME_CTEMP:
case MB_SENSOR_C2_3_NVME_CTEMP:
case MB_SENSOR_C2_4_NVME_CTEMP:
case MB_SENSOR_C3_AVA_FTEMP:
case MB_SENSOR_C3_AVA_RTEMP:
case MB_SENSOR_C3_1_NVME_CTEMP:
case MB_SENSOR_C3_2_NVME_CTEMP:
case MB_SENSOR_C3_3_NVME_CTEMP:
case MB_SENSOR_C3_4_NVME_CTEMP:
case MB_SENSOR_C4_AVA_FTEMP:
case MB_SENSOR_C4_AVA_RTEMP:
case MB_SENSOR_C4_1_NVME_CTEMP:
case MB_SENSOR_C4_2_NVME_CTEMP:
case MB_SENSOR_C4_3_NVME_CTEMP:
case MB_SENSOR_C4_4_NVME_CTEMP:
case MB_SENSOR_HSC_TEMP:
sprintf(units, "C");
break;
case MB_SENSOR_FAN0_TACH:
case MB_SENSOR_FAN1_TACH:
sprintf(units, "RPM");
break;
case MB_SENSOR_P3V3:
case MB_SENSOR_P5V:
case MB_SENSOR_P12V:
case MB_SENSOR_P1V05:
case MB_SENSOR_PVNN_PCH_STBY:
case MB_SENSOR_P3V3_STBY:
case MB_SENSOR_P5V_STBY:
case MB_SENSOR_P3V_BAT:
case MB_SENSOR_HSC_IN_VOLT:
case MB_SENSOR_VR_CPU0_VCCIN_VOLT:
case MB_SENSOR_VR_CPU0_VSA_VOLT:
case MB_SENSOR_VR_CPU0_VCCIO_VOLT:
case MB_SENSOR_VR_CPU0_VDDQ_GRPA_VOLT:
case MB_SENSOR_VR_CPU0_VDDQ_GRPB_VOLT:
case MB_SENSOR_VR_CPU1_VCCIN_VOLT:
case MB_SENSOR_VR_CPU1_VSA_VOLT:
case MB_SENSOR_VR_CPU1_VCCIO_VOLT:
case MB_SENSOR_VR_CPU1_VDDQ_GRPC_VOLT:
case MB_SENSOR_VR_CPU1_VDDQ_GRPD_VOLT:
case MB_SENSOR_VR_PCH_PVNN_VOLT:
case MB_SENSOR_VR_PCH_P1V05_VOLT:
case MB_SENSOR_C2_P12V_INA230_VOL:
case MB_SENSOR_C3_P12V_INA230_VOL:
case MB_SENSOR_C4_P12V_INA230_VOL:
case MB_SENSOR_CONN_P12V_INA230_VOL:
sprintf(units, "Volts");
break;
case MB_SENSOR_HSC_OUT_CURR:
case MB_SENSOR_VR_CPU0_VCCIN_CURR:
case MB_SENSOR_VR_CPU0_VSA_CURR:
case MB_SENSOR_VR_CPU0_VCCIO_CURR:
case MB_SENSOR_VR_CPU0_VDDQ_GRPA_CURR:
case MB_SENSOR_VR_CPU0_VDDQ_GRPB_CURR:
case MB_SENSOR_VR_CPU1_VCCIN_CURR:
case MB_SENSOR_VR_CPU1_VSA_CURR:
case MB_SENSOR_VR_CPU1_VCCIO_CURR:
case MB_SENSOR_VR_CPU1_VDDQ_GRPC_CURR:
case MB_SENSOR_VR_CPU1_VDDQ_GRPD_CURR:
case MB_SENSOR_VR_PCH_PVNN_CURR:
case MB_SENSOR_VR_PCH_P1V05_CURR:
case MB_SENSOR_C2_P12V_INA230_CURR:
case MB_SENSOR_C3_P12V_INA230_CURR:
case MB_SENSOR_C4_P12V_INA230_CURR:
case MB_SENSOR_CONN_P12V_INA230_CURR:
sprintf(units, "Amps");
break;
case MB_SENSOR_HSC_IN_POWER:
case MB_SENSOR_VR_CPU0_VCCIN_POWER:
case MB_SENSOR_VR_CPU0_VSA_POWER:
case MB_SENSOR_VR_CPU0_VCCIO_POWER:
case MB_SENSOR_VR_CPU0_VDDQ_GRPA_POWER:
case MB_SENSOR_VR_CPU0_VDDQ_GRPB_POWER:
case MB_SENSOR_VR_CPU1_VCCIN_POWER:
case MB_SENSOR_VR_CPU1_VSA_POWER:
case MB_SENSOR_VR_CPU1_VCCIO_POWER:
case MB_SENSOR_VR_CPU1_VDDQ_GRPC_POWER:
case MB_SENSOR_VR_CPU1_VDDQ_GRPD_POWER:
case MB_SENSOR_VR_PCH_PVNN_POWER:
case MB_SENSOR_VR_PCH_P1V05_POWER:
case MB_SENSOR_CPU0_PKG_POWER:
case MB_SENSOR_CPU1_PKG_POWER:
case MB_SENSOR_C2_P12V_INA230_PWR:
case MB_SENSOR_C3_P12V_INA230_PWR:
case MB_SENSOR_C4_P12V_INA230_PWR:
case MB_SENSOR_CONN_P12V_INA230_PWR:
sprintf(units, "Watts");
break;
default:
return -1;
}
break;
case FRU_NIC:
switch(sensor_num) {
case MEZZ_SENSOR_TEMP:
sprintf(units, "C");
break;
default:
return -1;
}
break;
default:
return -1;
}
return 0;
}
int
pal_get_fruid_path(uint8_t fru, char *path) {
char fname[16] = {0};
switch(fru) {
case FRU_MB:
sprintf(fname, "mb");
break;
case FRU_NIC:
sprintf(fname, "nic");
break;
case FRU_RISER_SLOT2:
sprintf(fname, "riser_slot2");
break;
case FRU_RISER_SLOT3:
sprintf(fname, "riser_slot3");
break;
case FRU_RISER_SLOT4:
sprintf(fname, "riser_slot4");
break;
default:
return -1;
}
sprintf(path, "/tmp/fruid_%s.bin", fname);
return 0;
}
int
pal_get_fruid_eeprom_path(uint8_t fru, char *path) {
switch(fru) {
case FRU_MB:
sprintf(path, FRU_EEPROM);
break;
default:
return -1;
}
return 0;
}
int
pal_get_fruid_name(uint8_t fru, char *name) {
switch(fru) {
case FRU_MB:
sprintf(name, "Mother Board");
break;
case FRU_NIC:
sprintf(name, "NIC Mezzanine");
break;
case FRU_RISER_SLOT2:
sprintf(name, "FRU content on the riser slot 2");
break;
case FRU_RISER_SLOT3:
sprintf(name, "FRU content on the riser slot 3");
break;
case FRU_RISER_SLOT4:
sprintf(name, "FRU content on the riser slot 4");
break;
default:
return -1;
}
return 0;
}
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);
}
}
/* Actions to be taken on Power On Reset */
if (pal_is_bmc_por()) {
/* Clear all the SEL errors */
memset(key, 0, MAX_KEY_LEN);
strcpy(key, "server_sel_error");
/* Write the value "1" which means FRU_STATUS_GOOD */
pal_set_key_value(key, "1");
/* Clear all the sensor health files*/
memset(key, 0, MAX_KEY_LEN);
strcpy(key, "server_sensor_health");
/* Write the value "1" which means FRU_STATUS_GOOD */
pal_set_key_value(key, "1");
}
return 0;
}
int
pal_get_fru_devtty(uint8_t fru, char *devtty) {
sprintf(devtty, "/dev/ttyS1");
return 0;
}
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_last_pwr_state(uint8_t fru, char *state) {
int ret;
char key[MAX_KEY_LEN] = {0};
sprintf(key, "%s", "pwr_server_last_state");
ret = pal_set_key_value(key, state);
if (ret < 0) {
#ifdef DEBUG
syslog(LOG_WARNING, "pal_set_last_pwr_state: pal_set_key_value failed for "
"fru %u", fru);
#endif
}
return ret;
}
int
pal_get_last_pwr_state(uint8_t fru, char *state) {
int ret;
char key[MAX_KEY_LEN] = {0};
sprintf(key, "%s", "pwr_server_last_state");
ret = pal_get_key_value(key, state);
if (ret < 0) {
#ifdef DEBUG
syslog(LOG_WARNING, "pal_get_last_pwr_state: pal_get_key_value failed for "
"fru %u", fru);
#endif
}
return ret;
}
// GUID for System and Device
static int
pal_get_guid(uint16_t offset, char *guid) {
int fd = 0;
ssize_t bytes_rd;
errno = 0;
// Check if file is present
if (access(FRU_EEPROM, F_OK) == -1) {
syslog(LOG_ERR, "pal_get_guid: unable to access the %s file: %s",
FRU_EEPROM, strerror(errno));
return errno;
}
// Open the file
fd = open(FRU_EEPROM, O_RDONLY);
if (fd == -1) {
syslog(LOG_ERR, "pal_get_guid: unable to open the %s file: %s",
FRU_EEPROM, strerror(errno));
return errno;
}
// seek to the offset
lseek(fd, offset, SEEK_SET);
// Read bytes from location
bytes_rd = read(fd, guid, GUID_SIZE);
if (bytes_rd != GUID_SIZE) {
syslog(LOG_ERR, "pal_get_guid: read to %s file failed: %s",
FRU_EEPROM, strerror(errno));
goto err_exit;
}
err_exit:
close(fd);
return errno;
}
static int
pal_set_guid(uint16_t offset, char *guid) {
int fd = 0;
ssize_t bytes_wr;
errno = 0;
// Check for file presence
if (access(FRU_EEPROM, F_OK) == -1) {
syslog(LOG_ERR, "pal_set_guid: unable to access the %s file: %s",
FRU_EEPROM, strerror(errno));
return errno;
}
// Open file
fd = open(FRU_EEPROM, O_WRONLY);
if (fd == -1) {
syslog(LOG_ERR, "pal_set_guid: unable to open the %s file: %s",
FRU_EEPROM, strerror(errno));
return errno;
}
// Seek the offset
lseek(fd, offset, SEEK_SET);
// Write GUID data
bytes_wr = write(fd, guid, GUID_SIZE);
if (bytes_wr != GUID_SIZE) {
syslog(LOG_ERR, "pal_set_guid: write to %s file failed: %s",
FRU_EEPROM, strerror(errno));
goto err_exit;
}
err_exit:
close(fd);
return errno;
}
int
pal_set_sys_guid(uint8_t fru, char *str) {
pal_populate_guid(g_sys_guid, str);
return pal_set_guid(OFFSET_SYS_GUID, g_sys_guid);
}
int
pal_set_dev_guid(uint8_t fru, char *str) {
pal_populate_guid(g_dev_guid, str);
return pal_set_guid(OFFSET_DEV_GUID, g_dev_guid);
}
int
pal_get_sys_guid(uint8_t fru, char *guid) {
pal_get_guid(OFFSET_SYS_GUID, g_sys_guid);
memcpy(guid, g_sys_guid, GUID_SIZE);
return 0;
}
int
pal_get_dev_guid(uint8_t fru, char *guid) {
pal_get_guid(OFFSET_DEV_GUID, g_dev_guid);
memcpy(guid, g_dev_guid, GUID_SIZE);
return 0;
}
void
pal_get_chassis_status(uint8_t slot, uint8_t *req_data, uint8_t *res_data, uint8_t *res_len) {
char str_server_por_cfg[64];
char buff[MAX_VALUE_LEN];
int policy = 3;
unsigned char *data = res_data;
// Platform Power Policy
memset(str_server_por_cfg, 0 , sizeof(char) * 64);
sprintf(str_server_por_cfg, "%s", "server_por_cfg");
if (pal_get_key_value(str_server_por_cfg, buff) == 0)
{
if (!memcmp(buff, "off", strlen("off")))
policy = 0;
else if (!memcmp(buff, "lps", strlen("lps")))
policy = 1;
else if (!memcmp(buff, "on", strlen("on")))
policy = 2;
else
policy = 3;
}
*data++ = ((is_server_off())?0x00:0x01) | (policy << 5);
*data++ = 0x00; // Last Power Event
*data++ = 0x40; // Misc. Chassis Status
*data++ = 0x00; // Front Panel Button Disable
*res_len = data - res_data;
}
int
pal_set_sysfw_ver(uint8_t fru, 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_server");
for (i = 0; i < SIZE_SYSFW_VER; i++) {
sprintf(tstr, "%02x", ver[i]);
strcat(str, tstr);
}
return pal_set_key_value(key, str);
}
int
pal_get_sysfw_ver(uint8_t fru, uint8_t *ver) {
int i;
int j = 0;
int ret;
int msb, lsb;
char key[MAX_KEY_LEN] = {0};
char str[MAX_VALUE_LEN] = {0};
char tstr[4] = {0};
sprintf(key, "sysfw_ver_server");
ret = pal_get_key_value(key, str);
if (ret) {
return ret;
}
for (i = 0; i < 2*SIZE_SYSFW_VER; i += 2) {
sprintf(tstr, "%c\n", str[i]);
msb = strtol(tstr, NULL, 16);
sprintf(tstr, "%c\n", str[i+1]);
lsb = strtol(tstr, NULL, 16);
ver[j++] = (msb << 4) | lsb;
}
return 0;
}
int
pal_set_boot_order(uint8_t slot, uint8_t *boot, uint8_t *res_data, uint8_t *res_len) {
int i, j, network_dev = 0;
char key[MAX_KEY_LEN] = {0};
char str[MAX_VALUE_LEN] = {0};
char tstr[10] = {0};
*res_len = 0;
sprintf(key, "server_boot_order");
for (i = 0; i < SIZE_BOOT_ORDER; i++) {
//Byte 0 is boot mode, Byte 1~5 is boot order
if ((i > 0) && (boot[i] != 0xFF)) {
for (j = i+1; j < SIZE_BOOT_ORDER; j++) {
if ( boot[i] == boot[j])
return CC_INVALID_PARAM;
}
//If Bit 2:0 is 001b (Network), Bit3 is IPv4/IPv6 order
//Bit3=0b: IPv4 first
//Bit3=1b: IPv6 first
if ( boot[i] == BOOT_DEVICE_IPV4 || boot[i] == BOOT_DEVICE_IPV6)
network_dev++;
}
snprintf(tstr, 3, "%02x", boot[i]);
strncat(str, tstr, 3);
}
//Not allow having more than 1 network boot device in the boot order.
if (network_dev > 1)
return CC_INVALID_PARAM;
return pal_set_key_value(key, str);
}
int
pal_get_boot_order(uint8_t slot, uint8_t *req_data, uint8_t *boot, uint8_t *res_len) {
int i;
int j = 0;
int ret;
int msb, lsb;
char key[MAX_KEY_LEN] = {0};
char str[MAX_VALUE_LEN] = {0};
char tstr[4] = {0};
sprintf(key, "server_boot_order");
ret = pal_get_key_value(key, str);
if (ret) {
*res_len = 0;
return ret;
}
for (i = 0; i < 2*SIZE_BOOT_ORDER; i += 2) {
sprintf(tstr, "%c\n", str[i]);
msb = strtol(tstr, NULL, 16);
sprintf(tstr, "%c\n", str[i+1]);
lsb = strtol(tstr, NULL, 16);
boot[j++] = (msb << 4) | lsb;
}
*res_len = SIZE_BOOT_ORDER;
return 0;
}
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) {
return 0;
}
fclose(fp);
}
return (por)?1:0;
}
int
pal_get_fru_discrete_list(uint8_t fru, uint8_t **sensor_list, int *cnt) {
switch(fru) {
case FRU_MB:
*sensor_list = (uint8_t *) mb_discrete_sensor_list;
*cnt = mb_discrete_sensor_cnt;
break;
default:
if (fru > MAX_NUM_FRUS)
return -1;
// Nothing to read yet.
*sensor_list = NULL;
*cnt = 0;
}
return 0;
}
static void
_print_sensor_discrete_log(uint8_t fru, uint8_t snr_num, char *snr_name,
uint8_t val, char *event) {
if (val) {
syslog(LOG_CRIT, "ASSERT: %s discrete - raised - FRU: %d, num: 0x%X,"
" snr: %-16s val: 0x%X", event, fru, snr_num, snr_name, val);
} else {
syslog(LOG_CRIT, "DEASSERT: %s discrete - settled - FRU: %d, num: 0x%X,"
" snr: %-16s val: 0x%X", event, fru, snr_num, snr_name, val);
}
pal_update_ts_sled();
}
int
pal_sensor_discrete_check(uint8_t fru, uint8_t snr_num, char *snr_name,
uint8_t o_val, uint8_t n_val) {
return 0;
}
#define MAX_DUMP_TIME 10800 /* 3 hours */
static pthread_t tid_dwr = -1;
static void *dwr_handler(void *arg) {
#if 0
int len;
ipmb_req_t *req;
ipmb_res_t *res;
//delay 30s for system reset
sleep(30);
// Get biosscratchpad7[26]: DWR assert check
req = ipmb_txb();
res = ipmb_rxb();
req->res_slave_addr = 0x2C; //ME's Slave Address
req->netfn_lun = NETFN_NM_REQ<<2;
req->cmd = CMD_NM_SEND_RAW_PECI;
req->data[0] = 0x57;
req->data[1] = 0x01;
req->data[2] = 0x00;
req->data[3] = 0x30; // CPU0
req->data[4] = 0x06;
req->data[5] = 0x05;
req->data[6] = 0x61; // RdPCIConfig
req->data[7] = 0x00; // Index
// Bus 0 Device 8 Fun 2, offset BCh
req->data[8] = 0xbc;
req->data[9] = 0x20;
req->data[10] = 0x04;
req->data[11] = 0x00;
// Invoke IPMB library handler
len = ipmb_send_buf(0x4, 12+MIN_IPMB_REQ_LEN);
if (len >= (8+MIN_IPMB_RES_LEN) && // Data len >= 8
res->cc == 0 && // IPMB Success
res->data[3] == 0x40 && // PECI Success
(res->data[7] & 0x04) == 0x04) { // DWR mode
// System is in DWR mode
syslog(LOG_WARNING, "Start DWR Autodump");
if (system("/usr/local/bin/autodump.sh --dwr &") != 0) {
syslog(LOG_ERR, "DWR autodump failed!\n");
}
} else {
syslog(LOG_WARNING, "Start Second Autodump");
if (system("/usr/local/bin/autodump.sh --second &") != 0) {
syslog(LOG_ERR, "Second autodump failed!\n");
}
}
#endif
syslog(LOG_WARNING, "Start Second/DWR Autodump");
if (system("/usr/local/bin/autodump.sh --second &") != 0) {
syslog(LOG_ERR, "Autodump.sh --second failed!\n");
}
tid_dwr = -1;
pthread_exit(NULL);
}
void
pal_second_crashdump_chk(void) {
int fd;
size_t len;
if (tid_dwr != -1)
pthread_cancel(tid_dwr);
if (pthread_create(&tid_dwr, NULL, dwr_handler, NULL) == 0) {
memset(postcodes_last, 0, sizeof(postcodes_last));
pal_get_80port_record(FRU_MB, postcodes_last, sizeof(postcodes_last), &len);
fd = creat("/tmp/DWR", 0644);
if (fd)
close(fd);
pthread_detach(tid_dwr);
}
else
tid_dwr = -1;
}
int
pal_sel_handler(uint8_t fru, uint8_t snr_num, uint8_t *event_data) {
return 0;
}
static int
pal_get_sensor_health_key(uint8_t fru, char *key)
{
switch (fru) {
case FRU_MB:
sprintf(key, "server_sensor_health");
break;
case FRU_NIC:
sprintf(key, "nic_sensor_health");
break;
default:
return -1;
}
return 0;
}
int
pal_set_sensor_health(uint8_t fru, uint8_t value) {
char key[MAX_KEY_LEN] = {0};
char cvalue[MAX_VALUE_LEN] = {0};
if (pal_get_sensor_health_key(fru, key))
return -1;
sprintf(cvalue, (value > 0) ? "1": "0");
return pal_set_key_value(key, cvalue);
}
int
pal_get_fru_health(uint8_t fru, uint8_t *value) {
char cvalue[MAX_VALUE_LEN] = {0};
char key[MAX_KEY_LEN] = {0};
int ret;
if (pal_get_sensor_health_key(fru, key)) {
return ERR_NOT_READY;
}
ret = pal_get_key_value(key, cvalue);
if (ret) {
syslog(LOG_INFO, "pal_get_fru_health(%d): getting value for %s failed\n", fru, key);
return ret;
}
*value = atoi(cvalue);
if (fru != FRU_MB)
return 0;
// If MB, get SEL error status.
sprintf(key, "server_sel_error");
memset(cvalue, 0, MAX_VALUE_LEN);
ret = pal_get_key_value(key, cvalue);
if (ret) {
syslog(LOG_INFO, "pal_get_fru_health(%d): getting value for %s failed\n", fru, key);
return ret;
}
*value = *value & atoi(cvalue);
return 0;
}
void
pal_inform_bic_mode(uint8_t fru, uint8_t mode) {
}
int
pal_get_fan_name(uint8_t num, char *name) {
switch(num) {
case FAN_0:
sprintf(name, "Fan 0");
break;
case FAN_1:
sprintf(name, "Fan 1");
break;
default:
return -1;
}
return 0;
}
int
pal_set_fan_speed(uint8_t fan, uint8_t pwm) {
int ret = -1;
if (fan >= pal_pwm_cnt) {
syslog(LOG_INFO, "pal_set_fan_speed: fan number is invalid - %d", fan);
return -1;
}
// Do not allow setting fan when server is off.
if (is_server_off()) {
return PAL_ENOTREADY;
}
if (fan == 0) {
ret = sensors_write_fan("pwm1", (float)pwm);
} else if (fan == 1) {
ret = sensors_write_fan("pwm2", (float)pwm);
}
return ret;
}
int
pal_get_fan_speed(uint8_t fan, int *rpm) {
int ret;
float value = 0.0;
if (fan == 0) {
ret = sensors_read_fan("fan1", &value);
} else if (fan == 1) {
ret = sensors_read_fan("fan3", &value);
} else {
syslog(LOG_INFO, "get_fan_speed: invalid fan#:%d", fan);
return -1;
}
*rpm = (int)value;
return ret;
}
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_handle_dcmi(uint8_t fru, uint8_t *request, uint8_t req_len, uint8_t *response, uint8_t *rlen) {
return me_xmit(request, req_len, response, rlen);
}
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 platform_id = 0x00;
uint8_t board_rev_id = 0x00;
uint8_t mb_slot_id = 0x00;
uint8_t raiser_card_slot_id = 0x00;
int completion_code=CC_UNSPECIFIED_ERROR;
ret = pal_get_platform_id(&platform_id);
if (ret) {
*res_len = 0x00;
return completion_code;
}
ret = pal_get_board_rev_id(&board_rev_id);
if (ret) {
*res_len = 0x00;
return completion_code;
}
ret = pal_get_mb_slot_id(&mb_slot_id);
if (ret) {
*res_len = 0x00;
return completion_code;
}
ret = pal_get_slot_cfg_id(&raiser_card_slot_id);
if (ret) {
*res_len = 0x00;
return completion_code;
}
// Prepare response buffer
completion_code = CC_SUCCESS;
res_data[0] = platform_id;
res_data[1] = board_rev_id;
res_data[2] = mb_slot_id;
res_data[3] = raiser_card_slot_id;
*res_len = 0x04;
return completion_code;
}
int
pal_get_platform_id(uint8_t *id) {
static bool cached = false;
static unsigned int cached_id = 0;
if (!cached) {
const char *shadows[] = {
"FM_BOARD_SKU_ID0",
"FM_BOARD_SKU_ID1",
"FM_BOARD_SKU_ID2",
"FM_BOARD_SKU_ID3",
"FM_BOARD_SKU_ID4"
};
if (gpio_get_value_by_shadow_list(shadows, ARRAY_SIZE(shadows), &cached_id)) {
return -1;
}
cached = true;
}
*id = (uint8_t)cached_id;
return 0;
}
int
pal_get_board_rev_id(uint8_t *id) {
static bool cached = false;
static unsigned int cached_id = 0;
if (!cached) {
const char *shadows[] = {
"FM_BOARD_REV_ID0",
"FM_BOARD_REV_ID1",
"FM_BOARD_REV_ID2"
};
if (gpio_get_value_by_shadow_list(shadows, ARRAY_SIZE(shadows), &cached_id)) {
return -1;
}
cached = true;
}
*id = (uint8_t)cached_id;
return 0;
}
int
pal_get_mb_slot_id(uint8_t *id) {
int fd = 0, ret = -1;
char fn[32];
uint8_t retry = 3, tcount, rcount, addr;
uint8_t tbuf[16] = {0};
uint8_t rbuf[16] = {0};
snprintf(fn, sizeof(fn), "/dev/i2c-%d", CPLD_BUS_ID);
fd = open(fn, O_RDWR);
if (fd < 0) {
goto err_exit;
}
//PCA9554 slave address
addr = 0x42;
//0x00: input register
tbuf[0] = 0x00;
tcount = 1;
rcount = 1;
while (ret < 0 && retry-- > 0 ) {
ret = i2c_rdwr_msg_transfer(fd, addr, tbuf, tcount, rbuf, rcount);
}
if (ret < 0) {
goto err_exit;
}
*id = rbuf[0] & 0x07;
err_exit:
if (fd > 0)
close(fd);
return ret;
}
int
pal_get_slot_cfg_id(uint8_t *id) {
static bool cached = false;
static unsigned int cached_id = 0;
if (!cached) {
const char *shadows[] = {
"FM_BOARD_SKU_ID5",
"FM_BOARD_SKU_ID6"
};
if (gpio_get_value_by_shadow_list(shadows, ARRAY_SIZE(shadows), &cached_id)) {
return -1;
}
cached = true;
}
*id = (uint8_t)cached_id;
return 0;
}
void
pal_log_clear(char *fru) {
if (!strcmp(fru, "mb")) {
pal_set_key_value("server_sensor_health", "1");
pal_set_key_value("server_sel_error", "1");
} else if (!strcmp(fru, "nic")) {
pal_set_key_value("nic_sensor_health", "1");
} else if (!strcmp(fru, "all")) {
pal_set_key_value("server_sensor_health", "1");
pal_set_key_value("server_sel_error", "1");
pal_set_key_value("nic_sensor_health", "1");
}
}
//For OEM command "CMD_OEM_GET_PLAT_INFO" 0x7e
int
pal_get_plat_sku_id(void) {
return 0;
}
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) {
return 0;
}
int
pal_get_pwm_value(uint8_t fan_num, uint8_t *value) {
int ret;
float val;
if (fan_num == 0) {
ret = sensors_read_fan("pwm1", &val);
} else if (fan_num == 1) {
ret = sensors_read_fan("pwm2", &val);
} else {
return -1;
}
if (!ret)
*value = (uint8_t)val;
return ret;
}
int
pal_fan_dead_handle(int fan_num) {
// TODO: Add action in case of fan dead
return 0;
}
int
pal_fan_recovered_handle(int fan_num) {
// TODO: Add action in case of fan recovered
return 0;
}
static bool
is_cpu_socket_occupy(unsigned int cpu_idx) {
static bool cached = false;
static unsigned int cached_id = 0;
if (!cached) {
const char *shadows[] = {
"FM_CPU0_SKTOCC_LVT3_N",
"FM_CPU1_SKTOCC_LVT3_N"
};
if (gpio_get_value_by_shadow_list(shadows, ARRAY_SIZE(shadows), &cached_id)) {
return false;
}
cached = true;
}
// bit == 1 implies CPU is absent.
if (cached_id & (1 << cpu_idx)) {
return false;
}
return true;
}
void
pal_sensor_assert_handle(uint8_t fru, uint8_t snr_num, float val, uint8_t thresh) {
char cmd[128];
char thresh_name[10];
switch (thresh) {
case UNR_THRESH:
sprintf(thresh_name, "UNR");
break;
case UCR_THRESH:
sprintf(thresh_name, "UCR");
break;
case UNC_THRESH:
sprintf(thresh_name, "UNCR");
break;
case LNR_THRESH:
sprintf(thresh_name, "LNR");
break;
case LCR_THRESH:
sprintf(thresh_name, "LCR");
break;
case LNC_THRESH:
sprintf(thresh_name, "LNCR");
break;
default:
syslog(LOG_WARNING, "pal_sensor_assert_handle: wrong thresh enum value");
exit(-1);
}
switch(snr_num) {
case MB_SENSOR_FAN0_TACH:
sprintf(cmd, "Fan0 %s %.0fRPM - Assert", thresh_name, val);
break;
case MB_SENSOR_FAN1_TACH:
sprintf(cmd, "Fan1 %s %.0fRPM - Assert", thresh_name, val);
break;
case MB_SENSOR_CPU0_TEMP:
sprintf(cmd, "P0 Temp %s %.0fC - Assert", thresh_name, val);
break;
case MB_SENSOR_CPU1_TEMP:
sprintf(cmd, "P1 Temp %s %.0fC - Assert", thresh_name, val);
break;
case MB_SENSOR_P3V_BAT:
sprintf(cmd, "P3V_BAT %s %.2fV - Assert", thresh_name, val);
break;
case MB_SENSOR_P3V3:
sprintf(cmd, "P3V3 %s %.2fV - Assert", thresh_name, val);
break;
case MB_SENSOR_P5V:
sprintf(cmd, "P5V %s %.2fV - Assert", thresh_name, val);
break;
case MB_SENSOR_P12V:
sprintf(cmd, "P12V %s %.2fV - Assert", thresh_name, val);
break;
case MB_SENSOR_P1V05:
sprintf(cmd, "P1V05 %s %.2fV - Assert", thresh_name, val);
break;
case MB_SENSOR_PVNN_PCH_STBY:
sprintf(cmd, "PVNN_PCH_STBY %s %.2fV - Assert", thresh_name, val);
break;
case MB_SENSOR_P3V3_STBY:
sprintf(cmd, "P3V3_STBY %s %.2fV - Assert", thresh_name, val);
break;
case MB_SENSOR_P5V_STBY:
sprintf(cmd, "P5V_STBY %s %.2fV - Assert", thresh_name, val);
break;
default:
return;
}
pal_add_cri_sel(cmd);
}
void
pal_sensor_deassert_handle(uint8_t fru, uint8_t snr_num, float val, uint8_t thresh) {
char cmd[128];
char thresh_name[10];
switch (thresh) {
case UNR_THRESH:
sprintf(thresh_name, "UNR");
break;
case UCR_THRESH:
sprintf(thresh_name, "UCR");
break;
case UNC_THRESH:
sprintf(thresh_name, "UNCR");
break;
case LNR_THRESH:
sprintf(thresh_name, "LNR");
break;
case LCR_THRESH:
sprintf(thresh_name, "LCR");
break;
case LNC_THRESH:
sprintf(thresh_name, "LNCR");
break;
default:
syslog(LOG_WARNING, "pal_sensor_assert_handle: wrong thresh enum value");
exit(-1);
}
switch(snr_num) {
case MB_SENSOR_FAN0_TACH:
sprintf(cmd, "Fan0 %s %3.0fRPM - Deassert", thresh_name, val);
break;
case MB_SENSOR_FAN1_TACH:
sprintf(cmd, "Fan1 %s %3.0fRPM - Deassert", thresh_name, val);
break;
case MB_SENSOR_CPU0_TEMP:
sprintf(cmd, "P0 Temp %s %3.0fC - Deassert", thresh_name, val);
break;
case MB_SENSOR_CPU1_TEMP:
sprintf(cmd, "P1 Temp %s %3.0fC - Deassert", thresh_name, val);
break;
case MB_SENSOR_P3V_BAT:
sprintf(cmd, "P3V_BAT %s %3.0fV - Deassert", thresh_name, val);
break;
case MB_SENSOR_P3V3:
sprintf(cmd, "P3V3 %s %3.0fV - Deassert", thresh_name, val);
break;
case MB_SENSOR_P5V:
sprintf(cmd, "P5V %s %3.0fV - Deassert", thresh_name, val);
break;
case MB_SENSOR_P12V:
sprintf(cmd, "P12V %s %3.0fV - Deassert", thresh_name, val);
break;
case MB_SENSOR_P1V05:
sprintf(cmd, "P1V05 %s %3.0fV - Deassert", thresh_name, val);
break;
case MB_SENSOR_PVNN_PCH_STBY:
sprintf(cmd, "PVNN_PCH_STBY %s %3.0fV - Deassert", thresh_name, val);
break;
case MB_SENSOR_P3V3_STBY:
sprintf(cmd, "P3V3_STBY %s %3.0fV - Deassert", thresh_name, val);
break;
case MB_SENSOR_P5V_STBY:
sprintf(cmd, "P5V_STBY %s %3.0fV - Deassert", thresh_name, val);
break;
default:
return;
}
pal_add_cri_sel(cmd);
}
void
pal_set_post_end(uint8_t slot, uint8_t *req_data, uint8_t *res_data, uint8_t *res_len)
{
*res_len = 0;
// log the post end event
syslog (LOG_INFO, "POST End Event for Payload#%d\n", slot);
// Sync time with system
if (system("/usr/local/bin/sync_date.sh &") != 0) {
syslog(LOG_ERR, "Sync date failed!\n");
}
}
int
pal_get_fw_info(uint8_t fru, unsigned char target, unsigned char* res, unsigned char* res_len)
{
return -1;
}
int
pal_get_last_boot_time(uint8_t slot, uint8_t *last_boot_time) {
return 0;
}
uint8_t
pal_set_power_restore_policy(uint8_t slot, uint8_t *pwr_policy, uint8_t *res_data) {
uint8_t completion_code;
completion_code = CC_SUCCESS; // Fill response with default values
unsigned char policy = *pwr_policy & 0x07; // Power restore policy
switch (policy)
{
case 0:
if (pal_set_key_value("server_por_cfg", "off") != 0)
completion_code = CC_UNSPECIFIED_ERROR;
break;
case 1:
if (pal_set_key_value("server_por_cfg", "lps") != 0)
completion_code = CC_UNSPECIFIED_ERROR;
break;
case 2:
if (pal_set_key_value("server_por_cfg", "on") != 0)
completion_code = CC_UNSPECIFIED_ERROR;
break;
case 3:
// no change (just get present policy support)
break;
default:
completion_code = CC_PARAM_OUT_OF_RANGE;
break;
}
return completion_code;
}
uint8_t
pal_get_status(void) {
char str_server_por_cfg[64];
char buff[MAX_VALUE_LEN];
int policy = 3;
uint8_t data;
// Platform Power Policy
memset(str_server_por_cfg, 0 , sizeof(char) * 64);
sprintf(str_server_por_cfg, "%s", "server_por_cfg");
if (pal_get_key_value(str_server_por_cfg, buff) == 0)
{
if (!memcmp(buff, "off", strlen("off")))
policy = 0;
else if (!memcmp(buff, "lps", strlen("lps")))
policy = 1;
else if (!memcmp(buff, "on", strlen("on")))
policy = 2;
else
policy = 3;
}
data = 0x01 | (policy << 5);
return data;
}
unsigned char option_offset[] = {0,1,2,3,4,6,11,20,37,164};
unsigned char option_size[] = {1,1,1,1,2,5,9,17,127};
void
pal_set_boot_option(unsigned char para,unsigned char* pbuff)
{
return;
}
int
pal_get_boot_option(unsigned char para,unsigned char* pbuff)
{
unsigned char size = option_size[para];
memset(pbuff, 0, size);
return size;
}
int
pal_parse_sel(uint8_t fru, uint8_t *sel, char *error_log)
{
uint8_t snr_num = sel[11];
uint8_t *event_data = &sel[10];
uint8_t *ed = &event_data[3];
char temp_log[512] = {0};
if( ( MEMORY_ECC_ERR == snr_num ) || ( MEMORY_ERR_LOG_DIS == snr_num ) )
{
strcpy(error_log, "");
if ( MEMORY_ECC_ERR == snr_num )
{
switch( ed[0] & 0x0F )
{
case 0x00:
{
strcat(error_log, "Correctable");
sprintf(temp_log, "DIMM%02X ECC err", ed[2]);
pal_add_cri_sel(temp_log);
}
break;
case 0x01:
{
strcat(error_log, "Uncorrectable");
sprintf(temp_log, "DIMM%02X UECC err", ed[2]);
pal_add_cri_sel( temp_log );
}
break;
case 0x02:
strcat(error_log,"Parity");
break;
case 0x05:
strcat(error_log, "Correctable ECC error Logging Limit Reached");
break;
default:
strcat(error_log, "Unknown");
break;
}
}
else if ( MEMORY_ERR_LOG_DIS == snr_num )
{
if ( 0x00 == ( ed[0] & 0x0F ) ) {
strcat(error_log, "Correctable Memory Error Logging Disabled");
} else {
strcat(error_log, "Unknown");
}
}
// Common routine for both MEM_ECC_ERR and MEMORY_ERR_LOG_DIS
sprintf(temp_log, " (DIMM %02X)", ed[2]);
strcat(error_log, temp_log);
sprintf(temp_log, " Logical Rank %d", ed[1] & 0x03);
strcat(error_log, temp_log);
switch((ed[1] & 0x0C) >> 2 ) {
case 0x00:
//Ignore when " All info available"
break;
case 0x01:
strcat(error_log, " DIMM info not valid");
break;
case 0x02:
strcat(error_log, " CHN info not valid");
break;
case 0x03:
strcat(error_log, " CPU info not valid");
break;
default:
strcat(error_log, " Unknown");
break;
}
if ( ( ( event_data[2] & 0x80 ) >> 7 ) == 0) {
sprintf(temp_log, " Assertion");
strcat(error_log, temp_log);
} else {
sprintf(temp_log, " Deassertion");
strcat(error_log, temp_log);
}
return 0;
}
pal_parse_sel_helper(fru, sel, error_log);
return 0;
}
int
pal_parse_oem_sel(uint8_t fru, uint8_t *sel, char *error_log)
{
char str[128];
uint16_t bank, col;
uint8_t record_type = (uint8_t) sel[2];
uint32_t mfg_id;
error_log[0] = '\0';
/* Manufacturer ID (byte 9:7) */
mfg_id = (*(uint32_t*)&sel[7]) & 0xFFFFFF;
if (record_type == 0xc0 && mfg_id == 0x1c4c) {
snprintf(str, sizeof(str), "Slot %d PCIe err", sel[14]);
pal_add_cri_sel(str);
sprintf(error_log, "VID:0x%02x%2x DID:0x%02x%2x Slot:0x%x Error ID:0x%x",
sel[11], sel[10], sel[13], sel[12], sel[14], sel[15]);
}
else if (record_type == 0xc2 && mfg_id == 0x1c4c) {
sprintf(error_log, "Extra info:0x%x MSCOD:0x%02x%02x MCACOD:0x%02x%02x",
sel[11], sel[13], sel[12], sel[15], sel[14]);
}
else if (record_type == 0xc3 && mfg_id == 0x1c4c) {
bank= (sel[11] & 0xf0) >> 4;
col= ((sel[11] & 0x0f) << 8) | sel[12];
sprintf(error_log, "Fail Device:0x%x Bank:0x%x Column:0x%x Failed Row:0x%02x%02x%02x",
sel[10], bank, col, sel[13], sel[14], sel[15]);
}
else
return 0;
return 0;
}
void
pal_sensor_sts_check(uint8_t snr_num, float val, uint8_t *thresh) {
int ret;
int fru = 1;
float ucr_thresh_val,lcr_thresh_val;
ret = pal_get_sensor_threshold(fru, snr_num, UCR_THRESH, &ucr_thresh_val);
if (ret) {
syslog(LOG_WARNING, "get ucr fail:%f",lcr_thresh_val);
}
ret = pal_get_sensor_threshold(fru, snr_num, LCR_THRESH, &lcr_thresh_val);
if (ret) {
syslog(LOG_WARNING, "get lcr fail:%f",lcr_thresh_val);
}
if(val >= ucr_thresh_val)
*thresh = UCR_THRESH;
else if(val <= lcr_thresh_val)
*thresh = LCR_THRESH;
else
*thresh = 0;
}
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] = {0};
char str[MAX_VALUE_LEN] = {0};
char tstr[10] = {0};
int i;
int completion_code = CC_UNSPECIFIED_ERROR;
*res_len = 0;
sprintf(key, "mb_cpu_ppin");
if (req_len > SIZE_CPU_PPIN*2)
req_len = SIZE_CPU_PPIN*2;
for (i = 0; i < req_len; i++) {
sprintf(tstr, "%02x", req_data[i]);
strcat(str, tstr);
}
if (kv_set(key, str, 0, KV_FPERSIST) != 0)
return completion_code;
completion_code = CC_SUCCESS;
return completion_code;
}
int
pal_get_syscfg_text (char *text) {
char key[MAX_KEY_LEN], value[MAX_VALUE_LEN], entry[MAX_VALUE_LEN];
char *key_prefix = "sys_config/";
int num_cpu=2, num_dimm, num_drive=14;
int index, surface, bubble;
size_t ret;
unsigned char board_id, revision_id;
char **dimm_labels;
struct dimm_map map[24], temp_map;
if (text == NULL)
return -1;
// Clear string buffer
text[0] = '\0';
// CPU information
for (index = 0; index < num_cpu; index++) {
if (!is_cpu_socket_occupy((unsigned int)index))
continue;
sprintf(entry, "CPU%d:", index);
// Processor#
snprintf(key, MAX_KEY_LEN, "%sfru1_cpu%d_product_name",
key_prefix, index);
if (kv_get(key, value, &ret, KV_FPERSIST) == 0 && ret >= 26) {
// Read 4 bytes Processor#
if (snprintf(&entry[strlen(entry)], 5, "%s", &value[22]) > 5) {
syslog(LOG_ERR, "%s: CPU processor ID truncation detected!\n", __func__);
}
}
// Frequency & Core Number
snprintf(key, MAX_KEY_LEN, "%sfru1_cpu%d_basic_info",
key_prefix, index);
if(kv_get(key, value, &ret, KV_FPERSIST) == 0 && ret >= 5) {
sprintf(&entry[strlen(entry)], "/%.1fG/%dc",
(float) (value[4] << 8 | value[3])/1000, value[0]);
}
sprintf(&entry[strlen(entry)], "\n");
strcat(text, entry);
}
// prepare DIMM map
pal_get_platform_id(&board_id);
pal_get_board_rev_id(&revision_id);
if (board_id & PLAT_ID_SKU_MASK) {
// Double Side
num_dimm = 24;
if (revision_id < BOARD_REV_PVT)
dimm_labels = dimm_label_DS_DVT;
else
dimm_labels = dimm_label_DS_PVT;
} else {
// Single Side
num_dimm = 12;
if (revision_id < BOARD_REV_PVT)
dimm_labels = dimm_label_SS_DVT;
else
dimm_labels = dimm_label_SS_PVT;
}
// Initialize map
for (index = 0; index < num_dimm; index++) {
map[index].index = index;
map[index].label = dimm_labels[index];
}
// Bubble Sort the map according label string
surface = num_dimm;
for (surface = num_dimm; surface > 1;) {
bubble = 0;
for(index = 0; index < surface - 1; index++) {
if (strcmp(map[index].label, map[index+1].label) > 0) {
// Swap
temp_map = map[index+1];
map[index+1] = map[index];
map[index] = temp_map;
bubble = index + 1;
}
}
surface = bubble;
}
// DIMM information
for (index = 0; index < num_dimm; index++) {
sprintf(entry, "MEM%s:", map[index].label);
// Check Present
snprintf(key, MAX_KEY_LEN, "%sfru1_dimm%d_location",
key_prefix, map[index].index);
if(kv_get(key, value, &ret, KV_FPERSIST) == 0 && ret >= 1) {
// Skip if not present
if (value[0] != 0x01)
continue;
}
// Module Manufacturer ID
snprintf(key, MAX_KEY_LEN, "%sfru1_dimm%d_manufacturer_id",
key_prefix, map[index].index);
if(kv_get(key, value, &ret, KV_FPERSIST) == 0 && ret >= 2) {
switch (value[1]) {
case 0xce:
sprintf(&entry[strlen(entry)], "Samsung");
break;
case 0xad:
sprintf(&entry[strlen(entry)], "Hynix");
break;
case 0x2c:
sprintf(&entry[strlen(entry)], "Micron");
break;
default:
sprintf(&entry[strlen(entry)], "unknown");
break;
}
}
// Speed
snprintf(key, MAX_KEY_LEN, "%sfru1_dimm%d_speed",
key_prefix, map[index].index);
if(kv_get(key, value, &ret, KV_FPERSIST) == 0 && ret >= 6) {
sprintf(&entry[strlen(entry)], "/%dMhz/%dGB",
value[1]<<8 | value[0],
(value[5]<<24 | value[4]<<16 | value[3]<<8 | value[2])/1024 );
}
sprintf(&entry[strlen(entry)], "\n");
strcat(text, entry);
}
// Drive information
for (index = 0; index < num_drive; index++) {
sprintf(entry, "HDD%d:", index);
// Check Present
snprintf(key, MAX_KEY_LEN, "%sfru1_B_drive%d_location",
key_prefix, index);
if(kv_get(key, value, &ret, KV_FPERSIST) == 0 && ret >= 3) {
// Skip if not present
if (value[2] == 0xff)
continue;
}
// Model name
snprintf(key, MAX_KEY_LEN, "%sfru1_B_drive%d_model_name",
key_prefix, index);
if(kv_get(key, value, &ret, KV_FPERSIST) == 0 && ret >= 1) {
snprintf(&entry[strlen(entry)], ret+1, "%s", value);
}
sprintf(&entry[strlen(entry)], "\n");
strcat(text, entry);
}
return 0;
}
int
pal_set_adr_trigger(uint8_t slot, bool trigger) {
if (slot != FRU_MB) {
return -1;
}
if (trigger) {
FORCE_ADR();
}
return 0;
}
int
pal_get_nm_selftest_result(uint8_t fruid, uint8_t *data)
{
uint8_t bus_id = 0x4;
int rlen = 0;
int ret = PAL_EOK;
rlen = ipmb_send(
bus_id,
0x2c,
NETFN_APP_REQ << 2,
CMD_APP_GET_SELFTEST_RESULTS);
if ( rlen < 2 )
{
ret = PAL_ENOTSUP;
}
else
{
//get the response data
memcpy(data, ipmb_rxb()->data, 2);
}
return ret;
}
int pal_add_i2c_device(uint8_t bus, char *device_name, uint8_t slave_addr)
{
char cmd[64] = {0};
int ret = 0;
const char *template_path="echo %s 0x%x > /sys/bus/i2c/devices/i2c-%d/new_device";
sprintf(cmd, template_path, device_name, slave_addr, bus);
#if DEBUG
syslog(LOG_WARNING, "[%s] Cmd: %s", __func__, cmd);
#endif
ret = system(cmd);
if (ret != 0) {
syslog(LOG_ERR, "Adding I2C device %d:%d:%s failed\n", bus, slave_addr, device_name);
}
return ret;
}
int pal_del_i2c_device(uint8_t bus, uint8_t slave_addr)
{
char cmd[64] = {0};
int ret = 0;
const char *template_path="echo 0x%x > /sys/bus/i2c/devices/i2c-%d/delete_device";
sprintf(cmd, template_path, slave_addr, bus);
#if DEBUG
syslog(LOG_WARNING, "[%s] Cmd: %s", __func__, cmd);
#endif
ret = system(cmd);
if (ret != 0) {
syslog(LOG_ERR, "Deleting I2C device %d:%d failed\n", bus, slave_addr);
}
return ret;
}
bool
pal_is_ava_card(uint8_t riser_slot)
{
int fd = 0;
char fn[32];
bool ret;
uint8_t ava_fruid_addr = 0xa0;
uint8_t tbuf[16] = {0};
uint8_t rbuf[16] = {0};
uint8_t tcount, rcount;
int val;
// control I2C multiplexer to target channel.
val = mux_lock(&riser_mux, riser_slot, 2);
if ( val < 0 ) {
syslog(LOG_WARNING, "[%s]Cannot switch the riser card channel", __func__);
ret = false;
goto error_exit;
}
snprintf(fn, sizeof(fn), "/dev/i2c-%d", RISER_BUS_ID);
fd = open(fn, O_RDWR);
if ( fd < 0 ) {
ret = false;
goto release_mux_and_exit;
}
//Send I2C to AVA for FRU present check
rcount = 1;
tcount = 0;
val = i2c_rdwr_msg_transfer(fd, ava_fruid_addr, tbuf, tcount, rbuf, rcount);
if( val < 0 ) {
ret = false;
goto release_mux_and_exit;
}
ret = true;
release_mux_and_exit:
mux_release(&riser_mux);
error_exit:
if (fd > 0)
{
close(fd);
}
return ret;
}
bool pal_is_retimer_card ( uint8_t riser_slot )
{
int fd = 0;
char fn[32];
bool ret;
uint8_t re_timer_present_chk_addr = 0x82;
uint8_t tbuf = 0x0;
uint8_t rbuf = 0x0;
uint8_t tcount, rcount;
int val;
// control I2C multiplexer to target channel.
val = mux_lock(&riser_mux, riser_slot, 2);
if ( val < 0 )
{
syslog(LOG_WARNING, "[%s]Cannot switch the riser card channel", __func__);
ret = false;
goto error_exit;
}
snprintf(fn, sizeof(fn), "/dev/i2c-%d", RISER_BUS_ID);
fd = open(fn, O_RDWR);
if ( fd < 0 )
{
ret = false;
goto release_mux_and_exit;
}
//Send I2C to re-timer
tcount = 1;
rcount = 1;
val = i2c_rdwr_msg_transfer(fd, re_timer_present_chk_addr, &tbuf, tcount, &rbuf, rcount);
if( val < 0 )
{
ret = false;
goto release_mux_and_exit;
}
ret = true;
release_mux_and_exit:
mux_release(&riser_mux);
error_exit:
if (fd > 0)
{
close(fd);
}
return ret;
}
bool pal_is_pcie_ssd_card( uint8_t riser_slot )
{
bool ret = false;
int fd = 0;
char fn[32];
uint8_t pcie_ssd_addr = 0xd4;
uint8_t tbuf[16] = {0};
uint8_t rbuf[16] = {0};
uint8_t tcount, rcount;
int val;
if( !(pal_is_retimer_card(riser_slot) || pal_is_ava_card(riser_slot) ) )
{
// control I2C multiplexer to target channel.
val = mux_lock(&riser_mux, riser_slot, 2);
if ( val < 0 ) {
syslog(LOG_WARNING, "[%s]Cannot switch the riser card channel", __func__);
ret = false;
goto error_exit;
}
snprintf(fn, sizeof(fn), "/dev/i2c-%d", RISER_BUS_ID);
fd = open(fn, O_RDWR);
if ( fd < 0 ) {
ret = false;
goto release_mux_and_exit;
}
//Read to check card present
tbuf[0] = 0x00;
tcount = 1;
rcount = 8;
val = i2c_rdwr_msg_transfer(fd, pcie_ssd_addr, tbuf, tcount, rbuf, rcount);
if( val < 0 ) {
ret = false;
goto release_mux_and_exit;
}
ret = true;
release_mux_and_exit:
mux_release(&riser_mux);
error_exit:
if (fd > 0)
{
close(fd);
}
}
return ret;
}
int pal_riser_mux_switch (uint8_t riser_slot)
{
return mux_lock(&riser_mux, riser_slot, 2);
}
int pal_riser_mux_release(void)
{
return mux_release( &riser_mux);
}
int
pal_is_fru_on_riser_card(uint8_t riser_slot, uint8_t *device_type)
{
int ret = PAL_ENOTSUP;
if ( true == pal_is_ava_card(riser_slot) )
{
*device_type = FOUND_AVA_DEVICE;
ret = PAL_EOK;
}
else if ( true == pal_is_retimer_card(riser_slot) )
{
*device_type = FOUND_RETIMER_DEVICE;
ret = PAL_EOK;
}
else
{
//riser_slot start from 2
syslog(LOG_WARNING, "Unknown or no device on the riser slot %d", riser_slot+2);
}
return ret;
}
bool
pal_is_BBV_prsnt()
{
int fd = 0;
char fn[32];
bool ret;
uint8_t BBV_present_chk_addr = 0x92;
uint8_t re_timer_present_chk_addr = 0x82;
uint8_t tbuf[16] = {0};
uint8_t rbuf[16] = {0};
uint8_t tcount=0, rcount;
int val;
snprintf(fn, sizeof(fn), "/dev/i2c-%d", RISER_BUS_ID);
fd = open(fn, O_RDWR);
if ( fd < 0 ) {
ret = false;
goto error_exit;
}
//Send I2C to Bridge card on BBV
rcount = 1;
val = i2c_rdwr_msg_transfer(fd, BBV_present_chk_addr, tbuf, tcount, rbuf, rcount);
if( val < 0 ) {
ret = false;
goto error_exit;
}
//Send I2C to re-timer
rcount = 1;
val = i2c_rdwr_msg_transfer(fd, re_timer_present_chk_addr, tbuf, tcount, rbuf, rcount);
if( val < 0 ) {
ret = false;
goto error_exit;
}
ret = true;
error_exit:
if (fd > 0)
{
close(fd);
}
return ret;
}
int
pal_CPU_error_num_chk(bool is_caterr)
{
int len;
int cpu_num = -1;
ipmb_req_t *req;
ipmb_res_t *res;
// Get biosscratchpad7[26]: DWR
req = ipmb_txb();
res = ipmb_rxb();
req->res_slave_addr = 0x2C; //ME's Slave Address
req->netfn_lun = NETFN_NM_REQ<<2;
req->cmd = CMD_NM_SEND_RAW_PECI;
req->data[0] = 0x57;
req->data[1] = 0x01;
req->data[2] = 0x00;
req->data[3] = 0x30;
req->data[4] = 0x05;
req->data[5] = 0x05;
req->data[6] = 0xa1;
req->data[7] = 0x00;
req->data[8] = 0x00;
req->data[9] = 0x05;
req->data[10] = 0x00;
// Invoke IPMB library handler
len = ipmb_send_buf(0x4, 11+MIN_IPMB_REQ_LEN);
// Data len >= 4 and IPMB Success
if ( ( len >= (4+MIN_IPMB_RES_LEN) ) && ( res->cc == 0 ) && ( res->data[3] == 0x40 ) ) {
if( is_caterr ) {
if(((res->data[7] & 0xE0) > 0) && ((res->data[7] & 0x1C) > 0))
cpu_num = 2; //Both
else if((res->data[7] & 0xE0) > 0)
cpu_num = 1; //CPU1
else if((res->data[7] & 0x1C) > 0)
cpu_num = 0; // CPU0
} else {
if(((res->data[6] & 0xE0) > 0) && ((res->data[6] & 0x1C) > 0))
cpu_num = 2; //Both
else if((res->data[6] & 0xE0) > 0)
cpu_num = 1; //CPU1
else if((res->data[6] & 0x1C) > 0)
cpu_num = 0; // CPU0
}
}
return cpu_num;
}
int
pal_mmap (uint32_t base, uint8_t offset, int option, uint32_t para)
{
uint32_t mmap_fd;
uint32_t ctrl;
void *reg_base;
void *reg_offset;
mmap_fd = open("/dev/mem", O_RDWR | O_SYNC );
if (mmap_fd < 0) {
return -1;
}
reg_base = mmap(NULL, PAGE_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, mmap_fd, base);
reg_offset = (char*) reg_base + offset;
ctrl = *(volatile uint32_t*) reg_offset;
switch(option) {
case UARTSW_BY_BMC: //UART Switch control by bmc
ctrl &= 0x00ffffff;
break;
case UARTSW_BY_DEBUG: //UART Switch control by debug card
ctrl |= 0x01000000;
break;
case SET_SEVEN_SEGMENT: //set channel on the seven segment display
ctrl &= 0x00ffffff;
ctrl |= para;
break;
default:
syslog(LOG_WARNING, "pal_mmap: unknown option");
break;
}
*(volatile uint32_t*) reg_offset = ctrl;
munmap(reg_base, PAGE_SIZE);
close(mmap_fd);
return 0;
}
int
pal_uart_switch_for_led_ctrl (void)
{
static uint32_t pre_channel = 0xffffffff;
unsigned int vals;
uint32_t channel = 0;
const char *shadows[] = {
"FM_UARTSW_LSB_N",
"FM_UARTSW_MSB_N"
};
//UART Switch control by bmc
pal_mmap (AST_GPIO_BASE, UARTSW_OFFSET, UARTSW_BY_BMC, 0);
if (gpio_get_value_by_shadow_list(shadows, ARRAY_SIZE(shadows), &vals)) {
return -1;
}
// The GPIOs are active-low. So, invert it.
channel = (uint32_t)(~vals & 0x3);
// Shift to get to the bit position of the led.
channel = channel << 24;
// If the requested channel is the same as the previous, do nothing.
if (channel == pre_channel) {
return -1;
}
pre_channel = channel;
//show channel on 7-segment display
pal_mmap (AST_GPIO_BASE, SEVEN_SEGMENT_OFFSET, SET_SEVEN_SEGMENT, channel);
return 0;
}
void
pal_set_def_restart_cause(uint8_t slot)
{
char pwr_policy[MAX_VALUE_LEN] = {0};
char last_pwr_st[MAX_VALUE_LEN] = {0};
if ( FRU_MB == slot )
{
kv_get("pwr_server_last_state", last_pwr_st, NULL, KV_FPERSIST);
kv_get("server_por_cfg", pwr_policy, NULL, KV_FPERSIST);
if( pal_is_bmc_por() )
{
if( !strcmp( pwr_policy, "on") )
{
pal_set_restart_cause(FRU_MB, RESTART_CAUSE_AUTOMATIC_PWR_UP);
}
else if( !strcmp( pwr_policy, "lps") && !strcmp( last_pwr_st, "on") )
{
pal_set_restart_cause(FRU_MB, RESTART_CAUSE_AUTOMATIC_PWR_UP_LPR);
}
}
}
}
struct fsc_monitor
{
uint8_t sensor_num;
char *sensor_name;
bool (*check_sensor_sts)(uint8_t);
bool is_alive;
uint8_t init_count;
uint8_t retry;
};
static struct fsc_monitor fsc_monitor_riser_list[] =
{
{MB_SENSOR_C2_NVME_CTEMP , "mb_c2_nvme_ctemp" , pal_is_pcie_ssd_card , false, 5, 5},
{MB_SENSOR_C2_1_NVME_CTEMP, "mb_c2_0_nvme_ctemp", pal_is_ava_card , false, 5, 5},
{MB_SENSOR_C2_2_NVME_CTEMP, "mb_c2_1_nvme_ctemp", pal_is_ava_card , false, 5, 5},
{MB_SENSOR_C2_3_NVME_CTEMP, "mb_c2_2_nvme_ctemp", pal_is_ava_card , false, 5, 5},
{MB_SENSOR_C2_4_NVME_CTEMP, "mb_c2_3_nvme_ctemp", pal_is_ava_card , false, 5, 5},
{MB_SENSOR_C3_NVME_CTEMP , "mb_c3_nvme_ctemp" , pal_is_pcie_ssd_card , false, 5, 5},
{MB_SENSOR_C3_1_NVME_CTEMP, "mb_c3_0_nvme_ctemp", pal_is_ava_card , false, 5, 5},
{MB_SENSOR_C3_2_NVME_CTEMP, "mb_c3_1_nvme_ctemp", pal_is_ava_card , false, 5, 5},
{MB_SENSOR_C3_3_NVME_CTEMP, "mb_c3_2_nvme_ctemp", pal_is_ava_card , false, 5, 5},
{MB_SENSOR_C3_4_NVME_CTEMP, "mb_c3_3_nvme_ctemp", pal_is_ava_card , false, 5, 5},
{MB_SENSOR_C4_NVME_CTEMP , "mb_c4_nvme_ctemp" , pal_is_pcie_ssd_card , false, 5, 5},
{MB_SENSOR_C4_1_NVME_CTEMP, "mb_c4_0_nvme_ctemp", pal_is_ava_card , false, 5, 5},
{MB_SENSOR_C4_2_NVME_CTEMP, "mb_c4_1_nvme_ctemp", pal_is_ava_card , false, 5, 5},
{MB_SENSOR_C4_3_NVME_CTEMP, "mb_c4_2_nvme_ctemp", pal_is_ava_card , false, 5, 5},
{MB_SENSOR_C4_4_NVME_CTEMP, "mb_c4_3_nvme_ctemp", pal_is_ava_card , false, 5, 5},
};
static int fsc_monitor_riser_list_size = sizeof(fsc_monitor_riser_list) / sizeof(struct fsc_monitor);
static struct fsc_monitor fsc_monitor_basic_snr_list[] =
{
{MB_SENSOR_INLET_REMOTE_TEMP , "mb_inlet_remote_temp" , NULL, false, 5, 5},
{MB_SENSOR_CPU0_PKG_POWER , "mb_cpu0_pkg_power" , NULL, false, 5, 5},
{MB_SENSOR_CPU1_PKG_POWER , "mb_cpu1_pkg_power" , NULL, false, 5, 5},
{MB_SENSOR_CPU0_THERM_MARGIN , "mb_cpu0_therm_margin" , NULL, false, 5, 5},
{MB_SENSOR_CPU1_THERM_MARGIN , "mb_cpu1_therm_margin" , NULL, false, 5, 5},
//dimm sensors wait for 240s. 240=80*3(fsc monitor interval)
{MB_SENSOR_CPU0_DIMM_GRPA_TEMP, "mb_cpu0_dimm_grpa_temp", pal_is_dimm_present, false, 80, 5},
{MB_SENSOR_CPU0_DIMM_GRPB_TEMP, "mb_cpu0_dimm_grpb_temp", pal_is_dimm_present, false, 80, 5},
{MB_SENSOR_CPU1_DIMM_GRPC_TEMP, "mb_cpu1_dimm_grpc_temp", pal_is_dimm_present, false, 80, 5},
{MB_SENSOR_CPU1_DIMM_GRPD_TEMP, "mb_cpu1_dimm_grpd_temp", pal_is_dimm_present, false, 80, 5},
};
static int fsc_monitor_basic_snr_list_size = sizeof(fsc_monitor_basic_snr_list) / sizeof(struct fsc_monitor);
int pal_fsc_get_target_snr(char *sname, struct fsc_monitor *fsc_fru_list, int fsc_fru_list_size)
{
int i;
for ( i=0; i<fsc_fru_list_size; i++)
{
if ( 0 == strcmp(sname, fsc_fru_list[i].sensor_name) )
{
#ifdef FSC_DEBUG
syslog(LOG_WARNING,"[%s]sensor is found:%s, idx:%d", __func__, sname, i);
#endif
return i;
}
}
syslog(LOG_WARNING,"[%s]Unknown sensor name:%s", __func__, sname);
return PAL_ENOTSUP;
}
int
pal_init_fsc_snr_sts(uint8_t fru_id, struct fsc_monitor *curr_snr)
{
int ret = PAL_EOK;
int actual_fru_id;
float value;
bool is_snr_prsnt = false;
bool is_check_snr_num = false;
//if the sensor is exist, return.
if ( true == curr_snr->is_alive )
{
curr_snr->init_count = 0;
return ret;
}
if ( fru_id >= FRU_RISER_SLOT2 )
{
actual_fru_id = fru_id - FRU_RISER_SLOT2;
}
else
{
actual_fru_id = fru_id;
if ( (MB_SENSOR_CPU0_DIMM_GRPA_TEMP == curr_snr->sensor_num) || (MB_SENSOR_CPU0_DIMM_GRPB_TEMP == curr_snr->sensor_num) ||
(MB_SENSOR_CPU1_DIMM_GRPC_TEMP == curr_snr->sensor_num) || (MB_SENSOR_CPU1_DIMM_GRPD_TEMP == curr_snr->sensor_num) )
{
is_check_snr_num = true;
}
}
//some sensors need to be judged with preidentify function
if ( NULL != curr_snr->check_sensor_sts )
{
if ( true == is_check_snr_num )
{
//check sensor present based on the sensor name
is_snr_prsnt = curr_snr->check_sensor_sts(curr_snr->sensor_num);
}
else
{
//check sensor present based on its fru
is_snr_prsnt = curr_snr->check_sensor_sts(actual_fru_id);
}
#ifdef FSC_DEBUG
syslog(LOG_WARNING,"[%s]Check snr status. is_snr_prsnt:%d, fru_id:%d, actual_fru_id:%d", __func__, is_snr_prsnt, fru_id, actual_fru_id);
#endif
if ( (true == is_snr_prsnt) && (false == curr_snr->is_alive) )
{
//if the fru is exist, check the reading
//if the reading is N/A, we assume the sensor is not present
//if the reading is the numerical value, we assume the sensor is present
ret = sensor_cache_read(fru_id, curr_snr->sensor_num, &value);
#ifdef FSC_DEBUG
syslog(LOG_WARNING,"[%s]Check snr reading. fru_id:%d, snum:%x, ret=%d", __func__, fru_id, curr_snr->sensor_num, ret);
#endif
if ( PAL_EOK == ret )
{
#ifdef FSC_DEBUG
syslog(LOG_WARNING,"[%s] snr num %x is found. ret=%d", __func__, curr_snr->sensor_num, ret);
#endif
curr_snr->is_alive = true;
}
}
}
else
{
//no preidentify function. sensors should exist anyway
#ifdef FSC_DEBUG
syslog(LOG_WARNING,"[%s] snr num %x is found. ret=%d", __func__, curr_snr->sensor_num, ret);
#endif
ret = PAL_EOK;
curr_snr->is_alive = true;
}
curr_snr->init_count--;
return ret;
}
void
pal_reinit_fsc_monitor_list()
{
int i;
//dimm sensors need to be re-init when the system do reset
//we only re-init the basic snr list since the dimm sensors is included in it
for ( i=0; i<fsc_monitor_basic_snr_list_size; i++ )
{
fsc_monitor_basic_snr_list[i].is_alive = false;
fsc_monitor_basic_snr_list[i].retry = 5;
if ( (MB_SENSOR_CPU0_DIMM_GRPA_TEMP == fsc_monitor_basic_snr_list[i].sensor_num) ||
(MB_SENSOR_CPU0_DIMM_GRPB_TEMP == fsc_monitor_basic_snr_list[i].sensor_num) ||
(MB_SENSOR_CPU1_DIMM_GRPC_TEMP == fsc_monitor_basic_snr_list[i].sensor_num) ||
(MB_SENSOR_CPU1_DIMM_GRPD_TEMP == fsc_monitor_basic_snr_list[i].sensor_num) )
{
fsc_monitor_basic_snr_list[i].init_count = 80;
}
else
{
fsc_monitor_basic_snr_list[i].init_count = 5;
}
}
}
bool pal_sensor_is_valid(char *fru_name, char *sensor_name)
{
const uint8_t init_done = 0;
uint8_t fru_id;
struct fsc_monitor *fsc_fru_list;
int fsc_fru_list_size;
int index;
int ret;
static time_t rst_time = 0;
struct stat file_stat;
//check the fru name is valid or not
ret = pal_get_fru_id(fru_name, &fru_id);
if ( ret < 0 )
{
syslog(LOG_WARNING,"[%s] Wrong fru#%s", __func__, fru_name);
return false;
}
//if power reset is executed, re-init the list
if ( (stat("/tmp/rst_touch", &file_stat) == 0) && (file_stat.st_mtime > rst_time) )
{
rst_time = file_stat.st_mtime;
//in order to record rst_time, the function will be executed at first time
pal_reinit_fsc_monitor_list();
}
//check the fru is riser or not
if ( fru_id >= FRU_RISER_SLOT2 )
{
fsc_fru_list = fsc_monitor_riser_list;
fsc_fru_list_size = fsc_monitor_riser_list_size;
}
else
{
fsc_fru_list = fsc_monitor_basic_snr_list;
fsc_fru_list_size = fsc_monitor_basic_snr_list_size;
}
//get the target sensor
ret = pal_fsc_get_target_snr(sensor_name, fsc_fru_list, fsc_fru_list_size);
if ( ret < 0 )
{
syslog(LOG_WARNING,"[%s] undefined sensor: %s", __func__, sensor_name);
return false;
}
index = ret;
//init the snr list before checking snr fail
if ( init_done != fsc_fru_list[index].init_count )
{
//if we get a sensor reading, it will be checked below
//return false if the sensor is not ready
ret = pal_init_fsc_snr_sts(fru_id, &fsc_fru_list[index]);
if ( PAL_EOK != ret )
{
return false;
}
}
//after a sensor is init done, we check its is_alive flag
//If the flag is true, return true to make fsc check it
//if the flag is false, return false to make fsc skip to check it
if ( false == fsc_fru_list[index].is_alive )
{
return false;
}
//to avoid getting the different reading between here and fscd
//wait for two loop
if ( fsc_fru_list[index].retry > 3 )
{
fsc_fru_list[index].retry--;
return false;
}
return true;
}
bool
pal_sensor_is_source_host(uint8_t fru, uint8_t sensor_id)
{
if (fru == FRU_MB && sensor_id == MB_SENSOR_HOST_BOOT_TEMP) {
return true;
}
return false;
}