111b9c3b1SVijay Khemka /* 211b9c3b1SVijay Khemka * Copyright (c) 2018 Intel Corporation. 311b9c3b1SVijay Khemka * Copyright (c) 2018-present Facebook. 411b9c3b1SVijay Khemka * 511b9c3b1SVijay Khemka * Licensed under the Apache License, Version 2.0 (the "License"); 611b9c3b1SVijay Khemka * you may not use this file except in compliance with the License. 711b9c3b1SVijay Khemka * You may obtain a copy of the License at 811b9c3b1SVijay Khemka * 911b9c3b1SVijay Khemka * http://www.apache.org/licenses/LICENSE-2.0 1011b9c3b1SVijay Khemka * 1111b9c3b1SVijay Khemka * Unless required by applicable law or agreed to in writing, software 1211b9c3b1SVijay Khemka * distributed under the License is distributed on an "AS IS" BASIS, 1311b9c3b1SVijay Khemka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1411b9c3b1SVijay Khemka * See the License for the specific language governing permissions and 1511b9c3b1SVijay Khemka * limitations under the License. 1611b9c3b1SVijay Khemka */ 1711b9c3b1SVijay Khemka 1811b9c3b1SVijay Khemka #include <ipmid/api.hpp> 1911b9c3b1SVijay Khemka 2011b9c3b1SVijay Khemka #include <boost/algorithm/string/join.hpp> 2111b9c3b1SVijay Khemka #include <nlohmann/json.hpp> 2211b9c3b1SVijay Khemka #include <iostream> 2311b9c3b1SVijay Khemka #include <sstream> 2411b9c3b1SVijay Khemka #include <fstream> 2511b9c3b1SVijay Khemka #include <phosphor-logging/log.hpp> 2611b9c3b1SVijay Khemka #include <sdbusplus/message/types.hpp> 2711b9c3b1SVijay Khemka #include <sdbusplus/timer.hpp> 2811b9c3b1SVijay Khemka #include <storagecommands.hpp> 2911b9c3b1SVijay Khemka 3011b9c3b1SVijay Khemka //---------------------------------------------------------------------- 3111b9c3b1SVijay Khemka // Platform specific functions for storing app data 3211b9c3b1SVijay Khemka //---------------------------------------------------------------------- 3311b9c3b1SVijay Khemka 34*139aa4f0SVijay Khemka static std::string byteToStr(uint8_t byte) 35*139aa4f0SVijay Khemka { 36*139aa4f0SVijay Khemka std::stringstream ss; 37*139aa4f0SVijay Khemka 38*139aa4f0SVijay Khemka ss << std::hex << std::uppercase << std::setfill('0'); 39*139aa4f0SVijay Khemka ss << std::setw(2) << (int)byte; 40*139aa4f0SVijay Khemka 41*139aa4f0SVijay Khemka return ss.str(); 42*139aa4f0SVijay Khemka } 43*139aa4f0SVijay Khemka 4411b9c3b1SVijay Khemka static void toHexStr(std::vector<uint8_t> &bytes, std::string &hexStr) 4511b9c3b1SVijay Khemka { 4611b9c3b1SVijay Khemka std::stringstream stream; 4711b9c3b1SVijay Khemka stream << std::hex << std::uppercase << std::setfill('0'); 4811b9c3b1SVijay Khemka for (const uint8_t byte : bytes) 4911b9c3b1SVijay Khemka { 5011b9c3b1SVijay Khemka stream << std::setw(2) << static_cast<int>(byte); 5111b9c3b1SVijay Khemka } 5211b9c3b1SVijay Khemka hexStr = stream.str(); 5311b9c3b1SVijay Khemka } 5411b9c3b1SVijay Khemka 5511b9c3b1SVijay Khemka static int fromHexStr(const std::string hexStr, std::vector<uint8_t> &data) 5611b9c3b1SVijay Khemka { 5711b9c3b1SVijay Khemka for (unsigned int i = 0; i < hexStr.size(); i += 2) 5811b9c3b1SVijay Khemka { 5911b9c3b1SVijay Khemka try 6011b9c3b1SVijay Khemka { 6111b9c3b1SVijay Khemka data.push_back(static_cast<uint8_t>( 6211b9c3b1SVijay Khemka std::stoul(hexStr.substr(i, 2), nullptr, 16))); 6311b9c3b1SVijay Khemka } 6411b9c3b1SVijay Khemka catch (std::invalid_argument &e) 6511b9c3b1SVijay Khemka { 6611b9c3b1SVijay Khemka phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); 6711b9c3b1SVijay Khemka return -1; 6811b9c3b1SVijay Khemka } 6911b9c3b1SVijay Khemka catch (std::out_of_range &e) 7011b9c3b1SVijay Khemka { 7111b9c3b1SVijay Khemka phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); 7211b9c3b1SVijay Khemka return -1; 7311b9c3b1SVijay Khemka } 7411b9c3b1SVijay Khemka } 7511b9c3b1SVijay Khemka return 0; 7611b9c3b1SVijay Khemka } 7711b9c3b1SVijay Khemka 7811b9c3b1SVijay Khemka namespace fb_oem::ipmi::sel 7911b9c3b1SVijay Khemka { 8011b9c3b1SVijay Khemka 8111b9c3b1SVijay Khemka class SELData 8211b9c3b1SVijay Khemka { 8311b9c3b1SVijay Khemka private: 8411b9c3b1SVijay Khemka nlohmann::json selDataObj; 8511b9c3b1SVijay Khemka 8611b9c3b1SVijay Khemka void flush() 8711b9c3b1SVijay Khemka { 8811b9c3b1SVijay Khemka std::ofstream file(SEL_JSON_DATA_FILE); 8911b9c3b1SVijay Khemka file << selDataObj; 9011b9c3b1SVijay Khemka file.close(); 9111b9c3b1SVijay Khemka } 9211b9c3b1SVijay Khemka 9311b9c3b1SVijay Khemka void init() 9411b9c3b1SVijay Khemka { 9511b9c3b1SVijay Khemka selDataObj[KEY_SEL_VER] = 0x51; 9611b9c3b1SVijay Khemka selDataObj[KEY_SEL_COUNT] = 0; 9711b9c3b1SVijay Khemka selDataObj[KEY_ADD_TIME] = 0xFFFFFFFF; 9811b9c3b1SVijay Khemka selDataObj[KEY_ERASE_TIME] = 0xFFFFFFFF; 9911b9c3b1SVijay Khemka selDataObj[KEY_OPER_SUPP] = 0x02; 10011b9c3b1SVijay Khemka /* Spec indicates that more than 64kB is free */ 10111b9c3b1SVijay Khemka selDataObj[KEY_FREE_SPACE] = 0xFFFF; 10211b9c3b1SVijay Khemka } 10311b9c3b1SVijay Khemka 10411b9c3b1SVijay Khemka public: 10511b9c3b1SVijay Khemka SELData() 10611b9c3b1SVijay Khemka { 10711b9c3b1SVijay Khemka /* Get App data stored in json file */ 10811b9c3b1SVijay Khemka std::ifstream file(SEL_JSON_DATA_FILE); 10911b9c3b1SVijay Khemka if (file) 11011b9c3b1SVijay Khemka { 11111b9c3b1SVijay Khemka file >> selDataObj; 11211b9c3b1SVijay Khemka file.close(); 11311b9c3b1SVijay Khemka } 11411b9c3b1SVijay Khemka 11511b9c3b1SVijay Khemka /* Initialize SelData object if no entries. */ 11611b9c3b1SVijay Khemka if (selDataObj.find(KEY_SEL_COUNT) == selDataObj.end()) 11711b9c3b1SVijay Khemka { 11811b9c3b1SVijay Khemka init(); 11911b9c3b1SVijay Khemka } 12011b9c3b1SVijay Khemka } 12111b9c3b1SVijay Khemka 12211b9c3b1SVijay Khemka int clear() 12311b9c3b1SVijay Khemka { 12411b9c3b1SVijay Khemka /* Clear the complete Sel Json object */ 12511b9c3b1SVijay Khemka selDataObj.clear(); 12611b9c3b1SVijay Khemka /* Reinitialize it with basic data */ 12711b9c3b1SVijay Khemka init(); 12811b9c3b1SVijay Khemka /* Save the erase time */ 12911b9c3b1SVijay Khemka struct timespec selTime = {}; 13011b9c3b1SVijay Khemka if (clock_gettime(CLOCK_REALTIME, &selTime) < 0) 13111b9c3b1SVijay Khemka { 13211b9c3b1SVijay Khemka return -1; 13311b9c3b1SVijay Khemka } 13411b9c3b1SVijay Khemka selDataObj[KEY_ERASE_TIME] = selTime.tv_sec; 13511b9c3b1SVijay Khemka flush(); 13611b9c3b1SVijay Khemka return 0; 13711b9c3b1SVijay Khemka } 13811b9c3b1SVijay Khemka 13911b9c3b1SVijay Khemka uint32_t getCount() 14011b9c3b1SVijay Khemka { 14111b9c3b1SVijay Khemka return selDataObj[KEY_SEL_COUNT]; 14211b9c3b1SVijay Khemka } 14311b9c3b1SVijay Khemka 14411b9c3b1SVijay Khemka void getInfo(GetSELInfoData &info) 14511b9c3b1SVijay Khemka { 14611b9c3b1SVijay Khemka info.selVersion = selDataObj[KEY_SEL_VER]; 14711b9c3b1SVijay Khemka info.entries = selDataObj[KEY_SEL_COUNT]; 14811b9c3b1SVijay Khemka info.freeSpace = selDataObj[KEY_FREE_SPACE]; 14911b9c3b1SVijay Khemka info.addTimeStamp = selDataObj[KEY_ADD_TIME]; 15011b9c3b1SVijay Khemka info.eraseTimeStamp = selDataObj[KEY_ERASE_TIME]; 15111b9c3b1SVijay Khemka info.operationSupport = selDataObj[KEY_OPER_SUPP]; 15211b9c3b1SVijay Khemka } 15311b9c3b1SVijay Khemka 15411b9c3b1SVijay Khemka int getEntry(uint32_t index, std::string &rawStr) 15511b9c3b1SVijay Khemka { 15611b9c3b1SVijay Khemka std::stringstream ss; 15711b9c3b1SVijay Khemka ss << std::hex; 15811b9c3b1SVijay Khemka ss << std::setw(2) << std::setfill('0') << index; 15911b9c3b1SVijay Khemka 16011b9c3b1SVijay Khemka /* Check or the requested SEL Entry, if record is available */ 16111b9c3b1SVijay Khemka if (selDataObj.find(ss.str()) == selDataObj.end()) 16211b9c3b1SVijay Khemka { 16311b9c3b1SVijay Khemka return -1; 16411b9c3b1SVijay Khemka } 16511b9c3b1SVijay Khemka 16611b9c3b1SVijay Khemka rawStr = selDataObj[ss.str()][KEY_SEL_ENTRY_RAW]; 16711b9c3b1SVijay Khemka return 0; 16811b9c3b1SVijay Khemka } 16911b9c3b1SVijay Khemka 17011b9c3b1SVijay Khemka int addEntry(std::string keyStr) 17111b9c3b1SVijay Khemka { 17211b9c3b1SVijay Khemka struct timespec selTime = {}; 17311b9c3b1SVijay Khemka 17411b9c3b1SVijay Khemka if (clock_gettime(CLOCK_REALTIME, &selTime) < 0) 17511b9c3b1SVijay Khemka { 17611b9c3b1SVijay Khemka return -1; 17711b9c3b1SVijay Khemka } 17811b9c3b1SVijay Khemka 17911b9c3b1SVijay Khemka selDataObj[KEY_ADD_TIME] = selTime.tv_sec; 18011b9c3b1SVijay Khemka 18111b9c3b1SVijay Khemka int selCount = selDataObj[KEY_SEL_COUNT]; 18211b9c3b1SVijay Khemka selDataObj[KEY_SEL_COUNT] = ++selCount; 18311b9c3b1SVijay Khemka 18411b9c3b1SVijay Khemka std::stringstream ss; 18511b9c3b1SVijay Khemka ss << std::hex; 18611b9c3b1SVijay Khemka ss << std::setw(2) << std::setfill('0') << selCount; 18711b9c3b1SVijay Khemka 18811b9c3b1SVijay Khemka selDataObj[ss.str()][KEY_SEL_ENTRY_RAW] = keyStr; 18911b9c3b1SVijay Khemka flush(); 19011b9c3b1SVijay Khemka return selCount; 19111b9c3b1SVijay Khemka } 19211b9c3b1SVijay Khemka }; 19311b9c3b1SVijay Khemka 194*139aa4f0SVijay Khemka /* 195*139aa4f0SVijay Khemka * A Function to parse common SEL message, a helper funciton 196*139aa4f0SVijay Khemka * for parseStdSel. 197*139aa4f0SVijay Khemka * 198*139aa4f0SVijay Khemka * Note that this function __CANNOT__ be overriden. 199*139aa4f0SVijay Khemka * To add board specific routine, please override parseStdSel. 200*139aa4f0SVijay Khemka */ 201*139aa4f0SVijay Khemka 202*139aa4f0SVijay Khemka /*Used by decoding ME event*/ 203*139aa4f0SVijay Khemka std::vector<std::string> nmDomName = { 204*139aa4f0SVijay Khemka "Entire Platform", "CPU Subsystem", 205*139aa4f0SVijay Khemka "Memory Subsystem", "HW Protection", 206*139aa4f0SVijay Khemka "High Power I/O subsystem", "Unknown"}; 207*139aa4f0SVijay Khemka 208*139aa4f0SVijay Khemka /* Default log message for unknown type */ 209*139aa4f0SVijay Khemka static void logDefault(uint8_t *data, std::string &errLog) 210*139aa4f0SVijay Khemka { 211*139aa4f0SVijay Khemka errLog = "Unknown"; 212*139aa4f0SVijay Khemka } 213*139aa4f0SVijay Khemka 214*139aa4f0SVijay Khemka static void logSysEvent(uint8_t *data, std::string &errLog) 215*139aa4f0SVijay Khemka { 216*139aa4f0SVijay Khemka if (data[0] == 0xE5) 217*139aa4f0SVijay Khemka { 218*139aa4f0SVijay Khemka errLog = "Cause of Time change - "; 219*139aa4f0SVijay Khemka switch (data[2]) 220*139aa4f0SVijay Khemka { 221*139aa4f0SVijay Khemka case 0x00: 222*139aa4f0SVijay Khemka errLog += "NTP"; 223*139aa4f0SVijay Khemka break; 224*139aa4f0SVijay Khemka case 0x01: 225*139aa4f0SVijay Khemka errLog += "Host RTL"; 226*139aa4f0SVijay Khemka break; 227*139aa4f0SVijay Khemka case 0x02: 228*139aa4f0SVijay Khemka errLog += "Set SEL time cmd"; 229*139aa4f0SVijay Khemka break; 230*139aa4f0SVijay Khemka case 0x03: 231*139aa4f0SVijay Khemka errLog += "Set SEL time UTC offset cmd"; 232*139aa4f0SVijay Khemka break; 233*139aa4f0SVijay Khemka default: 234*139aa4f0SVijay Khemka errLog += "Unknown"; 235*139aa4f0SVijay Khemka } 236*139aa4f0SVijay Khemka 237*139aa4f0SVijay Khemka if (data[1] == 0x00) 238*139aa4f0SVijay Khemka errLog += " - First Time"; 239*139aa4f0SVijay Khemka else if (data[1] == 0x80) 240*139aa4f0SVijay Khemka errLog += " - Second Time"; 241*139aa4f0SVijay Khemka } 242*139aa4f0SVijay Khemka else 243*139aa4f0SVijay Khemka { 244*139aa4f0SVijay Khemka errLog = "Unknown"; 245*139aa4f0SVijay Khemka } 246*139aa4f0SVijay Khemka } 247*139aa4f0SVijay Khemka 248*139aa4f0SVijay Khemka static void logThermalEvent(uint8_t *data, std::string &errLog) 249*139aa4f0SVijay Khemka { 250*139aa4f0SVijay Khemka if (data[0] == 0x1) 251*139aa4f0SVijay Khemka { 252*139aa4f0SVijay Khemka errLog = "Limit Exceeded"; 253*139aa4f0SVijay Khemka } 254*139aa4f0SVijay Khemka else 255*139aa4f0SVijay Khemka { 256*139aa4f0SVijay Khemka errLog = "Unknown"; 257*139aa4f0SVijay Khemka } 258*139aa4f0SVijay Khemka } 259*139aa4f0SVijay Khemka 260*139aa4f0SVijay Khemka static void logCritIrq(uint8_t *data, std::string &errLog) 261*139aa4f0SVijay Khemka { 262*139aa4f0SVijay Khemka 263*139aa4f0SVijay Khemka if (data[0] == 0x0) 264*139aa4f0SVijay Khemka { 265*139aa4f0SVijay Khemka errLog = "NMI / Diagnostic Interrupt"; 266*139aa4f0SVijay Khemka } 267*139aa4f0SVijay Khemka else if (data[0] == 0x03) 268*139aa4f0SVijay Khemka { 269*139aa4f0SVijay Khemka errLog = "Software NMI"; 270*139aa4f0SVijay Khemka } 271*139aa4f0SVijay Khemka else 272*139aa4f0SVijay Khemka { 273*139aa4f0SVijay Khemka errLog = "Unknown"; 274*139aa4f0SVijay Khemka } 275*139aa4f0SVijay Khemka 276*139aa4f0SVijay Khemka /* TODO: Call add_cri_sel for CRITICAL_IRQ */ 277*139aa4f0SVijay Khemka } 278*139aa4f0SVijay Khemka 279*139aa4f0SVijay Khemka static void logPostErr(uint8_t *data, std::string &errLog) 280*139aa4f0SVijay Khemka { 281*139aa4f0SVijay Khemka 282*139aa4f0SVijay Khemka if ((data[0] & 0x0F) == 0x0) 283*139aa4f0SVijay Khemka { 284*139aa4f0SVijay Khemka errLog = "System Firmware Error"; 285*139aa4f0SVijay Khemka } 286*139aa4f0SVijay Khemka else 287*139aa4f0SVijay Khemka { 288*139aa4f0SVijay Khemka errLog = "Unknown"; 289*139aa4f0SVijay Khemka } 290*139aa4f0SVijay Khemka 291*139aa4f0SVijay Khemka if (((data[0] >> 6) & 0x03) == 0x3) 292*139aa4f0SVijay Khemka { 293*139aa4f0SVijay Khemka // TODO: Need to implement IPMI spec based Post Code 294*139aa4f0SVijay Khemka errLog += ", IPMI Post Code"; 295*139aa4f0SVijay Khemka } 296*139aa4f0SVijay Khemka else if (((data[0] >> 6) & 0x03) == 0x2) 297*139aa4f0SVijay Khemka { 298*139aa4f0SVijay Khemka errLog += 299*139aa4f0SVijay Khemka ", OEM Post Code 0x" + byteToStr(data[2]) + byteToStr(data[1]); 300*139aa4f0SVijay Khemka 301*139aa4f0SVijay Khemka switch ((data[2] << 8) | data[1]) 302*139aa4f0SVijay Khemka { 303*139aa4f0SVijay Khemka case 0xA105: 304*139aa4f0SVijay Khemka errLog += ", BMC Failed (No Response)"; 305*139aa4f0SVijay Khemka break; 306*139aa4f0SVijay Khemka case 0xA106: 307*139aa4f0SVijay Khemka errLog += ", BMC Failed (Self Test Fail)"; 308*139aa4f0SVijay Khemka break; 309*139aa4f0SVijay Khemka case 0xA10A: 310*139aa4f0SVijay Khemka errLog += ", System Firmware Corruption Detected"; 311*139aa4f0SVijay Khemka break; 312*139aa4f0SVijay Khemka case 0xA10B: 313*139aa4f0SVijay Khemka errLog += ", TPM Self-Test FAIL Detected"; 314*139aa4f0SVijay Khemka } 315*139aa4f0SVijay Khemka } 316*139aa4f0SVijay Khemka } 317*139aa4f0SVijay Khemka 318*139aa4f0SVijay Khemka static void logMchChkErr(uint8_t *data, std::string &errLog) 319*139aa4f0SVijay Khemka { 320*139aa4f0SVijay Khemka /* TODO: Call add_cri_sel for CRITICAL_IRQ */ 321*139aa4f0SVijay Khemka if ((data[0] & 0x0F) == 0x0B) 322*139aa4f0SVijay Khemka { 323*139aa4f0SVijay Khemka errLog = "Uncorrectable"; 324*139aa4f0SVijay Khemka } 325*139aa4f0SVijay Khemka else if ((data[0] & 0x0F) == 0x0C) 326*139aa4f0SVijay Khemka { 327*139aa4f0SVijay Khemka errLog = "Correctable"; 328*139aa4f0SVijay Khemka } 329*139aa4f0SVijay Khemka else 330*139aa4f0SVijay Khemka { 331*139aa4f0SVijay Khemka errLog = "Unknown"; 332*139aa4f0SVijay Khemka } 333*139aa4f0SVijay Khemka 334*139aa4f0SVijay Khemka errLog += ", Machine Check bank Number " + std::to_string(data[1]) + 335*139aa4f0SVijay Khemka ", CPU " + std::to_string(data[2] >> 5) + ", Core " + 336*139aa4f0SVijay Khemka std::to_string(data[2] & 0x1F); 337*139aa4f0SVijay Khemka } 338*139aa4f0SVijay Khemka 339*139aa4f0SVijay Khemka static void logPcieErr(uint8_t *data, std::string &errLog) 340*139aa4f0SVijay Khemka { 341*139aa4f0SVijay Khemka std::stringstream tmp1, tmp2; 342*139aa4f0SVijay Khemka tmp1 << std::hex << std::uppercase << std::setfill('0'); 343*139aa4f0SVijay Khemka tmp2 << std::hex << std::uppercase << std::setfill('0'); 344*139aa4f0SVijay Khemka tmp1 << " (Bus " << std::setw(2) << (int)(data[2]) << " / Dev " 345*139aa4f0SVijay Khemka << std::setw(2) << (int)(data[1] >> 3) << " / Fun " << std::setw(2) 346*139aa4f0SVijay Khemka << (int)(data[1] & 0x7) << ")"; 347*139aa4f0SVijay Khemka 348*139aa4f0SVijay Khemka switch (data[0] & 0xF) 349*139aa4f0SVijay Khemka { 350*139aa4f0SVijay Khemka case 0x4: 351*139aa4f0SVijay Khemka errLog = "PCI PERR" + tmp1.str(); 352*139aa4f0SVijay Khemka break; 353*139aa4f0SVijay Khemka case 0x5: 354*139aa4f0SVijay Khemka errLog = "PCI SERR" + tmp1.str(); 355*139aa4f0SVijay Khemka break; 356*139aa4f0SVijay Khemka case 0x7: 357*139aa4f0SVijay Khemka errLog = "Correctable" + tmp1.str(); 358*139aa4f0SVijay Khemka break; 359*139aa4f0SVijay Khemka case 0x8: 360*139aa4f0SVijay Khemka errLog = "Uncorrectable" + tmp1.str(); 361*139aa4f0SVijay Khemka break; 362*139aa4f0SVijay Khemka case 0xA: 363*139aa4f0SVijay Khemka errLog = "Bus Fatal" + tmp1.str(); 364*139aa4f0SVijay Khemka break; 365*139aa4f0SVijay Khemka case 0xD: 366*139aa4f0SVijay Khemka { 367*139aa4f0SVijay Khemka uint32_t venId = (uint32_t)data[1] << 8 | (uint32_t)data[2]; 368*139aa4f0SVijay Khemka tmp2 << "Vendor ID: 0x" << std::setw(4) << venId; 369*139aa4f0SVijay Khemka errLog = tmp2.str(); 370*139aa4f0SVijay Khemka } 371*139aa4f0SVijay Khemka break; 372*139aa4f0SVijay Khemka case 0xE: 373*139aa4f0SVijay Khemka { 374*139aa4f0SVijay Khemka uint32_t devId = (uint32_t)data[1] << 8 | (uint32_t)data[2]; 375*139aa4f0SVijay Khemka tmp2 << "Device ID: 0x" << std::setw(4) << devId; 376*139aa4f0SVijay Khemka errLog = tmp2.str(); 377*139aa4f0SVijay Khemka } 378*139aa4f0SVijay Khemka break; 379*139aa4f0SVijay Khemka case 0xF: 380*139aa4f0SVijay Khemka tmp2 << "Error ID from downstream: 0x" << std::setw(2) 381*139aa4f0SVijay Khemka << (int)(data[1]) << std::setw(2) << (int)(data[2]); 382*139aa4f0SVijay Khemka errLog = tmp2.str(); 383*139aa4f0SVijay Khemka break; 384*139aa4f0SVijay Khemka default: 385*139aa4f0SVijay Khemka errLog = "Unknown"; 386*139aa4f0SVijay Khemka } 387*139aa4f0SVijay Khemka } 388*139aa4f0SVijay Khemka 389*139aa4f0SVijay Khemka static void logIioErr(uint8_t *data, std::string &errLog) 390*139aa4f0SVijay Khemka { 391*139aa4f0SVijay Khemka std::vector<std::string> tmpStr = { 392*139aa4f0SVijay Khemka "IRP0", "IRP1", " IIO-Core", "VT-d", "Intel Quick Data", 393*139aa4f0SVijay Khemka "Misc", " DMA", "ITC", "OTC", "CI"}; 394*139aa4f0SVijay Khemka 395*139aa4f0SVijay Khemka if ((data[0] & 0xF) == 0) 396*139aa4f0SVijay Khemka { 397*139aa4f0SVijay Khemka errLog += "CPU " + std::to_string(data[2] >> 5) + ", Error ID 0x" + 398*139aa4f0SVijay Khemka byteToStr(data[1]) + " - "; 399*139aa4f0SVijay Khemka 400*139aa4f0SVijay Khemka if ((data[2] & 0xF) <= 0x9) 401*139aa4f0SVijay Khemka { 402*139aa4f0SVijay Khemka errLog += tmpStr[(data[2] & 0xF)]; 403*139aa4f0SVijay Khemka } 404*139aa4f0SVijay Khemka else 405*139aa4f0SVijay Khemka { 406*139aa4f0SVijay Khemka errLog += "Reserved"; 407*139aa4f0SVijay Khemka } 408*139aa4f0SVijay Khemka } 409*139aa4f0SVijay Khemka else 410*139aa4f0SVijay Khemka { 411*139aa4f0SVijay Khemka errLog = "Unknown"; 412*139aa4f0SVijay Khemka } 413*139aa4f0SVijay Khemka } 414*139aa4f0SVijay Khemka 415*139aa4f0SVijay Khemka static void logMemErr(uint8_t *dataPtr, std::string &errLog) 416*139aa4f0SVijay Khemka { 417*139aa4f0SVijay Khemka uint8_t snrType = dataPtr[0]; 418*139aa4f0SVijay Khemka uint8_t snrNum = dataPtr[1]; 419*139aa4f0SVijay Khemka uint8_t *data = &(dataPtr[3]); 420*139aa4f0SVijay Khemka 421*139aa4f0SVijay Khemka /* TODO: add pal_add_cri_sel */ 422*139aa4f0SVijay Khemka 423*139aa4f0SVijay Khemka if (snrNum == memoryEccError) 424*139aa4f0SVijay Khemka { 425*139aa4f0SVijay Khemka /* SEL from MEMORY_ECC_ERR Sensor */ 426*139aa4f0SVijay Khemka switch (data[0] & 0x0F) 427*139aa4f0SVijay Khemka { 428*139aa4f0SVijay Khemka case 0x0: 429*139aa4f0SVijay Khemka if (snrType == 0x0C) 430*139aa4f0SVijay Khemka { 431*139aa4f0SVijay Khemka errLog = "Correctable"; 432*139aa4f0SVijay Khemka } 433*139aa4f0SVijay Khemka else if (snrType == 0x10) 434*139aa4f0SVijay Khemka { 435*139aa4f0SVijay Khemka errLog = "Correctable ECC error Logging Disabled"; 436*139aa4f0SVijay Khemka } 437*139aa4f0SVijay Khemka break; 438*139aa4f0SVijay Khemka case 0x1: 439*139aa4f0SVijay Khemka errLog = "Uncorrectable"; 440*139aa4f0SVijay Khemka break; 441*139aa4f0SVijay Khemka case 0x5: 442*139aa4f0SVijay Khemka errLog = "Correctable ECC error Logging Limit Disabled"; 443*139aa4f0SVijay Khemka break; 444*139aa4f0SVijay Khemka default: 445*139aa4f0SVijay Khemka errLog = "Unknown"; 446*139aa4f0SVijay Khemka } 447*139aa4f0SVijay Khemka } 448*139aa4f0SVijay Khemka else if (snrNum == memoryErrLogDIS) 449*139aa4f0SVijay Khemka { 450*139aa4f0SVijay Khemka // SEL from MEMORY_ERR_LOG_DIS Sensor 451*139aa4f0SVijay Khemka if ((data[0] & 0x0F) == 0x0) 452*139aa4f0SVijay Khemka { 453*139aa4f0SVijay Khemka errLog = "Correctable Memory Error Logging Disabled"; 454*139aa4f0SVijay Khemka } 455*139aa4f0SVijay Khemka else 456*139aa4f0SVijay Khemka { 457*139aa4f0SVijay Khemka errLog = "Unknown"; 458*139aa4f0SVijay Khemka } 459*139aa4f0SVijay Khemka } 460*139aa4f0SVijay Khemka else 461*139aa4f0SVijay Khemka { 462*139aa4f0SVijay Khemka errLog = "Unknown"; 463*139aa4f0SVijay Khemka return; 464*139aa4f0SVijay Khemka } 465*139aa4f0SVijay Khemka 466*139aa4f0SVijay Khemka /* Common routine for both MEM_ECC_ERR and MEMORY_ERR_LOG_DIS */ 467*139aa4f0SVijay Khemka 468*139aa4f0SVijay Khemka errLog += " (DIMM " + byteToStr(data[2]) + ") Logical Rank " + 469*139aa4f0SVijay Khemka std::to_string(data[1] & 0x03); 470*139aa4f0SVijay Khemka 471*139aa4f0SVijay Khemka /* DIMM number (data[2]): 472*139aa4f0SVijay Khemka * Bit[7:5]: Socket number (Range: 0-7) 473*139aa4f0SVijay Khemka * Bit[4:3]: Channel number (Range: 0-3) 474*139aa4f0SVijay Khemka * Bit[2:0]: DIMM number (Range: 0-7) 475*139aa4f0SVijay Khemka */ 476*139aa4f0SVijay Khemka 477*139aa4f0SVijay Khemka /* TODO: Verify these bits */ 478*139aa4f0SVijay Khemka std::string cpuStr = "CPU# " + std::to_string((data[2] & 0xE0) >> 5); 479*139aa4f0SVijay Khemka std::string chStr = "CHN# " + std::to_string((data[2] & 0x18) >> 3); 480*139aa4f0SVijay Khemka std::string dimmStr = "DIMM# " + std::to_string(data[2] & 0x7); 481*139aa4f0SVijay Khemka 482*139aa4f0SVijay Khemka switch ((data[1] & 0xC) >> 2) 483*139aa4f0SVijay Khemka { 484*139aa4f0SVijay Khemka case 0x0: 485*139aa4f0SVijay Khemka { 486*139aa4f0SVijay Khemka 487*139aa4f0SVijay Khemka /* All Info Valid */ 488*139aa4f0SVijay Khemka uint8_t chnNum = (data[2] & 0x1C) >> 2; 489*139aa4f0SVijay Khemka uint8_t dimmNum = data[2] & 0x3; 490*139aa4f0SVijay Khemka 491*139aa4f0SVijay Khemka /* TODO: If critical SEL logging is available, do it */ 492*139aa4f0SVijay Khemka if (snrType == 0x0C) 493*139aa4f0SVijay Khemka { 494*139aa4f0SVijay Khemka if ((data[0] & 0x0F) == 0x0) 495*139aa4f0SVijay Khemka { 496*139aa4f0SVijay Khemka /* TODO: add_cri_sel */ 497*139aa4f0SVijay Khemka /* "DIMM"+ 'A'+ chnNum + dimmNum + " ECC err,FRU:1" 498*139aa4f0SVijay Khemka */ 499*139aa4f0SVijay Khemka } 500*139aa4f0SVijay Khemka else if ((data[0] & 0x0F) == 0x1) 501*139aa4f0SVijay Khemka { 502*139aa4f0SVijay Khemka /* TODO: add_cri_sel */ 503*139aa4f0SVijay Khemka /* "DIMM"+ 'A'+ chnNum + dimmNum + " UECC err,FRU:1" 504*139aa4f0SVijay Khemka */ 505*139aa4f0SVijay Khemka } 506*139aa4f0SVijay Khemka } 507*139aa4f0SVijay Khemka /* Continue to parse the error into a string. All Info Valid 508*139aa4f0SVijay Khemka */ 509*139aa4f0SVijay Khemka errLog += " (" + cpuStr + ", " + chStr + ", " + dimmStr + ")"; 510*139aa4f0SVijay Khemka } 511*139aa4f0SVijay Khemka 512*139aa4f0SVijay Khemka break; 513*139aa4f0SVijay Khemka case 0x1: 514*139aa4f0SVijay Khemka 515*139aa4f0SVijay Khemka /* DIMM info not valid */ 516*139aa4f0SVijay Khemka errLog += " (" + cpuStr + ", " + chStr + ")"; 517*139aa4f0SVijay Khemka break; 518*139aa4f0SVijay Khemka case 0x2: 519*139aa4f0SVijay Khemka 520*139aa4f0SVijay Khemka /* CHN info not valid */ 521*139aa4f0SVijay Khemka errLog += " (" + cpuStr + ", " + dimmStr + ")"; 522*139aa4f0SVijay Khemka break; 523*139aa4f0SVijay Khemka case 0x3: 524*139aa4f0SVijay Khemka 525*139aa4f0SVijay Khemka /* CPU info not valid */ 526*139aa4f0SVijay Khemka errLog += " (" + chStr + ", " + dimmStr + ")"; 527*139aa4f0SVijay Khemka break; 528*139aa4f0SVijay Khemka } 529*139aa4f0SVijay Khemka } 530*139aa4f0SVijay Khemka 531*139aa4f0SVijay Khemka static void logPwrErr(uint8_t *data, std::string &errLog) 532*139aa4f0SVijay Khemka { 533*139aa4f0SVijay Khemka 534*139aa4f0SVijay Khemka if (data[0] == 0x1) 535*139aa4f0SVijay Khemka { 536*139aa4f0SVijay Khemka errLog = "SYS_PWROK failure"; 537*139aa4f0SVijay Khemka /* Also try logging to Critial log file, if available */ 538*139aa4f0SVijay Khemka /* "SYS_PWROK failure,FRU:1" */ 539*139aa4f0SVijay Khemka } 540*139aa4f0SVijay Khemka else if (data[0] == 0x2) 541*139aa4f0SVijay Khemka { 542*139aa4f0SVijay Khemka errLog = "PCH_PWROK failure"; 543*139aa4f0SVijay Khemka /* Also try logging to Critial log file, if available */ 544*139aa4f0SVijay Khemka /* "PCH_PWROK failure,FRU:1" */ 545*139aa4f0SVijay Khemka } 546*139aa4f0SVijay Khemka else 547*139aa4f0SVijay Khemka { 548*139aa4f0SVijay Khemka errLog = "Unknown"; 549*139aa4f0SVijay Khemka } 550*139aa4f0SVijay Khemka } 551*139aa4f0SVijay Khemka 552*139aa4f0SVijay Khemka static void logCatErr(uint8_t *data, std::string &errLog) 553*139aa4f0SVijay Khemka { 554*139aa4f0SVijay Khemka 555*139aa4f0SVijay Khemka if (data[0] == 0x0) 556*139aa4f0SVijay Khemka { 557*139aa4f0SVijay Khemka errLog = "IERR/CATERR"; 558*139aa4f0SVijay Khemka /* Also try logging to Critial log file, if available */ 559*139aa4f0SVijay Khemka /* "IERR,FRU:1 */ 560*139aa4f0SVijay Khemka } 561*139aa4f0SVijay Khemka else if (data[0] == 0xB) 562*139aa4f0SVijay Khemka { 563*139aa4f0SVijay Khemka errLog = "MCERR/CATERR"; 564*139aa4f0SVijay Khemka /* Also try logging to Critial log file, if available */ 565*139aa4f0SVijay Khemka /* "MCERR,FRU:1 */ 566*139aa4f0SVijay Khemka } 567*139aa4f0SVijay Khemka else 568*139aa4f0SVijay Khemka { 569*139aa4f0SVijay Khemka errLog = "Unknown"; 570*139aa4f0SVijay Khemka } 571*139aa4f0SVijay Khemka } 572*139aa4f0SVijay Khemka 573*139aa4f0SVijay Khemka static void logDimmHot(uint8_t *data, std::string &errLog) 574*139aa4f0SVijay Khemka { 575*139aa4f0SVijay Khemka if ((data[0] << 16 | data[1] << 8 | data[2]) == 0x01FFFF) 576*139aa4f0SVijay Khemka { 577*139aa4f0SVijay Khemka errLog = "SOC MEMHOT"; 578*139aa4f0SVijay Khemka } 579*139aa4f0SVijay Khemka else 580*139aa4f0SVijay Khemka { 581*139aa4f0SVijay Khemka errLog = "Unknown"; 582*139aa4f0SVijay Khemka /* Also try logging to Critial log file, if available */ 583*139aa4f0SVijay Khemka /* ""CPU_DIMM_HOT %s,FRU:1" */ 584*139aa4f0SVijay Khemka } 585*139aa4f0SVijay Khemka } 586*139aa4f0SVijay Khemka 587*139aa4f0SVijay Khemka static void logSwNMI(uint8_t *data, std::string &errLog) 588*139aa4f0SVijay Khemka { 589*139aa4f0SVijay Khemka if ((data[0] << 16 | data[1] << 8 | data[2]) == 0x03FFFF) 590*139aa4f0SVijay Khemka { 591*139aa4f0SVijay Khemka errLog = "Software NMI"; 592*139aa4f0SVijay Khemka } 593*139aa4f0SVijay Khemka else 594*139aa4f0SVijay Khemka { 595*139aa4f0SVijay Khemka errLog = "Unknown SW NMI"; 596*139aa4f0SVijay Khemka } 597*139aa4f0SVijay Khemka } 598*139aa4f0SVijay Khemka 599*139aa4f0SVijay Khemka static void logCPUThermalSts(uint8_t *data, std::string &errLog) 600*139aa4f0SVijay Khemka { 601*139aa4f0SVijay Khemka switch (data[0]) 602*139aa4f0SVijay Khemka { 603*139aa4f0SVijay Khemka case 0x0: 604*139aa4f0SVijay Khemka errLog = "CPU Critical Temperature"; 605*139aa4f0SVijay Khemka break; 606*139aa4f0SVijay Khemka case 0x1: 607*139aa4f0SVijay Khemka errLog = "PROCHOT#"; 608*139aa4f0SVijay Khemka break; 609*139aa4f0SVijay Khemka case 0x2: 610*139aa4f0SVijay Khemka errLog = "TCC Activation"; 611*139aa4f0SVijay Khemka break; 612*139aa4f0SVijay Khemka default: 613*139aa4f0SVijay Khemka errLog = "Unknown"; 614*139aa4f0SVijay Khemka } 615*139aa4f0SVijay Khemka } 616*139aa4f0SVijay Khemka 617*139aa4f0SVijay Khemka static void logMEPwrState(uint8_t *data, std::string &errLog) 618*139aa4f0SVijay Khemka { 619*139aa4f0SVijay Khemka switch (data[0]) 620*139aa4f0SVijay Khemka { 621*139aa4f0SVijay Khemka case 0: 622*139aa4f0SVijay Khemka errLog = "RUNNING"; 623*139aa4f0SVijay Khemka break; 624*139aa4f0SVijay Khemka case 2: 625*139aa4f0SVijay Khemka errLog = "POWER_OFF"; 626*139aa4f0SVijay Khemka break; 627*139aa4f0SVijay Khemka default: 628*139aa4f0SVijay Khemka errLog = "Unknown[" + std::to_string(data[0]) + "]"; 629*139aa4f0SVijay Khemka break; 630*139aa4f0SVijay Khemka } 631*139aa4f0SVijay Khemka } 632*139aa4f0SVijay Khemka 633*139aa4f0SVijay Khemka static void logSPSFwHealth(uint8_t *data, std::string &errLog) 634*139aa4f0SVijay Khemka { 635*139aa4f0SVijay Khemka if ((data[0] & 0x0F) == 0x00) 636*139aa4f0SVijay Khemka { 637*139aa4f0SVijay Khemka const std::vector<std::string> tmpStr = { 638*139aa4f0SVijay Khemka "Recovery GPIO forced", 639*139aa4f0SVijay Khemka "Image execution failed", 640*139aa4f0SVijay Khemka "Flash erase error", 641*139aa4f0SVijay Khemka "Flash state information", 642*139aa4f0SVijay Khemka "Internal error", 643*139aa4f0SVijay Khemka "BMC did not respond", 644*139aa4f0SVijay Khemka "Direct Flash update", 645*139aa4f0SVijay Khemka "Manufacturing error", 646*139aa4f0SVijay Khemka "Automatic Restore to Factory Presets", 647*139aa4f0SVijay Khemka "Firmware Exception", 648*139aa4f0SVijay Khemka "Flash Wear-Out Protection Warning", 649*139aa4f0SVijay Khemka "Unknown", 650*139aa4f0SVijay Khemka "Unknown", 651*139aa4f0SVijay Khemka "DMI interface error", 652*139aa4f0SVijay Khemka "MCTP interface error", 653*139aa4f0SVijay Khemka "Auto-configuration finished", 654*139aa4f0SVijay Khemka "Unsupported Segment Defined Feature", 655*139aa4f0SVijay Khemka "Unknown", 656*139aa4f0SVijay Khemka "CPU Debug Capability Disabled", 657*139aa4f0SVijay Khemka "UMA operation error"}; 658*139aa4f0SVijay Khemka 659*139aa4f0SVijay Khemka if (data[1] < 0x14) 660*139aa4f0SVijay Khemka { 661*139aa4f0SVijay Khemka errLog = tmpStr[data[1]]; 662*139aa4f0SVijay Khemka } 663*139aa4f0SVijay Khemka else 664*139aa4f0SVijay Khemka { 665*139aa4f0SVijay Khemka errLog = "Unknown"; 666*139aa4f0SVijay Khemka } 667*139aa4f0SVijay Khemka } 668*139aa4f0SVijay Khemka else if ((data[0] & 0x0F) == 0x01) 669*139aa4f0SVijay Khemka { 670*139aa4f0SVijay Khemka errLog = "SMBus link failure"; 671*139aa4f0SVijay Khemka } 672*139aa4f0SVijay Khemka else 673*139aa4f0SVijay Khemka { 674*139aa4f0SVijay Khemka errLog = "Unknown"; 675*139aa4f0SVijay Khemka } 676*139aa4f0SVijay Khemka } 677*139aa4f0SVijay Khemka 678*139aa4f0SVijay Khemka static void logNmExcA(uint8_t *data, std::string &errLog) 679*139aa4f0SVijay Khemka { 680*139aa4f0SVijay Khemka /*NM4.0 #550710, Revision 1.95, and turn to p.155*/ 681*139aa4f0SVijay Khemka if (data[0] == 0xA8) 682*139aa4f0SVijay Khemka { 683*139aa4f0SVijay Khemka errLog = "Policy Correction Time Exceeded"; 684*139aa4f0SVijay Khemka } 685*139aa4f0SVijay Khemka else 686*139aa4f0SVijay Khemka { 687*139aa4f0SVijay Khemka errLog = "Unknown"; 688*139aa4f0SVijay Khemka } 689*139aa4f0SVijay Khemka } 690*139aa4f0SVijay Khemka 691*139aa4f0SVijay Khemka static void logPCHThermal(uint8_t *data, std::string &errLog) 692*139aa4f0SVijay Khemka { 693*139aa4f0SVijay Khemka const std::vector<std::string> thresEvtName = {"Lower Non-critical", 694*139aa4f0SVijay Khemka "Unknown", 695*139aa4f0SVijay Khemka "Lower Critical", 696*139aa4f0SVijay Khemka "Unknown", 697*139aa4f0SVijay Khemka "Lower Non-recoverable", 698*139aa4f0SVijay Khemka "Unknown", 699*139aa4f0SVijay Khemka "Unknown", 700*139aa4f0SVijay Khemka "Upper Non-critical", 701*139aa4f0SVijay Khemka "Unknown", 702*139aa4f0SVijay Khemka "Upper Critical", 703*139aa4f0SVijay Khemka "Unknown", 704*139aa4f0SVijay Khemka "Upper Non-recoverable"}; 705*139aa4f0SVijay Khemka 706*139aa4f0SVijay Khemka if ((data[0] & 0x0f) < 12) 707*139aa4f0SVijay Khemka { 708*139aa4f0SVijay Khemka errLog = thresEvtName[(data[0] & 0x0f)]; 709*139aa4f0SVijay Khemka } 710*139aa4f0SVijay Khemka else 711*139aa4f0SVijay Khemka { 712*139aa4f0SVijay Khemka errLog = "Unknown"; 713*139aa4f0SVijay Khemka } 714*139aa4f0SVijay Khemka 715*139aa4f0SVijay Khemka errLog += ", curr_val: " + std::to_string(data[1]) + 716*139aa4f0SVijay Khemka " C, thresh_val: " + std::to_string(data[2]) + " C"; 717*139aa4f0SVijay Khemka } 718*139aa4f0SVijay Khemka 719*139aa4f0SVijay Khemka static void logNmHealth(uint8_t *data, std::string &errLog) 720*139aa4f0SVijay Khemka { 721*139aa4f0SVijay Khemka std::vector<std::string> nmErrType = { 722*139aa4f0SVijay Khemka "Unknown", 723*139aa4f0SVijay Khemka "Unknown", 724*139aa4f0SVijay Khemka "Unknown", 725*139aa4f0SVijay Khemka "Unknown", 726*139aa4f0SVijay Khemka "Unknown", 727*139aa4f0SVijay Khemka "Unknown", 728*139aa4f0SVijay Khemka "Unknown", 729*139aa4f0SVijay Khemka "Extended Telemetry Device Reading Failure", 730*139aa4f0SVijay Khemka "Outlet Temperature Reading Failure", 731*139aa4f0SVijay Khemka "Volumetric Airflow Reading Failure", 732*139aa4f0SVijay Khemka "Policy Misconfiguration", 733*139aa4f0SVijay Khemka "Power Sensor Reading Failure", 734*139aa4f0SVijay Khemka "Inlet Temperature Reading Failure", 735*139aa4f0SVijay Khemka "Host Communication Error", 736*139aa4f0SVijay Khemka "Real-time Clock Synchronization Failure", 737*139aa4f0SVijay Khemka "Platform Shutdown Initiated by Intel NM Policy", 738*139aa4f0SVijay Khemka "Unknown"}; 739*139aa4f0SVijay Khemka uint8_t nmTypeIdx = (data[0] & 0xf); 740*139aa4f0SVijay Khemka uint8_t domIdx = (data[1] & 0xf); 741*139aa4f0SVijay Khemka uint8_t errIdx = ((data[1] >> 4) & 0xf); 742*139aa4f0SVijay Khemka 743*139aa4f0SVijay Khemka if (nmTypeIdx == 2) 744*139aa4f0SVijay Khemka { 745*139aa4f0SVijay Khemka errLog = "SensorIntelNM"; 746*139aa4f0SVijay Khemka } 747*139aa4f0SVijay Khemka else 748*139aa4f0SVijay Khemka { 749*139aa4f0SVijay Khemka errLog = "Unknown"; 750*139aa4f0SVijay Khemka } 751*139aa4f0SVijay Khemka 752*139aa4f0SVijay Khemka errLog += ", Domain:" + nmDomName[domIdx] + 753*139aa4f0SVijay Khemka ", ErrType:" + nmErrType[errIdx] + ", Err:0x" + 754*139aa4f0SVijay Khemka byteToStr(data[2]); 755*139aa4f0SVijay Khemka } 756*139aa4f0SVijay Khemka 757*139aa4f0SVijay Khemka static void logNmCap(uint8_t *data, std::string &errLog) 758*139aa4f0SVijay Khemka { 759*139aa4f0SVijay Khemka 760*139aa4f0SVijay Khemka const std::vector<std::string> nmCapStsStr = {"Not Available", "Available"}; 761*139aa4f0SVijay Khemka if (data[0] & 0x7) // BIT1=policy, BIT2=monitoring, BIT3=pwr 762*139aa4f0SVijay Khemka // limit and the others are reserved 763*139aa4f0SVijay Khemka { 764*139aa4f0SVijay Khemka errLog = "PolicyInterface:" + nmCapStsStr[BIT(data[0], 0)] + 765*139aa4f0SVijay Khemka ",Monitoring:" + nmCapStsStr[BIT(data[0], 1)] + 766*139aa4f0SVijay Khemka ",PowerLimit:" + nmCapStsStr[BIT(data[0], 2)]; 767*139aa4f0SVijay Khemka } 768*139aa4f0SVijay Khemka else 769*139aa4f0SVijay Khemka { 770*139aa4f0SVijay Khemka errLog = "Unknown"; 771*139aa4f0SVijay Khemka } 772*139aa4f0SVijay Khemka } 773*139aa4f0SVijay Khemka 774*139aa4f0SVijay Khemka static void logNmThreshold(uint8_t *data, std::string &errLog) 775*139aa4f0SVijay Khemka { 776*139aa4f0SVijay Khemka uint8_t thresNum = (data[0] & 0x3); 777*139aa4f0SVijay Khemka uint8_t domIdx = (data[1] & 0xf); 778*139aa4f0SVijay Khemka uint8_t polId = data[2]; 779*139aa4f0SVijay Khemka uint8_t polEvtIdx = BIT(data[0], 3); 780*139aa4f0SVijay Khemka const std::vector<std::string> polEvtStr = { 781*139aa4f0SVijay Khemka "Threshold Exceeded", "Policy Correction Time Exceeded"}; 782*139aa4f0SVijay Khemka 783*139aa4f0SVijay Khemka errLog = "Threshold Number:" + std::to_string(thresNum) + "-" + 784*139aa4f0SVijay Khemka polEvtStr[polEvtIdx] + ", Domain:" + nmDomName[domIdx] + 785*139aa4f0SVijay Khemka ", PolicyID:0x" + byteToStr(polId); 786*139aa4f0SVijay Khemka } 787*139aa4f0SVijay Khemka 788*139aa4f0SVijay Khemka static void logPwrThreshold(uint8_t *data, std::string &errLog) 789*139aa4f0SVijay Khemka { 790*139aa4f0SVijay Khemka if (data[0] == 0x00) 791*139aa4f0SVijay Khemka { 792*139aa4f0SVijay Khemka errLog = "Limit Not Exceeded"; 793*139aa4f0SVijay Khemka } 794*139aa4f0SVijay Khemka else if (data[0] == 0x01) 795*139aa4f0SVijay Khemka { 796*139aa4f0SVijay Khemka errLog = "Limit Exceeded"; 797*139aa4f0SVijay Khemka } 798*139aa4f0SVijay Khemka else 799*139aa4f0SVijay Khemka { 800*139aa4f0SVijay Khemka errLog = "Unknown"; 801*139aa4f0SVijay Khemka } 802*139aa4f0SVijay Khemka } 803*139aa4f0SVijay Khemka 804*139aa4f0SVijay Khemka static void logMSMI(uint8_t *data, std::string &errLog) 805*139aa4f0SVijay Khemka { 806*139aa4f0SVijay Khemka 807*139aa4f0SVijay Khemka if (data[0] == 0x0) 808*139aa4f0SVijay Khemka { 809*139aa4f0SVijay Khemka errLog = "IERR/MSMI"; 810*139aa4f0SVijay Khemka } 811*139aa4f0SVijay Khemka else if (data[0] == 0x0B) 812*139aa4f0SVijay Khemka { 813*139aa4f0SVijay Khemka errLog = "MCERR/MSMI"; 814*139aa4f0SVijay Khemka } 815*139aa4f0SVijay Khemka else 816*139aa4f0SVijay Khemka { 817*139aa4f0SVijay Khemka errLog = "Unknown"; 818*139aa4f0SVijay Khemka } 819*139aa4f0SVijay Khemka } 820*139aa4f0SVijay Khemka 821*139aa4f0SVijay Khemka static void logHprWarn(uint8_t *data, std::string &errLog) 822*139aa4f0SVijay Khemka { 823*139aa4f0SVijay Khemka if (data[2] == 0x01) 824*139aa4f0SVijay Khemka { 825*139aa4f0SVijay Khemka if (data[1] == 0xFF) 826*139aa4f0SVijay Khemka { 827*139aa4f0SVijay Khemka errLog = "Infinite Time"; 828*139aa4f0SVijay Khemka } 829*139aa4f0SVijay Khemka else 830*139aa4f0SVijay Khemka { 831*139aa4f0SVijay Khemka errLog = std::to_string(data[1]) + " minutes"; 832*139aa4f0SVijay Khemka } 833*139aa4f0SVijay Khemka } 834*139aa4f0SVijay Khemka else 835*139aa4f0SVijay Khemka { 836*139aa4f0SVijay Khemka errLog = "Unknown"; 837*139aa4f0SVijay Khemka } 838*139aa4f0SVijay Khemka } 839*139aa4f0SVijay Khemka 840*139aa4f0SVijay Khemka static const boost::container::flat_map< 841*139aa4f0SVijay Khemka uint8_t, 842*139aa4f0SVijay Khemka std::pair<std::string, std::function<void(uint8_t *, std::string &)>>> 843*139aa4f0SVijay Khemka sensorNameTable = {{0xE9, {"SYSTEM_EVENT", logSysEvent}}, 844*139aa4f0SVijay Khemka {0x7D, {"THERM_THRESH_EVT", logThermalEvent}}, 845*139aa4f0SVijay Khemka {0xAA, {"BUTTON", logDefault}}, 846*139aa4f0SVijay Khemka {0xAB, {"POWER_STATE", logDefault}}, 847*139aa4f0SVijay Khemka {0xEA, {"CRITICAL_IRQ", logCritIrq}}, 848*139aa4f0SVijay Khemka {0x2B, {"POST_ERROR", logPostErr}}, 849*139aa4f0SVijay Khemka {0x40, {"MACHINE_CHK_ERR", logMchChkErr}}, 850*139aa4f0SVijay Khemka {0x41, {"PCIE_ERR", logPcieErr}}, 851*139aa4f0SVijay Khemka {0x43, {"IIO_ERR", logIioErr}}, 852*139aa4f0SVijay Khemka {0X63, {"MEMORY_ECC_ERR", logDefault}}, 853*139aa4f0SVijay Khemka {0X87, {"MEMORY_ERR_LOG_DIS", logDefault}}, 854*139aa4f0SVijay Khemka {0X51, {"PROCHOT_EXT", logDefault}}, 855*139aa4f0SVijay Khemka {0X56, {"PWR_ERR", logPwrErr}}, 856*139aa4f0SVijay Khemka {0xE6, {"CATERR_A", logCatErr}}, 857*139aa4f0SVijay Khemka {0xEB, {"CATERR_B", logCatErr}}, 858*139aa4f0SVijay Khemka {0xB3, {"CPU_DIMM_HOT", logDimmHot}}, 859*139aa4f0SVijay Khemka {0x90, {"SOFTWARE_NMI", logSwNMI}}, 860*139aa4f0SVijay Khemka {0x1C, {"CPU0_THERM_STATUS", logCPUThermalSts}}, 861*139aa4f0SVijay Khemka {0x1D, {"CPU1_THERM_STATUS", logCPUThermalSts}}, 862*139aa4f0SVijay Khemka {0x16, {"ME_POWER_STATE", logMEPwrState}}, 863*139aa4f0SVijay Khemka {0x17, {"SPS_FW_HEALTH", logSPSFwHealth}}, 864*139aa4f0SVijay Khemka {0x18, {"NM_EXCEPTION_A", logNmExcA}}, 865*139aa4f0SVijay Khemka {0x08, {"PCH_THERM_THRESHOLD", logPCHThermal}}, 866*139aa4f0SVijay Khemka {0x19, {"NM_HEALTH", logNmHealth}}, 867*139aa4f0SVijay Khemka {0x1A, {"NM_CAPABILITIES", logNmCap}}, 868*139aa4f0SVijay Khemka {0x1B, {"NM_THRESHOLD", logNmThreshold}}, 869*139aa4f0SVijay Khemka {0x3B, {"PWR_THRESH_EVT", logPwrThreshold}}, 870*139aa4f0SVijay Khemka {0xE7, {"MSMI", logMSMI}}, 871*139aa4f0SVijay Khemka {0xC5, {"HPR_WARNING", logHprWarn}}}; 872*139aa4f0SVijay Khemka 873*139aa4f0SVijay Khemka static void parseSelHelper(StdSELEntry *data, std::string &errStr) 874*139aa4f0SVijay Khemka { 875*139aa4f0SVijay Khemka 876*139aa4f0SVijay Khemka /* Check if sensor type is OS_BOOT (0x1f) */ 877*139aa4f0SVijay Khemka if (data->sensorType == 0x1F) 878*139aa4f0SVijay Khemka { 879*139aa4f0SVijay Khemka /* OS_BOOT used by OS */ 880*139aa4f0SVijay Khemka switch (data->eventData1 & 0xF) 881*139aa4f0SVijay Khemka { 882*139aa4f0SVijay Khemka case 0x07: 883*139aa4f0SVijay Khemka errStr = "Base OS/Hypervisor Installation started"; 884*139aa4f0SVijay Khemka break; 885*139aa4f0SVijay Khemka case 0x08: 886*139aa4f0SVijay Khemka errStr = "Base OS/Hypervisor Installation completed"; 887*139aa4f0SVijay Khemka break; 888*139aa4f0SVijay Khemka case 0x09: 889*139aa4f0SVijay Khemka errStr = "Base OS/Hypervisor Installation aborted"; 890*139aa4f0SVijay Khemka break; 891*139aa4f0SVijay Khemka case 0x0A: 892*139aa4f0SVijay Khemka errStr = "Base OS/Hypervisor Installation failed"; 893*139aa4f0SVijay Khemka break; 894*139aa4f0SVijay Khemka default: 895*139aa4f0SVijay Khemka errStr = "Unknown"; 896*139aa4f0SVijay Khemka } 897*139aa4f0SVijay Khemka return; 898*139aa4f0SVijay Khemka } 899*139aa4f0SVijay Khemka 900*139aa4f0SVijay Khemka auto findSensorName = sensorNameTable.find(data->sensorNum); 901*139aa4f0SVijay Khemka if (findSensorName == sensorNameTable.end()) 902*139aa4f0SVijay Khemka { 903*139aa4f0SVijay Khemka errStr = "Unknown"; 904*139aa4f0SVijay Khemka return; 905*139aa4f0SVijay Khemka } 906*139aa4f0SVijay Khemka else 907*139aa4f0SVijay Khemka { 908*139aa4f0SVijay Khemka switch (data->sensorNum) 909*139aa4f0SVijay Khemka { 910*139aa4f0SVijay Khemka /* logMemErr function needs data from sensor type */ 911*139aa4f0SVijay Khemka case memoryEccError: 912*139aa4f0SVijay Khemka case memoryErrLogDIS: 913*139aa4f0SVijay Khemka findSensorName->second.second(&(data->sensorType), errStr); 914*139aa4f0SVijay Khemka break; 915*139aa4f0SVijay Khemka /* Other sensor function needs only event data for parsing */ 916*139aa4f0SVijay Khemka default: 917*139aa4f0SVijay Khemka findSensorName->second.second(&(data->eventData1), errStr); 918*139aa4f0SVijay Khemka } 919*139aa4f0SVijay Khemka } 920*139aa4f0SVijay Khemka 921*139aa4f0SVijay Khemka if (((data->eventData3 & 0x80) >> 7) == 0) 922*139aa4f0SVijay Khemka { 923*139aa4f0SVijay Khemka errStr += " Assertion"; 924*139aa4f0SVijay Khemka } 925*139aa4f0SVijay Khemka else 926*139aa4f0SVijay Khemka { 927*139aa4f0SVijay Khemka errStr += " Deassertion"; 928*139aa4f0SVijay Khemka } 929*139aa4f0SVijay Khemka } 930*139aa4f0SVijay Khemka 931f36f345fSVijay Khemka static void parseStdSel(StdSELEntry *data, std::string &errStr) 932f36f345fSVijay Khemka { 933f36f345fSVijay Khemka std::stringstream tmpStream; 934f36f345fSVijay Khemka tmpStream << std::hex << std::uppercase; 935f36f345fSVijay Khemka 936f36f345fSVijay Khemka /* TODO: add pal_add_cri_sel */ 937f36f345fSVijay Khemka switch (data->sensorNum) 938f36f345fSVijay Khemka { 939f36f345fSVijay Khemka case memoryEccError: 940f36f345fSVijay Khemka switch (data->eventData1 & 0x0F) 941f36f345fSVijay Khemka { 942f36f345fSVijay Khemka case 0x00: 943f36f345fSVijay Khemka errStr = "Correctable"; 944f36f345fSVijay Khemka tmpStream << "DIMM" << std::setw(2) << std::setfill('0') 945f36f345fSVijay Khemka << data->eventData3 << " ECC err"; 946f36f345fSVijay Khemka break; 947f36f345fSVijay Khemka case 0x01: 948f36f345fSVijay Khemka errStr = "Uncorrectable"; 949f36f345fSVijay Khemka tmpStream << "DIMM" << std::setw(2) << std::setfill('0') 950f36f345fSVijay Khemka << data->eventData3 << " UECC err"; 951f36f345fSVijay Khemka break; 952f36f345fSVijay Khemka case 0x02: 953f36f345fSVijay Khemka errStr = "Parity"; 954f36f345fSVijay Khemka break; 955f36f345fSVijay Khemka case 0x05: 956f36f345fSVijay Khemka errStr = "Correctable ECC error Logging Limit Reached"; 957f36f345fSVijay Khemka break; 958f36f345fSVijay Khemka default: 959f36f345fSVijay Khemka errStr = "Unknown"; 960f36f345fSVijay Khemka } 961f36f345fSVijay Khemka break; 962f36f345fSVijay Khemka case memoryErrLogDIS: 963f36f345fSVijay Khemka if ((data->eventData1 & 0x0F) == 0) 964f36f345fSVijay Khemka { 965f36f345fSVijay Khemka errStr = "Correctable Memory Error Logging Disabled"; 966f36f345fSVijay Khemka } 967f36f345fSVijay Khemka else 968f36f345fSVijay Khemka { 969f36f345fSVijay Khemka errStr = "Unknown"; 970f36f345fSVijay Khemka } 971f36f345fSVijay Khemka break; 972f36f345fSVijay Khemka default: 973*139aa4f0SVijay Khemka parseSelHelper(data, errStr); 974f36f345fSVijay Khemka return; 975f36f345fSVijay Khemka } 976f36f345fSVijay Khemka 977f36f345fSVijay Khemka errStr += " (DIMM " + std::to_string(data->eventData3) + ")"; 978f36f345fSVijay Khemka errStr += " Logical Rank " + std::to_string(data->eventData2 & 0x03); 979f36f345fSVijay Khemka 980f36f345fSVijay Khemka switch ((data->eventData2 & 0x0C) >> 2) 981f36f345fSVijay Khemka { 982f36f345fSVijay Khemka case 0x00: 983f36f345fSVijay Khemka // Ignore when " All info available" 984f36f345fSVijay Khemka break; 985f36f345fSVijay Khemka case 0x01: 986f36f345fSVijay Khemka errStr += " DIMM info not valid"; 987f36f345fSVijay Khemka break; 988f36f345fSVijay Khemka case 0x02: 989f36f345fSVijay Khemka errStr += " CHN info not valid"; 990f36f345fSVijay Khemka break; 991f36f345fSVijay Khemka case 0x03: 992f36f345fSVijay Khemka errStr += " CPU info not valid"; 993f36f345fSVijay Khemka break; 994f36f345fSVijay Khemka default: 995f36f345fSVijay Khemka errStr += " Unknown"; 996f36f345fSVijay Khemka } 997f36f345fSVijay Khemka 998f36f345fSVijay Khemka if (((data->eventType & 0x80) >> 7) == 0) 999f36f345fSVijay Khemka { 1000f36f345fSVijay Khemka errStr += " Assertion"; 1001f36f345fSVijay Khemka } 1002f36f345fSVijay Khemka else 1003f36f345fSVijay Khemka { 1004f36f345fSVijay Khemka errStr += " Deassertion"; 1005f36f345fSVijay Khemka } 1006f36f345fSVijay Khemka 1007f36f345fSVijay Khemka return; 1008f36f345fSVijay Khemka } 1009f36f345fSVijay Khemka 1010f36f345fSVijay Khemka static void parseOemSel(TsOemSELEntry *data, std::string &errStr) 1011f36f345fSVijay Khemka { 1012f36f345fSVijay Khemka std::stringstream tmpStream; 1013f36f345fSVijay Khemka tmpStream << std::hex << std::uppercase << std::setfill('0'); 1014f36f345fSVijay Khemka 1015f36f345fSVijay Khemka switch (data->recordType) 1016f36f345fSVijay Khemka { 1017f36f345fSVijay Khemka case 0xC0: 1018f36f345fSVijay Khemka tmpStream << "VID:0x" << std::setw(2) << (int)data->oemData[1] 1019f36f345fSVijay Khemka << std::setw(2) << (int)data->oemData[0] << " DID:0x" 1020f36f345fSVijay Khemka << std::setw(2) << (int)data->oemData[3] << std::setw(2) 1021f36f345fSVijay Khemka << (int)data->oemData[2] << " Slot:0x" << std::setw(2) 1022f36f345fSVijay Khemka << (int)data->oemData[4] << " Error ID:0x" << std::setw(2) 1023f36f345fSVijay Khemka << (int)data->oemData[5]; 1024f36f345fSVijay Khemka break; 1025f36f345fSVijay Khemka case 0xC2: 1026f36f345fSVijay Khemka tmpStream << "Extra info:0x" << std::setw(2) 1027f36f345fSVijay Khemka << (int)data->oemData[1] << " MSCOD:0x" << std::setw(2) 1028f36f345fSVijay Khemka << (int)data->oemData[3] << std::setw(2) 1029f36f345fSVijay Khemka << (int)data->oemData[2] << " MCACOD:0x" << std::setw(2) 1030f36f345fSVijay Khemka << (int)data->oemData[5] << std::setw(2) 1031f36f345fSVijay Khemka << (int)data->oemData[4]; 1032f36f345fSVijay Khemka break; 1033f36f345fSVijay Khemka case 0xC3: 1034f36f345fSVijay Khemka int bank = (data->oemData[1] & 0xf0) >> 4; 1035f36f345fSVijay Khemka int col = ((data->oemData[1] & 0x0f) << 8) | data->oemData[2]; 1036f36f345fSVijay Khemka 1037f36f345fSVijay Khemka tmpStream << "Fail Device:0x" << std::setw(2) 1038f36f345fSVijay Khemka << (int)data->oemData[0] << " Bank:0x" << std::setw(2) 1039f36f345fSVijay Khemka << bank << " Column:0x" << std::setw(2) << col 1040f36f345fSVijay Khemka << " Failed Row:0x" << std::setw(2) 1041f36f345fSVijay Khemka << (int)data->oemData[3] << std::setw(2) 1042f36f345fSVijay Khemka << (int)data->oemData[4] << std::setw(2) 1043f36f345fSVijay Khemka << (int)data->oemData[5]; 1044f36f345fSVijay Khemka } 1045f36f345fSVijay Khemka 1046f36f345fSVijay Khemka errStr = tmpStream.str(); 1047f36f345fSVijay Khemka 1048f36f345fSVijay Khemka return; 1049f36f345fSVijay Khemka } 1050f36f345fSVijay Khemka 105134a875f3SVijay Khemka static void parseOemUnifiedSel(NtsOemSELEntry *data, std::string &errStr) 105234a875f3SVijay Khemka { 105334a875f3SVijay Khemka uint8_t *ptr = data->oemData; 105434a875f3SVijay Khemka int genInfo = ptr[0]; 105534a875f3SVijay Khemka int errType = genInfo & 0x0f; 105634a875f3SVijay Khemka std::vector<std::string> dimmEvent = { 105734a875f3SVijay Khemka "Memory training failure", "Memory correctable error", 105834a875f3SVijay Khemka "Memory uncorrectable error", "Reserved"}; 105934a875f3SVijay Khemka 106034a875f3SVijay Khemka std::stringstream tmpStream; 106134a875f3SVijay Khemka tmpStream << std::hex << std::uppercase << std::setfill('0'); 106234a875f3SVijay Khemka 106334a875f3SVijay Khemka switch (errType) 106434a875f3SVijay Khemka { 106534a875f3SVijay Khemka case unifiedPcieErr: 106634a875f3SVijay Khemka if (((genInfo & 0x10) >> 4) == 0) // x86 106734a875f3SVijay Khemka { 106834a875f3SVijay Khemka tmpStream << "GeneralInfo: x86/PCIeErr(0x" << std::setw(2) 106934a875f3SVijay Khemka << genInfo << "),"; 107034a875f3SVijay Khemka } 107134a875f3SVijay Khemka 107234a875f3SVijay Khemka tmpStream << " Bus " << std::setw(2) << (int)(ptr[8]) << "/Dev " 107334a875f3SVijay Khemka << std::setw(2) << (int)(ptr[7] >> 3) << "/Fun " 107434a875f3SVijay Khemka << std::setw(2) << (int)(ptr[7] & 0x7) 107534a875f3SVijay Khemka << ", TotalErrID1Cnt: 0x" << std::setw(4) 107634a875f3SVijay Khemka << (int)((ptr[10] << 8) | ptr[9]) << ", ErrID2: 0x" 107734a875f3SVijay Khemka << std::setw(2) << (int)(ptr[11]) << ", ErrID1: 0x" 107834a875f3SVijay Khemka << std::setw(2) << (int)(ptr[12]); 107934a875f3SVijay Khemka 108034a875f3SVijay Khemka break; 108134a875f3SVijay Khemka case unifiedMemErr: 108234a875f3SVijay Khemka tmpStream << "GeneralInfo: MemErr(0x" << std::setw(2) << genInfo 108334a875f3SVijay Khemka << "), DIMM Slot Location: Sled " << std::setw(2) 108434a875f3SVijay Khemka << (int)((ptr[5] >> 4) & 0x03) << "/Socket " 108534a875f3SVijay Khemka << std::setw(2) << (int)(ptr[5] & 0x0f) << ", Channel " 108634a875f3SVijay Khemka << std::setw(2) << (int)(ptr[6] & 0x0f) << ", Slot " 108734a875f3SVijay Khemka << std::setw(2) << (int)(ptr[7] & 0x0f) 108834a875f3SVijay Khemka << ", DIMM Failure Event: " << dimmEvent[(ptr[9] & 0x03)] 108934a875f3SVijay Khemka << ", Major Code: 0x" << std::setw(2) << (int)(ptr[10]) 109034a875f3SVijay Khemka << ", Minor Code: 0x" << std::setw(2) << (int)(ptr[11]); 109134a875f3SVijay Khemka 109234a875f3SVijay Khemka break; 109334a875f3SVijay Khemka default: 109434a875f3SVijay Khemka std::vector<uint8_t> oemData(ptr, ptr + 13); 109534a875f3SVijay Khemka std::string oemDataStr; 109634a875f3SVijay Khemka toHexStr(oemData, oemDataStr); 109734a875f3SVijay Khemka tmpStream << "Undefined Error Type(0x" << std::setw(2) << errType 109834a875f3SVijay Khemka << "), Raw: " << oemDataStr; 109934a875f3SVijay Khemka } 110034a875f3SVijay Khemka 110134a875f3SVijay Khemka errStr = tmpStream.str(); 110234a875f3SVijay Khemka 110334a875f3SVijay Khemka return; 110434a875f3SVijay Khemka } 110534a875f3SVijay Khemka 1106f36f345fSVijay Khemka static void parseSelData(std::vector<uint8_t> &reqData, std::string &msgLog) 1107f36f345fSVijay Khemka { 1108f36f345fSVijay Khemka 1109f36f345fSVijay Khemka /* Get record type */ 1110f36f345fSVijay Khemka int recType = reqData[2]; 1111f36f345fSVijay Khemka std::string errType, errLog; 1112f36f345fSVijay Khemka 1113f36f345fSVijay Khemka uint8_t *ptr = NULL; 1114f36f345fSVijay Khemka 1115f36f345fSVijay Khemka std::stringstream recTypeStream; 1116f36f345fSVijay Khemka recTypeStream << std::hex << std::uppercase << std::setfill('0') 1117f36f345fSVijay Khemka << std::setw(2) << recType; 1118f36f345fSVijay Khemka 1119f36f345fSVijay Khemka msgLog = "SEL Entry: FRU: 1, Record: "; 1120f36f345fSVijay Khemka 1121f36f345fSVijay Khemka if (recType == stdErrType) 1122f36f345fSVijay Khemka { 1123f36f345fSVijay Khemka StdSELEntry *data = reinterpret_cast<StdSELEntry *>(&reqData[0]); 1124f36f345fSVijay Khemka std::string sensorName; 1125f36f345fSVijay Khemka 1126f36f345fSVijay Khemka errType = stdErr; 1127f36f345fSVijay Khemka if (data->sensorType == 0x1F) 1128f36f345fSVijay Khemka { 1129f36f345fSVijay Khemka sensorName = "OS"; 1130f36f345fSVijay Khemka } 1131f36f345fSVijay Khemka else 1132f36f345fSVijay Khemka { 1133f36f345fSVijay Khemka auto findSensorName = sensorNameTable.find(data->sensorNum); 1134f36f345fSVijay Khemka if (findSensorName == sensorNameTable.end()) 1135f36f345fSVijay Khemka { 1136f36f345fSVijay Khemka sensorName = "Unknown"; 1137f36f345fSVijay Khemka } 1138f36f345fSVijay Khemka else 1139f36f345fSVijay Khemka { 1140*139aa4f0SVijay Khemka sensorName = findSensorName->second.first; 1141f36f345fSVijay Khemka } 1142f36f345fSVijay Khemka } 1143f36f345fSVijay Khemka 1144f36f345fSVijay Khemka std::tm *ts = localtime((time_t *)(&(data->timeStamp))); 1145f36f345fSVijay Khemka std::string timeStr = std::asctime(ts); 1146f36f345fSVijay Khemka 1147f36f345fSVijay Khemka parseStdSel(data, errLog); 1148f36f345fSVijay Khemka ptr = &(data->eventData1); 1149f36f345fSVijay Khemka std::vector<uint8_t> evtData(ptr, ptr + 3); 1150f36f345fSVijay Khemka std::string eventData; 1151f36f345fSVijay Khemka toHexStr(evtData, eventData); 1152f36f345fSVijay Khemka 1153f36f345fSVijay Khemka std::stringstream senNumStream; 1154f36f345fSVijay Khemka senNumStream << std::hex << std::uppercase << std::setfill('0') 1155f36f345fSVijay Khemka << std::setw(2) << (int)(data->sensorNum); 1156f36f345fSVijay Khemka 1157f36f345fSVijay Khemka msgLog += errType + " (0x" + recTypeStream.str() + 1158f36f345fSVijay Khemka "), Time: " + timeStr + ", Sensor: " + sensorName + " (0x" + 1159f36f345fSVijay Khemka senNumStream.str() + "), Event Data: (" + eventData + ") " + 1160f36f345fSVijay Khemka errLog; 1161f36f345fSVijay Khemka } 1162f36f345fSVijay Khemka else if ((recType >= oemTSErrTypeMin) && (recType <= oemTSErrTypeMax)) 1163f36f345fSVijay Khemka { 1164f36f345fSVijay Khemka /* timestamped OEM SEL records */ 1165f36f345fSVijay Khemka TsOemSELEntry *data = reinterpret_cast<TsOemSELEntry *>(&reqData[0]); 1166f36f345fSVijay Khemka ptr = data->mfrId; 1167f36f345fSVijay Khemka std::vector<uint8_t> mfrIdData(ptr, ptr + 3); 1168f36f345fSVijay Khemka std::string mfrIdStr; 1169f36f345fSVijay Khemka toHexStr(mfrIdData, mfrIdStr); 1170f36f345fSVijay Khemka 1171f36f345fSVijay Khemka ptr = data->oemData; 1172f36f345fSVijay Khemka std::vector<uint8_t> oemData(ptr, ptr + 6); 1173f36f345fSVijay Khemka std::string oemDataStr; 1174f36f345fSVijay Khemka toHexStr(oemData, oemDataStr); 1175f36f345fSVijay Khemka 1176f36f345fSVijay Khemka std::tm *ts = localtime((time_t *)(&(data->timeStamp))); 1177f36f345fSVijay Khemka std::string timeStr = std::asctime(ts); 1178f36f345fSVijay Khemka 1179f36f345fSVijay Khemka errType = oemTSErr; 1180f36f345fSVijay Khemka parseOemSel(data, errLog); 1181f36f345fSVijay Khemka 1182f36f345fSVijay Khemka msgLog += errType + " (0x" + recTypeStream.str() + 1183f36f345fSVijay Khemka "), Time: " + timeStr + ", MFG ID: " + mfrIdStr + 1184f36f345fSVijay Khemka ", OEM Data: (" + oemDataStr + ") " + errLog; 1185f36f345fSVijay Khemka } 118634a875f3SVijay Khemka else if (recType == fbUniErrType) 118734a875f3SVijay Khemka { 118834a875f3SVijay Khemka NtsOemSELEntry *data = reinterpret_cast<NtsOemSELEntry *>(&reqData[0]); 118934a875f3SVijay Khemka errType = fbUniSELErr; 119034a875f3SVijay Khemka parseOemUnifiedSel(data, errLog); 119134a875f3SVijay Khemka msgLog += errType + " (0x" + recTypeStream.str() + "), " + errLog; 119234a875f3SVijay Khemka } 1193f36f345fSVijay Khemka else if ((recType >= oemNTSErrTypeMin) && (recType <= oemNTSErrTypeMax)) 1194f36f345fSVijay Khemka { 1195f36f345fSVijay Khemka /* Non timestamped OEM SEL records */ 1196f36f345fSVijay Khemka NtsOemSELEntry *data = reinterpret_cast<NtsOemSELEntry *>(&reqData[0]); 1197f36f345fSVijay Khemka errType = oemNTSErr; 1198f36f345fSVijay Khemka 1199f36f345fSVijay Khemka ptr = data->oemData; 1200f36f345fSVijay Khemka std::vector<uint8_t> oemData(ptr, ptr + 13); 1201f36f345fSVijay Khemka std::string oemDataStr; 1202f36f345fSVijay Khemka toHexStr(oemData, oemDataStr); 1203f36f345fSVijay Khemka 1204f36f345fSVijay Khemka parseOemSel((TsOemSELEntry *)data, errLog); 1205f36f345fSVijay Khemka msgLog += errType + " (0x" + recTypeStream.str() + "), OEM Data: (" + 1206f36f345fSVijay Khemka oemDataStr + ") " + errLog; 1207f36f345fSVijay Khemka } 1208f36f345fSVijay Khemka else 1209f36f345fSVijay Khemka { 1210f36f345fSVijay Khemka errType = unknownErr; 1211f36f345fSVijay Khemka toHexStr(reqData, errLog); 1212f36f345fSVijay Khemka msgLog += 1213f36f345fSVijay Khemka errType + " (0x" + recTypeStream.str() + ") RawData: " + errLog; 1214f36f345fSVijay Khemka } 1215f36f345fSVijay Khemka } 1216f36f345fSVijay Khemka 121711b9c3b1SVijay Khemka } // namespace fb_oem::ipmi::sel 121811b9c3b1SVijay Khemka 121911b9c3b1SVijay Khemka namespace ipmi 122011b9c3b1SVijay Khemka { 122111b9c3b1SVijay Khemka 122211b9c3b1SVijay Khemka namespace storage 122311b9c3b1SVijay Khemka { 122411b9c3b1SVijay Khemka 122511b9c3b1SVijay Khemka static void registerSELFunctions() __attribute__((constructor)); 122611b9c3b1SVijay Khemka static fb_oem::ipmi::sel::SELData selObj __attribute__((init_priority(101))); 122711b9c3b1SVijay Khemka 122811b9c3b1SVijay Khemka ipmi::RspType<uint8_t, // SEL version 122911b9c3b1SVijay Khemka uint16_t, // SEL entry count 123011b9c3b1SVijay Khemka uint16_t, // free space 123111b9c3b1SVijay Khemka uint32_t, // last add timestamp 123211b9c3b1SVijay Khemka uint32_t, // last erase timestamp 123311b9c3b1SVijay Khemka uint8_t> // operation support 123411b9c3b1SVijay Khemka ipmiStorageGetSELInfo() 123511b9c3b1SVijay Khemka { 123611b9c3b1SVijay Khemka 123711b9c3b1SVijay Khemka fb_oem::ipmi::sel::GetSELInfoData info; 123811b9c3b1SVijay Khemka 123911b9c3b1SVijay Khemka selObj.getInfo(info); 124011b9c3b1SVijay Khemka return ipmi::responseSuccess(info.selVersion, info.entries, info.freeSpace, 124111b9c3b1SVijay Khemka info.addTimeStamp, info.eraseTimeStamp, 124211b9c3b1SVijay Khemka info.operationSupport); 124311b9c3b1SVijay Khemka } 124411b9c3b1SVijay Khemka 124511b9c3b1SVijay Khemka ipmi::RspType<uint16_t, std::vector<uint8_t>> 124611b9c3b1SVijay Khemka ipmiStorageGetSELEntry(std::vector<uint8_t> data) 124711b9c3b1SVijay Khemka { 124811b9c3b1SVijay Khemka 124911b9c3b1SVijay Khemka if (data.size() != sizeof(fb_oem::ipmi::sel::GetSELEntryRequest)) 125011b9c3b1SVijay Khemka { 125111b9c3b1SVijay Khemka return ipmi::responseReqDataLenInvalid(); 125211b9c3b1SVijay Khemka } 125311b9c3b1SVijay Khemka 125411b9c3b1SVijay Khemka fb_oem::ipmi::sel::GetSELEntryRequest *reqData = 125511b9c3b1SVijay Khemka reinterpret_cast<fb_oem::ipmi::sel::GetSELEntryRequest *>(&data[0]); 125611b9c3b1SVijay Khemka 125711b9c3b1SVijay Khemka if (reqData->reservID != 0) 125811b9c3b1SVijay Khemka { 125911b9c3b1SVijay Khemka if (!checkSELReservation(reqData->reservID)) 126011b9c3b1SVijay Khemka { 126111b9c3b1SVijay Khemka return ipmi::responseInvalidReservationId(); 126211b9c3b1SVijay Khemka } 126311b9c3b1SVijay Khemka } 126411b9c3b1SVijay Khemka 126511b9c3b1SVijay Khemka uint16_t selCnt = selObj.getCount(); 126611b9c3b1SVijay Khemka if (selCnt == 0) 126711b9c3b1SVijay Khemka { 126811b9c3b1SVijay Khemka return ipmi::responseSensorInvalid(); 126911b9c3b1SVijay Khemka } 127011b9c3b1SVijay Khemka 127111b9c3b1SVijay Khemka /* If it is asked for first entry */ 127211b9c3b1SVijay Khemka if (reqData->recordID == fb_oem::ipmi::sel::firstEntry) 127311b9c3b1SVijay Khemka { 127411b9c3b1SVijay Khemka /* First Entry (0x0000) as per Spec */ 127511b9c3b1SVijay Khemka reqData->recordID = 1; 127611b9c3b1SVijay Khemka } 127711b9c3b1SVijay Khemka else if (reqData->recordID == fb_oem::ipmi::sel::lastEntry) 127811b9c3b1SVijay Khemka { 127911b9c3b1SVijay Khemka /* Last entry (0xFFFF) as per Spec */ 128011b9c3b1SVijay Khemka reqData->recordID = selCnt; 128111b9c3b1SVijay Khemka } 128211b9c3b1SVijay Khemka 128311b9c3b1SVijay Khemka std::string ipmiRaw; 128411b9c3b1SVijay Khemka 128511b9c3b1SVijay Khemka if (selObj.getEntry(reqData->recordID, ipmiRaw) < 0) 128611b9c3b1SVijay Khemka { 128711b9c3b1SVijay Khemka return ipmi::responseSensorInvalid(); 128811b9c3b1SVijay Khemka } 128911b9c3b1SVijay Khemka 129011b9c3b1SVijay Khemka std::vector<uint8_t> recDataBytes; 129111b9c3b1SVijay Khemka if (fromHexStr(ipmiRaw, recDataBytes) < 0) 129211b9c3b1SVijay Khemka { 129311b9c3b1SVijay Khemka return ipmi::responseUnspecifiedError(); 129411b9c3b1SVijay Khemka } 129511b9c3b1SVijay Khemka 129611b9c3b1SVijay Khemka /* Identify the next SEL record ID. If recordID is same as 129711b9c3b1SVijay Khemka * total SeL count then next id should be last entry else 129811b9c3b1SVijay Khemka * it should be incremented by 1 to current RecordID 129911b9c3b1SVijay Khemka */ 130011b9c3b1SVijay Khemka uint16_t nextRecord; 130111b9c3b1SVijay Khemka if (reqData->recordID == selCnt) 130211b9c3b1SVijay Khemka { 130311b9c3b1SVijay Khemka nextRecord = fb_oem::ipmi::sel::lastEntry; 130411b9c3b1SVijay Khemka } 130511b9c3b1SVijay Khemka else 130611b9c3b1SVijay Khemka { 130711b9c3b1SVijay Khemka nextRecord = reqData->recordID + 1; 130811b9c3b1SVijay Khemka } 130911b9c3b1SVijay Khemka 131011b9c3b1SVijay Khemka if (reqData->readLen == fb_oem::ipmi::sel::entireRecord) 131111b9c3b1SVijay Khemka { 131211b9c3b1SVijay Khemka return ipmi::responseSuccess(nextRecord, recDataBytes); 131311b9c3b1SVijay Khemka } 131411b9c3b1SVijay Khemka else 131511b9c3b1SVijay Khemka { 131611b9c3b1SVijay Khemka if (reqData->offset >= fb_oem::ipmi::sel::selRecordSize || 131711b9c3b1SVijay Khemka reqData->readLen > fb_oem::ipmi::sel::selRecordSize) 131811b9c3b1SVijay Khemka { 131911b9c3b1SVijay Khemka return ipmi::responseUnspecifiedError(); 132011b9c3b1SVijay Khemka } 132111b9c3b1SVijay Khemka std::vector<uint8_t> recPartData; 132211b9c3b1SVijay Khemka 132311b9c3b1SVijay Khemka auto diff = fb_oem::ipmi::sel::selRecordSize - reqData->offset; 132411b9c3b1SVijay Khemka auto readLength = std::min(diff, static_cast<int>(reqData->readLen)); 132511b9c3b1SVijay Khemka 132611b9c3b1SVijay Khemka for (int i = 0; i < readLength; i++) 132711b9c3b1SVijay Khemka { 132811b9c3b1SVijay Khemka recPartData.push_back(recDataBytes[i + reqData->offset]); 132911b9c3b1SVijay Khemka } 133011b9c3b1SVijay Khemka return ipmi::responseSuccess(nextRecord, recPartData); 133111b9c3b1SVijay Khemka } 133211b9c3b1SVijay Khemka } 133311b9c3b1SVijay Khemka 133411b9c3b1SVijay Khemka ipmi::RspType<uint16_t> ipmiStorageAddSELEntry(std::vector<uint8_t> data) 133511b9c3b1SVijay Khemka { 133611b9c3b1SVijay Khemka /* Per the IPMI spec, need to cancel any reservation when a 133711b9c3b1SVijay Khemka * SEL entry is added 133811b9c3b1SVijay Khemka */ 133911b9c3b1SVijay Khemka cancelSELReservation(); 134011b9c3b1SVijay Khemka 134111b9c3b1SVijay Khemka if (data.size() != fb_oem::ipmi::sel::selRecordSize) 134211b9c3b1SVijay Khemka { 134311b9c3b1SVijay Khemka return ipmi::responseReqDataLenInvalid(); 134411b9c3b1SVijay Khemka } 134511b9c3b1SVijay Khemka 134611b9c3b1SVijay Khemka std::string ipmiRaw, logErr; 134711b9c3b1SVijay Khemka toHexStr(data, ipmiRaw); 134811b9c3b1SVijay Khemka 1349f36f345fSVijay Khemka /* Parse sel data and get an error log to be filed */ 1350f36f345fSVijay Khemka fb_oem::ipmi::sel::parseSelData(data, logErr); 1351f36f345fSVijay Khemka 135211b9c3b1SVijay Khemka /* Log the Raw SEL message to the journal */ 135311b9c3b1SVijay Khemka std::string journalMsg = "SEL Entry Added: " + ipmiRaw; 1354f36f345fSVijay Khemka 135511b9c3b1SVijay Khemka phosphor::logging::log<phosphor::logging::level::INFO>(journalMsg.c_str()); 1356f36f345fSVijay Khemka phosphor::logging::log<phosphor::logging::level::INFO>(logErr.c_str()); 135711b9c3b1SVijay Khemka 135811b9c3b1SVijay Khemka int responseID = selObj.addEntry(ipmiRaw.c_str()); 135911b9c3b1SVijay Khemka if (responseID < 0) 136011b9c3b1SVijay Khemka { 136111b9c3b1SVijay Khemka return ipmi::responseUnspecifiedError(); 136211b9c3b1SVijay Khemka } 136311b9c3b1SVijay Khemka return ipmi::responseSuccess((uint16_t)responseID); 136411b9c3b1SVijay Khemka } 136511b9c3b1SVijay Khemka 1366c1921c63SVijay Khemka ipmi::RspType<uint8_t> ipmiStorageClearSEL(uint16_t reservationID, 1367c1921c63SVijay Khemka const std::array<uint8_t, 3> &clr, 1368c1921c63SVijay Khemka uint8_t eraseOperation) 1369c1921c63SVijay Khemka { 1370c1921c63SVijay Khemka if (!checkSELReservation(reservationID)) 1371c1921c63SVijay Khemka { 1372c1921c63SVijay Khemka return ipmi::responseInvalidReservationId(); 1373c1921c63SVijay Khemka } 1374c1921c63SVijay Khemka 1375c1921c63SVijay Khemka static constexpr std::array<uint8_t, 3> clrExpected = {'C', 'L', 'R'}; 1376c1921c63SVijay Khemka if (clr != clrExpected) 1377c1921c63SVijay Khemka { 1378c1921c63SVijay Khemka return ipmi::responseInvalidFieldRequest(); 1379c1921c63SVijay Khemka } 1380c1921c63SVijay Khemka 1381c1921c63SVijay Khemka /* If there is no sel then return erase complete */ 1382c1921c63SVijay Khemka if (selObj.getCount() == 0) 1383c1921c63SVijay Khemka { 1384c1921c63SVijay Khemka return ipmi::responseSuccess(fb_oem::ipmi::sel::eraseComplete); 1385c1921c63SVijay Khemka } 1386c1921c63SVijay Khemka 1387c1921c63SVijay Khemka /* Erasure status cannot be fetched, so always return erasure 1388c1921c63SVijay Khemka * status as `erase completed`. 1389c1921c63SVijay Khemka */ 1390c1921c63SVijay Khemka if (eraseOperation == fb_oem::ipmi::sel::getEraseStatus) 1391c1921c63SVijay Khemka { 1392c1921c63SVijay Khemka return ipmi::responseSuccess(fb_oem::ipmi::sel::eraseComplete); 1393c1921c63SVijay Khemka } 1394c1921c63SVijay Khemka 1395c1921c63SVijay Khemka /* Check that initiate erase is correct */ 1396c1921c63SVijay Khemka if (eraseOperation != fb_oem::ipmi::sel::initiateErase) 1397c1921c63SVijay Khemka { 1398c1921c63SVijay Khemka return ipmi::responseInvalidFieldRequest(); 1399c1921c63SVijay Khemka } 1400c1921c63SVijay Khemka 1401c1921c63SVijay Khemka /* Per the IPMI spec, need to cancel any reservation when the 1402c1921c63SVijay Khemka * SEL is cleared 1403c1921c63SVijay Khemka */ 1404c1921c63SVijay Khemka cancelSELReservation(); 1405c1921c63SVijay Khemka 1406c1921c63SVijay Khemka /* Clear the complete Sel Json object */ 1407c1921c63SVijay Khemka if (selObj.clear() < 0) 1408c1921c63SVijay Khemka { 1409c1921c63SVijay Khemka return ipmi::responseUnspecifiedError(); 1410c1921c63SVijay Khemka } 1411c1921c63SVijay Khemka 1412c1921c63SVijay Khemka return ipmi::responseSuccess(fb_oem::ipmi::sel::eraseComplete); 1413c1921c63SVijay Khemka } 1414c1921c63SVijay Khemka 1415c1921c63SVijay Khemka ipmi::RspType<uint32_t> ipmiStorageGetSELTime() 1416c1921c63SVijay Khemka { 1417c1921c63SVijay Khemka struct timespec selTime = {}; 1418c1921c63SVijay Khemka 1419c1921c63SVijay Khemka if (clock_gettime(CLOCK_REALTIME, &selTime) < 0) 1420c1921c63SVijay Khemka { 1421c1921c63SVijay Khemka return ipmi::responseUnspecifiedError(); 1422c1921c63SVijay Khemka } 1423c1921c63SVijay Khemka 1424c1921c63SVijay Khemka return ipmi::responseSuccess(selTime.tv_sec); 1425c1921c63SVijay Khemka } 1426c1921c63SVijay Khemka 1427c1921c63SVijay Khemka ipmi::RspType<> ipmiStorageSetSELTime(uint32_t selTime) 1428c1921c63SVijay Khemka { 1429c1921c63SVijay Khemka // Set SEL Time is not supported 1430c1921c63SVijay Khemka return ipmi::responseInvalidCommand(); 1431c1921c63SVijay Khemka } 1432c1921c63SVijay Khemka 1433c1921c63SVijay Khemka ipmi::RspType<uint16_t> ipmiStorageGetSELTimeUtcOffset() 1434c1921c63SVijay Khemka { 1435c1921c63SVijay Khemka /* TODO: For now, the SEL time stamp is based on UTC time, 1436c1921c63SVijay Khemka * so return 0x0000 as offset. Might need to change once 1437c1921c63SVijay Khemka * supporting zones in SEL time stamps 1438c1921c63SVijay Khemka */ 1439c1921c63SVijay Khemka 1440c1921c63SVijay Khemka uint16_t utcOffset = 0x0000; 1441c1921c63SVijay Khemka return ipmi::responseSuccess(utcOffset); 1442c1921c63SVijay Khemka } 1443c1921c63SVijay Khemka 144411b9c3b1SVijay Khemka void registerSELFunctions() 144511b9c3b1SVijay Khemka { 144611b9c3b1SVijay Khemka // <Get SEL Info> 144711b9c3b1SVijay Khemka ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage, 144811b9c3b1SVijay Khemka ipmi::storage::cmdGetSelInfo, ipmi::Privilege::User, 144911b9c3b1SVijay Khemka ipmiStorageGetSELInfo); 145011b9c3b1SVijay Khemka 145111b9c3b1SVijay Khemka // <Get SEL Entry> 145211b9c3b1SVijay Khemka ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage, 145311b9c3b1SVijay Khemka ipmi::storage::cmdGetSelEntry, ipmi::Privilege::User, 145411b9c3b1SVijay Khemka ipmiStorageGetSELEntry); 145511b9c3b1SVijay Khemka 145611b9c3b1SVijay Khemka // <Add SEL Entry> 145711b9c3b1SVijay Khemka ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage, 145811b9c3b1SVijay Khemka ipmi::storage::cmdAddSelEntry, 145911b9c3b1SVijay Khemka ipmi::Privilege::Operator, ipmiStorageAddSELEntry); 146011b9c3b1SVijay Khemka 1461c1921c63SVijay Khemka // <Clear SEL> 1462c1921c63SVijay Khemka ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage, 1463c1921c63SVijay Khemka ipmi::storage::cmdClearSel, ipmi::Privilege::Operator, 1464c1921c63SVijay Khemka ipmiStorageClearSEL); 1465c1921c63SVijay Khemka 1466c1921c63SVijay Khemka // <Get SEL Time> 1467c1921c63SVijay Khemka ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage, 1468c1921c63SVijay Khemka ipmi::storage::cmdGetSelTime, ipmi::Privilege::User, 1469c1921c63SVijay Khemka ipmiStorageGetSELTime); 1470c1921c63SVijay Khemka 1471c1921c63SVijay Khemka // <Set SEL Time> 1472c1921c63SVijay Khemka ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage, 1473c1921c63SVijay Khemka ipmi::storage::cmdSetSelTime, 1474c1921c63SVijay Khemka ipmi::Privilege::Operator, ipmiStorageSetSELTime); 1475c1921c63SVijay Khemka 1476c1921c63SVijay Khemka // <Get SEL Time UTC Offset> 1477c1921c63SVijay Khemka ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage, 1478c1921c63SVijay Khemka ipmi::storage::cmdGetSelTimeUtcOffset, 1479c1921c63SVijay Khemka ipmi::Privilege::User, 1480c1921c63SVijay Khemka ipmiStorageGetSELTimeUtcOffset); 1481c1921c63SVijay Khemka 148211b9c3b1SVijay Khemka return; 148311b9c3b1SVijay Khemka } 148411b9c3b1SVijay Khemka 148511b9c3b1SVijay Khemka } // namespace storage 148611b9c3b1SVijay Khemka } // namespace ipmi 1487