meta-facebook/meta-lightning/recipes-lightning/fblibs/files/pal/pal.c (1,369 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.
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <syslog.h>
#include <sys/mman.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <pthread.h>
#include <openbmc/obmc-i2c.h>
#include <openbmc/kv.h>
#include "pal.h"
#include "pal_sensors.h"
#include <string.h>
#define BIT(value, index) ((value >> index) & 1)
#define LIGHTNING_PLATFORM_NAME "Lightning"
#define LAST_KEY "last_key"
#define GPIO_VAL "/sys/class/gpio/gpio%d/value"
#define GPIO_DIR "/sys/class/gpio/gpio%d/direction"
#define GPIO_HAND_SW_ID1 138
#define GPIO_HAND_SW_ID2 139
#define GPIO_HAND_SW_ID4 140
#define GPIO_HAND_SW_ID8 141
#define GPIO_DEBUG_RST_BTN 54
#define GPIO_DEBUG_UART_COUNT 125
#define GPIO_BMC_UART_SWITCH 123
#define GPIO_RESET_PCIE_SWITCH 8
#define GPIO_HB_LED 115
#define GPIO_BMC_SELF_TRAY_INTRU 108 // 0: tray pull-in, 1: tray pull-out
#define GPIO_BMC_PEER_TRAY_INTRU 0 // 0: tray pull-in, 1: tray pull-out
#define GPIO_TRAY_LOCATION_ID 55 // 0: lower tray, 1: upper tray
#define GPIO_DEBUG_CARD_HIGH_HEX_0 48
#define GPIO_DEBUG_CARD_HIGH_HEX_1 49
#define GPIO_DEBUG_CARD_HIGH_HEX_2 50
#define GPIO_DEBUG_CARD_HIGH_HEX_3 51
#define GPIO_DEBUG_CARD_LOW_HEX_0 72
#define GPIO_DEBUG_CARD_LOW_HEX_1 73
#define GPIO_DEBUG_CARD_LOW_HEX_2 74
#define GPIO_DEBUG_CARD_LOW_HEX_3 75
#define I2C_DEV_FAN "/dev/i2c-5"
#define I2C_ADDR_FAN 0x2d
#define FAN_REGISTER_H 0x80
#define FAN_REGISTER_L 0x81
#define I2C_ADDR_FAN_LED 0x60
#define LARGEST_DEVICE_NAME 120
#define PWM_DIR "/sys/devices/platform/ast_pwm_tacho.0"
#define PWM_UNIT_MAX 96
#define I2C_MUX_FLASH1 0
#define I2C_MUX_FLASH2 1
#define I2C_DEV_FLASH1 "/dev/i2c-7"
#define I2C_DEV_FLASH2 "/dev/i2c-8"
#define MAX_SERIAL_NUM 20
/* NVMe-MI SSD Status Flag bit mask */
#define NVME_SFLGS_MASK_BIT 0x28 //Just check bit 3,5
#define NVME_SFLGS_CHECK_VALUE 0x28 // normal - bit 3,5 = 1
/* NVMe-MI SSD SMART Critical Warning */
#define NVME_SMART_WARNING_MASK_BIT 0x1F // Check bit 0~4
const char pal_fru_list[] = "all, peb, pdpb, fcb";
const char pal_fru_list_wo_all[] = "peb, pdpb, fcb";
size_t pal_pwm_cnt = 1;
size_t pal_tach_cnt = 12;
const char pal_pwm_list[] = "0";
const char pal_tach_list[] = "0...11";
/* A mapping tabel for fan id to pwm id. */
uint8_t fanid2pwmid_mapping[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
/* sensornum-errorcode mapping table */
const uint8_t sennum2errcode_mapping[MAX_SENSOR_NUM + 1] = {
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x00 - 0x0F
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x10 - 0x1F
0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0xFF, 0xFF, 0xFF, 0xFF, // 0x20 - 0x2F
0xFF, 0xFF, 0xFF, 0xFF, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x30, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x30 - 0x3F
0xFF, 0xFF, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2D, 0x2E, 0x2E, 0xFF, 0x2E, 0x20, // 0x40 - 0x4F
0x1F, 0x22, 0x21, 0x28, 0x27, 0xFF, 0x25, 0x26, 0x24, 0x23, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x50 - 0x5F
0xFF, 0xFF, 0xFF, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, // 0x60 - 0x6F
0x3F, 0x40, 0xFF, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, // 0x70 - 0x7F
0x3F, 0x40, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x80 - 0x8F
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x90 - 0x9F
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xA0 - 0xAF
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xB0 - 0xBF
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xC0 - 0xCF
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xD0 - 0xDF
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xE0 - 0xEF
0x2C, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF // 0xF0 - 0xFF
};
char * key_list[] = {
"peb_sensor_health",
"pdpb_sensor_health",
"fcb_sensor_health",
"bmc_health",
"system_identify",
/* Add more Keys here */
LAST_KEY /* This is the last key of the list */
};
char * def_val_list[] = {
"1", /* peb_sensor_health */
"1", /* pdbb_sensor_health */
"1", /* fcb_sensor_health */
"1", /* bmc_health */
"off", /* system_identify */
/* Add more def values for the correspoding keys*/
LAST_KEY /* Same as last entry of the key_list */
};
// Helper Functions
static int
read_device(const char *device, int *value) {
FILE *fp;
int rc;
fp = fopen(device, "r");
if (!fp) {
int err = errno;
#ifdef DEBUG
syslog(LOG_INFO, "failed to open device %s", device);
#endif
return err;
}
rc = fscanf(fp, "%d", value);
fclose(fp);
if (rc != 1) {
#ifdef DEBUG
syslog(LOG_INFO, "failed to read device %s", device);
#endif
return ENOENT;
} else {
return 0;
}
}
static int
write_device(const char *device, const char *value) {
FILE *fp;
int rc;
fp = fopen(device, "w");
if (!fp) {
int err = errno;
#ifdef DEBUG
syslog(LOG_INFO, "failed to open device for write %s", device);
#endif
return err;
}
rc = fputs(value, fp);
fclose(fp);
if (rc < 0) {
#ifdef DEBUG
syslog(LOG_INFO, "failed to write device %s", device);
#endif
return ENOENT;
} else {
return 0;
}
}
static int
read_device_hex(const char *device, int *value) {
FILE *fp;
int rc;
fp = fopen(device, "r");
if (!fp) {
#ifdef DEBUG
syslog(LOG_INFO, "failed to open device %s", device);
#endif
return errno;
}
rc = fscanf(fp, "%x", value);
fclose(fp);
if (rc != 1) {
#ifdef DEBUG
syslog(LOG_INFO, "failed to read device %s", device);
#endif
return ENOENT;
} else {
return 0;
}
}
// Platform Abstraction Layer (PAL) Functions
int
pal_get_platform_name(char *name) {
strcpy(name, LIGHTNING_PLATFORM_NAME);
return 0;
}
int
pal_get_num_slots(uint8_t *num) {
*num = MAX_NUM_SLOTS;
return 0;
}
int
pal_is_fru_prsnt(uint8_t fru, uint8_t *status) {
switch(fru) {
case FRU_PEB:
case FRU_PDPB:
case FRU_FCB:
*status = 1;
break;
default:
return -1;
}
return 0;
}
// Return the DEBUGCARD's UART Channel Button Status
int
pal_get_uart_chan_btn(uint8_t *status) {
char path[64] = {0};
int val;
sprintf(path, GPIO_VAL, GPIO_DEBUG_UART_COUNT);
if (read_device(path, &val))
return -1;
*status = (uint8_t) val;
return 0;
}
// Return the current uart position
int
pal_get_uart_chan(uint8_t *status) {
char path[64] = {0};
int val;
sprintf(path, GPIO_VAL, GPIO_BMC_UART_SWITCH);
if (read_device(path, &val))
return -1;
*status = (uint8_t) val;
return 0;
}
// Set the UART Channel
int
pal_set_uart_chan(uint8_t status) {
char path[64] = {0};
char *val;
val = (status == 0) ? "0": "1";
sprintf(path, GPIO_VAL, GPIO_BMC_UART_SWITCH);
if (write_device(path, val))
return -1;
return 0;
}
// Return the DEBUGCARD's Reset Button status
int
pal_get_rst_btn(uint8_t *status) {
char path[64] = {0};
int val;
sprintf(path, GPIO_VAL, GPIO_DEBUG_RST_BTN);
if (read_device(path, &val))
return -1;
*status = (uint8_t) val;
return 0;
}
// Update the LED for the given slot with the status
int
pal_set_led(uint8_t led, uint8_t status) {
char path[64] = {0};
char *val;
if (status) {
val = "1";
} else {
val = "0";
}
sprintf(path, GPIO_VAL, led);
if (write_device(path, val)) {
return -1;
}
return 0;
}
// Update Heartbeat LED
int
pal_set_hb_led(uint8_t status) {
return pal_set_led(LED_HB, status);
}
int
pal_get_fru_id(char *str, uint8_t *fru) {
return lightning_common_fru_id(str, fru);
}
int
pal_get_fru_name(uint8_t fru, char *name) {
return lightning_common_fru_name(fru, name);
}
int
pal_get_fru_sensor_list(uint8_t fru, uint8_t **sensor_list, int *cnt) {
uint8_t sw = 0;
uint8_t sku = 0;
switch(fru) {
case FRU_PEB:
while (lightning_pcie_switch(fru, &sw) < 0);
if (sw == PCIE_SW_PMC) {
*sensor_list = (uint8_t *) peb_sensor_pmc_list;
*cnt = peb_sensor_pmc_cnt;
} else if (sw == PCIE_SW_PLX) {
*sensor_list = (uint8_t *) peb_sensor_plx_list;
*cnt = peb_sensor_plx_cnt;
} else
return -1;
break;
case FRU_PDPB:
while (lightning_ssd_sku(&sku) < 0);
if (sku == U2_SKU) {
*sensor_list = (uint8_t *) pdpb_u2_sensor_list;
*cnt = pdpb_u2_sensor_cnt;
} else if (sku == M2_SKU) {
*sensor_list = (uint8_t *) pdpb_m2_sensor_list;
*cnt = pdpb_m2_sensor_cnt;
} else
return -1;
break;
case FRU_FCB:
*sensor_list = (uint8_t *) fcb_sensor_list;
*cnt = fcb_sensor_cnt;
break;
default:
#ifdef DEBUG
syslog(LOG_WARNING, "pal_get_fru_sensor_list: Wrong fru id %u", fru);
#endif
return -1;
}
return 0;
}
int
pal_sensor_sdr_init(uint8_t fru, sensor_info_t *sinfo) {
return lightning_sensor_sdr_init(fru, sinfo);
}
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};
int ret, retry = 0;
FILE *fp = NULL;
int tmp = 0;
bool isNegative = false;
int round_value_tmp = 0;
switch(fru) {
case FRU_PEB:
sprintf(key, "peb_sensor%d", sensor_num);
break;
case FRU_PDPB:
sprintf(key, "pdpb_sensor%d", sensor_num);
break;
case FRU_FCB:
sprintf(key, "fcb_sensor%d", sensor_num);
break;
}
//if enclosure-util read SSD, skip SSD monitor
if ((access(SKIP_READ_SSD_TEMP, F_OK) == 0) &&
(((sensor_num >= PDPB_SENSOR_FLASH_TEMP_0) && (sensor_num <= PDPB_SENSOR_FLASH_TEMP_14)) ||
((sensor_num >= PDPB_SENSOR_AMB_TEMP_0) && (sensor_num <= PDPB_SENSOR_AMB_TEMP_14)))) {
fp = fopen(SKIP_READ_SSD_TEMP, "r+");
if (!fp) {
return -1;
}
/* To avoid the flag file is not removed by enclosure-util */
fscanf(fp, "%d ", &tmp);
if (tmp < 1) {
fclose(fp);
remove(SKIP_READ_SSD_TEMP);
return -1;
}
else {
rewind(fp);
fprintf(fp, "%d ", tmp-1);
}
fclose(fp);
return -1;
}
// Add retry to avoid N/A which caused by sesnor reading collision
while (retry < MAX_RETRY) {
ret = lightning_sensor_read(fru, sensor_num, value);
if (!ret)
break;
retry++;
}
if(ret < 0) {
syslog(LOG_WARNING, "%s(): lightning_sensor_read() failed", __func__);
strcpy(str, "NA");
}
else if (ret == 1) { //case: skip monitoring due to enclosure-util running. but not return NA
return -1;
}
else {
// Round the current sensor value to the nearest hundredth before checking the threshold and cached key/val
if((*((float*)value)) < 0) {
isNegative = true;
*((float*)value) = -(*((float*)value));
}
round_value_tmp = ((*((float*)value)) * 100) + 0.5;
*((float*)value) = round_value_tmp / (100*1.0);
if(isNegative) {
*((float*)value) = -(*((float*)value));
}
// On successful sensor read
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;
}
}
int
pal_get_sensor_threshold(uint8_t fru, uint8_t sensor_num, uint8_t thresh, void *value) {
return lightning_sensor_threshold(fru, sensor_num, thresh, value);
}
int
pal_get_sensor_name(uint8_t fru, uint8_t sensor_num, char *name) {
return lightning_sensor_name(fru, sensor_num, name);
}
int
pal_get_sensor_units(uint8_t fru, uint8_t sensor_num, char *units) {
return lightning_sensor_units(fru, sensor_num, units);
}
int
pal_get_sensor_poll_interval(uint8_t fru, uint8_t sensor_num, uint32_t *value) {
return lightning_sensor_poll_interval(fru, sensor_num, value);
}
int
pal_get_fruid_path(uint8_t fru, char *path) {
return lightning_get_fruid_path(fru, path);
}
int
pal_get_fruid_eeprom_path(uint8_t fru, char *path) {
return lightning_get_fruid_eeprom_path(fru, path);
}
int
pal_get_fruid_name(uint8_t fru, char *name) {
return lightning_get_fruid_name(fru, name);
}
static int
get_key_value(char* key, char *value) {
int ret;
if (!strcmp(key, "system_identify")) {
ret = kv_get(key, value, NULL, KV_FPERSIST);
} else {
ret = kv_get(key, value, NULL, 0);
}
return ret;
}
static int
set_key_value(char *key, char *value) {
int ret;
if (!strcmp(key, "system_identify")) {
ret = kv_set(key, value, 0, KV_FPERSIST);
} else {
ret = kv_set(key, value, 0, 0);
}
return ret;
}
int
pal_set_def_key_value() {
int i;
for (i = 0; strcmp(key_list[i], LAST_KEY) != 0; i++) {
unsigned int flag = KV_FCREATE;
if (!strcmp(key_list[i], "system_identify")) {
flag |= KV_FPERSIST;
}
if (kv_set(key_list[i], def_val_list[i], 0, flag) != 0) {
#ifdef DEBUG
syslog(LOG_WARNING, "pal_set_def_key_value: kv_set failed. %d", ret);
#endif
}
}
return 0;
}
static int
pal_key_check(char *key) {
int i;
i = 0;
while(strcmp(key_list[i], LAST_KEY)) {
// If Key is valid, return success
if (!strcmp(key, key_list[i]))
return 0;
i++;
}
#ifdef DEBUG
syslog(LOG_WARNING, "pal_key_check: invalid key - %s", key);
#endif
return -1;
}
int
pal_set_key_value(char *key, char *value) {
int i = 0;
int max_retry = 5;
int ret = 0;
// Check is key is defined and valid
if (pal_key_check(key))
return -1;
//Retry for max_retry Times
for (i = 0; i < max_retry; i++) {
ret = 0;
ret = set_key_value(key, value);
if (ret != 0) {
syslog(LOG_ERR, "%s, failed to write device (%s), ret: %d, retry: %d", __func__, key, ret, i);
}
else {
break;
}
msleep(100);
}
return ret;
}
int
pal_get_key_value(char *key, char *value) {
int i = 0;
int max_retry = 5;
int ret = 0;
// Check is key is defined and valid
if (pal_key_check(key))
return -1;
//Retry for max_retry Times
for (i = 0; i < max_retry; i++) {
ret = get_key_value(key, value);
if (ret != 0) {
syslog(LOG_ERR, "%s, failed to read device (%s), ret: %d, retry: %d", __func__, key, ret, i);
}
else {
break;
}
msleep(100);
}
return ret;
}
void
pal_dump_key_value(void) {
int i = 0;
int ret = 0;
char value[MAX_VALUE_LEN] = {0x0};
while (strcmp(key_list[i], LAST_KEY)) {
printf("%s:", key_list[i]);
if ((ret = get_key_value(key_list[i], value)) < 0) {
printf("\n");
} else {
printf("%s\n", value);
}
i++;
memset(value, 0, MAX_VALUE_LEN);
}
}
int
pal_set_sensor_health(uint8_t fru, uint8_t value) {
char key[MAX_KEY_LEN] = {0};
char cvalue[MAX_VALUE_LEN] = {0};
switch(fru) {
case FRU_PEB:
strcpy(key, "peb_sensor_health");
break;
case FRU_PDPB:
strcpy(key, "pdpb_sensor_health");
break;
case FRU_FCB:
strcpy(key, "fcb_sensor_health");
break;
case BMC_HEALTH:
strcpy(key, "bmc_health");
break;
default:
return -1;
}
sprintf(cvalue, (value > 0) ? "1": "0");
return kv_set(key, cvalue, 0, 0);
}
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;
switch(fru) {
case FRU_PEB:
strcpy(key, "peb_sensor_health");
break;
case FRU_PDPB:
strcpy(key, "pdpb_sensor_health");
break;
case FRU_FCB:
strcpy(key, "fcb_sensor_health");
break;
case BMC_HEALTH:
strcpy(key, "bmc_health");
break;
default:
return -1;
}
ret = kv_get(key, cvalue, NULL, 0);
if (ret) {
return ret;
}
*value = atoi(cvalue);
return 0;
}
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_PEB:
*caps = FRU_CAPABILITY_FRUID_ALL | FRU_CAPABILITY_SENSOR_ALL |
FRU_CAPABILITY_MANAGEMENT_CONTROLLER;
break;
case FRU_PDPB:
case FRU_FCB:
*caps = FRU_CAPABILITY_FRUID_ALL | FRU_CAPABILITY_SENSOR_ALL;
break;
default:
ret = -1;
break;
}
return ret;
}
int
pal_get_fan_name(uint8_t num, char *name) {
switch(num) {
case FAN_1_FRONT:
sprintf(name, "Fan 1 Front");
break;
case FAN_1_REAR:
sprintf(name, "Fan 1 Rear");
break;
case FAN_2_FRONT:
sprintf(name, "Fan 2 Front");
break;
case FAN_2_REAR:
sprintf(name, "Fan 2 Rear");
break;
case FAN_3_FRONT:
sprintf(name, "Fan 3 Front");
break;
case FAN_3_REAR:
sprintf(name, "Fan 3 Rear");
break;
case FAN_4_FRONT:
sprintf(name, "Fan 4 Front");
break;
case FAN_4_REAR:
sprintf(name, "Fan 4 Rear");
break;
case FAN_5_FRONT:
sprintf(name, "Fan 5 Front");
break;
case FAN_5_REAR:
sprintf(name, "Fan 5 Rear");
break;
case FAN_6_FRONT:
sprintf(name, "Fan 6 Front");
break;
case FAN_6_REAR:
sprintf(name, "Fan 6 Rear");
break;
default:
return -1;
}
return 0;
}
static int
write_fan_value(const int fan, const char *device, const int value) {
char full_name[LARGEST_DEVICE_NAME];
char device_name[LARGEST_DEVICE_NAME];
char output_value[LARGEST_DEVICE_NAME];
snprintf(device_name, LARGEST_DEVICE_NAME, device, fan);
snprintf(full_name, LARGEST_DEVICE_NAME, "%s/%s", PWM_DIR, device_name);
snprintf(output_value, LARGEST_DEVICE_NAME, "%d", value);
return write_device(full_name, output_value);
}
int
pal_set_fan_speed(uint8_t fan, uint8_t pwm) {
int unit;
int ret = 0;
if (fan >= pal_pwm_cnt) {
syslog(LOG_INFO, "pal_set_fan_speed: fan number is invalid - %d", fan);
return -1;
}
// Convert the percentage to our 1/96th unit.
unit = pwm * PWM_UNIT_MAX / 100;
// For 0%, turn off the PWM entirely
if (unit == 0) {
ret = write_fan_value(fan, "pwm%d_en", 0);
if (ret < 0) {
syslog(LOG_INFO, "set_fan_speed: write_fan_value failed");
return -1;
}
return 0;
// For 100%, set falling and rising to the same value
} else if (unit == PWM_UNIT_MAX) {
unit = 0;
}
ret = write_fan_value(fan, "pwm%d_type", 0);
if (ret < 0) {
syslog(LOG_INFO, "set_fan_speed: write_fan_value failed");
return -1;
}
ret = write_fan_value(fan, "pwm%d_rising", 0);
if (ret < 0) {
syslog(LOG_INFO, "set_fan_speed: write_fan_value failed");
return -1;
}
ret = write_fan_value(fan, "pwm%d_falling", unit);
if (ret < 0) {
syslog(LOG_INFO, "set_fan_speed: write_fan_value failed");
return -1;
}
ret = write_fan_value(fan, "pwm%d_en", 1);
if (ret < 0) {
syslog(LOG_INFO, "set_fan_speed: write_fan_value failed");
return -1;
}
return 0;
}
int
pal_get_fan_speed(uint8_t fan, int *rpm) {
int ret;
float value;
ret = sensor_cache_read(FRU_FCB, FCB_SENSOR_FAN1_FRONT_SPEED + fan, &value);
if (ret == 0)
*rpm = (int) value;
return ret;
}
int
pal_is_fru_ready(uint8_t fru, uint8_t *status) {
*status = 1;
return 0;
}
int
pal_get_pwm_value(uint8_t fan_num, uint8_t *value) {
char path[64] = {0};
char device_name[64] = {0};
int val = 0;
int pwm_enable = 0;
snprintf(device_name, LARGEST_DEVICE_NAME, "pwm%d_en", fanid2pwmid_mapping[fan_num]);
snprintf(path, LARGEST_DEVICE_NAME, "%s/%s", PWM_DIR, device_name);
if (read_device(path, &pwm_enable)) {
syslog(LOG_INFO, "pal_get_pwm_value: read %s failed", path);
return -1;
}
// Check the PWM is enable or not
if(pwm_enable) {
// fan number should in this range
if(fan_num >= 0 && fan_num <= 11)
snprintf(device_name, LARGEST_DEVICE_NAME, "pwm%d_falling", fanid2pwmid_mapping[fan_num]);
else {
syslog(LOG_INFO, "pal_get_pwm_value: fan number is invalid - %d", fan_num);
return -1;
}
snprintf(path, LARGEST_DEVICE_NAME, "%s/%s", PWM_DIR, device_name);
if (read_device_hex(path, &val)) {
syslog(LOG_INFO, "pal_get_pwm_value: read %s failed", path);
return -1;
}
if(val)
*value = (100 * val) / PWM_UNIT_MAX;
else
// 0 means duty cycle is 100%
*value = 100;
}
else
//PWM is disable
*value = 0;
return 0;
}
int
pal_set_fan_led(uint8_t num, uint8_t operation) {
int dev, ret, res;
int led_offset;
uint8_t reg, data;
if(num > MAX_FAN_LED_NUM) {
syslog(LOG_ERR, "%s: Wrong LED ID\n", __func__);
return -1;
}
dev = open(I2C_DEV_FAN, O_RDWR);
if(dev < 0) {
syslog(LOG_ERR, "%s: open() failed\n", __func__);
return -1;
}
ret = ioctl(dev, I2C_SLAVE, I2C_ADDR_FAN_LED);
if(ret < 0) {
syslog(LOG_ERR, "%s: ioctl() assigned i2c addr failed\n", __func__);
close(dev);
return -1;
}
led_offset = num;
if(num < 4) {
reg = REG_LS0;
} else {
reg = REG_LS1;
led_offset -= 4;
}
//Read the input register
res = i2c_smbus_read_byte_data(dev, reg);
if(res < 0) {
close(dev);
syslog(LOG_ERR, "%s: i2c_smbus_read_byte_data failed\n", __func__);
return -1;
}
data = res & ~(3 << (led_offset << 1));
switch(operation) {
case FAN_LED_ON:
break;
case FAN_LED_OFF:
data |= (1 << (led_offset << 1));
break;
case FAN_LED_BLINK_PWM0_RATE:
data |= (2 << (led_offset << 1));
break;
case FAN_LED_BLINK_PWM1_RATE:
data |= (3 << (led_offset << 1));
break;
default:
break;
}
res = i2c_smbus_write_byte_data(dev, reg, data);
if(res < 0) {
close(dev);
syslog(LOG_ERR, "%s: i2c_smbus_write_byte_data failed\n", __func__);
return -1;
}
close(dev);
return 0;
}
int
pal_fan_dead_handle(int fan_num) {
int ret;
/* Because two fans map to one LED, and fan ID start at 1 */
ret = pal_set_fan_led( ((fan_num - FAN_INDEX_BASE) / 2), FAN_LED_OFF);
if(ret < 0) {
syslog(LOG_ERR, "%s: pal_set_fan_led failed\n", __func__);
return -1;
}
return 0;
}
int
pal_fan_recovered_handle(int fan_num) {
int ret;
/* Because two fans map to one LED, and fan ID start at 1 */
ret = pal_set_fan_led( ((fan_num - FAN_INDEX_BASE) / 2), FAN_LED_ON);
if(ret < 0) {
syslog(LOG_ERR, "%s: pal_set_fan_led failed\n", __func__);
return -1;
}
return 0;
}
// Reset PCIe Switch
int
pal_reset_pcie_switch() {
char path[64] = {0};
sprintf(path, GPIO_VAL, GPIO_RESET_PCIE_SWITCH);
if (write_device(path, "0"))
return -1;
msleep(100);
if (write_device(path, "1"))
return -1;
return 0;
}
int
pal_self_tray_location(uint8_t *value) {
char path[64] = {0};
int val;
sprintf(path, GPIO_VAL, GPIO_TRAY_LOCATION_ID);
if (read_device(path, &val))
return -1;
*value = (uint8_t) val;
return 0;
}
int
pal_self_tray_insertion(uint8_t *value) {
char path[64] = {0};
int val;
sprintf(path, GPIO_VAL, GPIO_BMC_SELF_TRAY_INTRU);
if (read_device(path, &val))
return -1;
*value = (uint8_t) val;
return 0;
}
int
pal_peer_tray_insertion(uint8_t *value) {
char path[64] = {0};
int val;
sprintf(path, GPIO_VAL, GPIO_BMC_PEER_TRAY_INTRU);
if (read_device(path, &val))
return -1;
*value = (uint8_t) val;
return 0;
}
int
pal_get_tray_location(char *self_tray_name, uint8_t self_len,
char *peer_tray_name, uint8_t peer_len,
uint8_t *peer_tray_pwr) {
uint8_t val = 0;
char cvalue[MAX_VALUE_LEN];
if ((self_tray_name == NULL) || (peer_tray_name == NULL)){
syslog(LOG_ERR, "%s(): Error - Null Pointer", __func__);
}
// We already have this information
if (kv_get("tray_location", cvalue, NULL, 0) == 0) {
return 0;
}
if (pal_self_tray_location(&val) == -1)
return -1;
if (val == 1) {
snprintf(self_tray_name, self_len, "Upper Tray");
snprintf(peer_tray_name, peer_len, "Lower Tray");
*peer_tray_pwr = FCB_SENSOR_P12VL;
} else if (val == 0) {
snprintf(self_tray_name, self_len, "Lower Tray");
snprintf(peer_tray_name, peer_len, "Upper Tray");
*peer_tray_pwr = FCB_SENSOR_P12VU;
} else {
syslog(LOG_WARNING, "%s(): invalid tray_location_id: %d", __func__, val);
return -1;
}
if (self_len > MAX_VALUE_LEN){
syslog(LOG_ERR, "%s(): Invalid Parameter. self_len:%d, max len:%d",
__func__, self_len, MAX_VALUE_LEN);
return -1;
}
return kv_set("tray_location", self_tray_name, 0, 0);
}
void
pal_log_clear(char *fru) {
if (!strcmp(fru, "peb")) {
pal_set_key_value("peb_sensor_health", "1");
} else if (!strcmp(fru, "pdpb")) {
pal_set_key_value("pdpb_sensor_health", "1");
} else if (!strcmp(fru, "fcb")) {
pal_set_key_value("fcb_sensor_health", "1");
} else if (!strcmp(fru, "all")) {
pal_set_key_value("peb_sensor_health", "1");
pal_set_key_value("pdpb_sensor_health", "1");
pal_set_key_value("fcb_sensor_health", "1");
pal_set_key_value("bmc_health", "1");
}
}
void
pal_sensor_assert_handle(uint8_t fru, uint8_t snr_num, float val, uint8_t thresh) {
uint8_t *sensorStatus = NULL;
uint8_t error_code_num = sennum2errcode_mapping[snr_num];
int fd, ret;
if (access(ERR_CODE_FILE, F_OK) == -1)
fd = open("/tmp/share_sensor_status", O_CREAT | O_RDWR | O_TRUNC, 00777);
else
fd = open("/tmp/share_sensor_status", O_CREAT | O_RDWR, 00777);
if (fd == -1) {
syslog(LOG_ERR, "%s(): Error opening file for reading", __func__);
return;
}
ret = pal_flock_retry(fd);
if (ret) {
syslog(LOG_WARNING, "%s(): failed to flock on %s. %s", __func__, ERR_CODE_FILE, strerror(errno));
close(fd);
return;
}
lseek(fd, (sizeof(uint8_t) * MAX_SENSOR_NUM) - 1, SEEK_SET);
write(fd, "", 1);
sensorStatus = (uint8_t*) mmap(NULL, (sizeof(uint8_t) * MAX_SENSOR_NUM),
PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (sensorStatus == MAP_FAILED){
syslog(LOG_ERR, "%s(): Error mmapping the file. %s", __func__, strerror(errno));
flock(fd, LOCK_UN);
close(fd);
return;
}
switch (thresh) {
case UNC_THRESH:
sensorStatus[snr_num] = SETBIT(sensorStatus[snr_num], UNC_THRESH);
break;
case UCR_THRESH:
sensorStatus[snr_num] = SETBIT(sensorStatus[snr_num], UCR_THRESH);
break;
case UNR_THRESH:
sensorStatus[snr_num] = SETBIT(sensorStatus[snr_num], UNR_THRESH);
break;
case LNC_THRESH:
sensorStatus[snr_num] = SETBIT(sensorStatus[snr_num], LNC_THRESH);
break;
case LCR_THRESH:
sensorStatus[snr_num] = SETBIT(sensorStatus[snr_num], LCR_THRESH);
break;
case LNR_THRESH:
sensorStatus[snr_num] = SETBIT(sensorStatus[snr_num], LNR_THRESH);
break;
default:
syslog(LOG_ERR, "%s(): wrong threshold value", __func__);
return;
}
pal_write_error_code_file(error_code_num, ERR_ASSERT);
munmap(sensorStatus, sizeof(bool) * MAX_SENSOR_NUM);
flock(fd, LOCK_UN);
close(fd);
}
void
pal_sensor_deassert_handle(uint8_t fru, uint8_t snr_num, float val, uint8_t thresh) {
uint8_t *sensorStatus = NULL;
uint8_t error_code_num = sennum2errcode_mapping[snr_num];
int i, fd, ret;
bool tmp = 0;
if (access(ERR_CODE_FILE, F_OK) == -1)
fd = open("/tmp/share_sensor_status", O_CREAT | O_RDWR | O_TRUNC, 00777);
else
fd = open("/tmp/share_sensor_status", O_CREAT | O_RDWR, 00777);
if (fd == -1) {
syslog(LOG_ERR, "%s(): Error opening file for reading", __func__);
return;
}
ret = pal_flock_retry(fd);
if (ret) {
syslog(LOG_WARNING, "%s(): failed to flock on %s. %s", __func__, ERR_CODE_FILE, strerror(errno));
close(fd);
return;
}
lseek(fd, (sizeof(uint8_t) * MAX_SENSOR_NUM) - 1, SEEK_SET);
write(fd, "", 1);
sensorStatus = (uint8_t*) mmap(NULL, (sizeof(uint8_t) * MAX_SENSOR_NUM),
PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (sensorStatus == MAP_FAILED){
syslog(LOG_ERR, "%s(): Error mmapping the file. %s", __func__, strerror(errno));
flock(fd, LOCK_UN);
close(fd);
return;
}
switch (thresh) {
case UNC_THRESH:
sensorStatus[snr_num] = CLEARBIT(sensorStatus[snr_num], UNC_THRESH);
case UCR_THRESH:
sensorStatus[snr_num] = CLEARBIT(sensorStatus[snr_num], UCR_THRESH);
case UNR_THRESH:
sensorStatus[snr_num] = CLEARBIT(sensorStatus[snr_num], UNR_THRESH);
break;
case LNC_THRESH:
sensorStatus[snr_num] = CLEARBIT(sensorStatus[snr_num], LNC_THRESH);
case LCR_THRESH:
sensorStatus[snr_num] = CLEARBIT(sensorStatus[snr_num], LCR_THRESH);
case LNR_THRESH:
sensorStatus[snr_num] = CLEARBIT(sensorStatus[snr_num], LNR_THRESH);
break;
default:
syslog(LOG_ERR, "%s(): wrong threshold value", __func__);
return;
}
for (i = 0; i < MAX_SENSOR_NUM; i++) {
if (sennum2errcode_mapping[i] == error_code_num) {
tmp |= sensorStatus[i];
}
}
if (tmp == ERR_DEASSERT){
pal_write_error_code_file(error_code_num, ERR_DEASSERT);
}
munmap(sensorStatus, sizeof(bool) * MAX_SENSOR_NUM);
flock(fd, LOCK_UN);
close(fd);
}
void
pal_err_code_enable(const uint8_t error_num) {
// error code distributed over 0~99
if (error_num < (ERROR_CODE_NUM * 8))
pal_write_error_code_file(error_num, ERR_ASSERT);
else
syslog(LOG_WARNING, "%s(): wrong error code number", __func__);
}
void
pal_err_code_disable(const uint8_t error_num) {
// error code distributed over 0~99
if (error_num < (ERROR_CODE_NUM * 8))
pal_write_error_code_file(error_num, ERR_DEASSERT);
else
syslog(LOG_WARNING, "%s(): wrong error code number", __func__);
}
int
pal_read_error_code_file(uint8_t *error_code_array) {
FILE *fp = NULL;
uint8_t ret = 0;
int i = 0;
int tmp = 0;
if (access(ERR_CODE_FILE, F_OK) == -1) {
memset(error_code_array, 0, ERROR_CODE_NUM);
return 0;
}
else
fp = fopen(ERR_CODE_FILE, "r");
if (!fp)
return -1;
ret = pal_flock_retry(fileno(fp));
if (ret) {
int err = errno;
syslog(LOG_WARNING, "%s(): failed to flock on %s, err %d", __func__, ERR_CODE_FILE, err);
fclose(fp);
return -1;
}
for (i = 0; fscanf(fp, "%X", &tmp) != EOF && i < ERROR_CODE_NUM; i++)
error_code_array[i] = (uint8_t) tmp;
flock(fileno(fp), LOCK_UN);
fclose(fp);
return 0;
}
int
pal_write_error_code_file(const uint8_t error_num, const bool status) {
FILE *fp = NULL;
uint8_t ret = 0;
int i = 0;
int stat = 0;
int bit_stat = 0;
uint8_t error_code_array[ERROR_CODE_NUM] = {0};
if (pal_read_error_code_file(error_code_array) != 0){
syslog(LOG_ERR, "%s(): pal_read_error_code_file() failed", __func__);
return -1;
}
if (access(ERR_CODE_FILE, F_OK) == -1)
fp = fopen(ERR_CODE_FILE, "w");
else
fp = fopen(ERR_CODE_FILE, "r+");
if (!fp){
syslog(LOG_ERR, "%s(): open %s failed. %s", __func__, ERR_CODE_FILE, strerror(errno));
return -1;
}
ret = pal_flock_retry(fileno(fp));
if (ret) {
syslog(LOG_WARNING, "%s(): failed to flock on %s. %s", __func__, ERR_CODE_FILE, strerror(errno));
fclose(fp);
return -1;
}
stat = error_num / 8;
bit_stat = error_num % 8;
if (status)
error_code_array[stat] |= 1 << bit_stat;
else
error_code_array[stat] &= ~(1 << bit_stat);
for(i = 0; i < ERROR_CODE_NUM; i++) {
fprintf(fp, "%X ", error_code_array[i]);
if(error_code_array[i] != 0) {
ret = 1;
}
}
fprintf(fp, "\n");
flock(fileno(fp), LOCK_UN);
fclose(fp);
return ret;
}
int
pal_drive_status(const char* i2c_bus) {
ssd_data ssd;
t_status_flags status_flag_decoding;
t_smart_warning smart_warning_decoding;
t_key_value_pair temp_decoding;
t_key_value_pair pdlu_decoding;
t_key_value_pair vendor_decoding;
t_key_value_pair sn_decoding;
if (nvme_vendor_read_decode(i2c_bus, &ssd.vendor, &vendor_decoding))
printf("Fail on reading Vendor ID\n");
else
printf("%s: %s\n", vendor_decoding.key, vendor_decoding.value);
if (nvme_serial_num_read_decode(i2c_bus, ssd.serial_num, MAX_SERIAL_NUM, &sn_decoding))
printf("Fail on reading Serial Number\n");
else
printf("%s: %s\n", sn_decoding.key, sn_decoding.value);
if (nvme_temp_read_decode(i2c_bus, &ssd.temp, &temp_decoding))
printf("Fail on reading Composite Temperature\n");
else
printf("%s: %s\n", temp_decoding.key, temp_decoding.value);
if (nvme_pdlu_read_decode(i2c_bus, &ssd.pdlu, &pdlu_decoding))
printf("Fail on reading Percentage Drive Life Used\n");
else
printf("%s: %s\n", pdlu_decoding.key, pdlu_decoding.value);
if (nvme_sflgs_read_decode(i2c_bus, &ssd.sflgs, &status_flag_decoding))
printf("Fail on reading Status Flags\n");
else {
printf("%s: %s\n", status_flag_decoding.self.key, status_flag_decoding.self.value);
printf(" %s: %s\n", status_flag_decoding.read_complete.key, status_flag_decoding.read_complete.value);
printf(" %s: %s\n", status_flag_decoding.ready.key, status_flag_decoding.ready.value);
printf(" %s: %s\n", status_flag_decoding.functional.key, status_flag_decoding.functional.value);
printf(" %s: %s\n", status_flag_decoding.reset_required.key, status_flag_decoding.reset_required.value);
printf(" %s: %s\n", status_flag_decoding.port0_link.key, status_flag_decoding.port0_link.value);
printf(" %s: %s\n", status_flag_decoding.port1_link.key, status_flag_decoding.port1_link.value);
}
if (nvme_smart_warning_read_decode(i2c_bus, &ssd.warning, &smart_warning_decoding))
printf("Fail on reading SMART Critical Warning\n");
else {
printf("%s: %s\n", smart_warning_decoding.self.key, smart_warning_decoding.self.value);
printf(" %s: %s\n", smart_warning_decoding.spare_space.key, smart_warning_decoding.spare_space.value);
printf(" %s: %s\n", smart_warning_decoding.temp_warning.key, smart_warning_decoding.temp_warning.value);
printf(" %s: %s\n", smart_warning_decoding.reliability.key, smart_warning_decoding.reliability.value);
printf(" %s: %s\n", smart_warning_decoding.media_status.key, smart_warning_decoding.media_status.value);
printf(" %s: %s\n", smart_warning_decoding.backup_device.key, smart_warning_decoding.backup_device.value);
}
printf("\n");
return 0;
}
int
pal_read_nvme_data(uint8_t slot_num, uint8_t cmd) {
uint8_t sku;
int ret;
ret = lightning_ssd_sku(&sku);
if (ret < 0) {
syslog(LOG_DEBUG, "%s(): lightning_ssd_sku failed", __func__);
return -1;
}
if (sku == U2_SKU) {
ret = pal_u2_flash_read_nvme_data(slot_num, cmd);
/*Drive status report
0: drive is not health
1: drive is health*/
if (ret == 0)
return 1;
else
return 0;
}
else if (sku == M2_SKU) {
ret = pal_m2_flash_read_nvme_data(slot_num, cmd);
return ret;
}
else {
syslog(LOG_DEBUG, "%s(): unknown ssd sku", __func__);
return -1;
}
}
int
pal_u2_flash_read_nvme_data(uint8_t slot_num, uint8_t cmd) {
int ret;
uint8_t mux;
uint8_t chan;
char bus[32];
mux = lightning_flash_list[slot_num] / 10;
chan = lightning_flash_list[slot_num] % 10;
/* Set 1-level mux */
ret = lightning_flash_mux_sel_chan(mux, chan);
if(ret < 0) {
syslog(LOG_DEBUG, "%s(): lightning_flash_mux_sel_chan on Mux %d failed", __func__, mux);
return -1;
}
if (mux == I2C_MUX_FLASH1)
sprintf(bus, "%s", I2C_DEV_FLASH1);
else if (mux == I2C_MUX_FLASH2)
sprintf(bus, "%s", I2C_DEV_FLASH2);
else {
syslog(LOG_DEBUG, "%s(): unknown mux", __func__);
return -1;
}
if (cmd == CMD_DRIVE_STATUS) {
printf("Slot%d:\n", slot_num);
ret = pal_drive_status(bus);
if(ret < 0) {
syslog(LOG_DEBUG, "%s(): pal_drive_status failed", __func__);
return -1;
}
ret = pal_drive_health(bus);
return ret;
}
else if (cmd == CMD_DRIVE_HEALTH) {
ret = pal_drive_health(bus);
return ret;
}
else {
syslog(LOG_DEBUG, "%s(): unknown cmd", __func__);
return -1;
}
}
int
pal_m2_flash_read_nvme_data(uint8_t slot_num, uint8_t cmd) {
int ret1;
int ret2;
/* read the M.2 NVMe-MI data on channel 0 */
ret1 = pal_m2_read_nvme_data(slot_num, M2_MUX_CHANNEL_0, cmd);
if (ret1 < 0)
syslog(LOG_DEBUG, "%s(): pal_m2_read_nvme_data on channel 0 failed", __func__);
/* read the M.2 NVMe-MI data on channel 1 */
ret2 = pal_m2_read_nvme_data(slot_num, M2_MUX_CHANNEL_1, cmd);
if (ret2 < 0)
syslog(LOG_DEBUG, "%s(): pal_m2_read_nvme_data on channel 1 failed", __func__);
/*Drive status report
2: two drives are not health
3: only first drive is health
4: only second drive is health
5: two drives are health*/
if ((ret1 == 0) && (ret2 == 0))
return 5;
else if ((ret1 == 0) && (ret2 != 0))
return 3;
else if ((ret1 != 0) && (ret2 == 0))
return 4;
else
return 2;
}
int
pal_m2_read_nvme_data(uint8_t slot_num, uint8_t m2_mux_chan, uint8_t cmd) {
int ret;
uint8_t mux;
uint8_t chan;
char bus[32];
mux = lightning_flash_list[slot_num] / 10;
chan = lightning_flash_list[slot_num] % 10;
/* Set 1-level mux */
ret = lightning_flash_mux_sel_chan(mux, chan);
if(ret < 0) {
syslog(LOG_DEBUG, "%s(): lightning_flash_mux_sel_chan on Mux %d failed", __func__, mux);
return -1;
}
/* Set 2-level mux */
ret = lightning_flash_sec_mux_sel_chan(mux, m2_mux_chan);
if(ret < 0) {
syslog(LOG_DEBUG, "%s(): lightning_flash_sec_mux_sel_chan on Mux %d failed", __func__, mux);
return -1;
}
if (mux == I2C_MUX_FLASH1)
sprintf(bus, "%s", I2C_DEV_FLASH1);
else if (mux == I2C_MUX_FLASH2)
sprintf(bus, "%s", I2C_DEV_FLASH2);
else {
syslog(LOG_DEBUG, "%s(): unknown mux", __func__);
return -1;
}
if (cmd == CMD_DRIVE_STATUS) {
printf("Slot%d Drive%d\n", slot_num, m2_mux_chan);
ret = pal_drive_status(bus);
if(ret < 0) {
syslog(LOG_DEBUG, "%s(): pal_drive_status failed", __func__);
return ret;
}
ret = pal_drive_health(bus);
return ret;
}
else if (cmd == CMD_DRIVE_HEALTH) {
ret = pal_drive_health(bus);
return ret;
}
else {
syslog(LOG_DEBUG, "%s(): unknown cmd", __func__);
return -1;
}
}
int
pal_drive_health(const char* dev) {
uint8_t sflgs;
uint8_t warning;
if (nvme_smart_warning_read(dev, &warning))
return -1;
else
if ((warning & NVME_SMART_WARNING_MASK_BIT) != NVME_SMART_WARNING_MASK_BIT)
return -1;
if (nvme_sflgs_read(dev, &sflgs))
return -1;
else
if ((sflgs & NVME_SFLGS_MASK_BIT) != NVME_SFLGS_CHECK_VALUE)
return -1;
return 0;
}
void
pal_i2c_crash_assert_handle(int i2c_bus_num) {
// I2C bus number: 0~13
if (i2c_bus_num < I2C_BUS_MAX_NUMBER)
pal_err_code_enable(ERR_CODE_I2C_CRASH_BASE + i2c_bus_num);
else
syslog(LOG_WARNING, "%s(): wrong I2C bus number", __func__);
}
void
pal_i2c_crash_deassert_handle(int i2c_bus_num) {
// I2C bus number: 0~13
if (i2c_bus_num < I2C_BUS_MAX_NUMBER)
pal_err_code_disable(ERR_CODE_I2C_CRASH_BASE + i2c_bus_num);
else
syslog(LOG_WARNING, "%s(): wrong I2C bus number", __func__);
}
int
pal_bmc_err_enable(const char *error_item) {
if (strcasestr(error_item, "CPU") != 0ULL) {
pal_err_code_enable(ERR_CODE_CPU);
} else if (strcasestr(error_item, "Memory") != 0ULL) {
pal_err_code_enable(ERR_CODE_MEM);
} else if (strcasestr(error_item, "ECC Unrecoverable") != 0ULL) {
// Skip reporting ECC error code
} else if (strcasestr(error_item, "ECC Recoverable") != 0ULL) {
// Skip reporting ECC error code
} else {
syslog(LOG_WARNING, "%s: invalid bmc health item: %s", __func__, error_item);
return -1;
}
return 0;
}
int
pal_bmc_err_disable(const char *error_item) {
if (strcasestr(error_item, "CPU") != 0ULL) {
pal_err_code_disable(ERR_CODE_CPU);
} else if (strcasestr(error_item, "Memory") != 0ULL) {
pal_err_code_disable(ERR_CODE_MEM);
} else if (strcasestr(error_item, "ECC Unrecoverable") != 0ULL) {
// Skip reporting ECC error code
} else if (strcasestr(error_item, "ECC Recoverable") != 0ULL) {
// Skip reporting ECC error code
} else {
syslog(LOG_WARNING, "%s: invalid bmc health item: %s", __func__, error_item);
return -1;
}
return 0;
}
int
pal_get_boot_option(unsigned char para,unsigned char* pbuff)
{
unsigned char option_size[] = {1,1,1,1,2,5,9,17,127};
unsigned char size = option_size[para];
memset(pbuff, 0, size);
return size;
}
int
pal_set_debug_card_led(const int display_num) {
int val;
int high_hex = display_num / 16;
int low_hex = display_num % 16;
val = low_hex % 2;
if (pal_set_gpio_value(GPIO_DEBUG_CARD_LOW_HEX_0, val))
return -1;
val = (low_hex / 2) % 2;
if (pal_set_gpio_value(GPIO_DEBUG_CARD_LOW_HEX_1, val))
return -1;
val = (low_hex / 4) % 2;
if (pal_set_gpio_value(GPIO_DEBUG_CARD_LOW_HEX_2, val))
return -1;
val = (low_hex / 8) % 2;
if (pal_set_gpio_value(GPIO_DEBUG_CARD_LOW_HEX_3, val))
return -1;
val = high_hex % 2;
if (pal_set_gpio_value(GPIO_DEBUG_CARD_HIGH_HEX_0, val))
return -1;
val = (high_hex / 2) % 2;
if (pal_set_gpio_value(GPIO_DEBUG_CARD_HIGH_HEX_1, val))
return -1;
val = (high_hex / 4) % 2;
if (pal_set_gpio_value(GPIO_DEBUG_CARD_HIGH_HEX_2, val))
return -1;
val = (high_hex / 8) % 2;
if (pal_set_gpio_value(GPIO_DEBUG_CARD_HIGH_HEX_3, val))
return -1;
return 0;
}