meta-facebook/meta-fby2/recipes-fby2/gpiointrd/files/gpiointrd.c (1,049 lines of code) (raw):

/* * sensord * * Copyright 2015-present Facebook. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <stdio.h> #include <stdlib.h> #include <stdbool.h> #include <unistd.h> #include <errno.h> #include <syslog.h> #include <stdint.h> #include <math.h> #include <string.h> #include <time.h> #include <pthread.h> #include <sys/un.h> #include <sys/file.h> #include <openbmc/kv.h> #include <openbmc/ipmi.h> #include <openbmc/pal.h> #include <openbmc/libgpio.h> #include <openbmc/fruid.h> #include <openbmc/pal_sensors.h> #include <facebook/bic.h> #include <facebook/fby2_gpio.h> #include <facebook/fby2_sensor.h> #include <facebook/fby2_common.h> #define POLL_TIMEOUT -1 /* Forever */ #define MAX_NUM_SLOTS 4 #define SLOT_FILE "/tmp/slot%d.bin" #define SLOT_RECORD_FILE "/tmp/slot%d.rc" #define SV_TYPE_RECORD_FILE "/tmp/server_type%d.rc" #define HOTSERVICE_SCRPIT "/usr/local/bin/hotservice-reinit.sh" #define HOTSERVICE_FILE "/tmp/slot%d_reinit" #define HSLOT_PID "/tmp/slot%u_reinit.pid" #define PWR_UTL_LOCK "/var/run/power-util_%d.lock" #define POST_FLAG_FILE "/tmp/cache_store/slot%d_post_flag" #define SYS_CONFIG_FILE "/mnt/data/kv_store/sys_config/fru%d_*" #define SYS_CONFIG_M2_DEV_FILE "/mnt/data/kv_store/sys_config/fru%d_m2_%d_info" #define SENSORDUMP_BIN "/usr/local/bin/sensordump.sh" #define SLOT_REMOVAL_PRECHECK_SCRIPT "/usr/local/bin/slot-removal-precheck.sh" #define FAN_LATCH_POLL_TIME 600 #define DEBUG_ME_EJECTOR_LOG 0 // Enable log "GPIO_SLOTX_EJECTOR_LATCH_DETECT_N is 1 and SLOT_12v is ON" before mechanism issue is fixed static uint8_t IsHotServiceStart[MAX_NODES + 1] = {0}; static uint8_t IsFanLatchAction = 0; static void *hsvc_event_handler(void *ptr); static void *fan_latch_event_handler(void *ptr); static pthread_mutex_t hsvc_mutex[MAX_NODES + 1]; static pthread_mutex_t fan_latch_mutex; static pthread_t fan_latch_tid; // polling fan latch static pthread_t fan_latch_action_tid; // start/stop fscd static struct timespec last_ejector_ts[MAX_NODES + 1]; static uint8_t IsLatchOpenStart[MAX_NODES + 1] = {0}; static void *latch_open_handler(void *ptr); static pthread_mutex_t latch_open_mutex[MAX_NODES + 1]; static uint8_t dev_fru_complete[MAX_NODES + 1][MAX_NUM_DEVS + 1] = {DEV_FRU_NOT_COMPLETE}; static bool is_slot_missing(); static char **fru_prsnt_log_string[3][MAX_NODES+1] = { // slot1, slot2, slot3, slot4 {"", "Slot1 Removal", "Slot2 Removal", "Slot3 Removal", "Slot4 Removal"}, {"", "Slot1 Insertion", "Slot2 Insertion", "Slot3 Insertion", "Slot4 Insertion"}, {"", "Slot1 Removal Without 12V-OFF", "Slot2 Removal Without 12V-OFF", "Slot3 Removal Without 12V-OFF", "Slot4 Removal Without 12V-OFF"} }; static char* gpio_slot_latch[] = { 0, "SLOT1_EJECTOR_LATCH_DETECT_N", "SLOT2_EJECTOR_LATCH_DETECT_N", "SLOT3_EJECTOR_LATCH_DETECT_N", "SLOT4_EJECTOR_LATCH_DETECT_N" }; static uint32_t gpv2_dev_nvme_temp[] = { 0, GPV2_SENSOR_DEV0_Temp, GPV2_SENSOR_DEV1_Temp, GPV2_SENSOR_DEV2_Temp, GPV2_SENSOR_DEV3_Temp, GPV2_SENSOR_DEV4_Temp, GPV2_SENSOR_DEV5_Temp, GPV2_SENSOR_DEV6_Temp, GPV2_SENSOR_DEV7_Temp, GPV2_SENSOR_DEV8_Temp, GPV2_SENSOR_DEV9_Temp, GPV2_SENSOR_DEV10_Temp, GPV2_SENSOR_DEV11_Temp}; struct threadinfo { uint8_t is_running; uint8_t fru; pthread_t pt; }; static struct threadinfo t_fru_cache[MAX_NUM_FRUS] = {0, }; typedef struct { uint8_t def_val; char name[64]; uint32_t num; char log[256]; } def_chk_info; struct delayed_log { useconds_t usec; char msg[256]; }; typedef struct { uint8_t slot_id; uint8_t action; } hot_service_info; enum { REMOVAl = 0, INSERTION = 1, }; enum { OPEN = 0, CLOSE =1, }; enum { SLOT_PRESNT = 0, SLOT_MISSING = 1, }; slot_kv_st slot_kv_list[] = { // {slot_key, slot_def_val} {"pwr_server%d_last_state", "on"}, {"sysfw_ver_slot%d", "0"}, {"slot%d_por_cfg", "lps"}, {"slot%d_sensor_health", "1"}, {"slot%d_sel_error", "1"}, {"slot%d_boot_order", "0000000"}, {"slot%d_cpu_ppin", "0"}, {"fru%d_restart_cause", "3"}, }; int fan_latch_action(int action) { int ret = 0; char cmd[128]; if ( IsFanLatchAction ) { syslog(LOG_WARNING, "[%s] Close the previous thread for fan latch\n", __func__); ret = pthread_cancel(fan_latch_action_tid); if (ret == ESRCH) { syslog(LOG_INFO, "fan_latch_action: No pthread exists"); } else { sprintf(cmd, "ps | grep 'fscd_end.sh\\|setup-fan.sh' | awk '{print $1}'| xargs kill "); log_system(cmd); syslog(LOG_INFO, "fan_latch_action: Previous thread is cancelled"); } } //Create thread for fan latch event detect if (pthread_create(&fan_latch_action_tid, NULL, fan_latch_event_handler, (void *)action) < 0) { syslog(LOG_WARNING, "[%s] Create fan_latch_event_handler thread failed for fan latch\n",__func__); return -1; } return 0; } void * fan_latch_poll_handler(void *priv) { FILE* fp; int value = 0; int is_fscd_running = 0; char cmd[128]; char buf[32]; int res; sprintf(cmd, "ps -w | grep /usr/bin/fscd.py | wc -l"); while (1) { fby2_common_get_gpio_val("FAN_LATCH_DETECT", &value); is_fscd_running = 0; if((fp = popen(cmd, "r")) != NULL) { if(fgets(buf, sizeof(buf), fp) != NULL) { res = atoi(buf); if(res > 2) { is_fscd_running = 1; } } pclose(fp); } if (!value && !is_fscd_running) { // If sled in and fscd is not runnig, start fscd syslog(LOG_WARNING,"Sled Fan Latch Clsoe: start fscd"); fan_latch_action(CLOSE); } else if (value && is_fscd_running) { // If sled out and fscd is running, stop fscd syslog(LOG_WARNING,"Sled Fan Latch Open: stop fscd"); fan_latch_action(OPEN); } sleep(FAN_LATCH_POLL_TIME); } } // Thread for delay event static void * delay_log(void *arg) { struct delayed_log* log = (struct delayed_log*)arg; pthread_detach(pthread_self()); if (arg) { usleep(log->usec); syslog(LOG_CRIT, "%s", log->msg); free(arg); } pthread_exit(NULL); } 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 void create_sensordump(void) { log_system(SENSORDUMP_BIN); } static void * hsc_alert_handler(void *arg) { pthread_detach(pthread_self()); if (fby2_check_hsc_sts_iout() == 1) { // bit5: IOUT_OC_WARN syslog(LOG_CRIT, "ASSERT: OC_warning triggered (falling edge detected for SMB_HOTSWAP_ALERT_N)"); create_sensordump(); sleep(1); fby2_check_hsc_fault(); } pthread_exit(NULL); } static int fruid_cache_init(uint8_t slot_id, uint8_t fru_id) { int ret; int fru_size = 0; char fruid_temp_path[64] = {0}; char fruid_path[64] = {0}; if (fru_id == 0) { sprintf(fruid_temp_path, "/tmp/tfruid_slot%d.bin", slot_id); sprintf(fruid_path, "/tmp/fruid_slot%d.bin", slot_id); } else { sprintf(fruid_temp_path, "/tmp/tfruid_slot%d_dev%d.bin", slot_id, fru_id); sprintf(fruid_path, "/tmp/fruid_slot%d_dev%d.bin", slot_id, fru_id); } ret = bic_read_fruid(slot_id, fru_id, fruid_temp_path, &fru_size); if (ret) { syslog(LOG_WARNING, "fruid_cache_init: bic_read_fruid slot%d dev=%d returns %d, fru_size: %d\n", slot_id, fru_id-1, ret, fru_size); } rename(fruid_temp_path, fruid_path); return ret; } static void * fru_cache_dump(void *arg) { uint8_t fru = *(uint8_t *) arg; uint8_t self_test_result[2] = {0}; char key[MAX_KEY_LEN]; char buf[MAX_VALUE_LEN]; int ret; int retry; uint8_t status[MAX_NUM_DEVS+1] = {DEVICE_POWER_OFF}; uint8_t type = DEV_TYPE_UNKNOWN; uint8_t nvme_ready = 0; uint8_t all_nvme_ready = 0; uint8_t dev_id; const int max_retry = 3; int oldstate; int finish_count = 0; // fru finish int nvme_ready_count = 0; float value; fruid_info_t fruid; pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate); pal_set_nvme_ready(fru,all_nvme_ready); pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate); // Check BIC Self Test Result do { pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate); ret = bic_get_self_test_result(fru, self_test_result); pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate); if (ret == 0) { syslog(LOG_INFO, "bic_get_self_test_result: %X %X\n", self_test_result[0], self_test_result[1]); break; } sleep(5); } while (ret != 0); sleep(2); //wait for BIC poll at least one cycle // Get GPV2 devices' FRU for (dev_id = 1; dev_id <= MAX_NUM_DEVS; dev_id++) { //check for power status ret = pal_get_dev_info(fru, dev_id, &nvme_ready ,&status[dev_id], &type, 0); syslog(LOG_WARNING, "fru_cache_dump: Slot%u Dev%d power=%u nvme_ready=%u type=%u", fru, dev_id-1, status[dev_id], nvme_ready, type); if (dev_fru_complete[fru][dev_id] != DEV_FRU_NOT_COMPLETE) { finish_count++; continue; } if (ret == 0) { if (status[dev_id] == DEVICE_POWER_ON) { retry = 0; while (1) { pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate); ret = fruid_cache_init(fru, dev_id); pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate); retry++; if ((ret == 0) || (retry == max_retry)) break; msleep(50); } if (retry >= max_retry) { syslog(LOG_WARNING, "fru_cache_dump: Fail on getting Slot%u Dev%d FRU", fru, dev_id-1); } else { pal_get_dev_fruid_path(fru, dev_id, buf); //check file's checksum pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate); ret = fruid_parse(buf, &fruid); if (ret != 0) { // Fail syslog(LOG_WARNING, "fru_cache_dump: Slot%u Dev%d FRU data checksum is invalid", fru, dev_id-1); } else { // Success free_fruid_info(&fruid); dev_fru_complete[fru][dev_id] = DEV_FRU_COMPLETE; finish_count++; syslog(LOG_WARNING, "fru_cache_dump: Finish getting Slot%u Dev%d FRU", fru, dev_id-1); } pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate); } } else { // DEVICE_POWER_OFF finish_count++; } sprintf(key, "slot%u_dev%u_pres", fru, dev_id-1); sprintf(buf, "%u", status[dev_id]); pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate); if (kv_set(key, buf, 0, 0) < 0) { syslog(LOG_WARNING, "fru_cache_dump: kv_set Slot%u Dev%d present status failed", fru, dev_id-1); } pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate); } else { // Device Status Unknown finish_count++; syslog(LOG_WARNING, "fru_cache_dump: Fail to access Slot%u Dev%d power status", fru, dev_id-1); } } // If NVMe is ready, try to get the FRU which was failed to get and // update the fan speed control table according to the device type do { nvme_ready_count = 0; for (dev_id = 1; dev_id <= MAX_NUM_DEVS; dev_id++) { if (status[dev_id] == DEVICE_POWER_OFF) {// M.2 device is present or not nvme_ready_count++; continue; } // check for device type ret = pal_get_dev_info(fru, dev_id, &nvme_ready, &status[dev_id], &type, 0); syslog(LOG_WARNING, "fru_cache_dump: Slot%u Dev%d power=%u nvme_ready=%u type=%u", fru, dev_id-1, status[dev_id], nvme_ready, type); if (ret || (!nvme_ready)) continue; nvme_ready_count++; if (dev_fru_complete[fru][dev_id] == DEV_FRU_NOT_COMPLETE) { // try to get fru or not if ((type == DEV_TYPE_VSI_ACC) || (type == DEV_TYPE_BRCM_ACC) || (type == DEV_TYPE_OTHER_ACC)) { // device type has FRU retry = 0; while (1) { pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate); ret = fruid_cache_init(fru, dev_id); pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate); retry++; if ((ret == 0) || (retry == max_retry)) break; msleep(50); } if (retry >= max_retry) { syslog(LOG_WARNING, "fru_cache_dump: Fail on getting Slot%u Dev%d FRU", fru, dev_id-1); } else { pal_get_dev_fruid_path(fru, dev_id, buf); // check file's checksum pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate); ret = fruid_parse(buf, &fruid); if (ret != 0) { // Fail syslog(LOG_WARNING, "fru_cache_dump: Slot%u Dev%d FRU data checksum is invalid", fru, dev_id-1); } else { // Success free_fruid_info(&fruid); dev_fru_complete[fru][dev_id] = DEV_FRU_COMPLETE; finish_count++; syslog(LOG_WARNING, "fru_cache_dump: Finish getting Slot%u Dev%d FRU", fru, dev_id-1); } pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate); } } else { dev_fru_complete[fru][dev_id] = DEV_FRU_IGNORE; finish_count++; syslog(LOG_WARNING, "fru_cache_dump: Slot%u Dev%d ignore FRU", fru, dev_id-1); } } } if (!all_nvme_ready && (nvme_ready_count == MAX_NUM_DEVS)) { //set nvme is ready all_nvme_ready = 1; pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate); pal_set_nvme_ready(fru,all_nvme_ready); pal_set_nvme_ready_timestamp(fru); pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate); syslog(LOG_WARNING, "fru_cache_dump: Slot%u all devices' NVMe are ready", fru); } sleep(10); } while ((finish_count < MAX_NUM_DEVS) || (nvme_ready_count < MAX_NUM_DEVS)); t_fru_cache[fru-1].is_running = 0; syslog(LOG_INFO, "%s: FRU %d cache is finished.", __func__, fru); pthread_detach(pthread_self()); pthread_exit(0); } int fru_cahe_init(uint8_t fru) { int ret; uint8_t idx; if (fru != FRU_SLOT1 && fru != FRU_SLOT3) { return -1; } idx = fru - 1; // If yes, kill that thread and start a new one if (t_fru_cache[idx].is_running) { ret = pthread_cancel(t_fru_cache[idx].pt); if (ret == ESRCH) { syslog(LOG_INFO, "%s: No dump FRU cache pthread exists", __func__); } else { pthread_join(t_fru_cache[idx].pt, NULL); syslog(LOG_INFO, "%s: Previous dump FRU cache thread is cancelled", __func__); } } // Start a thread to generate the FRU t_fru_cache[idx].fru = fru; if (pthread_create(&t_fru_cache[idx].pt, NULL, fru_cache_dump, (void *)&t_fru_cache[idx].fru) < 0) { syslog(LOG_WARNING, "%s: pthread_create for FRU %d failed", __func__, fru); return -1; } t_fru_cache[idx].is_running = 1; syslog(LOG_INFO, "%s: FRU %d cache is being generated.", __func__, fru); return 0; } static bool is_slot_missing() { char vpath[80] = {0}; int value = 0; int i = 0; char* slot_presnt_gpio[] = {"SLOT1_PRSNT_N", "SLOT2_PRSNT_N", "SLOT3_PRSNT_N", "SLOT4_PRSNT_N"}; for (i = 0; i < MAX_NUM_SLOTS; i++) { fby2_common_get_gpio_val(slot_presnt_gpio[i], &value); if (value == SLOT_MISSING) { return true; } } return false; } static void gpio_event_handle(gpiopoll_pin_t *gp, gpio_value_t last, gpio_value_t curr) { char cmd[128] = {0}; uint8_t slot_id; uint8_t slot_12v = 1; int value; char vpath[80] = {0}; char locstr[MAX_VALUE_LEN]; static bool prsnt_assert[MAX_NODES + 1]={0}; static pthread_t hsvc_action_tid[MAX_NODES + 1]; static pthread_t latch_open_tid[MAX_NODES + 1]; hot_service_info hsvc_info[MAX_NODES + 1]; uint8_t action; struct timespec ts; pthread_t hsc_alert_tid; const struct gpiopoll_config *cfg = gpio_poll_get_config(gp); if (strncmp(cfg->shadow, "FAN_LATCH_DETECT", sizeof(cfg->shadow)) == 0) { // GPIO_FAN_LATCH_DETECT if (curr == 1) { // low to high syslog(LOG_CRIT, "ASSERT: SLED is not seated"); action = OPEN; } else { // high to low syslog(LOG_CRIT, "DEASSERT: SLED is seated"); action = CLOSE; } fan_latch_action(action); } else if ((strncmp(cfg->shadow, "SLOT1_EJECTOR_LATCH_DETECT_N", sizeof(cfg->shadow)) == 0) || (strncmp(cfg->shadow, "SLOT2_EJECTOR_LATCH_DETECT_N", sizeof(cfg->shadow)) == 0) || (strncmp(cfg->shadow, "SLOT3_EJECTOR_LATCH_DETECT_N", sizeof(cfg->shadow)) == 0) || (strncmp(cfg->shadow, "SLOT4_EJECTOR_LATCH_DETECT_N", sizeof(cfg->shadow)) == 0) ) // GnPIO_SLOT1/2/3/4_EJECTOR_LATCH_DETECT_N { if (strncmp(cfg->shadow, "SLOT1_EJECTOR_LATCH_DETECT_N", sizeof(cfg->shadow)) == 0) { slot_id = 1; } else if (strncmp(cfg->shadow, "SLOT2_EJECTOR_LATCH_DETECT_N", sizeof(cfg->shadow)) == 0) { slot_id = 2; } else if (strncmp(cfg->shadow, "SLOT3_EJECTOR_LATCH_DETECT_N", sizeof(cfg->shadow)) == 0) { slot_id = 3; } else { slot_id = 4; } if (curr == 1) { // low to high clock_gettime(CLOCK_MONOTONIC, &ts); if (last_ejector_ts[slot_id].tv_sec && ((ts.tv_sec - last_ejector_ts[slot_id].tv_sec) < 5)) { return; } last_ejector_ts[slot_id].tv_sec = ts.tv_sec; fby2_common_get_gpio_val("FAN_LATCH_DETECT", &value); // 12V action would be triggered when SLED is pulled out // if SLED is seated, log the event that slot latch is open if (!value) { syslog(LOG_CRIT,"FRU: %u, SLOT%u_EJECTOR_LATCH is not closed while in VCubby", slot_id, slot_id); } else { syslog(LOG_CRIT,"FRU: %u, SLOT%u_EJECTOR_LATCH is not closed", slot_id, slot_id); pthread_mutex_lock(&latch_open_mutex[slot_id]); if ( IsLatchOpenStart[slot_id] ) { #ifdef DEBUG syslog(LOG_WARNING, "[%s] Close the previous thread for slot%x\n", __func__, slot_id); #endif pthread_cancel(latch_open_tid[slot_id]); } //Create thread for latch open detect value = slot_id; if (pthread_create(&latch_open_tid[slot_id], NULL, latch_open_handler, (void *)value) < 0) { syslog(LOG_WARNING, "[%s] Create latch_open_handler thread failed for slot%u", __func__, slot_id); pthread_mutex_unlock(&latch_open_mutex[slot_id]); return; } IsLatchOpenStart[slot_id] = true; pthread_mutex_unlock(&latch_open_mutex[slot_id]); } // end of SLED seated check } //End of low to high } //End of GPIO_SLOT1/2/3/4_EJECTOR_LATCH_DETECT_N else if ((strncmp(cfg->shadow, "SLOT1_PRSNT_B_N", sizeof(cfg->shadow)) == 0) || (strncmp(cfg->shadow, "SLOT2_PRSNT_B_N", sizeof(cfg->shadow)) == 0) || (strncmp(cfg->shadow, "SLOT3_PRSNT_B_N", sizeof(cfg->shadow)) == 0) || (strncmp(cfg->shadow, "SLOT4_PRSNT_B_N", sizeof(cfg->shadow)) == 0) || (strncmp(cfg->shadow, "SLOT1_PRSNT_N" , sizeof(cfg->shadow)) == 0) || (strncmp(cfg->shadow, "SLOT2_PRSNT_N" , sizeof(cfg->shadow)) == 0) || (strncmp(cfg->shadow, "SLOT3_PRSNT_N" , sizeof(cfg->shadow)) == 0) || (strncmp(cfg->shadow, "SLOT4_PRSNT_N" , sizeof(cfg->shadow)) == 0) ) // GPIO_SLOT1/2/3/4_PRSNT_B_N, GPIO_SLOT1/2/3/4_PRSNT_N { if ((strncmp(cfg->shadow, "SLOT1_PRSNT_B_N", sizeof(cfg->shadow)) == 0) || (strncmp(cfg->shadow, "SLOT1_PRSNT_N", sizeof(cfg->shadow)) == 0)) { slot_id = 1; } else if ((strncmp(cfg->shadow, "SLOT2_PRSNT_B_N", sizeof(cfg->shadow)) == 0) || (strncmp(cfg->shadow, "SLOT2_PRSNT_N", sizeof(cfg->shadow)) == 0)) { slot_id = 2; } else if ((strncmp(cfg->shadow, "SLOT3_PRSNT_B_N", sizeof(cfg->shadow)) == 0) || (strncmp(cfg->shadow, "SLOT3_PRSNT_N", sizeof(cfg->shadow)) == 0)) { slot_id = 3; } else { slot_id = 4; } // Use flag to ignore the interrupt of pair present pin if (prsnt_assert[slot_id]) { prsnt_assert[slot_id] = false; return; } // HOT SERVER event would be detected prsnt_assert[slot_id] = true; if (curr == 1) { // SLOT Removal hsvc_info[slot_id].slot_id = slot_id; hsvc_info[slot_id].action = REMOVAl; pthread_mutex_lock(&hsvc_mutex[slot_id]); if ( IsHotServiceStart[slot_id] ) { #ifdef DEBUG syslog(LOG_WARNING, "[%s] Close the previous thread for slot%x\n", __func__, slot_id); #endif pthread_cancel(hsvc_action_tid[slot_id]); } if (IsLatchOpenStart[slot_id]) { pthread_cancel(latch_open_tid[slot_id]); pthread_mutex_lock(&latch_open_mutex[slot_id]); IsLatchOpenStart[slot_id] = false; pthread_mutex_unlock(&latch_open_mutex[slot_id]); } //Create thread for hsvc event detect if (pthread_create(&hsvc_action_tid[slot_id], NULL, hsvc_event_handler, &hsvc_info[slot_id]) < 0) { syslog(LOG_WARNING, "[%s] Create hsvc_event_handler thread failed for slot%x\n",__func__, slot_id); pthread_mutex_unlock(&hsvc_mutex[slot_id]); return; } IsHotServiceStart[slot_id] = true; pthread_mutex_unlock(&hsvc_mutex[slot_id]); } else { // SLOT INSERTION hsvc_info[slot_id].slot_id = slot_id; hsvc_info[slot_id].action = INSERTION; pthread_mutex_lock(&hsvc_mutex[slot_id]); if ( IsHotServiceStart[slot_id] ) { #ifdef DEBUG syslog(LOG_WARNING, "[%s] Close the previous thread for slot%x\n", __func__, slot_id); #endif pthread_cancel(hsvc_action_tid[slot_id]); } //Create thread for hsvc event detect if (pthread_create(&hsvc_action_tid[slot_id], NULL, hsvc_event_handler, &hsvc_info[slot_id]) < 0) { syslog(LOG_WARNING, "[%s] Create hsvc_event_handler thread failed for slot%x\n",__func__, slot_id); pthread_mutex_unlock(&hsvc_mutex[slot_id]); return; } IsHotServiceStart[slot_id] = true; pthread_mutex_unlock(&hsvc_mutex[slot_id]); } } // End of GPIO_SLOT1/2/3/4_PRSNT_B_N, GPIO_SLOT1/2/3/4_PRSNT_N else if (strncmp(cfg->shadow, "UART_SEL", sizeof(cfg->shadow)) == 0) { if (pal_get_hand_sw(&slot_id)) { slot_id = HAND_SW_BMC; } slot_id = (slot_id >= HAND_SW_BMC) ? HAND_SW_SERVER1 : (slot_id + 1); sprintf(locstr, "%u", slot_id); kv_set("spb_hand_sw", locstr, 0, 0); syslog(LOG_INFO, "change hand_sw location to FRU %s by button", locstr); } else if ((strncmp(cfg->shadow, "SLOT1_POWER_EN", sizeof(cfg->shadow)) == 0) || (strncmp(cfg->shadow, "SLOT2_POWER_EN", sizeof(cfg->shadow)) == 0) || (strncmp(cfg->shadow, "SLOT3_POWER_EN", sizeof(cfg->shadow)) == 0) || (strncmp(cfg->shadow, "SLOT4_POWER_EN", sizeof(cfg->shadow)) == 0) ) // SLOT1/2/3/4_POWER_EN { if (strncmp(cfg->shadow, "SLOT1_POWER_EN", sizeof(cfg->shadow)) == 0) { slot_id = 1; } else if (strncmp(cfg->shadow, "SLOT2_POWER_EN", sizeof(cfg->shadow)) == 0) { slot_id = 2; } else if (strncmp(cfg->shadow, "SLOT3_POWER_EN", sizeof(cfg->shadow)) == 0) { slot_id = 3; } else { slot_id = 4; } if (curr == 1) { // low to high syslog(LOG_WARNING, "[%s] slot%d power enable pin on", __func__,slot_id); #if defined(CONFIG_FBY2_GPV2) if (fby2_get_slot_type(slot_id) == SLOT_TYPE_GPV2) { if (pal_is_server_12v_on(slot_id, &slot_12v)) syslog(LOG_WARNING, "%s : pal_is_server_12v_on failed for slot: %u", __func__, slot_id); if (slot_12v) fru_cahe_init(slot_id); } #endif } else { // high to low syslog(LOG_WARNING, "[%s] slot%d power enable pin off", __func__,slot_id); fby2_common_set_ierr(slot_id,false); } } else if (strncmp(cfg->shadow, "SMB_HOTSWAP_ALERT_N", sizeof(cfg->shadow)) == 0) { if (curr == 0) { if (pthread_create(&hsc_alert_tid, NULL, hsc_alert_handler, NULL)) { syslog(LOG_WARNING, "[%s] Create hsc_alert_handler thread failed", __func__); } } } } static void * latch_open_handler(void *ptr) { uint8_t slot_id = (int)ptr; uint8_t pair_slot_id; uint8_t slot_12v = 1; int ret; int value; char path_slot[128]; char path_pair_slot[128]; int pair_set_type; char vpath[80] = {0}; pthread_detach(pthread_self()); pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); pair_set_type = pal_get_pair_slot_type(slot_id); switch(pair_set_type) { case TYPE_CF_A_SV: case TYPE_GP_A_SV: case TYPE_GPV2_A_SV: if (0 == slot_id%2) pair_slot_id = slot_id - 1; else pair_slot_id = slot_id + 1; sprintf(path_slot, PWR_UTL_LOCK, slot_id); sprintf(path_pair_slot, PWR_UTL_LOCK, pair_slot_id); if ((access(path_slot, F_OK) == 0) || (access(path_pair_slot, F_OK) == 0)) { pthread_mutex_lock(&latch_open_mutex[slot_id]); IsLatchOpenStart[slot_id] = false; pthread_mutex_unlock(&latch_open_mutex[slot_id]); pthread_exit(0); } break; default: sprintf(path_slot, PWR_UTL_LOCK, slot_id); if (access(path_slot, F_OK) == 0) { pthread_mutex_lock(&latch_open_mutex[slot_id]); IsLatchOpenStart[slot_id] = false; pthread_mutex_unlock(&latch_open_mutex[slot_id]); pthread_exit(0); } break; } ret = pal_is_server_12v_on(slot_id, &slot_12v); if (ret < 0) syslog(LOG_WARNING, "%s : pal_is_server_12v_on failed for slot: %u", __func__, slot_id); if (slot_12v) { fby2_common_get_gpio_val("FAN_LATCH_DETECT", &value); // 12V action would be triggered when SLED is pulled out if (value) { // Active 12V off to protect server/device board if(pal_set_server_power(slot_id, SERVER_12V_OFF) < 0) syslog(LOG_WARNING,"%s : server_12v_off failed for slot: %u", __func__, slot_id); } } pthread_mutex_lock(&latch_open_mutex[slot_id]); IsLatchOpenStart[slot_id] = false; pthread_mutex_unlock(&latch_open_mutex[slot_id]); pthread_exit(0); } static void * fan_latch_event_handler(void *ptr) { char cmd[128] = {0}; uint8_t action = (int)ptr; int ret = 0; pthread_mutex_lock(&fan_latch_mutex); IsFanLatchAction = true; pthread_mutex_unlock(&fan_latch_mutex); pthread_detach(pthread_self()); pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); syslog(LOG_WARNING,"%s : action: %u", __func__, action); switch(action) { case OPEN : memset(cmd, 0, sizeof(cmd)); sprintf(cmd, "/usr/local/bin/fscd_end.sh 0"); ret = system(cmd); syslog(LOG_INFO, "fan_latch_event_handler: OPEN ret = %d",ret); break; case CLOSE : memset(cmd, 0, sizeof(cmd)); if (((fby2_common_get_spb_type() == TYPE_SPB_YV250) && (is_slot_missing() == true)) == false) { sprintf(cmd, "/etc/init.d/setup-fan.sh"); ret = system(cmd); syslog(LOG_INFO, "fan_latch_event_handler: CLOSE ret = %d",ret); } break; } pthread_mutex_lock(&fan_latch_mutex); IsFanLatchAction = false; pthread_mutex_unlock(&fan_latch_mutex); pthread_exit(0); } static void * hsvc_event_handler(void *ptr) { int ret=-1; uint8_t value; uint8_t status; char vpath[80] = {0}; char hspath[80] = {0}; char postpath[80] = {0}; char sys_config_path[80] = {0}; char cmd[128] = {0}; char slotrcpath[80] = {0}; char slot_kv[80] = {0}; int i = 0, slot_type; uint8_t server_type; char event_log[80] = {0}; hot_service_info *hsvc_info = (hot_service_info *)ptr; pthread_detach(pthread_self()); switch(hsvc_info->action) { case REMOVAl : usleep(250000); //Delay 250ms to wait for slot present pin status stable ret = pal_is_fru_prsnt(hsvc_info->slot_id, &value); if (ret < 0) { syslog(LOG_ERR, "%s pal_is_fru_prsnt failed for fru: %d\n", __func__, hsvc_info->slot_id); break; } if (value) { printf("Not remove entirely\n"); } else { //Card has been removed sprintf(cmd, "%s slot%u", SLOT_REMOVAL_PRECHECK_SCRIPT, hsvc_info->slot_id); log_system(cmd); pal_baseboard_clock_control(hsvc_info->slot_id, GPIO_VALUE_HIGH); // Disable baseboard clock passing buffer to prevent voltage leakage ret = pal_is_server_12v_on(hsvc_info->slot_id, &value); /* Check whether the system is 12V off or on */ if (ret < 0) { syslog(LOG_ERR, "pal_get_server_power: pal_is_server_12v_on failed"); break; } if (value) { sprintf(event_log, "FRU: %d, %s", hsvc_info->slot_id, fru_prsnt_log_string[2][hsvc_info->slot_id]); syslog(LOG_CRIT, "%s", event_log); //Card removal without 12V-off /* Turn off 12V to given slot when Server/GP/CF be removed brutally */ if (bic_set_slot_12v(hsvc_info->slot_id, 0)) { break; } ret = pal_slot_pair_12V_off(hsvc_info->slot_id); /* Turn off 12V to pair of slots when Server/GP/CF be removed brutally with pair config */ if (0 != ret) printf("pal_slot_pair_12V_off failed for fru: %d\n", hsvc_info->slot_id); } else { sprintf(event_log, "FRU: %d, %s", hsvc_info->slot_id, fru_prsnt_log_string[0][hsvc_info->slot_id]); syslog(LOG_CRIT, "%s", event_log); //Card removal with 12V-off } // Re-init kv list for(i=0; i < sizeof(slot_kv_list)/sizeof(slot_kv_st); i++) { memset(slot_kv, 0, sizeof(slot_kv)); sprintf(slot_kv, slot_kv_list[i].slot_key, hsvc_info->slot_id); if ((ret = pal_set_key_value(slot_kv, slot_kv_list[i].slot_def_val)) < 0) { syslog(LOG_WARNING, "%s pal_set_def_key_value: kv_set failed. %d", __func__, ret); } } // resart sensord sprintf(cmd, "sv stop sensord"); log_system(cmd); sprintf(cmd, "rm -rf /tmp/cache_store/slot%d*", hsvc_info->slot_id); log_system(cmd); sprintf(cmd, "sv start sensord"); log_system(cmd); // Remove FRU when board has been removed sprintf(cmd, "rm -rf /tmp/fruid_slot%d*", hsvc_info->slot_id); log_system(cmd); // Remove post flag file when board has been removed sprintf(postpath, POST_FLAG_FILE, hsvc_info->slot_id); memset(cmd, 0, sizeof(cmd)); sprintf(cmd,"rm %s",postpath); log_system(cmd); // Remove DIMM and CPU related file when board has been removed sprintf(sys_config_path, SYS_CONFIG_FILE, hsvc_info->slot_id); memset(cmd, 0, sizeof(cmd)); sprintf(cmd,"rm %s",sys_config_path); log_system(cmd); // Create file for 12V-on re-init sprintf(hspath, HOTSERVICE_FILE, hsvc_info->slot_id); memset(cmd, 0, sizeof(cmd)); sprintf(cmd,"touch %s",hspath); log_system(cmd); // Assign slot type sprintf(slotrcpath, SLOT_RECORD_FILE, hsvc_info->slot_id); slot_type = fby2_get_slot_type(hsvc_info->slot_id); sprintf(cmd, "echo %d > %s", slot_type, slotrcpath); log_system(cmd); if (slot_type == SLOT_TYPE_SERVER) { // Assign server type server_type = 0xFF; ret = fby2_get_server_type(hsvc_info->slot_id, &server_type); if (ret) { syslog(LOG_ERR, "%s, Get server type failed\n", __func__); } sprintf(slotrcpath, SV_TYPE_RECORD_FILE, hsvc_info->slot_id); sprintf(cmd, "echo %d > %s", server_type, slotrcpath); log_system(cmd); } else if (slot_type == SLOT_TYPE_GPV2) { // Remove GPv2 M.2 DEV INFO for (int dev_id = 2; dev_id < MAX_NUM_DEVS +2; dev_id++) { // 2-base for GPv2 sprintf(sys_config_path, SYS_CONFIG_M2_DEV_FILE, hsvc_info->slot_id +1 , dev_id); sprintf(cmd,"rm %s",sys_config_path); log_system(cmd); } } #if defined(CONFIG_FBY2_GPV2) //clear slot type for detect invalid config syslog(LOG_WARNING, "REMOVAl: SLOT%d empty",hsvc_info->slot_id); fby2_set_slot_type(hsvc_info->slot_id,SLOT_TYPE_NULL); #endif } break; case INSERTION : sleep(5); //Delay 5 seconds to wait for slot present pin status stable ret = pal_is_fru_prsnt(hsvc_info->slot_id, &value); if (ret < 0) { syslog(LOG_ERR, "%s pal_is_fru_prsnt failed for fru: %d\n", __func__, hsvc_info->slot_id); break; } if (value) { //Card has been inserted sprintf(event_log, "FRU: %d, %s", hsvc_info->slot_id, fru_prsnt_log_string[1][hsvc_info->slot_id]); syslog(LOG_CRIT, "%s", event_log); // Create file for 12V-on re-init sprintf(hspath, HOTSERVICE_FILE, hsvc_info->slot_id); memset(cmd, 0, sizeof(cmd)); sprintf(cmd,"touch %s",hspath); log_system(cmd); #if defined(CONFIG_FBY2_GPV2) // Since clear slot type while slot remove (for GPV2 detect invalid config) // get the slot type before hot service as default slot type sprintf(slotrcpath, SLOT_FILE, hsvc_info->slot_id); slot_type = fby2_get_record_slot_type(hsvc_info->slot_id); sprintf(cmd, "echo %d > %s", slot_type, slotrcpath); log_system(cmd); #else // Assign slot type sprintf(slotrcpath, SLOT_RECORD_FILE, hsvc_info->slot_id); slot_type = fby2_get_slot_type(hsvc_info->slot_id); sprintf(cmd, "echo %d > %s", slot_type, slotrcpath); log_system(cmd); #endif pal_set_dev_config_setup(0); // set up device fan config if (slot_type == SLOT_TYPE_SERVER) { // Assign server type server_type = 0xFF; ret = fby2_get_server_type(hsvc_info->slot_id, &server_type); if (ret) { syslog(LOG_ERR, "%s, Get server type failed\n", __func__); } sprintf(slotrcpath, SV_TYPE_RECORD_FILE, hsvc_info->slot_id); sprintf(cmd, "echo %d > %s", server_type, slotrcpath); log_system(cmd); } else if (slot_type == SLOT_TYPE_GPV2) { syslog(LOG_WARNING, "Slot Insert: Slot%u GPV2 SDR and FRU update", hsvc_info->slot_id); pal_set_dev_sdr_setup(hsvc_info->slot_id,0); for (i=1; i<=MAX_NUM_DEVS; i++) dev_fru_complete[hsvc_info->slot_id][i] = DEV_FRU_NOT_COMPLETE; } /* Check whether the system is 12V off or on */ ret = pal_is_server_12v_on(hsvc_info->slot_id, &status); if (ret < 0) { syslog(LOG_ERR, "pal_get_server_power: pal_is_server_12v_on failed"); break; } if (!status) { sprintf(cmd, "/usr/local/bin/power-util slot%u 12V-on &",hsvc_info->slot_id); log_system(cmd); } } else { printf("Not insert entirely\n"); } break; } pthread_mutex_lock(&hsvc_mutex[hsvc_info->slot_id]); IsHotServiceStart[hsvc_info->slot_id] = false; pthread_mutex_unlock(&hsvc_mutex[hsvc_info->slot_id]); pthread_exit(0); } // YV2 static struct gpiopoll_config g_gpios[] = { // shadow, description, edge, handler,oneshot {"FAN_LATCH_DETECT", "GPIOH5", GPIO_EDGE_BOTH, gpio_event_handle, NULL}, {"SLOT1_EJECTOR_LATCH_DETECT_N", "GPIOP0", GPIO_EDGE_BOTH, gpio_event_handle, NULL}, {"SLOT2_EJECTOR_LATCH_DETECT_N", "GPIOP1", GPIO_EDGE_BOTH, gpio_event_handle, NULL}, {"SLOT3_EJECTOR_LATCH_DETECT_N", "GPIOP2", GPIO_EDGE_BOTH, gpio_event_handle, NULL}, {"SLOT4_EJECTOR_LATCH_DETECT_N", "GPIOP3", GPIO_EDGE_BOTH, gpio_event_handle, NULL}, {"SLOT1_PRSNT_B_N", "GPIOZ0", GPIO_EDGE_BOTH, gpio_event_handle, NULL}, {"SLOT2_PRSNT_B_N", "GPIOZ1", GPIO_EDGE_BOTH, gpio_event_handle, NULL}, {"SLOT3_PRSNT_B_N", "GPIOZ2", GPIO_EDGE_BOTH, gpio_event_handle, NULL}, {"SLOT4_PRSNT_B_N", "GPIOZ3", GPIO_EDGE_BOTH, gpio_event_handle, NULL}, {"SLOT1_PRSNT_N", "GPIOAA0", GPIO_EDGE_BOTH, gpio_event_handle, NULL}, {"SLOT2_PRSNT_N", "GPIOAA1", GPIO_EDGE_BOTH, gpio_event_handle, NULL}, {"SLOT3_PRSNT_N", "GPIOAA2", GPIO_EDGE_BOTH, gpio_event_handle, NULL}, {"SLOT4_PRSNT_N", "GPIOAA3", GPIO_EDGE_BOTH, gpio_event_handle, NULL}, {"UART_SEL", "GPIOO3", GPIO_EDGE_FALLING, gpio_event_handle, NULL}, {"SLOT1_POWER_EN", "GPIOI0", GPIO_EDGE_BOTH, gpio_event_handle, NULL}, {"SLOT2_POWER_EN", "GPIOI1", GPIO_EDGE_BOTH, gpio_event_handle, NULL}, {"SLOT3_POWER_EN", "GPIOI2", GPIO_EDGE_BOTH, gpio_event_handle, NULL}, {"SLOT4_POWER_EN", "GPIOI3", GPIO_EDGE_BOTH, gpio_event_handle, NULL}, {"SMB_HOTSWAP_ALERT_N", "GPION7", GPIO_EDGE_FALLING, gpio_event_handle, NULL}, }; // YV2.50 & YV2ND2 static struct gpiopoll_config g_gpios_yv250[] = { // shadow, description, edge, handler,oneshot {"FAN_LATCH_DETECT", "GPIOH5", GPIO_EDGE_BOTH, gpio_event_handle, NULL}, {"SLOT1_EJECTOR_LATCH_DETECT_N", "GPIOP0", GPIO_EDGE_BOTH, gpio_event_handle, NULL}, {"SLOT2_EJECTOR_LATCH_DETECT_N", "GPIOP1", GPIO_EDGE_BOTH, gpio_event_handle, NULL}, {"SLOT3_EJECTOR_LATCH_DETECT_N", "GPIOP2", GPIO_EDGE_BOTH, gpio_event_handle, NULL}, {"SLOT4_EJECTOR_LATCH_DETECT_N", "GPIOP3", GPIO_EDGE_BOTH, gpio_event_handle, NULL}, {"SLOT1_PRSNT_B_N", "GPIOZ0", GPIO_EDGE_BOTH, gpio_event_handle, NULL}, {"SLOT2_PRSNT_B_N", "GPIOZ1", GPIO_EDGE_BOTH, gpio_event_handle, NULL}, {"SLOT3_PRSNT_B_N", "GPIOZ2", GPIO_EDGE_BOTH, gpio_event_handle, NULL}, {"SLOT4_PRSNT_B_N", "GPIOZ3", GPIO_EDGE_BOTH, gpio_event_handle, NULL}, {"SLOT1_PRSNT_N", "GPIOAA0", GPIO_EDGE_BOTH, gpio_event_handle, NULL}, {"SLOT2_PRSNT_N", "GPIOAA1", GPIO_EDGE_BOTH, gpio_event_handle, NULL}, {"SLOT3_PRSNT_N", "GPIOAA2", GPIO_EDGE_BOTH, gpio_event_handle, NULL}, {"SLOT4_PRSNT_N", "GPIOAA3", GPIO_EDGE_BOTH, gpio_event_handle, NULL}, {"UART_SEL", "GPIOG7", GPIO_EDGE_FALLING, gpio_event_handle, NULL}, {"SLOT1_POWER_EN", "GPIOI0", GPIO_EDGE_BOTH, gpio_event_handle, NULL}, {"SLOT2_POWER_EN", "GPIOI1", GPIO_EDGE_BOTH, gpio_event_handle, NULL}, {"SLOT3_POWER_EN", "GPIOI2", GPIO_EDGE_BOTH, gpio_event_handle, NULL}, {"SLOT4_POWER_EN", "GPIOI3", GPIO_EDGE_BOTH, gpio_event_handle, NULL}, {"SMB_HOTSWAP_ALERT_N", "GPION7", GPIO_EDGE_FALLING, gpio_event_handle, NULL}, }; static def_chk_info def_gpio_chk[] = { // { default value, gpio name, gpio num, log } #if DEBUG_ME_EJECTOR_LOG { 0, "SLOT1_EJECTOR_LATCH_DETECT_N", GPIO_SLOT1_EJECTOR_LATCH_DETECT_N, "FRU: 1, GPIO_SLOT1_EJECTOR_LATCH_DETECT_N is \"1\" and SLOT_12v is ON" }, { 0, "SLOT2_EJECTOR_LATCH_DETECT_N", GPIO_SLOT2_EJECTOR_LATCH_DETECT_N, "FRU: 2, GPIO_SLOT2_EJECTOR_LATCH_DETECT_N is \"1\" and SLOT_12v is ON" }, { 0, "SLOT3_EJECTOR_LATCH_DETECT_N", GPIO_SLOT3_EJECTOR_LATCH_DETECT_N, "FRU: 3, GPIO_SLOT3_EJECTOR_LATCH_DETECT_N is \"1\" and SLOT_12v is ON" }, { 0, "SLOT4_EJECTOR_LATCH_DETECT_N", GPIO_SLOT4_EJECTOR_LATCH_DETECT_N, "FRU: 4, GPIO_SLOT4_EJECTOR_LATCH_DETECT_N is \"1\" and SLOT_12v is ON" }, #endif { 0, "FAN_LATCH_DETECT", GPIO_FAN_LATCH_DETECT, "ASSERT: SLED is not seated" }, }; static char* power_enable[] = { 0, "SLOT1_POWER_EN", "SLOT2_POWER_EN", "SLOT3_POWER_EN", "SLOT4_POWER_EN" }; static void slot_latch_check(void) { int slot_id; int value; char vpath[80] = {0}; int fd; char path[128] = {0}; int ret; int def_slot_latch_val = 0; int retry_count = 0; int max_retry_count = 40; for (slot_id = 1; slot_id <= MAX_NUM_SLOTS; slot_id++) { fby2_common_get_gpio_val(gpio_slot_latch[slot_id], &value); if (value != def_slot_latch_val) { sprintf(path, BIC_CACHED_PID, slot_id); while(retry_count < max_retry_count) { fd = open(path, O_WRONLY | O_CREAT, 0666); if (fd < 0) { syslog(LOG_WARNING, "%s: Open file failed for path: %s", __func__, path); retry_count++; continue; } ret = flock(fd, LOCK_EX | LOCK_NB); if (ret) { syslog(LOG_WARNING,"Waiting for bic-cached complete for slot%d",slot_id); retry_count++; sleep(1); } else { break; } } fby2_common_get_gpio_val("FAN_LATCH_DETECT", &value); // 12V action would be triggered when SLED is pulled out // if SLED is seated, log the event that slot latch is open if (!value) { syslog(LOG_CRIT,"FRU: %u, SLOT%u_EJECTOR_LATCH is not closed while in VCubby", slot_id, slot_id); } else { syslog(LOG_CRIT,"FRU: %u, SLOT%u_EJECTOR_LATCH is not closed", slot_id, slot_id); if (pal_set_server_power(slot_id, SERVER_12V_OFF) < 0) syslog(LOG_WARNING,"%s : server_12v_off failed for slot: %d", __func__, slot_id); } flock(fd, LOCK_UN); close(fd); remove(path); retry_count = 0; } } } static void default_gpio_check(void) { int i; int value; char vpath[80] = {0}; for (i=0; i<sizeof(def_gpio_chk)/sizeof(def_chk_info); i++) { fby2_common_get_gpio_val(def_gpio_chk[i].name, &value); if (value != def_gpio_chk[i].def_val) { syslog(LOG_CRIT, "%s", def_gpio_chk[i].log); } } #if defined(CONFIG_FBY2_GPV2) for (i=FRU_SLOT1; i<=FRU_SLOT4; i+=2) { if (fby2_get_slot_type(i) == SLOT_TYPE_GPV2) { fby2_common_get_gpio_val(power_enable[i], &value); if (value) { fru_cahe_init(i); } } } #endif } int main(int argc, void **argv) { int dev, rc, pid_file; uint8_t status = 0; int i; int spb_type; void *res; gpiopoll_desc_t *polldesc = NULL; for(i=1 ;i<MAX_NODES + 1; i++) { pthread_mutex_init(&hsvc_mutex[i], NULL); pthread_mutex_init(&latch_open_mutex[i], NULL); last_ejector_ts[i].tv_sec = 0; } pthread_mutex_init(&fan_latch_mutex, NULL); default_gpio_check(); slot_latch_check(); spb_type = fby2_common_get_spb_type(); pid_file = open("/var/run/gpiointrd.pid", O_CREAT | O_RDWR, 0666); rc = flock(pid_file, LOCK_EX | LOCK_NB); if(rc) { if(EWOULDBLOCK == errno) { syslog(LOG_ERR, "Another gpiointrd instance is running...\n"); exit(-1); } } else { openlog("gpiointrd", LOG_CONS, LOG_DAEMON); syslog(LOG_INFO, "gpiointrd: daemon started"); if (spb_type == TYPE_SPB_YV250 || spb_type == TYPE_SPB_YV2ND2) { polldesc = gpio_poll_open(g_gpios_yv250, sizeof(g_gpios_yv250)/sizeof(g_gpios_yv250[0])); } else { polldesc = gpio_poll_open(g_gpios, sizeof(g_gpios)/sizeof(g_gpios[0])); } if (!polldesc) { syslog(LOG_CRIT, "Cannot start poll operation on GPIOs"); } else { if (pthread_create(&fan_latch_tid, NULL, fan_latch_poll_handler, NULL)) { syslog(LOG_WARNING, "Poll Fan Latch returned error"); } if (gpio_poll(polldesc, POLL_TIMEOUT)) { syslog(LOG_CRIT, "Poll returned error"); } rc = pthread_join(fan_latch_tid, &res); if (rc != 0) { syslog(LOG_WARNING,"Pthread_join fialed error:%s\n", strerror(rc)); } else if (res == PTHREAD_CANCELED) { syslog(LOG_WARNING,"Potential race condition between close and poll"); } gpio_poll_close(polldesc); } } for(i=1; i<MAX_NODES + 1; i++) { pthread_mutex_destroy(&hsvc_mutex[i]); pthread_mutex_destroy(&latch_open_mutex[i]); } pthread_mutex_destroy(&fan_latch_mutex); return 0; }