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 <boost/algorithm/string/join.hpp> 19020ff3e4SPatrick Williams #include <boost/container/flat_map.hpp> 2063c99be4SVijay Khemka #include <ipmid/api.hpp> 2111b9c3b1SVijay Khemka #include <nlohmann/json.hpp> 2211b9c3b1SVijay Khemka #include <phosphor-logging/log.hpp> 2311b9c3b1SVijay Khemka #include <sdbusplus/message/types.hpp> 2411b9c3b1SVijay Khemka #include <sdbusplus/timer.hpp> 2511b9c3b1SVijay Khemka #include <storagecommands.hpp> 2611b9c3b1SVijay Khemka 2763c99be4SVijay Khemka #include <fstream> 2863c99be4SVijay Khemka #include <iostream> 2963c99be4SVijay Khemka #include <sstream> 3063c99be4SVijay Khemka 317451903cScchoux enum class MemErrType 327451903cScchoux { 337451903cScchoux memTrainErr = 0, 347451903cScchoux memPmicErr = 7 357451903cScchoux }; 367451903cScchoux 377451903cScchoux enum class PostEvtType 387451903cScchoux { 397451903cScchoux pxeBootFail = 0, 407451903cScchoux httpBootFail = 6, 417451903cScchoux getCertFail = 7, 427451903cScchoux amdAblFail = 10 437451903cScchoux }; 447451903cScchoux 457451903cScchoux enum class PcieEvtType 467451903cScchoux { 477451903cScchoux dpc = 0 487451903cScchoux }; 497451903cScchoux 507451903cScchoux enum class MemEvtType 517451903cScchoux { 527451903cScchoux ppr = 0, 537451903cScchoux adddc = 5, 547451903cScchoux noDimm = 7 557451903cScchoux }; 567451903cScchoux 5711b9c3b1SVijay Khemka //---------------------------------------------------------------------- 5811b9c3b1SVijay Khemka // Platform specific functions for storing app data 5911b9c3b1SVijay Khemka //---------------------------------------------------------------------- 6011b9c3b1SVijay Khemka 61139aa4f0SVijay Khemka static std::string byteToStr(uint8_t byte) 62139aa4f0SVijay Khemka { 63139aa4f0SVijay Khemka std::stringstream ss; 64139aa4f0SVijay Khemka 65139aa4f0SVijay Khemka ss << std::hex << std::uppercase << std::setfill('0'); 66139aa4f0SVijay Khemka ss << std::setw(2) << (int)byte; 67139aa4f0SVijay Khemka 68139aa4f0SVijay Khemka return ss.str(); 69139aa4f0SVijay Khemka } 70139aa4f0SVijay Khemka 7111b9c3b1SVijay Khemka static void toHexStr(std::vector<uint8_t>& bytes, std::string& hexStr) 7211b9c3b1SVijay Khemka { 7311b9c3b1SVijay Khemka std::stringstream stream; 7411b9c3b1SVijay Khemka stream << std::hex << std::uppercase << std::setfill('0'); 7511b9c3b1SVijay Khemka for (const uint8_t byte : bytes) 7611b9c3b1SVijay Khemka { 7711b9c3b1SVijay Khemka stream << std::setw(2) << static_cast<int>(byte); 7811b9c3b1SVijay Khemka } 7911b9c3b1SVijay Khemka hexStr = stream.str(); 8011b9c3b1SVijay Khemka } 8111b9c3b1SVijay Khemka 8211b9c3b1SVijay Khemka static int fromHexStr(const std::string hexStr, std::vector<uint8_t>& data) 8311b9c3b1SVijay Khemka { 8411b9c3b1SVijay Khemka for (unsigned int i = 0; i < hexStr.size(); i += 2) 8511b9c3b1SVijay Khemka { 8611b9c3b1SVijay Khemka try 8711b9c3b1SVijay Khemka { 8811b9c3b1SVijay Khemka data.push_back(static_cast<uint8_t>( 8911b9c3b1SVijay Khemka std::stoul(hexStr.substr(i, 2), nullptr, 16))); 9011b9c3b1SVijay Khemka } 9135d12546SPatrick Williams catch (const std::invalid_argument& e) 9211b9c3b1SVijay Khemka { 9311b9c3b1SVijay Khemka phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); 9411b9c3b1SVijay Khemka return -1; 9511b9c3b1SVijay Khemka } 9635d12546SPatrick Williams catch (const std::out_of_range& e) 9711b9c3b1SVijay Khemka { 9811b9c3b1SVijay Khemka phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); 9911b9c3b1SVijay Khemka return -1; 10011b9c3b1SVijay Khemka } 10111b9c3b1SVijay Khemka } 10211b9c3b1SVijay Khemka return 0; 10311b9c3b1SVijay Khemka } 10411b9c3b1SVijay Khemka 10511b9c3b1SVijay Khemka namespace fb_oem::ipmi::sel 10611b9c3b1SVijay Khemka { 10711b9c3b1SVijay Khemka 10811b9c3b1SVijay Khemka class SELData 10911b9c3b1SVijay Khemka { 11011b9c3b1SVijay Khemka private: 11111b9c3b1SVijay Khemka nlohmann::json selDataObj; 11211b9c3b1SVijay Khemka 11311b9c3b1SVijay Khemka void flush() 11411b9c3b1SVijay Khemka { 11511b9c3b1SVijay Khemka std::ofstream file(SEL_JSON_DATA_FILE); 11611b9c3b1SVijay Khemka file << selDataObj; 11711b9c3b1SVijay Khemka file.close(); 11811b9c3b1SVijay Khemka } 11911b9c3b1SVijay Khemka 12011b9c3b1SVijay Khemka void init() 12111b9c3b1SVijay Khemka { 12211b9c3b1SVijay Khemka selDataObj[KEY_SEL_VER] = 0x51; 12311b9c3b1SVijay Khemka selDataObj[KEY_SEL_COUNT] = 0; 12411b9c3b1SVijay Khemka selDataObj[KEY_ADD_TIME] = 0xFFFFFFFF; 12511b9c3b1SVijay Khemka selDataObj[KEY_ERASE_TIME] = 0xFFFFFFFF; 12611b9c3b1SVijay Khemka selDataObj[KEY_OPER_SUPP] = 0x02; 12711b9c3b1SVijay Khemka /* Spec indicates that more than 64kB is free */ 12811b9c3b1SVijay Khemka selDataObj[KEY_FREE_SPACE] = 0xFFFF; 12911b9c3b1SVijay Khemka } 13011b9c3b1SVijay Khemka 13111b9c3b1SVijay Khemka public: 13211b9c3b1SVijay Khemka SELData() 13311b9c3b1SVijay Khemka { 13411b9c3b1SVijay Khemka /* Get App data stored in json file */ 13511b9c3b1SVijay Khemka std::ifstream file(SEL_JSON_DATA_FILE); 13611b9c3b1SVijay Khemka if (file) 13711b9c3b1SVijay Khemka { 13811b9c3b1SVijay Khemka file >> selDataObj; 13911b9c3b1SVijay Khemka file.close(); 14011b9c3b1SVijay Khemka } 14111b9c3b1SVijay Khemka 14211b9c3b1SVijay Khemka /* Initialize SelData object if no entries. */ 14311b9c3b1SVijay Khemka if (selDataObj.find(KEY_SEL_COUNT) == selDataObj.end()) 14411b9c3b1SVijay Khemka { 14511b9c3b1SVijay Khemka init(); 14611b9c3b1SVijay Khemka } 14711b9c3b1SVijay Khemka } 14811b9c3b1SVijay Khemka 14911b9c3b1SVijay Khemka int clear() 15011b9c3b1SVijay Khemka { 15111b9c3b1SVijay Khemka /* Clear the complete Sel Json object */ 15211b9c3b1SVijay Khemka selDataObj.clear(); 15311b9c3b1SVijay Khemka /* Reinitialize it with basic data */ 15411b9c3b1SVijay Khemka init(); 15511b9c3b1SVijay Khemka /* Save the erase time */ 15611b9c3b1SVijay Khemka struct timespec selTime = {}; 15711b9c3b1SVijay Khemka if (clock_gettime(CLOCK_REALTIME, &selTime) < 0) 15811b9c3b1SVijay Khemka { 15911b9c3b1SVijay Khemka return -1; 16011b9c3b1SVijay Khemka } 16111b9c3b1SVijay Khemka selDataObj[KEY_ERASE_TIME] = selTime.tv_sec; 16211b9c3b1SVijay Khemka flush(); 16311b9c3b1SVijay Khemka return 0; 16411b9c3b1SVijay Khemka } 16511b9c3b1SVijay Khemka 16611b9c3b1SVijay Khemka uint32_t getCount() 16711b9c3b1SVijay Khemka { 16811b9c3b1SVijay Khemka return selDataObj[KEY_SEL_COUNT]; 16911b9c3b1SVijay Khemka } 17011b9c3b1SVijay Khemka 17111b9c3b1SVijay Khemka void getInfo(GetSELInfoData& info) 17211b9c3b1SVijay Khemka { 17311b9c3b1SVijay Khemka info.selVersion = selDataObj[KEY_SEL_VER]; 17411b9c3b1SVijay Khemka info.entries = selDataObj[KEY_SEL_COUNT]; 17511b9c3b1SVijay Khemka info.freeSpace = selDataObj[KEY_FREE_SPACE]; 17611b9c3b1SVijay Khemka info.addTimeStamp = selDataObj[KEY_ADD_TIME]; 17711b9c3b1SVijay Khemka info.eraseTimeStamp = selDataObj[KEY_ERASE_TIME]; 17811b9c3b1SVijay Khemka info.operationSupport = selDataObj[KEY_OPER_SUPP]; 17911b9c3b1SVijay Khemka } 18011b9c3b1SVijay Khemka 18111b9c3b1SVijay Khemka int getEntry(uint32_t index, std::string& rawStr) 18211b9c3b1SVijay Khemka { 18311b9c3b1SVijay Khemka std::stringstream ss; 18411b9c3b1SVijay Khemka ss << std::hex; 18511b9c3b1SVijay Khemka ss << std::setw(2) << std::setfill('0') << index; 18611b9c3b1SVijay Khemka 18711b9c3b1SVijay Khemka /* Check or the requested SEL Entry, if record is available */ 18811b9c3b1SVijay Khemka if (selDataObj.find(ss.str()) == selDataObj.end()) 18911b9c3b1SVijay Khemka { 19011b9c3b1SVijay Khemka return -1; 19111b9c3b1SVijay Khemka } 19211b9c3b1SVijay Khemka 19311b9c3b1SVijay Khemka rawStr = selDataObj[ss.str()][KEY_SEL_ENTRY_RAW]; 19411b9c3b1SVijay Khemka return 0; 19511b9c3b1SVijay Khemka } 19611b9c3b1SVijay Khemka 19711b9c3b1SVijay Khemka int addEntry(std::string keyStr) 19811b9c3b1SVijay Khemka { 19911b9c3b1SVijay Khemka struct timespec selTime = {}; 20011b9c3b1SVijay Khemka 20111b9c3b1SVijay Khemka if (clock_gettime(CLOCK_REALTIME, &selTime) < 0) 20211b9c3b1SVijay Khemka { 20311b9c3b1SVijay Khemka return -1; 20411b9c3b1SVijay Khemka } 20511b9c3b1SVijay Khemka 20611b9c3b1SVijay Khemka selDataObj[KEY_ADD_TIME] = selTime.tv_sec; 20711b9c3b1SVijay Khemka 20811b9c3b1SVijay Khemka int selCount = selDataObj[KEY_SEL_COUNT]; 20911b9c3b1SVijay Khemka selDataObj[KEY_SEL_COUNT] = ++selCount; 21011b9c3b1SVijay Khemka 21111b9c3b1SVijay Khemka std::stringstream ss; 21211b9c3b1SVijay Khemka ss << std::hex; 21311b9c3b1SVijay Khemka ss << std::setw(2) << std::setfill('0') << selCount; 21411b9c3b1SVijay Khemka 21511b9c3b1SVijay Khemka selDataObj[ss.str()][KEY_SEL_ENTRY_RAW] = keyStr; 21611b9c3b1SVijay Khemka flush(); 21711b9c3b1SVijay Khemka return selCount; 21811b9c3b1SVijay Khemka } 21911b9c3b1SVijay Khemka }; 22011b9c3b1SVijay Khemka 221139aa4f0SVijay Khemka /* 222519530beSManojkiran Eda * A Function to parse common SEL message, a helper function 223139aa4f0SVijay Khemka * for parseStdSel. 224139aa4f0SVijay Khemka * 225519530beSManojkiran Eda * Note that this function __CANNOT__ be overridden. 226139aa4f0SVijay Khemka * To add board specific routine, please override parseStdSel. 227139aa4f0SVijay Khemka */ 228139aa4f0SVijay Khemka 229139aa4f0SVijay Khemka /*Used by decoding ME event*/ 230139aa4f0SVijay Khemka std::vector<std::string> nmDomName = { 231139aa4f0SVijay Khemka "Entire Platform", "CPU Subsystem", 232139aa4f0SVijay Khemka "Memory Subsystem", "HW Protection", 233139aa4f0SVijay Khemka "High Power I/O subsystem", "Unknown"}; 234139aa4f0SVijay Khemka 235139aa4f0SVijay Khemka /* Default log message for unknown type */ 236e39f9393SWilly Tu static void logDefault(uint8_t*, std::string& errLog) 237139aa4f0SVijay Khemka { 238139aa4f0SVijay Khemka errLog = "Unknown"; 239139aa4f0SVijay Khemka } 240139aa4f0SVijay Khemka 241139aa4f0SVijay Khemka static void logSysEvent(uint8_t* data, std::string& errLog) 242139aa4f0SVijay Khemka { 243139aa4f0SVijay Khemka if (data[0] == 0xE5) 244139aa4f0SVijay Khemka { 245139aa4f0SVijay Khemka errLog = "Cause of Time change - "; 246139aa4f0SVijay Khemka switch (data[2]) 247139aa4f0SVijay Khemka { 248139aa4f0SVijay Khemka case 0x00: 249139aa4f0SVijay Khemka errLog += "NTP"; 250139aa4f0SVijay Khemka break; 251139aa4f0SVijay Khemka case 0x01: 252139aa4f0SVijay Khemka errLog += "Host RTL"; 253139aa4f0SVijay Khemka break; 254139aa4f0SVijay Khemka case 0x02: 255139aa4f0SVijay Khemka errLog += "Set SEL time cmd"; 256139aa4f0SVijay Khemka break; 257139aa4f0SVijay Khemka case 0x03: 258139aa4f0SVijay Khemka errLog += "Set SEL time UTC offset cmd"; 259139aa4f0SVijay Khemka break; 260139aa4f0SVijay Khemka default: 261139aa4f0SVijay Khemka errLog += "Unknown"; 262139aa4f0SVijay Khemka } 263139aa4f0SVijay Khemka 264139aa4f0SVijay Khemka if (data[1] == 0x00) 265139aa4f0SVijay Khemka errLog += " - First Time"; 266139aa4f0SVijay Khemka else if (data[1] == 0x80) 267139aa4f0SVijay Khemka errLog += " - Second Time"; 268139aa4f0SVijay Khemka } 269139aa4f0SVijay Khemka else 270139aa4f0SVijay Khemka { 271139aa4f0SVijay Khemka errLog = "Unknown"; 272139aa4f0SVijay Khemka } 273139aa4f0SVijay Khemka } 274139aa4f0SVijay Khemka 275139aa4f0SVijay Khemka static void logThermalEvent(uint8_t* data, std::string& errLog) 276139aa4f0SVijay Khemka { 277139aa4f0SVijay Khemka if (data[0] == 0x1) 278139aa4f0SVijay Khemka { 279139aa4f0SVijay Khemka errLog = "Limit Exceeded"; 280139aa4f0SVijay Khemka } 281139aa4f0SVijay Khemka else 282139aa4f0SVijay Khemka { 283139aa4f0SVijay Khemka errLog = "Unknown"; 284139aa4f0SVijay Khemka } 285139aa4f0SVijay Khemka } 286139aa4f0SVijay Khemka 287139aa4f0SVijay Khemka static void logCritIrq(uint8_t* data, std::string& errLog) 288139aa4f0SVijay Khemka { 289139aa4f0SVijay Khemka if (data[0] == 0x0) 290139aa4f0SVijay Khemka { 291139aa4f0SVijay Khemka errLog = "NMI / Diagnostic Interrupt"; 292139aa4f0SVijay Khemka } 293139aa4f0SVijay Khemka else if (data[0] == 0x03) 294139aa4f0SVijay Khemka { 295139aa4f0SVijay Khemka errLog = "Software NMI"; 296139aa4f0SVijay Khemka } 297139aa4f0SVijay Khemka else 298139aa4f0SVijay Khemka { 299139aa4f0SVijay Khemka errLog = "Unknown"; 300139aa4f0SVijay Khemka } 301139aa4f0SVijay Khemka 302139aa4f0SVijay Khemka /* TODO: Call add_cri_sel for CRITICAL_IRQ */ 303139aa4f0SVijay Khemka } 304139aa4f0SVijay Khemka 305139aa4f0SVijay Khemka static void logPostErr(uint8_t* data, std::string& errLog) 306139aa4f0SVijay Khemka { 307139aa4f0SVijay Khemka if ((data[0] & 0x0F) == 0x0) 308139aa4f0SVijay Khemka { 309139aa4f0SVijay Khemka errLog = "System Firmware Error"; 310139aa4f0SVijay Khemka } 311139aa4f0SVijay Khemka else 312139aa4f0SVijay Khemka { 313139aa4f0SVijay Khemka errLog = "Unknown"; 314139aa4f0SVijay Khemka } 315139aa4f0SVijay Khemka 316139aa4f0SVijay Khemka if (((data[0] >> 6) & 0x03) == 0x3) 317139aa4f0SVijay Khemka { 318139aa4f0SVijay Khemka // TODO: Need to implement IPMI spec based Post Code 319139aa4f0SVijay Khemka errLog += ", IPMI Post Code"; 320139aa4f0SVijay Khemka } 321139aa4f0SVijay Khemka else if (((data[0] >> 6) & 0x03) == 0x2) 322139aa4f0SVijay Khemka { 3232405ae98SPatrick Williams errLog += ", OEM Post Code 0x" + byteToStr(data[2]) + 3242405ae98SPatrick Williams byteToStr(data[1]); 325139aa4f0SVijay Khemka 326139aa4f0SVijay Khemka switch ((data[2] << 8) | data[1]) 327139aa4f0SVijay Khemka { 328139aa4f0SVijay Khemka case 0xA105: 329139aa4f0SVijay Khemka errLog += ", BMC Failed (No Response)"; 330139aa4f0SVijay Khemka break; 331139aa4f0SVijay Khemka case 0xA106: 332139aa4f0SVijay Khemka errLog += ", BMC Failed (Self Test Fail)"; 333139aa4f0SVijay Khemka break; 334139aa4f0SVijay Khemka case 0xA10A: 335139aa4f0SVijay Khemka errLog += ", System Firmware Corruption Detected"; 336139aa4f0SVijay Khemka break; 337139aa4f0SVijay Khemka case 0xA10B: 338139aa4f0SVijay Khemka errLog += ", TPM Self-Test FAIL Detected"; 339139aa4f0SVijay Khemka } 340139aa4f0SVijay Khemka } 341139aa4f0SVijay Khemka } 342139aa4f0SVijay Khemka 343139aa4f0SVijay Khemka static void logMchChkErr(uint8_t* data, std::string& errLog) 344139aa4f0SVijay Khemka { 345139aa4f0SVijay Khemka /* TODO: Call add_cri_sel for CRITICAL_IRQ */ 346*d17c356eSDaniel Hsu switch (data[0] & 0x0F) 347139aa4f0SVijay Khemka { 348*d17c356eSDaniel Hsu case 0x0B: 349*d17c356eSDaniel Hsu switch ((data[1] >> 5) & 0x03) 350*d17c356eSDaniel Hsu { 351*d17c356eSDaniel Hsu case 0x00: 352*d17c356eSDaniel Hsu errLog = "Uncorrected Recoverable Error"; 353*d17c356eSDaniel Hsu break; 354*d17c356eSDaniel Hsu case 0x01: 355*d17c356eSDaniel Hsu errLog = "Uncorrected Thread Fatal Error"; 356*d17c356eSDaniel Hsu break; 357*d17c356eSDaniel Hsu case 0x02: 358*d17c356eSDaniel Hsu errLog = "Uncorrected System Fatal Error"; 359*d17c356eSDaniel Hsu break; 360*d17c356eSDaniel Hsu default: 361*d17c356eSDaniel Hsu errLog = "Unknown"; 362139aa4f0SVijay Khemka } 363*d17c356eSDaniel Hsu break; 364*d17c356eSDaniel Hsu case 0x0C: 365*d17c356eSDaniel Hsu switch ((data[1] >> 5) & 0x03) 366139aa4f0SVijay Khemka { 367*d17c356eSDaniel Hsu case 0x00: 368*d17c356eSDaniel Hsu errLog = "Correctable Error"; 369*d17c356eSDaniel Hsu break; 370*d17c356eSDaniel Hsu case 0x01: 371*d17c356eSDaniel Hsu errLog = "Deferred Error"; 372*d17c356eSDaniel Hsu break; 373*d17c356eSDaniel Hsu default: 374*d17c356eSDaniel Hsu errLog = "Unknown"; 375139aa4f0SVijay Khemka } 376*d17c356eSDaniel Hsu break; 377*d17c356eSDaniel Hsu default: 378139aa4f0SVijay Khemka errLog = "Unknown"; 379139aa4f0SVijay Khemka } 380139aa4f0SVijay Khemka 381139aa4f0SVijay Khemka errLog += ", Machine Check bank Number " + std::to_string(data[1]) + 382139aa4f0SVijay Khemka ", CPU " + std::to_string(data[2] >> 5) + ", Core " + 383139aa4f0SVijay Khemka std::to_string(data[2] & 0x1F); 384139aa4f0SVijay Khemka } 385139aa4f0SVijay Khemka 386139aa4f0SVijay Khemka static void logPcieErr(uint8_t* data, std::string& errLog) 387139aa4f0SVijay Khemka { 388139aa4f0SVijay Khemka std::stringstream tmp1, tmp2; 389139aa4f0SVijay Khemka tmp1 << std::hex << std::uppercase << std::setfill('0'); 390139aa4f0SVijay Khemka tmp2 << std::hex << std::uppercase << std::setfill('0'); 391139aa4f0SVijay Khemka tmp1 << " (Bus " << std::setw(2) << (int)(data[2]) << " / Dev " 392139aa4f0SVijay Khemka << std::setw(2) << (int)(data[1] >> 3) << " / Fun " << std::setw(2) 393139aa4f0SVijay Khemka << (int)(data[1] & 0x7) << ")"; 394139aa4f0SVijay Khemka 395139aa4f0SVijay Khemka switch (data[0] & 0xF) 396139aa4f0SVijay Khemka { 397139aa4f0SVijay Khemka case 0x4: 398139aa4f0SVijay Khemka errLog = "PCI PERR" + tmp1.str(); 399139aa4f0SVijay Khemka break; 400139aa4f0SVijay Khemka case 0x5: 401139aa4f0SVijay Khemka errLog = "PCI SERR" + tmp1.str(); 402139aa4f0SVijay Khemka break; 403139aa4f0SVijay Khemka case 0x7: 404139aa4f0SVijay Khemka errLog = "Correctable" + tmp1.str(); 405139aa4f0SVijay Khemka break; 406139aa4f0SVijay Khemka case 0x8: 407139aa4f0SVijay Khemka errLog = "Uncorrectable" + tmp1.str(); 408139aa4f0SVijay Khemka break; 409139aa4f0SVijay Khemka case 0xA: 410139aa4f0SVijay Khemka errLog = "Bus Fatal" + tmp1.str(); 411139aa4f0SVijay Khemka break; 412d1194024SVijay Khemka case 0xD: 413d1194024SVijay Khemka { 414139aa4f0SVijay Khemka uint32_t venId = (uint32_t)data[1] << 8 | (uint32_t)data[2]; 415139aa4f0SVijay Khemka tmp2 << "Vendor ID: 0x" << std::setw(4) << venId; 416139aa4f0SVijay Khemka errLog = tmp2.str(); 417139aa4f0SVijay Khemka } 418139aa4f0SVijay Khemka break; 419d1194024SVijay Khemka case 0xE: 420d1194024SVijay Khemka { 421139aa4f0SVijay Khemka uint32_t devId = (uint32_t)data[1] << 8 | (uint32_t)data[2]; 422139aa4f0SVijay Khemka tmp2 << "Device ID: 0x" << std::setw(4) << devId; 423139aa4f0SVijay Khemka errLog = tmp2.str(); 424139aa4f0SVijay Khemka } 425139aa4f0SVijay Khemka break; 426139aa4f0SVijay Khemka case 0xF: 427139aa4f0SVijay Khemka tmp2 << "Error ID from downstream: 0x" << std::setw(2) 428139aa4f0SVijay Khemka << (int)(data[1]) << std::setw(2) << (int)(data[2]); 429139aa4f0SVijay Khemka errLog = tmp2.str(); 430139aa4f0SVijay Khemka break; 431139aa4f0SVijay Khemka default: 432139aa4f0SVijay Khemka errLog = "Unknown"; 433139aa4f0SVijay Khemka } 434139aa4f0SVijay Khemka } 435139aa4f0SVijay Khemka 436139aa4f0SVijay Khemka static void logIioErr(uint8_t* data, std::string& errLog) 437139aa4f0SVijay Khemka { 438139aa4f0SVijay Khemka std::vector<std::string> tmpStr = { 439139aa4f0SVijay Khemka "IRP0", "IRP1", " IIO-Core", "VT-d", "Intel Quick Data", 440139aa4f0SVijay Khemka "Misc", " DMA", "ITC", "OTC", "CI"}; 441139aa4f0SVijay Khemka 442139aa4f0SVijay Khemka if ((data[0] & 0xF) == 0) 443139aa4f0SVijay Khemka { 444139aa4f0SVijay Khemka errLog += "CPU " + std::to_string(data[2] >> 5) + ", Error ID 0x" + 445139aa4f0SVijay Khemka byteToStr(data[1]) + " - "; 446139aa4f0SVijay Khemka 447139aa4f0SVijay Khemka if ((data[2] & 0xF) <= 0x9) 448139aa4f0SVijay Khemka { 449139aa4f0SVijay Khemka errLog += tmpStr[(data[2] & 0xF)]; 450139aa4f0SVijay Khemka } 451139aa4f0SVijay Khemka else 452139aa4f0SVijay Khemka { 453139aa4f0SVijay Khemka errLog += "Reserved"; 454139aa4f0SVijay Khemka } 455139aa4f0SVijay Khemka } 456139aa4f0SVijay Khemka else 457139aa4f0SVijay Khemka { 458139aa4f0SVijay Khemka errLog = "Unknown"; 459139aa4f0SVijay Khemka } 460139aa4f0SVijay Khemka } 461139aa4f0SVijay Khemka 462e39f9393SWilly Tu [[maybe_unused]] static void logMemErr(uint8_t* dataPtr, std::string& errLog) 463139aa4f0SVijay Khemka { 464139aa4f0SVijay Khemka uint8_t snrType = dataPtr[0]; 465139aa4f0SVijay Khemka uint8_t snrNum = dataPtr[1]; 466139aa4f0SVijay Khemka uint8_t* data = &(dataPtr[3]); 467139aa4f0SVijay Khemka 468139aa4f0SVijay Khemka /* TODO: add pal_add_cri_sel */ 469139aa4f0SVijay Khemka 470139aa4f0SVijay Khemka if (snrNum == memoryEccError) 471139aa4f0SVijay Khemka { 472139aa4f0SVijay Khemka /* SEL from MEMORY_ECC_ERR Sensor */ 473139aa4f0SVijay Khemka switch (data[0] & 0x0F) 474139aa4f0SVijay Khemka { 475139aa4f0SVijay Khemka case 0x0: 476139aa4f0SVijay Khemka if (snrType == 0x0C) 477139aa4f0SVijay Khemka { 478139aa4f0SVijay Khemka errLog = "Correctable"; 479139aa4f0SVijay Khemka } 480139aa4f0SVijay Khemka else if (snrType == 0x10) 481139aa4f0SVijay Khemka { 482139aa4f0SVijay Khemka errLog = "Correctable ECC error Logging Disabled"; 483139aa4f0SVijay Khemka } 484139aa4f0SVijay Khemka break; 485139aa4f0SVijay Khemka case 0x1: 486139aa4f0SVijay Khemka errLog = "Uncorrectable"; 487139aa4f0SVijay Khemka break; 488139aa4f0SVijay Khemka case 0x5: 489139aa4f0SVijay Khemka errLog = "Correctable ECC error Logging Limit Disabled"; 490139aa4f0SVijay Khemka break; 491139aa4f0SVijay Khemka default: 492139aa4f0SVijay Khemka errLog = "Unknown"; 493139aa4f0SVijay Khemka } 494139aa4f0SVijay Khemka } 495139aa4f0SVijay Khemka else if (snrNum == memoryErrLogDIS) 496139aa4f0SVijay Khemka { 497139aa4f0SVijay Khemka // SEL from MEMORY_ERR_LOG_DIS Sensor 498139aa4f0SVijay Khemka if ((data[0] & 0x0F) == 0x0) 499139aa4f0SVijay Khemka { 500139aa4f0SVijay Khemka errLog = "Correctable Memory Error Logging Disabled"; 501139aa4f0SVijay Khemka } 502139aa4f0SVijay Khemka else 503139aa4f0SVijay Khemka { 504139aa4f0SVijay Khemka errLog = "Unknown"; 505139aa4f0SVijay Khemka } 506139aa4f0SVijay Khemka } 507139aa4f0SVijay Khemka else 508139aa4f0SVijay Khemka { 509139aa4f0SVijay Khemka errLog = "Unknown"; 510139aa4f0SVijay Khemka return; 511139aa4f0SVijay Khemka } 512139aa4f0SVijay Khemka 513139aa4f0SVijay Khemka /* Common routine for both MEM_ECC_ERR and MEMORY_ERR_LOG_DIS */ 514139aa4f0SVijay Khemka 515139aa4f0SVijay Khemka errLog += " (DIMM " + byteToStr(data[2]) + ") Logical Rank " + 516139aa4f0SVijay Khemka std::to_string(data[1] & 0x03); 517139aa4f0SVijay Khemka 518139aa4f0SVijay Khemka /* DIMM number (data[2]): 519139aa4f0SVijay Khemka * Bit[7:5]: Socket number (Range: 0-7) 520139aa4f0SVijay Khemka * Bit[4:3]: Channel number (Range: 0-3) 521139aa4f0SVijay Khemka * Bit[2:0]: DIMM number (Range: 0-7) 522139aa4f0SVijay Khemka */ 523139aa4f0SVijay Khemka 524139aa4f0SVijay Khemka /* TODO: Verify these bits */ 525139aa4f0SVijay Khemka std::string cpuStr = "CPU# " + std::to_string((data[2] & 0xE0) >> 5); 526139aa4f0SVijay Khemka std::string chStr = "CHN# " + std::to_string((data[2] & 0x18) >> 3); 527139aa4f0SVijay Khemka std::string dimmStr = "DIMM#" + std::to_string(data[2] & 0x7); 528139aa4f0SVijay Khemka 529139aa4f0SVijay Khemka switch ((data[1] & 0xC) >> 2) 530139aa4f0SVijay Khemka { 531d1194024SVijay Khemka case 0x0: 532d1194024SVijay Khemka { 533139aa4f0SVijay Khemka /* All Info Valid */ 534e39f9393SWilly Tu [[maybe_unused]] uint8_t chnNum = (data[2] & 0x1C) >> 2; 535e39f9393SWilly Tu [[maybe_unused]] uint8_t dimmNum = data[2] & 0x3; 536139aa4f0SVijay Khemka 537139aa4f0SVijay Khemka /* TODO: If critical SEL logging is available, do it */ 538139aa4f0SVijay Khemka if (snrType == 0x0C) 539139aa4f0SVijay Khemka { 540139aa4f0SVijay Khemka if ((data[0] & 0x0F) == 0x0) 541139aa4f0SVijay Khemka { 542139aa4f0SVijay Khemka /* TODO: add_cri_sel */ 543139aa4f0SVijay Khemka /* "DIMM"+ 'A'+ chnNum + dimmNum + " ECC err,FRU:1" 544139aa4f0SVijay Khemka */ 545139aa4f0SVijay Khemka } 546139aa4f0SVijay Khemka else if ((data[0] & 0x0F) == 0x1) 547139aa4f0SVijay Khemka { 548139aa4f0SVijay Khemka /* TODO: add_cri_sel */ 549139aa4f0SVijay Khemka /* "DIMM"+ 'A'+ chnNum + dimmNum + " UECC err,FRU:1" 550139aa4f0SVijay Khemka */ 551139aa4f0SVijay Khemka } 552139aa4f0SVijay Khemka } 553139aa4f0SVijay Khemka /* Continue to parse the error into a string. All Info Valid 554139aa4f0SVijay Khemka */ 555139aa4f0SVijay Khemka errLog += " (" + cpuStr + ", " + chStr + ", " + dimmStr + ")"; 556139aa4f0SVijay Khemka } 557139aa4f0SVijay Khemka 558139aa4f0SVijay Khemka break; 559139aa4f0SVijay Khemka case 0x1: 560139aa4f0SVijay Khemka 561139aa4f0SVijay Khemka /* DIMM info not valid */ 562139aa4f0SVijay Khemka errLog += " (" + cpuStr + ", " + chStr + ")"; 563139aa4f0SVijay Khemka break; 564139aa4f0SVijay Khemka case 0x2: 565139aa4f0SVijay Khemka 566139aa4f0SVijay Khemka /* CHN info not valid */ 567139aa4f0SVijay Khemka errLog += " (" + cpuStr + ", " + dimmStr + ")"; 568139aa4f0SVijay Khemka break; 569139aa4f0SVijay Khemka case 0x3: 570139aa4f0SVijay Khemka 571139aa4f0SVijay Khemka /* CPU info not valid */ 572139aa4f0SVijay Khemka errLog += " (" + chStr + ", " + dimmStr + ")"; 573139aa4f0SVijay Khemka break; 574139aa4f0SVijay Khemka } 575139aa4f0SVijay Khemka } 576139aa4f0SVijay Khemka 577139aa4f0SVijay Khemka static void logPwrErr(uint8_t* data, std::string& errLog) 578139aa4f0SVijay Khemka { 579139aa4f0SVijay Khemka if (data[0] == 0x1) 580139aa4f0SVijay Khemka { 581139aa4f0SVijay Khemka errLog = "SYS_PWROK failure"; 582519530beSManojkiran Eda /* Also try logging to Critical log file, if available */ 583139aa4f0SVijay Khemka /* "SYS_PWROK failure,FRU:1" */ 584139aa4f0SVijay Khemka } 585139aa4f0SVijay Khemka else if (data[0] == 0x2) 586139aa4f0SVijay Khemka { 587139aa4f0SVijay Khemka errLog = "PCH_PWROK failure"; 588519530beSManojkiran Eda /* Also try logging to Critical log file, if available */ 589139aa4f0SVijay Khemka /* "PCH_PWROK failure,FRU:1" */ 590139aa4f0SVijay Khemka } 591139aa4f0SVijay Khemka else 592139aa4f0SVijay Khemka { 593139aa4f0SVijay Khemka errLog = "Unknown"; 594139aa4f0SVijay Khemka } 595139aa4f0SVijay Khemka } 596139aa4f0SVijay Khemka 597139aa4f0SVijay Khemka static void logCatErr(uint8_t* data, std::string& errLog) 598139aa4f0SVijay Khemka { 599139aa4f0SVijay Khemka if (data[0] == 0x0) 600139aa4f0SVijay Khemka { 601139aa4f0SVijay Khemka errLog = "IERR/CATERR"; 602519530beSManojkiran Eda /* Also try logging to Critical log file, if available */ 603139aa4f0SVijay Khemka /* "IERR,FRU:1 */ 604139aa4f0SVijay Khemka } 605139aa4f0SVijay Khemka else if (data[0] == 0xB) 606139aa4f0SVijay Khemka { 607139aa4f0SVijay Khemka errLog = "MCERR/CATERR"; 608519530beSManojkiran Eda /* Also try logging to Critical log file, if available */ 609139aa4f0SVijay Khemka /* "MCERR,FRU:1 */ 610139aa4f0SVijay Khemka } 611139aa4f0SVijay Khemka else 612139aa4f0SVijay Khemka { 613139aa4f0SVijay Khemka errLog = "Unknown"; 614139aa4f0SVijay Khemka } 615139aa4f0SVijay Khemka } 616139aa4f0SVijay Khemka 617139aa4f0SVijay Khemka static void logDimmHot(uint8_t* data, std::string& errLog) 618139aa4f0SVijay Khemka { 619139aa4f0SVijay Khemka if ((data[0] << 16 | data[1] << 8 | data[2]) == 0x01FFFF) 620139aa4f0SVijay Khemka { 621139aa4f0SVijay Khemka errLog = "SOC MEMHOT"; 622139aa4f0SVijay Khemka } 623139aa4f0SVijay Khemka else 624139aa4f0SVijay Khemka { 625139aa4f0SVijay Khemka errLog = "Unknown"; 626519530beSManojkiran Eda /* Also try logging to Critical log file, if available */ 627139aa4f0SVijay Khemka /* ""CPU_DIMM_HOT %s,FRU:1" */ 628139aa4f0SVijay Khemka } 629139aa4f0SVijay Khemka } 630139aa4f0SVijay Khemka 631139aa4f0SVijay Khemka static void logSwNMI(uint8_t* data, std::string& errLog) 632139aa4f0SVijay Khemka { 633139aa4f0SVijay Khemka if ((data[0] << 16 | data[1] << 8 | data[2]) == 0x03FFFF) 634139aa4f0SVijay Khemka { 635139aa4f0SVijay Khemka errLog = "Software NMI"; 636139aa4f0SVijay Khemka } 637139aa4f0SVijay Khemka else 638139aa4f0SVijay Khemka { 639139aa4f0SVijay Khemka errLog = "Unknown SW NMI"; 640139aa4f0SVijay Khemka } 641139aa4f0SVijay Khemka } 642139aa4f0SVijay Khemka 643139aa4f0SVijay Khemka static void logCPUThermalSts(uint8_t* data, std::string& errLog) 644139aa4f0SVijay Khemka { 645139aa4f0SVijay Khemka switch (data[0]) 646139aa4f0SVijay Khemka { 647139aa4f0SVijay Khemka case 0x0: 648139aa4f0SVijay Khemka errLog = "CPU Critical Temperature"; 649139aa4f0SVijay Khemka break; 650139aa4f0SVijay Khemka case 0x1: 651139aa4f0SVijay Khemka errLog = "PROCHOT#"; 652139aa4f0SVijay Khemka break; 653139aa4f0SVijay Khemka case 0x2: 654139aa4f0SVijay Khemka errLog = "TCC Activation"; 655139aa4f0SVijay Khemka break; 656139aa4f0SVijay Khemka default: 657139aa4f0SVijay Khemka errLog = "Unknown"; 658139aa4f0SVijay Khemka } 659139aa4f0SVijay Khemka } 660139aa4f0SVijay Khemka 661139aa4f0SVijay Khemka static void logMEPwrState(uint8_t* data, std::string& errLog) 662139aa4f0SVijay Khemka { 663139aa4f0SVijay Khemka switch (data[0]) 664139aa4f0SVijay Khemka { 665139aa4f0SVijay Khemka case 0: 666139aa4f0SVijay Khemka errLog = "RUNNING"; 667139aa4f0SVijay Khemka break; 668139aa4f0SVijay Khemka case 2: 669139aa4f0SVijay Khemka errLog = "POWER_OFF"; 670139aa4f0SVijay Khemka break; 671139aa4f0SVijay Khemka default: 672139aa4f0SVijay Khemka errLog = "Unknown[" + std::to_string(data[0]) + "]"; 673139aa4f0SVijay Khemka break; 674139aa4f0SVijay Khemka } 675139aa4f0SVijay Khemka } 676139aa4f0SVijay Khemka 677139aa4f0SVijay Khemka static void logSPSFwHealth(uint8_t* data, std::string& errLog) 678139aa4f0SVijay Khemka { 679139aa4f0SVijay Khemka if ((data[0] & 0x0F) == 0x00) 680139aa4f0SVijay Khemka { 681139aa4f0SVijay Khemka const std::vector<std::string> tmpStr = { 682139aa4f0SVijay Khemka "Recovery GPIO forced", 683139aa4f0SVijay Khemka "Image execution failed", 684139aa4f0SVijay Khemka "Flash erase error", 685139aa4f0SVijay Khemka "Flash state information", 686139aa4f0SVijay Khemka "Internal error", 687139aa4f0SVijay Khemka "BMC did not respond", 688139aa4f0SVijay Khemka "Direct Flash update", 689139aa4f0SVijay Khemka "Manufacturing error", 690139aa4f0SVijay Khemka "Automatic Restore to Factory Presets", 691139aa4f0SVijay Khemka "Firmware Exception", 692139aa4f0SVijay Khemka "Flash Wear-Out Protection Warning", 693139aa4f0SVijay Khemka "Unknown", 694139aa4f0SVijay Khemka "Unknown", 695139aa4f0SVijay Khemka "DMI interface error", 696139aa4f0SVijay Khemka "MCTP interface error", 697139aa4f0SVijay Khemka "Auto-configuration finished", 698139aa4f0SVijay Khemka "Unsupported Segment Defined Feature", 699139aa4f0SVijay Khemka "Unknown", 700139aa4f0SVijay Khemka "CPU Debug Capability Disabled", 701139aa4f0SVijay Khemka "UMA operation error"}; 702139aa4f0SVijay Khemka 703139aa4f0SVijay Khemka if (data[1] < 0x14) 704139aa4f0SVijay Khemka { 705139aa4f0SVijay Khemka errLog = tmpStr[data[1]]; 706139aa4f0SVijay Khemka } 707139aa4f0SVijay Khemka else 708139aa4f0SVijay Khemka { 709139aa4f0SVijay Khemka errLog = "Unknown"; 710139aa4f0SVijay Khemka } 711139aa4f0SVijay Khemka } 712139aa4f0SVijay Khemka else if ((data[0] & 0x0F) == 0x01) 713139aa4f0SVijay Khemka { 714139aa4f0SVijay Khemka errLog = "SMBus link failure"; 715139aa4f0SVijay Khemka } 716139aa4f0SVijay Khemka else 717139aa4f0SVijay Khemka { 718139aa4f0SVijay Khemka errLog = "Unknown"; 719139aa4f0SVijay Khemka } 720139aa4f0SVijay Khemka } 721139aa4f0SVijay Khemka 722139aa4f0SVijay Khemka static void logNmExcA(uint8_t* data, std::string& errLog) 723139aa4f0SVijay Khemka { 724139aa4f0SVijay Khemka /*NM4.0 #550710, Revision 1.95, and turn to p.155*/ 725139aa4f0SVijay Khemka if (data[0] == 0xA8) 726139aa4f0SVijay Khemka { 727139aa4f0SVijay Khemka errLog = "Policy Correction Time Exceeded"; 728139aa4f0SVijay Khemka } 729139aa4f0SVijay Khemka else 730139aa4f0SVijay Khemka { 731139aa4f0SVijay Khemka errLog = "Unknown"; 732139aa4f0SVijay Khemka } 733139aa4f0SVijay Khemka } 734139aa4f0SVijay Khemka 735139aa4f0SVijay Khemka static void logPCHThermal(uint8_t* data, std::string& errLog) 736139aa4f0SVijay Khemka { 737010dee04SPatrick Williams const std::vector<std::string> thresEvtName = { 738010dee04SPatrick Williams "Lower Non-critical", 739139aa4f0SVijay Khemka "Unknown", 740139aa4f0SVijay Khemka "Lower Critical", 741139aa4f0SVijay Khemka "Unknown", 742139aa4f0SVijay Khemka "Lower Non-recoverable", 743139aa4f0SVijay Khemka "Unknown", 744139aa4f0SVijay Khemka "Unknown", 745139aa4f0SVijay Khemka "Upper Non-critical", 746139aa4f0SVijay Khemka "Unknown", 747139aa4f0SVijay Khemka "Upper Critical", 748139aa4f0SVijay Khemka "Unknown", 749139aa4f0SVijay Khemka "Upper Non-recoverable"}; 750139aa4f0SVijay Khemka 751139aa4f0SVijay Khemka if ((data[0] & 0x0f) < 12) 752139aa4f0SVijay Khemka { 753139aa4f0SVijay Khemka errLog = thresEvtName[(data[0] & 0x0f)]; 754139aa4f0SVijay Khemka } 755139aa4f0SVijay Khemka else 756139aa4f0SVijay Khemka { 757139aa4f0SVijay Khemka errLog = "Unknown"; 758139aa4f0SVijay Khemka } 759139aa4f0SVijay Khemka 760139aa4f0SVijay Khemka errLog += ", curr_val: " + std::to_string(data[1]) + 761139aa4f0SVijay Khemka " C, thresh_val: " + std::to_string(data[2]) + " C"; 762139aa4f0SVijay Khemka } 763139aa4f0SVijay Khemka 764139aa4f0SVijay Khemka static void logNmHealth(uint8_t* data, std::string& errLog) 765139aa4f0SVijay Khemka { 766139aa4f0SVijay Khemka std::vector<std::string> nmErrType = { 767139aa4f0SVijay Khemka "Unknown", 768139aa4f0SVijay Khemka "Unknown", 769139aa4f0SVijay Khemka "Unknown", 770139aa4f0SVijay Khemka "Unknown", 771139aa4f0SVijay Khemka "Unknown", 772139aa4f0SVijay Khemka "Unknown", 773139aa4f0SVijay Khemka "Unknown", 774139aa4f0SVijay Khemka "Extended Telemetry Device Reading Failure", 775139aa4f0SVijay Khemka "Outlet Temperature Reading Failure", 776139aa4f0SVijay Khemka "Volumetric Airflow Reading Failure", 777139aa4f0SVijay Khemka "Policy Misconfiguration", 778139aa4f0SVijay Khemka "Power Sensor Reading Failure", 779139aa4f0SVijay Khemka "Inlet Temperature Reading Failure", 780139aa4f0SVijay Khemka "Host Communication Error", 781139aa4f0SVijay Khemka "Real-time Clock Synchronization Failure", 782139aa4f0SVijay Khemka "Platform Shutdown Initiated by Intel NM Policy", 783139aa4f0SVijay Khemka "Unknown"}; 784139aa4f0SVijay Khemka uint8_t nmTypeIdx = (data[0] & 0xf); 785139aa4f0SVijay Khemka uint8_t domIdx = (data[1] & 0xf); 786139aa4f0SVijay Khemka uint8_t errIdx = ((data[1] >> 4) & 0xf); 787139aa4f0SVijay Khemka 788139aa4f0SVijay Khemka if (nmTypeIdx == 2) 789139aa4f0SVijay Khemka { 790139aa4f0SVijay Khemka errLog = "SensorIntelNM"; 791139aa4f0SVijay Khemka } 792139aa4f0SVijay Khemka else 793139aa4f0SVijay Khemka { 794139aa4f0SVijay Khemka errLog = "Unknown"; 795139aa4f0SVijay Khemka } 796139aa4f0SVijay Khemka 797010dee04SPatrick Williams errLog += ", Domain:" + nmDomName[domIdx] + ", ErrType:" + 798010dee04SPatrick Williams nmErrType[errIdx] + ", Err:0x" + byteToStr(data[2]); 799139aa4f0SVijay Khemka } 800139aa4f0SVijay Khemka 801139aa4f0SVijay Khemka static void logNmCap(uint8_t* data, std::string& errLog) 802139aa4f0SVijay Khemka { 803139aa4f0SVijay Khemka const std::vector<std::string> nmCapStsStr = {"Not Available", "Available"}; 804139aa4f0SVijay Khemka if (data[0] & 0x7) // BIT1=policy, BIT2=monitoring, BIT3=pwr 805139aa4f0SVijay Khemka // limit and the others are reserved 806139aa4f0SVijay Khemka { 807139aa4f0SVijay Khemka errLog = "PolicyInterface:" + nmCapStsStr[BIT(data[0], 0)] + 808139aa4f0SVijay Khemka ",Monitoring:" + nmCapStsStr[BIT(data[0], 1)] + 809139aa4f0SVijay Khemka ",PowerLimit:" + nmCapStsStr[BIT(data[0], 2)]; 810139aa4f0SVijay Khemka } 811139aa4f0SVijay Khemka else 812139aa4f0SVijay Khemka { 813139aa4f0SVijay Khemka errLog = "Unknown"; 814139aa4f0SVijay Khemka } 815139aa4f0SVijay Khemka } 816139aa4f0SVijay Khemka 817139aa4f0SVijay Khemka static void logNmThreshold(uint8_t* data, std::string& errLog) 818139aa4f0SVijay Khemka { 819139aa4f0SVijay Khemka uint8_t thresNum = (data[0] & 0x3); 820139aa4f0SVijay Khemka uint8_t domIdx = (data[1] & 0xf); 821139aa4f0SVijay Khemka uint8_t polId = data[2]; 822139aa4f0SVijay Khemka uint8_t polEvtIdx = BIT(data[0], 3); 823139aa4f0SVijay Khemka const std::vector<std::string> polEvtStr = { 824139aa4f0SVijay Khemka "Threshold Exceeded", "Policy Correction Time Exceeded"}; 825139aa4f0SVijay Khemka 826139aa4f0SVijay Khemka errLog = "Threshold Number:" + std::to_string(thresNum) + "-" + 827139aa4f0SVijay Khemka polEvtStr[polEvtIdx] + ", Domain:" + nmDomName[domIdx] + 828139aa4f0SVijay Khemka ", PolicyID:0x" + byteToStr(polId); 829139aa4f0SVijay Khemka } 830139aa4f0SVijay Khemka 831139aa4f0SVijay Khemka static void logPwrThreshold(uint8_t* data, std::string& errLog) 832139aa4f0SVijay Khemka { 833139aa4f0SVijay Khemka if (data[0] == 0x00) 834139aa4f0SVijay Khemka { 835139aa4f0SVijay Khemka errLog = "Limit Not Exceeded"; 836139aa4f0SVijay Khemka } 837139aa4f0SVijay Khemka else if (data[0] == 0x01) 838139aa4f0SVijay Khemka { 839139aa4f0SVijay Khemka errLog = "Limit Exceeded"; 840139aa4f0SVijay Khemka } 841139aa4f0SVijay Khemka else 842139aa4f0SVijay Khemka { 843139aa4f0SVijay Khemka errLog = "Unknown"; 844139aa4f0SVijay Khemka } 845139aa4f0SVijay Khemka } 846139aa4f0SVijay Khemka 847139aa4f0SVijay Khemka static void logMSMI(uint8_t* data, std::string& errLog) 848139aa4f0SVijay Khemka { 849139aa4f0SVijay Khemka if (data[0] == 0x0) 850139aa4f0SVijay Khemka { 851139aa4f0SVijay Khemka errLog = "IERR/MSMI"; 852139aa4f0SVijay Khemka } 853139aa4f0SVijay Khemka else if (data[0] == 0x0B) 854139aa4f0SVijay Khemka { 855139aa4f0SVijay Khemka errLog = "MCERR/MSMI"; 856139aa4f0SVijay Khemka } 857139aa4f0SVijay Khemka else 858139aa4f0SVijay Khemka { 859139aa4f0SVijay Khemka errLog = "Unknown"; 860139aa4f0SVijay Khemka } 861139aa4f0SVijay Khemka } 862139aa4f0SVijay Khemka 863139aa4f0SVijay Khemka static void logHprWarn(uint8_t* data, std::string& errLog) 864139aa4f0SVijay Khemka { 865139aa4f0SVijay Khemka if (data[2] == 0x01) 866139aa4f0SVijay Khemka { 867139aa4f0SVijay Khemka if (data[1] == 0xFF) 868139aa4f0SVijay Khemka { 869139aa4f0SVijay Khemka errLog = "Infinite Time"; 870139aa4f0SVijay Khemka } 871139aa4f0SVijay Khemka else 872139aa4f0SVijay Khemka { 873139aa4f0SVijay Khemka errLog = std::to_string(data[1]) + " minutes"; 874139aa4f0SVijay Khemka } 875139aa4f0SVijay Khemka } 876139aa4f0SVijay Khemka else 877139aa4f0SVijay Khemka { 878139aa4f0SVijay Khemka errLog = "Unknown"; 879139aa4f0SVijay Khemka } 880139aa4f0SVijay Khemka } 881139aa4f0SVijay Khemka 882139aa4f0SVijay Khemka static const boost::container::flat_map< 883139aa4f0SVijay Khemka uint8_t, 884139aa4f0SVijay Khemka std::pair<std::string, std::function<void(uint8_t*, std::string&)>>> 885010dee04SPatrick Williams sensorNameTable = { 886010dee04SPatrick Williams {0xE9, {"SYSTEM_EVENT", logSysEvent}}, 887139aa4f0SVijay Khemka {0x7D, {"THERM_THRESH_EVT", logThermalEvent}}, 888139aa4f0SVijay Khemka {0xAA, {"BUTTON", logDefault}}, 889139aa4f0SVijay Khemka {0xAB, {"POWER_STATE", logDefault}}, 890139aa4f0SVijay Khemka {0xEA, {"CRITICAL_IRQ", logCritIrq}}, 891139aa4f0SVijay Khemka {0x2B, {"POST_ERROR", logPostErr}}, 892139aa4f0SVijay Khemka {0x40, {"MACHINE_CHK_ERR", logMchChkErr}}, 893139aa4f0SVijay Khemka {0x41, {"PCIE_ERR", logPcieErr}}, 894139aa4f0SVijay Khemka {0x43, {"IIO_ERR", logIioErr}}, 895139aa4f0SVijay Khemka {0X63, {"MEMORY_ECC_ERR", logDefault}}, 896139aa4f0SVijay Khemka {0X87, {"MEMORY_ERR_LOG_DIS", logDefault}}, 897139aa4f0SVijay Khemka {0X51, {"PROCHOT_EXT", logDefault}}, 898139aa4f0SVijay Khemka {0X56, {"PWR_ERR", logPwrErr}}, 899139aa4f0SVijay Khemka {0xE6, {"CATERR_A", logCatErr}}, 900139aa4f0SVijay Khemka {0xEB, {"CATERR_B", logCatErr}}, 901139aa4f0SVijay Khemka {0xB3, {"CPU_DIMM_HOT", logDimmHot}}, 902139aa4f0SVijay Khemka {0x90, {"SOFTWARE_NMI", logSwNMI}}, 903139aa4f0SVijay Khemka {0x1C, {"CPU0_THERM_STATUS", logCPUThermalSts}}, 904139aa4f0SVijay Khemka {0x1D, {"CPU1_THERM_STATUS", logCPUThermalSts}}, 905139aa4f0SVijay Khemka {0x16, {"ME_POWER_STATE", logMEPwrState}}, 906139aa4f0SVijay Khemka {0x17, {"SPS_FW_HEALTH", logSPSFwHealth}}, 907139aa4f0SVijay Khemka {0x18, {"NM_EXCEPTION_A", logNmExcA}}, 908139aa4f0SVijay Khemka {0x08, {"PCH_THERM_THRESHOLD", logPCHThermal}}, 909139aa4f0SVijay Khemka {0x19, {"NM_HEALTH", logNmHealth}}, 910139aa4f0SVijay Khemka {0x1A, {"NM_CAPABILITIES", logNmCap}}, 911139aa4f0SVijay Khemka {0x1B, {"NM_THRESHOLD", logNmThreshold}}, 912139aa4f0SVijay Khemka {0x3B, {"PWR_THRESH_EVT", logPwrThreshold}}, 913139aa4f0SVijay Khemka {0xE7, {"MSMI", logMSMI}}, 914139aa4f0SVijay Khemka {0xC5, {"HPR_WARNING", logHprWarn}}}; 915139aa4f0SVijay Khemka 916139aa4f0SVijay Khemka static void parseSelHelper(StdSELEntry* data, std::string& errStr) 917139aa4f0SVijay Khemka { 918139aa4f0SVijay Khemka /* Check if sensor type is OS_BOOT (0x1f) */ 919139aa4f0SVijay Khemka if (data->sensorType == 0x1F) 920139aa4f0SVijay Khemka { 921139aa4f0SVijay Khemka /* OS_BOOT used by OS */ 922139aa4f0SVijay Khemka switch (data->eventData1 & 0xF) 923139aa4f0SVijay Khemka { 924139aa4f0SVijay Khemka case 0x07: 925139aa4f0SVijay Khemka errStr = "Base OS/Hypervisor Installation started"; 926139aa4f0SVijay Khemka break; 927139aa4f0SVijay Khemka case 0x08: 928139aa4f0SVijay Khemka errStr = "Base OS/Hypervisor Installation completed"; 929139aa4f0SVijay Khemka break; 930139aa4f0SVijay Khemka case 0x09: 931139aa4f0SVijay Khemka errStr = "Base OS/Hypervisor Installation aborted"; 932139aa4f0SVijay Khemka break; 933139aa4f0SVijay Khemka case 0x0A: 934139aa4f0SVijay Khemka errStr = "Base OS/Hypervisor Installation failed"; 935139aa4f0SVijay Khemka break; 936139aa4f0SVijay Khemka default: 937139aa4f0SVijay Khemka errStr = "Unknown"; 938139aa4f0SVijay Khemka } 939139aa4f0SVijay Khemka return; 940139aa4f0SVijay Khemka } 941139aa4f0SVijay Khemka 942139aa4f0SVijay Khemka auto findSensorName = sensorNameTable.find(data->sensorNum); 943139aa4f0SVijay Khemka if (findSensorName == sensorNameTable.end()) 944139aa4f0SVijay Khemka { 945139aa4f0SVijay Khemka errStr = "Unknown"; 946139aa4f0SVijay Khemka return; 947139aa4f0SVijay Khemka } 948139aa4f0SVijay Khemka else 949139aa4f0SVijay Khemka { 950139aa4f0SVijay Khemka switch (data->sensorNum) 951139aa4f0SVijay Khemka { 952139aa4f0SVijay Khemka /* logMemErr function needs data from sensor type */ 953139aa4f0SVijay Khemka case memoryEccError: 954139aa4f0SVijay Khemka case memoryErrLogDIS: 955139aa4f0SVijay Khemka findSensorName->second.second(&(data->sensorType), errStr); 956139aa4f0SVijay Khemka break; 957139aa4f0SVijay Khemka /* Other sensor function needs only event data for parsing */ 958139aa4f0SVijay Khemka default: 959139aa4f0SVijay Khemka findSensorName->second.second(&(data->eventData1), errStr); 960139aa4f0SVijay Khemka } 961139aa4f0SVijay Khemka } 962139aa4f0SVijay Khemka 963139aa4f0SVijay Khemka if (((data->eventData3 & 0x80) >> 7) == 0) 964139aa4f0SVijay Khemka { 965139aa4f0SVijay Khemka errStr += " Assertion"; 966139aa4f0SVijay Khemka } 967139aa4f0SVijay Khemka else 968139aa4f0SVijay Khemka { 969139aa4f0SVijay Khemka errStr += " Deassertion"; 970139aa4f0SVijay Khemka } 971139aa4f0SVijay Khemka } 972139aa4f0SVijay Khemka 973c056dc00SManikandan Elumalai static void parseDimmPhyloc(StdSELEntry* data, std::string& errStr) 974c056dc00SManikandan Elumalai { 975c056dc00SManikandan Elumalai // Log when " All info available" 976c056dc00SManikandan Elumalai uint8_t chNum = (data->eventData3 & 0x18) >> 3; 977c056dc00SManikandan Elumalai uint8_t dimmNum = data->eventData3 & 0x7; 978c056dc00SManikandan Elumalai uint8_t rankNum = data->eventData2 & 0x03; 979c056dc00SManikandan Elumalai uint8_t nodeNum = (data->eventData3 & 0xE0) >> 5; 980c056dc00SManikandan Elumalai 981c056dc00SManikandan Elumalai if (chNum == 3 && dimmNum == 0) 982c056dc00SManikandan Elumalai { 983c056dc00SManikandan Elumalai errStr += " Node: " + std::to_string(nodeNum) + "," + 984c056dc00SManikandan Elumalai " Card: " + std::to_string(chNum) + "," + 985c056dc00SManikandan Elumalai " Module: " + std::to_string(dimmNum) + "," + 986c056dc00SManikandan Elumalai " Rank Number: " + std::to_string(rankNum) + "," + 987c056dc00SManikandan Elumalai " Location: DIMM A0"; 988c056dc00SManikandan Elumalai } 989c056dc00SManikandan Elumalai else if (chNum == 2 && dimmNum == 0) 990c056dc00SManikandan Elumalai { 991c056dc00SManikandan Elumalai errStr += " Node: " + std::to_string(nodeNum) + "," + 992c056dc00SManikandan Elumalai " Card: " + std::to_string(chNum) + "," + 993c056dc00SManikandan Elumalai " Module: " + std::to_string(dimmNum) + "," + 994c056dc00SManikandan Elumalai " Rank Number: " + std::to_string(rankNum) + "," + 995c056dc00SManikandan Elumalai " Location: DIMM B0"; 996c056dc00SManikandan Elumalai } 997c056dc00SManikandan Elumalai else if (chNum == 4 && dimmNum == 0) 998c056dc00SManikandan Elumalai { 999c056dc00SManikandan Elumalai errStr += " Node: " + std::to_string(nodeNum) + "," + 1000c056dc00SManikandan Elumalai " Card: " + std::to_string(chNum) + "," + 1001c056dc00SManikandan Elumalai " Module: " + std::to_string(dimmNum) + "," + 1002c056dc00SManikandan Elumalai " Rank Number: " + std::to_string(rankNum) + "," + 1003c056dc00SManikandan Elumalai " Location: DIMM C0 "; 1004c056dc00SManikandan Elumalai } 1005c056dc00SManikandan Elumalai else if (chNum == 5 && dimmNum == 0) 1006c056dc00SManikandan Elumalai { 1007c056dc00SManikandan Elumalai errStr += " Node: " + std::to_string(nodeNum) + "," + 1008c056dc00SManikandan Elumalai " Card: " + std::to_string(chNum) + "," + 1009c056dc00SManikandan Elumalai " Module: " + std::to_string(dimmNum) + "," + 1010c056dc00SManikandan Elumalai " Rank Number: " + std::to_string(rankNum) + "," + 1011c056dc00SManikandan Elumalai " Location: DIMM D0"; 1012c056dc00SManikandan Elumalai } 1013c056dc00SManikandan Elumalai else 1014c056dc00SManikandan Elumalai { 1015c056dc00SManikandan Elumalai errStr += " Node: " + std::to_string(nodeNum) + "," + 1016c056dc00SManikandan Elumalai " Card: " + std::to_string(chNum) + "," + 1017c056dc00SManikandan Elumalai " Module: " + std::to_string(dimmNum) + "," + 1018c056dc00SManikandan Elumalai " Rank Number: " + std::to_string(rankNum) + "," + 1019519530beSManojkiran Eda " Location: DIMM Unknown"; 1020c056dc00SManikandan Elumalai } 1021c056dc00SManikandan Elumalai } 1022c056dc00SManikandan Elumalai 1023f36f345fSVijay Khemka static void parseStdSel(StdSELEntry* data, std::string& errStr) 1024f36f345fSVijay Khemka { 1025f36f345fSVijay Khemka std::stringstream tmpStream; 1026f36f345fSVijay Khemka tmpStream << std::hex << std::uppercase; 1027f36f345fSVijay Khemka 1028f36f345fSVijay Khemka /* TODO: add pal_add_cri_sel */ 1029f36f345fSVijay Khemka switch (data->sensorNum) 1030f36f345fSVijay Khemka { 1031f36f345fSVijay Khemka case memoryEccError: 1032f36f345fSVijay Khemka switch (data->eventData1 & 0x0F) 1033f36f345fSVijay Khemka { 1034f36f345fSVijay Khemka case 0x00: 1035f36f345fSVijay Khemka errStr = "Correctable"; 1036f36f345fSVijay Khemka tmpStream << "DIMM" << std::setw(2) << std::setfill('0') 1037f36f345fSVijay Khemka << data->eventData3 << " ECC err"; 1038c056dc00SManikandan Elumalai parseDimmPhyloc(data, errStr); 1039f36f345fSVijay Khemka break; 1040f36f345fSVijay Khemka case 0x01: 1041f36f345fSVijay Khemka errStr = "Uncorrectable"; 1042f36f345fSVijay Khemka tmpStream << "DIMM" << std::setw(2) << std::setfill('0') 1043f36f345fSVijay Khemka << data->eventData3 << " UECC err"; 1044c056dc00SManikandan Elumalai parseDimmPhyloc(data, errStr); 1045f36f345fSVijay Khemka break; 1046f36f345fSVijay Khemka case 0x02: 1047f36f345fSVijay Khemka errStr = "Parity"; 1048f36f345fSVijay Khemka break; 1049f36f345fSVijay Khemka case 0x05: 1050f36f345fSVijay Khemka errStr = "Correctable ECC error Logging Limit Reached"; 1051f36f345fSVijay Khemka break; 1052f36f345fSVijay Khemka default: 1053f36f345fSVijay Khemka errStr = "Unknown"; 1054f36f345fSVijay Khemka } 1055f36f345fSVijay Khemka break; 1056f36f345fSVijay Khemka case memoryErrLogDIS: 1057f36f345fSVijay Khemka if ((data->eventData1 & 0x0F) == 0) 1058f36f345fSVijay Khemka { 1059f36f345fSVijay Khemka errStr = "Correctable Memory Error Logging Disabled"; 1060f36f345fSVijay Khemka } 1061f36f345fSVijay Khemka else 1062f36f345fSVijay Khemka { 1063f36f345fSVijay Khemka errStr = "Unknown"; 1064f36f345fSVijay Khemka } 1065f36f345fSVijay Khemka break; 1066f36f345fSVijay Khemka default: 1067139aa4f0SVijay Khemka parseSelHelper(data, errStr); 1068f36f345fSVijay Khemka return; 1069f36f345fSVijay Khemka } 1070f36f345fSVijay Khemka 1071f36f345fSVijay Khemka errStr += " (DIMM " + std::to_string(data->eventData3) + ")"; 1072f36f345fSVijay Khemka errStr += " Logical Rank " + std::to_string(data->eventData2 & 0x03); 1073f36f345fSVijay Khemka 1074f36f345fSVijay Khemka switch ((data->eventData2 & 0x0C) >> 2) 1075f36f345fSVijay Khemka { 1076f36f345fSVijay Khemka case 0x00: 1077f36f345fSVijay Khemka // Ignore when " All info available" 1078f36f345fSVijay Khemka break; 1079f36f345fSVijay Khemka case 0x01: 1080f36f345fSVijay Khemka errStr += " DIMM info not valid"; 1081f36f345fSVijay Khemka break; 1082f36f345fSVijay Khemka case 0x02: 1083f36f345fSVijay Khemka errStr += " CHN info not valid"; 1084f36f345fSVijay Khemka break; 1085f36f345fSVijay Khemka case 0x03: 1086f36f345fSVijay Khemka errStr += " CPU info not valid"; 1087f36f345fSVijay Khemka break; 1088f36f345fSVijay Khemka default: 1089f36f345fSVijay Khemka errStr += " Unknown"; 1090f36f345fSVijay Khemka } 1091f36f345fSVijay Khemka 1092f36f345fSVijay Khemka if (((data->eventType & 0x80) >> 7) == 0) 1093f36f345fSVijay Khemka { 1094f36f345fSVijay Khemka errStr += " Assertion"; 1095f36f345fSVijay Khemka } 1096f36f345fSVijay Khemka else 1097f36f345fSVijay Khemka { 1098f36f345fSVijay Khemka errStr += " Deassertion"; 1099f36f345fSVijay Khemka } 1100f36f345fSVijay Khemka 1101f36f345fSVijay Khemka return; 1102f36f345fSVijay Khemka } 1103f36f345fSVijay Khemka 1104f36f345fSVijay Khemka static void parseOemSel(TsOemSELEntry* data, std::string& errStr) 1105f36f345fSVijay Khemka { 1106f36f345fSVijay Khemka std::stringstream tmpStream; 1107f36f345fSVijay Khemka tmpStream << std::hex << std::uppercase << std::setfill('0'); 1108f36f345fSVijay Khemka 1109f36f345fSVijay Khemka switch (data->recordType) 1110f36f345fSVijay Khemka { 1111f36f345fSVijay Khemka case 0xC0: 1112f36f345fSVijay Khemka tmpStream << "VID:0x" << std::setw(2) << (int)data->oemData[1] 1113f36f345fSVijay Khemka << std::setw(2) << (int)data->oemData[0] << " DID:0x" 1114f36f345fSVijay Khemka << std::setw(2) << (int)data->oemData[3] << std::setw(2) 1115f36f345fSVijay Khemka << (int)data->oemData[2] << " Slot:0x" << std::setw(2) 1116f36f345fSVijay Khemka << (int)data->oemData[4] << " Error ID:0x" << std::setw(2) 1117f36f345fSVijay Khemka << (int)data->oemData[5]; 1118f36f345fSVijay Khemka break; 1119f36f345fSVijay Khemka case 0xC2: 1120f36f345fSVijay Khemka tmpStream << "Extra info:0x" << std::setw(2) 1121f36f345fSVijay Khemka << (int)data->oemData[1] << " MSCOD:0x" << std::setw(2) 1122f36f345fSVijay Khemka << (int)data->oemData[3] << std::setw(2) 1123f36f345fSVijay Khemka << (int)data->oemData[2] << " MCACOD:0x" << std::setw(2) 1124f36f345fSVijay Khemka << (int)data->oemData[5] << std::setw(2) 1125f36f345fSVijay Khemka << (int)data->oemData[4]; 1126f36f345fSVijay Khemka break; 1127f36f345fSVijay Khemka case 0xC3: 1128f36f345fSVijay Khemka int bank = (data->oemData[1] & 0xf0) >> 4; 1129f36f345fSVijay Khemka int col = ((data->oemData[1] & 0x0f) << 8) | data->oemData[2]; 1130f36f345fSVijay Khemka 1131f36f345fSVijay Khemka tmpStream << "Fail Device:0x" << std::setw(2) 1132f36f345fSVijay Khemka << (int)data->oemData[0] << " Bank:0x" << std::setw(2) 1133f36f345fSVijay Khemka << bank << " Column:0x" << std::setw(2) << col 1134f36f345fSVijay Khemka << " Failed Row:0x" << std::setw(2) 1135f36f345fSVijay Khemka << (int)data->oemData[3] << std::setw(2) 1136f36f345fSVijay Khemka << (int)data->oemData[4] << std::setw(2) 1137f36f345fSVijay Khemka << (int)data->oemData[5]; 1138f36f345fSVijay Khemka } 1139f36f345fSVijay Khemka 1140f36f345fSVijay Khemka errStr = tmpStream.str(); 1141f36f345fSVijay Khemka 1142f36f345fSVijay Khemka return; 1143f36f345fSVijay Khemka } 1144f36f345fSVijay Khemka 11457451903cScchoux static std::string dimmLocationStr(uint8_t socket, uint8_t channel, 11467451903cScchoux uint8_t slot) 11477451903cScchoux { 11487451903cScchoux uint8_t sled = (socket >> 4) & 0x3; 11497451903cScchoux 11507451903cScchoux socket &= 0xf; 11517451903cScchoux if (channel == 0xFF && slot == 0xFF) 11527451903cScchoux { 11537451903cScchoux return std::format( 11547451903cScchoux "DIMM Slot Location: Sled {:02}/Socket {:02}, Channel unknown" 11557451903cScchoux ", Slot unknown, DIMM unknown", 11567451903cScchoux sled, socket); 11577451903cScchoux } 11587451903cScchoux else 11597451903cScchoux { 11607451903cScchoux channel &= 0xf; 11617451903cScchoux slot &= 0xf; 11627451903cScchoux const char label[] = {'A', 'C', 'B', 'D'}; 11637451903cScchoux uint8_t idx = socket * 2 + slot; 11647451903cScchoux return std::format("DIMM Slot Location: Sled {:02}/Socket {:02}" 11657451903cScchoux ", Channel {:02}, Slot {:02} DIMM {}", 11667451903cScchoux sled, socket, channel, slot, 11677451903cScchoux (idx < sizeof(label)) 11687451903cScchoux ? label[idx] + std::to_string(channel) 11697451903cScchoux : "NA"); 11707451903cScchoux } 11717451903cScchoux } 11727451903cScchoux 117334a875f3SVijay Khemka static void parseOemUnifiedSel(NtsOemSELEntry* data, std::string& errStr) 117434a875f3SVijay Khemka { 117534a875f3SVijay Khemka uint8_t* ptr = data->oemData; 11767451903cScchoux uint8_t eventType = ptr[5] & 0xf; 117734a875f3SVijay Khemka int genInfo = ptr[0]; 117834a875f3SVijay Khemka int errType = genInfo & 0x0f; 11797451903cScchoux std::vector<std::string> dimmErr = { 11807451903cScchoux "Memory training failure", 11817451903cScchoux "Memory correctable error", 11827451903cScchoux "Memory uncorrectable error", 11837451903cScchoux "Memory correctable error (Patrol scrub)", 11847451903cScchoux "Memory uncorrectable error (Patrol scrub)", 11857451903cScchoux "Memory Parity Error (PCC=0)", 11867451903cScchoux "Memory Parity Error (PCC=1)", 11877451903cScchoux "Memory PMIC Error", 11887451903cScchoux "CXL Memory training error", 11897451903cScchoux "Reserved"}; 11907451903cScchoux std::vector<std::string> postEvent = { 11917451903cScchoux "System PXE boot fail", 11927451903cScchoux "CMOS/NVRAM configuration cleared", 11937451903cScchoux "TPM Self-Test Fail", 11947451903cScchoux "Boot Drive failure", 11957451903cScchoux "Data Drive failure", 11967451903cScchoux "Received invalid boot order request from BMC", 11977451903cScchoux "System HTTP boot fail", 11987451903cScchoux "BIOS fails to get the certificate from BMC", 11997451903cScchoux "Password cleared by jumper", 12007451903cScchoux "DXE FV check failure", 12017451903cScchoux "AMD ABL failure", 12027451903cScchoux "Reserved"}; 12037451903cScchoux std::vector<std::string> certErr = { 12047451903cScchoux "No certificate at BMC", "IPMI transaction fail", 12057451903cScchoux "Certificate data corrupted", "Reserved"}; 1206010dee04SPatrick Williams std::vector<std::string> pcieEvent = { 1207010dee04SPatrick Williams "PCIe DPC Event", 12087451903cScchoux "PCIe LER Event", 12097451903cScchoux "PCIe Link Retraining and Recovery", 12107451903cScchoux "PCIe Link CRC Error Check and Retry", 12117451903cScchoux "PCIe Corrupt Data Containment", 12127451903cScchoux "PCIe Express ECRC", 12137451903cScchoux "Reserved"}; 12147451903cScchoux std::vector<std::string> memEvent = { 12157451903cScchoux "Memory PPR event", 12167451903cScchoux "Memory Correctable Error logging limit reached", 12177451903cScchoux "Memory disable/map-out for FRB", 12187451903cScchoux "Memory SDDC", 12197451903cScchoux "Memory Address range/Partial mirroring", 12207451903cScchoux "Memory ADDDC", 12217451903cScchoux "Memory SMBus hang recovery", 12227451903cScchoux "No DIMM in System", 12237451903cScchoux "Reserved"}; 12247451903cScchoux std::vector<std::string> memPprTime = {"Boot time", "Autonomous", 12257451903cScchoux "Run time", "Reserved"}; 12267451903cScchoux std::vector<std::string> memPpr = {"PPR success", "PPR fail", "PPR request", 12277451903cScchoux "Reserved"}; 1228010dee04SPatrick Williams std::vector<std::string> memAdddc = { 1229010dee04SPatrick Williams "Bank VLS", "r-Bank VLS + re-buddy", "r-Bank VLS + Rank VLS", 12307451903cScchoux "r-Rank VLS + re-buddy", "Reserved"}; 12317451903cScchoux std::vector<std::string> pprEvent = {"PPR disable", "Soft PPR", "Hard PPR", 12327451903cScchoux "Reserved"}; 123334a875f3SVijay Khemka 123434a875f3SVijay Khemka std::stringstream tmpStream; 123534a875f3SVijay Khemka 123634a875f3SVijay Khemka switch (errType) 123734a875f3SVijay Khemka { 123834a875f3SVijay Khemka case unifiedPcieErr: 12397451903cScchoux tmpStream << std::format( 12407451903cScchoux "GeneralInfo: x86/PCIeErr(0x{:02X})" 12417451903cScchoux ", Bus {:02X}/Dev {:02X}/Fun {:02X}, TotalErrID1Cnt: 0x{:04X}" 12427451903cScchoux ", ErrID2: 0x{:02X}, ErrID1: 0x{:02X}", 12437451903cScchoux genInfo, ptr[8], ptr[7] >> 3, ptr[7] & 0x7, 12447451903cScchoux (ptr[10] << 8) | ptr[9], ptr[11], ptr[12]); 124534a875f3SVijay Khemka break; 124634a875f3SVijay Khemka case unifiedMemErr: 12477451903cScchoux eventType = ptr[9] & 0xf; 12487451903cScchoux tmpStream << std::format( 12497451903cScchoux "GeneralInfo: MemErr(0x{:02X}), {}, DIMM Failure Event: {}", 12507451903cScchoux genInfo, dimmLocationStr(ptr[5], ptr[6], ptr[7]), 12517451903cScchoux dimmErr[std::min(eventType, 12527451903cScchoux static_cast<uint8_t>(dimmErr.size() - 1))]); 125334a875f3SVijay Khemka 12547451903cScchoux if (static_cast<MemErrType>(eventType) == MemErrType::memTrainErr || 12557451903cScchoux static_cast<MemErrType>(eventType) == MemErrType::memPmicErr) 12567451903cScchoux { 12577451903cScchoux bool amd = ptr[9] & 0x80; 12587451903cScchoux tmpStream << std::format( 12597451903cScchoux ", Major Code: 0x{:02X}, Minor Code: 0x{:0{}X}", ptr[10], 12607451903cScchoux amd ? (ptr[12] << 8 | ptr[11]) : ptr[11], amd ? 4 : 2); 12617451903cScchoux } 12627451903cScchoux break; 12637451903cScchoux case unifiedIioErr: 12647451903cScchoux tmpStream << std::format( 12657451903cScchoux "GeneralInfo: IIOErr(0x{:02X})" 12667451903cScchoux ", IIO Port Location: Sled {:02}/Socket {:02}, Stack 0x{:02X}" 12677451903cScchoux ", Error Type: 0x{:02X}, Error Severity: 0x{:02X}" 12687451903cScchoux ", Error ID: 0x{:02X}", 12697451903cScchoux genInfo, (ptr[5] >> 4) & 0x3, ptr[5] & 0xf, ptr[6], ptr[10], 12707451903cScchoux ptr[11] & 0xf, ptr[12]); 12717451903cScchoux break; 12727451903cScchoux case unifiedPostEvt: 12737451903cScchoux tmpStream << std::format( 12747451903cScchoux "GeneralInfo: POST(0x{:02X}), POST Failure Event: {}", genInfo, 12757451903cScchoux postEvent[std::min( 12767451903cScchoux eventType, static_cast<uint8_t>(postEvent.size() - 1))]); 12777451903cScchoux 12787451903cScchoux switch (static_cast<PostEvtType>(eventType)) 12797451903cScchoux { 12807451903cScchoux case PostEvtType::pxeBootFail: 12817451903cScchoux case PostEvtType::httpBootFail: 12827451903cScchoux { 12837451903cScchoux uint8_t failType = ptr[10] & 0xf; 12847451903cScchoux tmpStream 12857451903cScchoux << std::format(", Fail Type: {}, Error Code: 0x{:02X}", 12867451903cScchoux (failType == 4 || failType == 6) 12877451903cScchoux ? std::format("IPv{} fail", failType) 12887451903cScchoux : std::format("0x{:02X}", ptr[10]), 12897451903cScchoux ptr[11]); 12907451903cScchoux break; 12917451903cScchoux } 12927451903cScchoux case PostEvtType::getCertFail: 12937451903cScchoux tmpStream << std::format( 12947451903cScchoux ", Failure Detail: {}", 12957451903cScchoux certErr[std::min( 12967451903cScchoux ptr[9], static_cast<uint8_t>(certErr.size() - 1))]); 12977451903cScchoux break; 12987451903cScchoux case PostEvtType::amdAblFail: 12997451903cScchoux tmpStream << std::format(", ABL Error Code: 0x{:04X}", 13007451903cScchoux (ptr[12] << 8) | ptr[11]); 13017451903cScchoux break; 13027451903cScchoux } 13037451903cScchoux break; 13047451903cScchoux case unifiedPcieEvt: 13057451903cScchoux tmpStream << std::format( 13067451903cScchoux "GeneralInfo: PCIeEvent(0x{:02X}), PCIe Failure Event: {}", 13077451903cScchoux genInfo, 13087451903cScchoux pcieEvent[std::min( 13097451903cScchoux eventType, static_cast<uint8_t>(pcieEvent.size() - 1))]); 13107451903cScchoux 13117451903cScchoux if (static_cast<PcieEvtType>(eventType) == PcieEvtType::dpc) 13127451903cScchoux { 13137451903cScchoux tmpStream << std::format( 13147451903cScchoux ", Status: 0x{:04X}, Source ID: 0x{:04X}", 13157451903cScchoux (ptr[8] << 8) | ptr[7], (ptr[10] << 8) | ptr[9]); 13167451903cScchoux } 13177451903cScchoux break; 13187451903cScchoux case unifiedMemEvt: 13197451903cScchoux eventType = ptr[9] & 0xf; 1320010dee04SPatrick Williams tmpStream 1321010dee04SPatrick Williams << std::format("GeneralInfo: MemEvent(0x{:02X})", genInfo) 1322010dee04SPatrick Williams << (static_cast<MemEvtType>(eventType) != MemEvtType::noDimm 1323010dee04SPatrick Williams ? std::format(", {}", 1324010dee04SPatrick Williams dimmLocationStr(ptr[5], ptr[6], ptr[7])) 13257451903cScchoux : "") 13267451903cScchoux << ", DIMM Failure Event: "; 13277451903cScchoux 13287451903cScchoux switch (static_cast<MemEvtType>(eventType)) 13297451903cScchoux { 13307451903cScchoux case MemEvtType::ppr: 13317451903cScchoux tmpStream << std::format("{} {}", 13327451903cScchoux memPprTime[(ptr[10] >> 2) & 0x3], 13337451903cScchoux memPpr[ptr[10] & 0x3]); 13347451903cScchoux break; 13357451903cScchoux case MemEvtType::adddc: 13367451903cScchoux tmpStream << std::format( 13377451903cScchoux "{} {}", 13387451903cScchoux memEvent[std::min(eventType, static_cast<uint8_t>( 13397451903cScchoux memEvent.size() - 1))], 13407451903cScchoux memAdddc[std::min( 13417451903cScchoux static_cast<uint8_t>(ptr[11] & 0xf), 13427451903cScchoux static_cast<uint8_t>(memAdddc.size() - 1))]); 13437451903cScchoux break; 13447451903cScchoux default: 13457451903cScchoux tmpStream << std::format( 13467451903cScchoux "{}", memEvent[std::min( 13477451903cScchoux eventType, 13487451903cScchoux static_cast<uint8_t>(memEvent.size() - 1))]); 13497451903cScchoux break; 13507451903cScchoux } 13517451903cScchoux break; 13527451903cScchoux case unifiedBootGuard: 13537451903cScchoux tmpStream << std::format( 13547451903cScchoux "GeneralInfo: Boot Guard ACM Failure Events(0x{:02X})" 13557451903cScchoux ", Error Class: 0x{:02X}, Error Code: 0x{:02X}", 13567451903cScchoux genInfo, ptr[9], ptr[10]); 13577451903cScchoux break; 13587451903cScchoux case unifiedPprEvt: 13597451903cScchoux tmpStream << std::format( 13607451903cScchoux "GeneralInfo: PPREvent(0x{:02X}), {}" 13617451903cScchoux ", DIMM Info: {:02X}{:02X}{:02X}{:02X}{:02X}{:02X}{:02X}", 13627451903cScchoux genInfo, 13637451903cScchoux pprEvent[std::min(eventType, 13647451903cScchoux static_cast<uint8_t>(pprEvent.size() - 1))], 13657451903cScchoux ptr[6], ptr[7], ptr[8], ptr[9], ptr[10], ptr[11], ptr[12]); 136634a875f3SVijay Khemka break; 136734a875f3SVijay Khemka default: 136834a875f3SVijay Khemka std::vector<uint8_t> oemData(ptr, ptr + 13); 136934a875f3SVijay Khemka std::string oemDataStr; 137034a875f3SVijay Khemka toHexStr(oemData, oemDataStr); 13717451903cScchoux tmpStream << std::format("Undefined Error Type(0x{:02X}), Raw: {}", 13727451903cScchoux errType, oemDataStr); 137334a875f3SVijay Khemka } 137434a875f3SVijay Khemka 137534a875f3SVijay Khemka errStr = tmpStream.str(); 137634a875f3SVijay Khemka 137734a875f3SVijay Khemka return; 137834a875f3SVijay Khemka } 137934a875f3SVijay Khemka 1380c056dc00SManikandan Elumalai static void parseSelData(uint8_t fruId, std::vector<uint8_t>& reqData, 1381c056dc00SManikandan Elumalai std::string& msgLog) 1382f36f345fSVijay Khemka { 1383f36f345fSVijay Khemka /* Get record type */ 1384f36f345fSVijay Khemka int recType = reqData[2]; 1385f36f345fSVijay Khemka std::string errType, errLog; 1386f36f345fSVijay Khemka 1387f36f345fSVijay Khemka uint8_t* ptr = NULL; 1388f36f345fSVijay Khemka 1389f36f345fSVijay Khemka std::stringstream recTypeStream; 1390f36f345fSVijay Khemka recTypeStream << std::hex << std::uppercase << std::setfill('0') 1391f36f345fSVijay Khemka << std::setw(2) << recType; 1392f36f345fSVijay Khemka 1393c056dc00SManikandan Elumalai msgLog = "SEL Entry: FRU: " + std::to_string(fruId) + ", Record: "; 1394f36f345fSVijay Khemka 1395f36f345fSVijay Khemka if (recType == stdErrType) 1396f36f345fSVijay Khemka { 1397f36f345fSVijay Khemka StdSELEntry* data = reinterpret_cast<StdSELEntry*>(&reqData[0]); 1398f36f345fSVijay Khemka std::string sensorName; 1399f36f345fSVijay Khemka 1400f36f345fSVijay Khemka errType = stdErr; 1401f36f345fSVijay Khemka if (data->sensorType == 0x1F) 1402f36f345fSVijay Khemka { 1403f36f345fSVijay Khemka sensorName = "OS"; 1404f36f345fSVijay Khemka } 1405f36f345fSVijay Khemka else 1406f36f345fSVijay Khemka { 1407f36f345fSVijay Khemka auto findSensorName = sensorNameTable.find(data->sensorNum); 1408f36f345fSVijay Khemka if (findSensorName == sensorNameTable.end()) 1409f36f345fSVijay Khemka { 1410f36f345fSVijay Khemka sensorName = "Unknown"; 1411f36f345fSVijay Khemka } 1412f36f345fSVijay Khemka else 1413f36f345fSVijay Khemka { 1414139aa4f0SVijay Khemka sensorName = findSensorName->second.first; 1415f36f345fSVijay Khemka } 1416f36f345fSVijay Khemka } 1417f36f345fSVijay Khemka 1418f36f345fSVijay Khemka parseStdSel(data, errLog); 1419f36f345fSVijay Khemka ptr = &(data->eventData1); 1420f36f345fSVijay Khemka std::vector<uint8_t> evtData(ptr, ptr + 3); 1421f36f345fSVijay Khemka std::string eventData; 1422f36f345fSVijay Khemka toHexStr(evtData, eventData); 1423f36f345fSVijay Khemka 1424f36f345fSVijay Khemka std::stringstream senNumStream; 1425f36f345fSVijay Khemka senNumStream << std::hex << std::uppercase << std::setfill('0') 1426f36f345fSVijay Khemka << std::setw(2) << (int)(data->sensorNum); 1427f36f345fSVijay Khemka 1428f36f345fSVijay Khemka msgLog += errType + " (0x" + recTypeStream.str() + 14290d053effSPeter Yin "), Sensor: " + sensorName + " (0x" + senNumStream.str() + 14300d053effSPeter Yin "), Event Data: (" + eventData + ") " + errLog; 1431f36f345fSVijay Khemka } 1432f36f345fSVijay Khemka else if ((recType >= oemTSErrTypeMin) && (recType <= oemTSErrTypeMax)) 1433f36f345fSVijay Khemka { 1434f36f345fSVijay Khemka /* timestamped OEM SEL records */ 1435f36f345fSVijay Khemka TsOemSELEntry* data = reinterpret_cast<TsOemSELEntry*>(&reqData[0]); 1436f36f345fSVijay Khemka ptr = data->mfrId; 1437f36f345fSVijay Khemka std::vector<uint8_t> mfrIdData(ptr, ptr + 3); 1438f36f345fSVijay Khemka std::string mfrIdStr; 1439f36f345fSVijay Khemka toHexStr(mfrIdData, mfrIdStr); 1440f36f345fSVijay Khemka 1441f36f345fSVijay Khemka ptr = data->oemData; 1442f36f345fSVijay Khemka std::vector<uint8_t> oemData(ptr, ptr + 6); 1443f36f345fSVijay Khemka std::string oemDataStr; 1444f36f345fSVijay Khemka toHexStr(oemData, oemDataStr); 1445f36f345fSVijay Khemka 1446f36f345fSVijay Khemka errType = oemTSErr; 1447f36f345fSVijay Khemka parseOemSel(data, errLog); 1448f36f345fSVijay Khemka 14490d053effSPeter Yin msgLog += errType + " (0x" + recTypeStream.str() + "), MFG ID: " + 14500d053effSPeter Yin mfrIdStr + ", OEM Data: (" + oemDataStr + ") " + errLog; 1451f36f345fSVijay Khemka } 145234a875f3SVijay Khemka else if (recType == fbUniErrType) 145334a875f3SVijay Khemka { 145434a875f3SVijay Khemka NtsOemSELEntry* data = reinterpret_cast<NtsOemSELEntry*>(&reqData[0]); 145534a875f3SVijay Khemka errType = fbUniSELErr; 145634a875f3SVijay Khemka parseOemUnifiedSel(data, errLog); 145734a875f3SVijay Khemka msgLog += errType + " (0x" + recTypeStream.str() + "), " + errLog; 145834a875f3SVijay Khemka } 1459f36f345fSVijay Khemka else if ((recType >= oemNTSErrTypeMin) && (recType <= oemNTSErrTypeMax)) 1460f36f345fSVijay Khemka { 1461f36f345fSVijay Khemka /* Non timestamped OEM SEL records */ 1462f36f345fSVijay Khemka NtsOemSELEntry* data = reinterpret_cast<NtsOemSELEntry*>(&reqData[0]); 1463f36f345fSVijay Khemka errType = oemNTSErr; 1464f36f345fSVijay Khemka 1465f36f345fSVijay Khemka ptr = data->oemData; 1466f36f345fSVijay Khemka std::vector<uint8_t> oemData(ptr, ptr + 13); 1467f36f345fSVijay Khemka std::string oemDataStr; 1468f36f345fSVijay Khemka toHexStr(oemData, oemDataStr); 1469f36f345fSVijay Khemka 1470f36f345fSVijay Khemka parseOemSel((TsOemSELEntry*)data, errLog); 1471f36f345fSVijay Khemka msgLog += errType + " (0x" + recTypeStream.str() + "), OEM Data: (" + 1472f36f345fSVijay Khemka oemDataStr + ") " + errLog; 1473f36f345fSVijay Khemka } 1474f36f345fSVijay Khemka else 1475f36f345fSVijay Khemka { 1476f36f345fSVijay Khemka errType = unknownErr; 1477f36f345fSVijay Khemka toHexStr(reqData, errLog); 14782405ae98SPatrick Williams msgLog += errType + " (0x" + recTypeStream.str() + 14792405ae98SPatrick Williams ") RawData: " + errLog; 1480f36f345fSVijay Khemka } 1481f36f345fSVijay Khemka } 1482f36f345fSVijay Khemka 148311b9c3b1SVijay Khemka } // namespace fb_oem::ipmi::sel 148411b9c3b1SVijay Khemka 148511b9c3b1SVijay Khemka namespace ipmi 148611b9c3b1SVijay Khemka { 148711b9c3b1SVijay Khemka 148811b9c3b1SVijay Khemka namespace storage 148911b9c3b1SVijay Khemka { 149011b9c3b1SVijay Khemka 149111b9c3b1SVijay Khemka static void registerSELFunctions() __attribute__((constructor)); 149211b9c3b1SVijay Khemka static fb_oem::ipmi::sel::SELData selObj __attribute__((init_priority(101))); 149311b9c3b1SVijay Khemka 149411b9c3b1SVijay Khemka ipmi::RspType<uint8_t, // SEL version 149511b9c3b1SVijay Khemka uint16_t, // SEL entry count 149611b9c3b1SVijay Khemka uint16_t, // free space 149711b9c3b1SVijay Khemka uint32_t, // last add timestamp 149811b9c3b1SVijay Khemka uint32_t, // last erase timestamp 149911b9c3b1SVijay Khemka uint8_t> // operation support 150011b9c3b1SVijay Khemka ipmiStorageGetSELInfo() 150111b9c3b1SVijay Khemka { 150211b9c3b1SVijay Khemka fb_oem::ipmi::sel::GetSELInfoData info; 150311b9c3b1SVijay Khemka 150411b9c3b1SVijay Khemka selObj.getInfo(info); 150511b9c3b1SVijay Khemka return ipmi::responseSuccess(info.selVersion, info.entries, info.freeSpace, 150611b9c3b1SVijay Khemka info.addTimeStamp, info.eraseTimeStamp, 150711b9c3b1SVijay Khemka info.operationSupport); 150811b9c3b1SVijay Khemka } 150911b9c3b1SVijay Khemka 151011b9c3b1SVijay Khemka ipmi::RspType<uint16_t, std::vector<uint8_t>> 151111b9c3b1SVijay Khemka ipmiStorageGetSELEntry(std::vector<uint8_t> data) 151211b9c3b1SVijay Khemka { 151311b9c3b1SVijay Khemka if (data.size() != sizeof(fb_oem::ipmi::sel::GetSELEntryRequest)) 151411b9c3b1SVijay Khemka { 151511b9c3b1SVijay Khemka return ipmi::responseReqDataLenInvalid(); 151611b9c3b1SVijay Khemka } 151711b9c3b1SVijay Khemka 151811b9c3b1SVijay Khemka fb_oem::ipmi::sel::GetSELEntryRequest* reqData = 151911b9c3b1SVijay Khemka reinterpret_cast<fb_oem::ipmi::sel::GetSELEntryRequest*>(&data[0]); 152011b9c3b1SVijay Khemka 152111b9c3b1SVijay Khemka if (reqData->reservID != 0) 152211b9c3b1SVijay Khemka { 152311b9c3b1SVijay Khemka if (!checkSELReservation(reqData->reservID)) 152411b9c3b1SVijay Khemka { 152511b9c3b1SVijay Khemka return ipmi::responseInvalidReservationId(); 152611b9c3b1SVijay Khemka } 152711b9c3b1SVijay Khemka } 152811b9c3b1SVijay Khemka 152911b9c3b1SVijay Khemka uint16_t selCnt = selObj.getCount(); 153011b9c3b1SVijay Khemka if (selCnt == 0) 153111b9c3b1SVijay Khemka { 153211b9c3b1SVijay Khemka return ipmi::responseSensorInvalid(); 153311b9c3b1SVijay Khemka } 153411b9c3b1SVijay Khemka 153511b9c3b1SVijay Khemka /* If it is asked for first entry */ 153611b9c3b1SVijay Khemka if (reqData->recordID == fb_oem::ipmi::sel::firstEntry) 153711b9c3b1SVijay Khemka { 153811b9c3b1SVijay Khemka /* First Entry (0x0000) as per Spec */ 153911b9c3b1SVijay Khemka reqData->recordID = 1; 154011b9c3b1SVijay Khemka } 154111b9c3b1SVijay Khemka else if (reqData->recordID == fb_oem::ipmi::sel::lastEntry) 154211b9c3b1SVijay Khemka { 154311b9c3b1SVijay Khemka /* Last entry (0xFFFF) as per Spec */ 154411b9c3b1SVijay Khemka reqData->recordID = selCnt; 154511b9c3b1SVijay Khemka } 154611b9c3b1SVijay Khemka 154711b9c3b1SVijay Khemka std::string ipmiRaw; 154811b9c3b1SVijay Khemka 154911b9c3b1SVijay Khemka if (selObj.getEntry(reqData->recordID, ipmiRaw) < 0) 155011b9c3b1SVijay Khemka { 155111b9c3b1SVijay Khemka return ipmi::responseSensorInvalid(); 155211b9c3b1SVijay Khemka } 155311b9c3b1SVijay Khemka 155411b9c3b1SVijay Khemka std::vector<uint8_t> recDataBytes; 155511b9c3b1SVijay Khemka if (fromHexStr(ipmiRaw, recDataBytes) < 0) 155611b9c3b1SVijay Khemka { 155711b9c3b1SVijay Khemka return ipmi::responseUnspecifiedError(); 155811b9c3b1SVijay Khemka } 155911b9c3b1SVijay Khemka 156011b9c3b1SVijay Khemka /* Identify the next SEL record ID. If recordID is same as 156111b9c3b1SVijay Khemka * total SeL count then next id should be last entry else 156211b9c3b1SVijay Khemka * it should be incremented by 1 to current RecordID 156311b9c3b1SVijay Khemka */ 156411b9c3b1SVijay Khemka uint16_t nextRecord; 156511b9c3b1SVijay Khemka if (reqData->recordID == selCnt) 156611b9c3b1SVijay Khemka { 156711b9c3b1SVijay Khemka nextRecord = fb_oem::ipmi::sel::lastEntry; 156811b9c3b1SVijay Khemka } 156911b9c3b1SVijay Khemka else 157011b9c3b1SVijay Khemka { 157111b9c3b1SVijay Khemka nextRecord = reqData->recordID + 1; 157211b9c3b1SVijay Khemka } 157311b9c3b1SVijay Khemka 157411b9c3b1SVijay Khemka if (reqData->readLen == fb_oem::ipmi::sel::entireRecord) 157511b9c3b1SVijay Khemka { 157611b9c3b1SVijay Khemka return ipmi::responseSuccess(nextRecord, recDataBytes); 157711b9c3b1SVijay Khemka } 157811b9c3b1SVijay Khemka else 157911b9c3b1SVijay Khemka { 158011b9c3b1SVijay Khemka if (reqData->offset >= fb_oem::ipmi::sel::selRecordSize || 158111b9c3b1SVijay Khemka reqData->readLen > fb_oem::ipmi::sel::selRecordSize) 158211b9c3b1SVijay Khemka { 158311b9c3b1SVijay Khemka return ipmi::responseUnspecifiedError(); 158411b9c3b1SVijay Khemka } 158511b9c3b1SVijay Khemka std::vector<uint8_t> recPartData; 158611b9c3b1SVijay Khemka 158711b9c3b1SVijay Khemka auto diff = fb_oem::ipmi::sel::selRecordSize - reqData->offset; 158811b9c3b1SVijay Khemka auto readLength = std::min(diff, static_cast<int>(reqData->readLen)); 158911b9c3b1SVijay Khemka 159011b9c3b1SVijay Khemka for (int i = 0; i < readLength; i++) 159111b9c3b1SVijay Khemka { 159211b9c3b1SVijay Khemka recPartData.push_back(recDataBytes[i + reqData->offset]); 159311b9c3b1SVijay Khemka } 159411b9c3b1SVijay Khemka return ipmi::responseSuccess(nextRecord, recPartData); 159511b9c3b1SVijay Khemka } 159611b9c3b1SVijay Khemka } 159711b9c3b1SVijay Khemka 1598010dee04SPatrick Williams ipmi::RspType<uint16_t> 1599010dee04SPatrick Williams ipmiStorageAddSELEntry(ipmi::Context::ptr ctx, std::vector<uint8_t> data) 160011b9c3b1SVijay Khemka { 160111b9c3b1SVijay Khemka /* Per the IPMI spec, need to cancel any reservation when a 160211b9c3b1SVijay Khemka * SEL entry is added 160311b9c3b1SVijay Khemka */ 160411b9c3b1SVijay Khemka cancelSELReservation(); 160511b9c3b1SVijay Khemka 160611b9c3b1SVijay Khemka if (data.size() != fb_oem::ipmi::sel::selRecordSize) 160711b9c3b1SVijay Khemka { 160811b9c3b1SVijay Khemka return ipmi::responseReqDataLenInvalid(); 160911b9c3b1SVijay Khemka } 161011b9c3b1SVijay Khemka 161111b9c3b1SVijay Khemka std::string ipmiRaw, logErr; 161211b9c3b1SVijay Khemka toHexStr(data, ipmiRaw); 161311b9c3b1SVijay Khemka 1614f36f345fSVijay Khemka /* Parse sel data and get an error log to be filed */ 1615c056dc00SManikandan Elumalai fb_oem::ipmi::sel::parseSelData((ctx->hostIdx + 1), data, logErr); 1616f36f345fSVijay Khemka 161715a7ae81SVijay Khemka static const std::string openBMCMessageRegistryVersion("0.1"); 1618010dee04SPatrick Williams std::string messageID = 1619010dee04SPatrick Williams "OpenBMC." + openBMCMessageRegistryVersion + ".SELEntryAdded"; 162015a7ae81SVijay Khemka 162111b9c3b1SVijay Khemka /* Log the Raw SEL message to the journal */ 162211b9c3b1SVijay Khemka std::string journalMsg = "SEL Entry Added: " + ipmiRaw; 1623f36f345fSVijay Khemka 162415a7ae81SVijay Khemka phosphor::logging::log<phosphor::logging::level::INFO>( 162515a7ae81SVijay Khemka journalMsg.c_str(), 162615a7ae81SVijay Khemka phosphor::logging::entry("IPMISEL_MESSAGE_ID=%s", messageID.c_str()), 162715a7ae81SVijay Khemka phosphor::logging::entry("IPMISEL_MESSAGE_ARGS=%s", logErr.c_str())); 162811b9c3b1SVijay Khemka 162921a79235SBonnieLo-wiwynn std::map<std::string, std::string> ad; 163021a79235SBonnieLo-wiwynn std::string severity = "xyz.openbmc_project.Logging.Entry.Level.Critical"; 163121a79235SBonnieLo-wiwynn ad.emplace("IPMI_RAW", ipmiRaw); 163221a79235SBonnieLo-wiwynn 163321a79235SBonnieLo-wiwynn auto bus = sdbusplus::bus::new_default(); 163421a79235SBonnieLo-wiwynn auto reqMsg = bus.new_method_call( 163521a79235SBonnieLo-wiwynn "xyz.openbmc_project.Logging", "/xyz/openbmc_project/logging", 163621a79235SBonnieLo-wiwynn "xyz.openbmc_project.Logging.Create", "Create"); 163721a79235SBonnieLo-wiwynn reqMsg.append(logErr, severity, ad); 163821a79235SBonnieLo-wiwynn 163921a79235SBonnieLo-wiwynn try 164021a79235SBonnieLo-wiwynn { 164121a79235SBonnieLo-wiwynn bus.call(reqMsg); 164221a79235SBonnieLo-wiwynn } 164321a79235SBonnieLo-wiwynn catch (sdbusplus::exception_t& e) 164421a79235SBonnieLo-wiwynn { 164521a79235SBonnieLo-wiwynn phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); 164621a79235SBonnieLo-wiwynn } 164721a79235SBonnieLo-wiwynn 164811b9c3b1SVijay Khemka int responseID = selObj.addEntry(ipmiRaw.c_str()); 164911b9c3b1SVijay Khemka if (responseID < 0) 165011b9c3b1SVijay Khemka { 165111b9c3b1SVijay Khemka return ipmi::responseUnspecifiedError(); 165211b9c3b1SVijay Khemka } 165311b9c3b1SVijay Khemka return ipmi::responseSuccess((uint16_t)responseID); 165411b9c3b1SVijay Khemka } 165511b9c3b1SVijay Khemka 1656c1921c63SVijay Khemka ipmi::RspType<uint8_t> ipmiStorageClearSEL(uint16_t reservationID, 1657c1921c63SVijay Khemka const std::array<uint8_t, 3>& clr, 1658c1921c63SVijay Khemka uint8_t eraseOperation) 1659c1921c63SVijay Khemka { 1660c1921c63SVijay Khemka if (!checkSELReservation(reservationID)) 1661c1921c63SVijay Khemka { 1662c1921c63SVijay Khemka return ipmi::responseInvalidReservationId(); 1663c1921c63SVijay Khemka } 1664c1921c63SVijay Khemka 1665c1921c63SVijay Khemka static constexpr std::array<uint8_t, 3> clrExpected = {'C', 'L', 'R'}; 1666c1921c63SVijay Khemka if (clr != clrExpected) 1667c1921c63SVijay Khemka { 1668c1921c63SVijay Khemka return ipmi::responseInvalidFieldRequest(); 1669c1921c63SVijay Khemka } 1670c1921c63SVijay Khemka 1671c1921c63SVijay Khemka /* If there is no sel then return erase complete */ 1672c1921c63SVijay Khemka if (selObj.getCount() == 0) 1673c1921c63SVijay Khemka { 1674c1921c63SVijay Khemka return ipmi::responseSuccess(fb_oem::ipmi::sel::eraseComplete); 1675c1921c63SVijay Khemka } 1676c1921c63SVijay Khemka 1677c1921c63SVijay Khemka /* Erasure status cannot be fetched, so always return erasure 1678c1921c63SVijay Khemka * status as `erase completed`. 1679c1921c63SVijay Khemka */ 1680c1921c63SVijay Khemka if (eraseOperation == fb_oem::ipmi::sel::getEraseStatus) 1681c1921c63SVijay Khemka { 1682c1921c63SVijay Khemka return ipmi::responseSuccess(fb_oem::ipmi::sel::eraseComplete); 1683c1921c63SVijay Khemka } 1684c1921c63SVijay Khemka 1685c1921c63SVijay Khemka /* Check that initiate erase is correct */ 1686c1921c63SVijay Khemka if (eraseOperation != fb_oem::ipmi::sel::initiateErase) 1687c1921c63SVijay Khemka { 1688c1921c63SVijay Khemka return ipmi::responseInvalidFieldRequest(); 1689c1921c63SVijay Khemka } 1690c1921c63SVijay Khemka 1691c1921c63SVijay Khemka /* Per the IPMI spec, need to cancel any reservation when the 1692c1921c63SVijay Khemka * SEL is cleared 1693c1921c63SVijay Khemka */ 1694c1921c63SVijay Khemka cancelSELReservation(); 1695c1921c63SVijay Khemka 1696c1921c63SVijay Khemka /* Clear the complete Sel Json object */ 1697c1921c63SVijay Khemka if (selObj.clear() < 0) 1698c1921c63SVijay Khemka { 1699c1921c63SVijay Khemka return ipmi::responseUnspecifiedError(); 1700c1921c63SVijay Khemka } 1701c1921c63SVijay Khemka 1702c1921c63SVijay Khemka return ipmi::responseSuccess(fb_oem::ipmi::sel::eraseComplete); 1703c1921c63SVijay Khemka } 1704c1921c63SVijay Khemka 1705c1921c63SVijay Khemka ipmi::RspType<uint32_t> ipmiStorageGetSELTime() 1706c1921c63SVijay Khemka { 1707c1921c63SVijay Khemka struct timespec selTime = {}; 1708c1921c63SVijay Khemka 1709c1921c63SVijay Khemka if (clock_gettime(CLOCK_REALTIME, &selTime) < 0) 1710c1921c63SVijay Khemka { 1711c1921c63SVijay Khemka return ipmi::responseUnspecifiedError(); 1712c1921c63SVijay Khemka } 1713c1921c63SVijay Khemka 1714c1921c63SVijay Khemka return ipmi::responseSuccess(selTime.tv_sec); 1715c1921c63SVijay Khemka } 1716c1921c63SVijay Khemka 1717e39f9393SWilly Tu ipmi::RspType<> ipmiStorageSetSELTime(uint32_t) 1718c1921c63SVijay Khemka { 1719c1921c63SVijay Khemka // Set SEL Time is not supported 1720c1921c63SVijay Khemka return ipmi::responseInvalidCommand(); 1721c1921c63SVijay Khemka } 1722c1921c63SVijay Khemka 1723c1921c63SVijay Khemka ipmi::RspType<uint16_t> ipmiStorageGetSELTimeUtcOffset() 1724c1921c63SVijay Khemka { 1725c1921c63SVijay Khemka /* TODO: For now, the SEL time stamp is based on UTC time, 1726c1921c63SVijay Khemka * so return 0x0000 as offset. Might need to change once 1727c1921c63SVijay Khemka * supporting zones in SEL time stamps 1728c1921c63SVijay Khemka */ 1729c1921c63SVijay Khemka 1730c1921c63SVijay Khemka uint16_t utcOffset = 0x0000; 1731c1921c63SVijay Khemka return ipmi::responseSuccess(utcOffset); 1732c1921c63SVijay Khemka } 1733c1921c63SVijay Khemka 173411b9c3b1SVijay Khemka void registerSELFunctions() 173511b9c3b1SVijay Khemka { 173611b9c3b1SVijay Khemka // <Get SEL Info> 173711b9c3b1SVijay Khemka ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage, 173811b9c3b1SVijay Khemka ipmi::storage::cmdGetSelInfo, ipmi::Privilege::User, 173911b9c3b1SVijay Khemka ipmiStorageGetSELInfo); 174011b9c3b1SVijay Khemka 174111b9c3b1SVijay Khemka // <Get SEL Entry> 174211b9c3b1SVijay Khemka ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage, 174311b9c3b1SVijay Khemka ipmi::storage::cmdGetSelEntry, ipmi::Privilege::User, 174411b9c3b1SVijay Khemka ipmiStorageGetSELEntry); 174511b9c3b1SVijay Khemka 174611b9c3b1SVijay Khemka // <Add SEL Entry> 174711b9c3b1SVijay Khemka ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage, 174811b9c3b1SVijay Khemka ipmi::storage::cmdAddSelEntry, 174911b9c3b1SVijay Khemka ipmi::Privilege::Operator, ipmiStorageAddSELEntry); 175011b9c3b1SVijay Khemka 1751c1921c63SVijay Khemka // <Clear SEL> 1752c1921c63SVijay Khemka ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage, 1753c1921c63SVijay Khemka ipmi::storage::cmdClearSel, ipmi::Privilege::Operator, 1754c1921c63SVijay Khemka ipmiStorageClearSEL); 1755c1921c63SVijay Khemka 1756c1921c63SVijay Khemka // <Get SEL Time> 1757c1921c63SVijay Khemka ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage, 1758c1921c63SVijay Khemka ipmi::storage::cmdGetSelTime, ipmi::Privilege::User, 1759c1921c63SVijay Khemka ipmiStorageGetSELTime); 1760c1921c63SVijay Khemka 1761c1921c63SVijay Khemka // <Set SEL Time> 1762c1921c63SVijay Khemka ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage, 1763c1921c63SVijay Khemka ipmi::storage::cmdSetSelTime, 1764c1921c63SVijay Khemka ipmi::Privilege::Operator, ipmiStorageSetSELTime); 1765c1921c63SVijay Khemka 1766c1921c63SVijay Khemka // <Get SEL Time UTC Offset> 1767c1921c63SVijay Khemka ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage, 1768c1921c63SVijay Khemka ipmi::storage::cmdGetSelTimeUtcOffset, 1769c1921c63SVijay Khemka ipmi::Privilege::User, 1770c1921c63SVijay Khemka ipmiStorageGetSELTimeUtcOffset); 1771c1921c63SVijay Khemka 177211b9c3b1SVijay Khemka return; 177311b9c3b1SVijay Khemka } 177411b9c3b1SVijay Khemka 177511b9c3b1SVijay Khemka } // namespace storage 177611b9c3b1SVijay Khemka } // namespace ipmi 1777