common/recipes-lib/sdr/files/sdr.c (532 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 <stdlib.h> #include <stdint.h> #include <stdbool.h> #include <math.h> #include <fcntl.h> #include <errno.h> #include <syslog.h> #include <string.h> #include <unistd.h> #include "sdr.h" #define FIELD_RATE_UNIT(x) ((x & (0x07 << 3)) >> 3) #define FIELD_OP(x) ((x & (0x03 << 1)) >> 1) #define FIELD_PERCENTAGE(x) (x & 0x01) #define FIELD_TYPE(x) ((x & (0x03 << 6)) >> 6) #define FIELD_LEN(x) (x & 0x1F) #ifndef ERR_NOT_READY #define ERR_NOT_READY -2 #endif #ifndef MAX_RETRIES_SDR_INIT #define MAX_RETRIES_SDR_INIT 1 #endif #define MAX_NAME_LEN 16 /* Array for BCD Plus definition. */ const char bcd_plus_array[] = "0123456789 -.XXX"; /* Array for 6-Bit ASCII definition. */ const char * ascii_6bit[4] = { " !\"#$%&'()*+,-./", "0123456789:;<=>?", "@ABCDEFGHIJKLMNO", "PQRSTUVWXYZ[\\]^_" }; /* List of all the Sensor Rate Units types. */ const char * sensor_rate_units[] = { "", /* 0x00 */ "per \xC2\xB5s", /* 0x01 */ "per ms", /* 0x02 */ "per s", /* 0x03 */ "per min", /* 0x04 */ "per hour", /* 0x05 */ "per day", /* 0x06 */ "reserved", /* 0x07 */ }; /* List of all the Sensor Base Units types. */ const char * sensor_base_units[] = { "", /* 000 */ "C", /* 001 */ "F", /* 002 */ "K", /* 003 */ "Volts", /* 004 */ "Amps", /* 005 */ "Watts", /* 006 */ "Joules", /* 007 */ "Coulombs", /* 008 */ "VA", /* 009 */ "Nits", /* 010 */ "lumen", /* 011 */ "lux", /* 012 */ "Candela", /* 013 */ "kPa", /* 014 */ "PSI", /* 015 */ "Newton", /* 016 */ "CFM", /* 017 */ "RPM", /* 018 */ "Hz", /* 019 */ "\xC2\xB5s", /* 020 */ "ms", /* 021 */ "sec", /* 022 */ "min", /* 023 */ "hour", /* 024 */ "day", /* 025 */ "week", /* 026 */ "mil", /* 027 */ "inches", /* 028 */ "feet", /* 029 */ "cu in", /* 030 */ "cu feet", /* 031 */ "mm", /* 032 */ "cm", /* 033 */ "m", /* 034 */ "cu cm", /* 035 */ "cu m", /* 036 */ "liters", /* 037 */ "fluid ounce", /* 038 */ "radians", /* 039 */ "steradians", /* 040 */ "revolutions", /* 041 */ "cycles", /* 042 */ "gravities", /* 043 */ "ounce", /* 044 */ "pound", /* 045 */ "ft-lb", /* 046 */ "oz-in", /* 047 */ "gauss", /* 048 */ "gilberts", /* 049 */ "henry", /* 050 */ "millihenry", /* 051 */ "farad", /* 052 */ "microfarad", /* 053 */ "ohms", /* 054 */ "siemens", /* 055 */ "mole", /* 056 */ "becquerel", /* 057 */ "PPM", /* 058 */ "reserved", /* 059 */ "Db", /* 060 */ "DbA", /* 061 */ "DbC", /* 062 */ "gray", /* 063 */ "sievert", /* 064 */ "color temp deg K", /* 065 */ "bit", /* 066 */ "kilobit", /* 067 */ "megabit", /* 068 */ "gigabit", /* 069 */ "B", /* 070 */ "KB", /* 071 */ "MB", /* 072 */ "GB", /* 073 */ "word", /* 074 */ "dword", /* 075 */ "qword", /* 076 */ "line", /* 077 */ "hit", /* 078 */ "miss", /* 079 */ "retry", /* 080 */ "reset", /* 081 */ "overflow", /* 082 */ "underrun", /* 083 */ "collision", /* 084 */ "packets", /* 085 */ "messages", /* 086 */ "characters", /* 087 */ "error", /* 088 */ "correctable error", /* 089 */ "uncorrectable error", /* 090 */ "fatal error", /* 091 */ "grams", /* 092 */ "", /* 093 */ }; /* Get the units of the sensor from the SDR */ static int _sdr_get_sensor_units(sdr_full_t *sdr, uint8_t *op, uint8_t *modifier, char *units) { int ret; uint8_t percent; uint8_t rate_idx; uint8_t base_idx; /* Bits 5:3 */ rate_idx = FIELD_RATE_UNIT(sdr->sensor_units1); /* Bits 2:1 */ *op = FIELD_OP(sdr->sensor_units1); /* Bit 0 */ percent = FIELD_PERCENTAGE(sdr->sensor_units1); base_idx = sdr->sensor_units2; if (*op == 0x0 || *op == 0x3) *modifier = 0; else *modifier = sdr->sensor_units3; if (percent) { sprintf(units, "%%"); } else { if (base_idx >= 0 && base_idx <= MAX_SENSOR_BASE_UNIT) { if (rate_idx > 0 && rate_idx < MAX_SENSOR_RATE_UNIT) { sprintf(units, "%s %s", sensor_base_units[base_idx], sensor_rate_units[rate_idx]); } else { sprintf(units, "%s", sensor_base_units[base_idx]); } } } return 0; } int sdr_get_sensor_units(uint8_t fru, uint8_t snr_num, char *units) { int ret = 0; uint8_t op; uint8_t modifier; sdr_full_t *sdr; sensor_info_t sinfo[MAX_SENSOR_NUM + 1] = {0}; if (pal_sensor_sdr_init(fru, sinfo) < 0) { sdr = NULL; } else { sdr = &sinfo[snr_num].sdr; } if (sdr != NULL) { ret = _sdr_get_sensor_units(sdr, &op, &modifier, units); if (ret < 0) { #ifdef DEBUG syslog(LOG_ERR, "_sdr_get_sensor_units failed for FRU: %d snr_num: %d", fru, snr_num); #endif } } else { ret = pal_get_sensor_units(fru, snr_num, units); if (ret < 0) { #ifdef DEBUG syslog(LOG_ERR, "pal_get_sensor_units failed for FRU: %d snr_num: %d", fru, snr_num); #endif } } return ret; } /* Get the name of the sensor from the SDR */ static int _sdr_get_sensor_name(sdr_full_t *sdr, char *name) { int field_type, field_len; int idx, idx_eff, val; char *str; /* Bits 7:6 */ field_type = FIELD_TYPE(sdr->str_type_len); /* Bits 4:0 */ field_len = FIELD_LEN(sdr->str_type_len) + 1; str = sdr->str; /* Case: length is zero */ if (field_len == 1) { #ifdef DEBUG syslog(LOG_WARNING, "get_sensor_name: str length is 0\n"); #endif return -1; } /* Retrieve field data depending on the type it was stored. */ switch (field_type) { case TYPE_BINARY: /* TODO: Need to add support to read data stored in binary type. */ break; case TYPE_BCD_PLUS: for (idx = 0; idx < field_len - 1; idx++) { name[idx * 2] = bcd_plus_array[(str[idx] >> 4) & 0x0F]; name[idx * 2 + 1] = bcd_plus_array[str[idx] & 0x0F]; } name[idx * 2] = '\0'; break; case TYPE_ASCII_6BIT: idx_eff = idx = 0; while (field_len > 0) { /* 6-Bits => Bits 5:0 of the first byte */ val = str[idx] & 0x3F; name[idx_eff++] = ascii_6bit[(val & 0xF0) >> 4][val & 0x0F]; field_len--; if (field_len > 0) { /* 6-Bits => Bits 3:0 of second byte + Bits 7:6 of first byte. */ val = ((str[idx] & 0xC0) >> 6) | ((str[idx + 1] & 0x0F) << 2); name[idx_eff++] = ascii_6bit[(val & 0xF0) >> 4][val & 0x0F]; field_len--; } if (field_len > 0) { /* 6-Bits => Bits 1:0 of third byte + Bits 7:4 of second byte. */ val = ((str[idx + 1] & 0xF0) >> 4) | ((str[idx + 2] & 0x03) << 4); name[idx_eff++] = ascii_6bit[(val & 0xF0) >> 4][val & 0x0F]; /* 6-Bits => Bits 7:2 of third byte. */ val = ((str[idx + 2] & 0xFC) >> 2); name[idx_eff++] = ascii_6bit[(val & 0xF0) >> 4][val & 0x0F]; field_len--; idx += 3; } } /* Add Null terminator */ name[idx_eff] = '\0'; break; case TYPE_ASCII_8BIT: snprintf(name, field_len, "%s", str); /* Add Null terminator */ name[field_len] = '\0'; break; } return 0; } int sdr_get_sensor_name(uint8_t fru, uint8_t snr_num, char *name) { int ret = 0; sdr_full_t *sdr; sensor_info_t sinfo[MAX_SENSOR_NUM + 1] = {0}; if (pal_sensor_sdr_init(fru, sinfo) < 0) { sdr = NULL; } else { sdr = &sinfo[snr_num].sdr; } if (sdr != NULL) { ret = _sdr_get_sensor_name(sdr, name); if (ret < 0) { #ifdef DEBUG syslog(LOG_ERR, "_sdr_get_sensor_name failed for FRU: %d snr_num: %d", fru, snr_num); #endif } } else { ret = pal_get_sensor_name(fru, snr_num, name); if (ret < 0) { #ifdef DEBUG syslog(LOG_ERR, "pal_get_sensor_name failed for FRU: %d snr_num: %d", fru, snr_num); #endif } } return ret; } /* Get the threshold values from the SDRs */ static int get_sdr_thresh_val(uint8_t fru, sdr_full_t *sdr, uint8_t snr_num, uint8_t thresh, float *value) { int ret; uint8_t m_lsb, m_msb; uint16_t m = 0; uint8_t b_lsb, b_msb; uint16_t b = 0; int8_t b_exp, r_exp; uint8_t thresh_val; switch (thresh) { case UCR_THRESH: thresh_val = sdr->uc_thresh; break; case UNC_THRESH: thresh_val = sdr->unc_thresh; break; case UNR_THRESH: thresh_val = sdr->unr_thresh; break; case LCR_THRESH: thresh_val = sdr->lc_thresh; break; case LNC_THRESH: thresh_val = sdr->lnc_thresh; break; case LNR_THRESH: thresh_val = sdr->lnr_thresh; break; case POS_HYST: thresh_val = sdr->pos_hyst; break; case NEG_HYST: thresh_val = sdr->neg_hyst; break; default: #ifdef DEBUG syslog(LOG_ERR, "get_sdr_thresh_val: reading unknown threshold val"); #endif return -1; } if (pal_convert_sensor_reading(sdr, (int)thresh_val, value) < 0) { return -1; } return 0; } /* * Populate all fields of thresh_sensor_t struct for a particular sensor. * Incase the threshold value is 0 mask the check for that threshvold * value in flag field. */ static int _sdr_get_snr_thresh(uint8_t fru, sdr_full_t *sdr, uint8_t snr_num, thresh_sensor_t *snr) { int ret; int value; float fvalue; uint8_t op, modifier; snr->curr_state = NORMAL_STATE; if (_sdr_get_sensor_name(sdr, snr->name)) { #ifdef DEBUG syslog(LOG_WARNING, "sdr_get_sensor_name: FRU %d: num: 0x%X: reading name" " from SDR failed.", fru, snr_num); #endif return -1; } // TODO: Add support for modifier (Mostly modifier is zero) if (_sdr_get_sensor_units(sdr, &op, &modifier, snr->units)) { #ifdef DEBUG syslog(LOG_WARNING, "sdr_get_sensor_units: FRU %d: num 0x%X: reading units" " from SDR failed.", fru, snr_num); #endif return -1; } if (get_sdr_thresh_val(fru, sdr, snr_num, UCR_THRESH, &fvalue)) { #ifdef DEBUG syslog(LOG_ERR, "get_sdr_thresh_val: failed for FRU: %d, num: 0x%X, %-16s, UCR_THRESH", fru, snr_num, snr->name); #endif } else { snr->ucr_thresh = fvalue; if (!(fvalue)) { snr->flag = CLEARBIT(snr->flag, UCR_THRESH); } } if (get_sdr_thresh_val(fru, sdr, snr_num, UNC_THRESH, &fvalue)) { #ifdef DEBUG syslog(LOG_ERR, "get_sdr_thresh_val: failed for FRU: %d, num: 0x%X, %-16s, UNC_THRESH", fru, snr_num, snr->name); #endif } else { snr->unc_thresh = fvalue; if (!(fvalue)) { snr->flag = CLEARBIT(snr->flag, UNC_THRESH); } } if (get_sdr_thresh_val(fru, sdr, snr_num, UNR_THRESH, &fvalue)) { #ifdef DEBUG syslog(LOG_ERR, "get_sdr_thresh_val: failed for FRU: %d, num: 0x%X, %-16s, UNR_THRESH", fru, snr_num, snr->name); #endif } else { snr->unr_thresh = fvalue; if (!(fvalue)) { snr->flag = CLEARBIT(snr->flag, UNR_THRESH); } } if (get_sdr_thresh_val(fru, sdr, snr_num, LCR_THRESH, &fvalue)) { #ifdef DEBUG syslog(LOG_ERR, "get_sdr_thresh_val: failed for FRU: %d, num: 0x%X, %-16s, LCR_THRESH", fru, snr_num, snr->name); #endif } else { snr->lcr_thresh = fvalue; if (!(fvalue)) { snr->flag = CLEARBIT(snr->flag, LCR_THRESH); } } if (get_sdr_thresh_val(fru, sdr, snr_num, LNC_THRESH, &fvalue)) { #ifdef DEBUG syslog(LOG_ERR, "get_sdr_thresh_val: failed for FRU: %d, num: 0x%X, %-16s, LNC_THRESH", fru, snr_num, snr->name); #endif } else { snr->lnc_thresh = fvalue; if (!(fvalue)) { snr->flag = CLEARBIT(snr->flag, LNC_THRESH); } } if (get_sdr_thresh_val(fru, sdr, snr_num, LNR_THRESH, &fvalue)) { #ifdef DEBUG syslog(LOG_ERR, "get_sdr_thresh_val: failed for FRU: %d, num: 0x%X, %-16s, LNR_THRESH", fru, snr_num, snr->name); #endif } else { snr->lnr_thresh = fvalue; if (!(fvalue)) { snr->flag = CLEARBIT(snr->flag, LNR_THRESH); } } if (get_sdr_thresh_val(fru, sdr, snr_num, POS_HYST, &fvalue)) { #ifdef DEBUG syslog(LOG_ERR, "get_sdr_thresh_val: failed for FRU: %d, num: 0x%X, %-16s, POS_HYST", fru, snr_num, snr->name); #endif } else { snr->pos_hyst = fvalue; } if (get_sdr_thresh_val(fru, sdr, snr_num, NEG_HYST, &fvalue)) { #ifdef DEBUG syslog(LOG_ERR, "get_sdr_thresh_val: failed for FRU: %d, num: 0x%X, %-16s, NEG_HYST", fru, snr_num, snr->name); #endif } else { snr->neg_hyst = fvalue; } return 0; } int sdr_get_snr_thresh(uint8_t fru, uint8_t snr_num, thresh_sensor_t *snr) { int ret = 0; sdr_full_t *sdr; #ifdef DEBUG int cnt = 0; #endif /* DEBUG */ int retry = 0; char fpath[64] = {0}; char initpath[64] = {0}; char initflag[64] = {0}; char fru_name[16]; sensor_info_t sinfo[MAX_SENSOR_NUM + 1] = {0}; ret = pal_sensor_sdr_init(fru, sinfo); while (ret == ERR_NOT_READY) { if (retry++ > MAX_RETRIES_SDR_INIT) { syslog(LOG_INFO, "sdr_get_snr_thresh: failed for fru: %d", fru); return ERR_NOT_READY; } #ifdef DEBUG syslog(LOG_INFO, "sdr_get_snr_thresh: fru: %d, ret: %d cnt: %d", fru, ret, cnt++); #endif /* DEBUG */ msleep(50); ret = pal_sensor_sdr_init(fru, sinfo); } if (ret < 0) { sdr = NULL; } else { sdr = &sinfo[snr_num].sdr; } /* Set all the threshold options set in the flag */ snr->flag = GETMASK(SENSOR_VALID) | GETMASK(UCR_THRESH) | GETMASK(UNC_THRESH) | GETMASK(UNR_THRESH) | GETMASK(LCR_THRESH) | GETMASK(LNC_THRESH) | GETMASK(LNR_THRESH); ret = pal_get_fru_name(fru, fru_name); if (ret < 0) { printf("%s: Fail to get fru%d name\n", __func__, fru); return -1; } sprintf(initpath, INIT_THRESHOLD_BIN, fru_name); if (0 == access(initpath, F_OK)) { // init done sprintf(fpath, THRESHOLD_BIN, fru_name); if (0 == access(fpath, F_OK)) { ret = pal_get_thresh_from_file(fru, snr_num, snr); if (0 != ret) { syslog(LOG_WARNING, "%s: Fail to get threshold from file for slot%d", __func__, fru); return -1; } return ret; } } if (sdr != NULL) { ret = _sdr_get_snr_thresh(fru, sdr, snr_num, snr); if (ret < 0) { #ifdef DEBUG syslog(LOG_ERR, "_sdr_get_snr_thresh failed for FRU: %d snr_num: %d", fru, snr_num); #endif } } else { ret = pal_get_sensor_name(fru, snr_num, snr->name); ret = pal_get_sensor_units(fru, snr_num, snr->units); ret = pal_get_sensor_poll_interval(fru, snr_num, &(snr->poll_interval)); ret = pal_get_sensor_threshold(fru, snr_num, UCR_THRESH, &(snr->ucr_thresh)); if (!(snr->ucr_thresh)) { snr->flag = CLEARBIT(snr->flag, UCR_THRESH); } ret = pal_get_sensor_threshold(fru, snr_num, UNC_THRESH, &(snr->unc_thresh)); if (!(snr->unc_thresh)) { snr->flag = CLEARBIT(snr->flag, UNC_THRESH); } ret = pal_get_sensor_threshold(fru, snr_num, UNR_THRESH, &(snr->unr_thresh)); if (!(snr->unr_thresh)) { snr->flag = CLEARBIT(snr->flag, UNR_THRESH); } ret = pal_get_sensor_threshold(fru, snr_num, LCR_THRESH, &(snr->lcr_thresh)); if (!(snr->lcr_thresh)) { snr->flag = CLEARBIT(snr->flag, LCR_THRESH); } ret = pal_get_sensor_threshold(fru, snr_num, LNC_THRESH, &(snr->lnc_thresh)); if (!(snr->lnc_thresh)) { snr->flag = CLEARBIT(snr->flag, LNC_THRESH); } ret = pal_get_sensor_threshold(fru, snr_num, LNR_THRESH, &(snr->lnr_thresh)); if (!(snr->lnr_thresh)) { snr->flag = CLEARBIT(snr->flag, LNR_THRESH); } ret = pal_get_sensor_threshold(fru, snr_num, POS_HYST, &(snr->pos_hyst)); ret = pal_get_sensor_threshold(fru, snr_num, NEG_HYST, &(snr->neg_hyst)); } pal_sensor_threshold_flag(fru, snr_num, &(snr->flag)); return ret; }