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> 1963c99be4SVijay Khemka #include <ipmid/api.hpp> 2011b9c3b1SVijay Khemka #include <nlohmann/json.hpp> 2111b9c3b1SVijay Khemka #include <phosphor-logging/log.hpp> 2211b9c3b1SVijay Khemka #include <sdbusplus/message/types.hpp> 2311b9c3b1SVijay Khemka #include <sdbusplus/timer.hpp> 2411b9c3b1SVijay Khemka #include <storagecommands.hpp> 2511b9c3b1SVijay Khemka 2663c99be4SVijay Khemka #include <fstream> 2763c99be4SVijay Khemka #include <iostream> 2863c99be4SVijay Khemka #include <sstream> 2963c99be4SVijay Khemka 3011b9c3b1SVijay Khemka //---------------------------------------------------------------------- 3111b9c3b1SVijay Khemka // Platform specific functions for storing app data 3211b9c3b1SVijay Khemka //---------------------------------------------------------------------- 3311b9c3b1SVijay Khemka 34139aa4f0SVijay Khemka static std::string byteToStr(uint8_t byte) 35139aa4f0SVijay Khemka { 36139aa4f0SVijay Khemka std::stringstream ss; 37139aa4f0SVijay Khemka 38139aa4f0SVijay Khemka ss << std::hex << std::uppercase << std::setfill('0'); 39139aa4f0SVijay Khemka ss << std::setw(2) << (int)byte; 40139aa4f0SVijay Khemka 41139aa4f0SVijay Khemka return ss.str(); 42139aa4f0SVijay Khemka } 43139aa4f0SVijay 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 194139aa4f0SVijay Khemka /* 195139aa4f0SVijay Khemka * A Function to parse common SEL message, a helper funciton 196139aa4f0SVijay Khemka * for parseStdSel. 197139aa4f0SVijay Khemka * 198139aa4f0SVijay Khemka * Note that this function __CANNOT__ be overriden. 199139aa4f0SVijay Khemka * To add board specific routine, please override parseStdSel. 200139aa4f0SVijay Khemka */ 201139aa4f0SVijay Khemka 202139aa4f0SVijay Khemka /*Used by decoding ME event*/ 203139aa4f0SVijay Khemka std::vector<std::string> nmDomName = { 204139aa4f0SVijay Khemka "Entire Platform", "CPU Subsystem", 205139aa4f0SVijay Khemka "Memory Subsystem", "HW Protection", 206139aa4f0SVijay Khemka "High Power I/O subsystem", "Unknown"}; 207139aa4f0SVijay Khemka 208139aa4f0SVijay Khemka /* Default log message for unknown type */ 209139aa4f0SVijay Khemka static void logDefault(uint8_t* data, std::string& errLog) 210139aa4f0SVijay Khemka { 211139aa4f0SVijay Khemka errLog = "Unknown"; 212139aa4f0SVijay Khemka } 213139aa4f0SVijay Khemka 214139aa4f0SVijay Khemka static void logSysEvent(uint8_t* data, std::string& errLog) 215139aa4f0SVijay Khemka { 216139aa4f0SVijay Khemka if (data[0] == 0xE5) 217139aa4f0SVijay Khemka { 218139aa4f0SVijay Khemka errLog = "Cause of Time change - "; 219139aa4f0SVijay Khemka switch (data[2]) 220139aa4f0SVijay Khemka { 221139aa4f0SVijay Khemka case 0x00: 222139aa4f0SVijay Khemka errLog += "NTP"; 223139aa4f0SVijay Khemka break; 224139aa4f0SVijay Khemka case 0x01: 225139aa4f0SVijay Khemka errLog += "Host RTL"; 226139aa4f0SVijay Khemka break; 227139aa4f0SVijay Khemka case 0x02: 228139aa4f0SVijay Khemka errLog += "Set SEL time cmd"; 229139aa4f0SVijay Khemka break; 230139aa4f0SVijay Khemka case 0x03: 231139aa4f0SVijay Khemka errLog += "Set SEL time UTC offset cmd"; 232139aa4f0SVijay Khemka break; 233139aa4f0SVijay Khemka default: 234139aa4f0SVijay Khemka errLog += "Unknown"; 235139aa4f0SVijay Khemka } 236139aa4f0SVijay Khemka 237139aa4f0SVijay Khemka if (data[1] == 0x00) 238139aa4f0SVijay Khemka errLog += " - First Time"; 239139aa4f0SVijay Khemka else if (data[1] == 0x80) 240139aa4f0SVijay Khemka errLog += " - Second Time"; 241139aa4f0SVijay Khemka } 242139aa4f0SVijay Khemka else 243139aa4f0SVijay Khemka { 244139aa4f0SVijay Khemka errLog = "Unknown"; 245139aa4f0SVijay Khemka } 246139aa4f0SVijay Khemka } 247139aa4f0SVijay Khemka 248139aa4f0SVijay Khemka static void logThermalEvent(uint8_t* data, std::string& errLog) 249139aa4f0SVijay Khemka { 250139aa4f0SVijay Khemka if (data[0] == 0x1) 251139aa4f0SVijay Khemka { 252139aa4f0SVijay Khemka errLog = "Limit Exceeded"; 253139aa4f0SVijay Khemka } 254139aa4f0SVijay Khemka else 255139aa4f0SVijay Khemka { 256139aa4f0SVijay Khemka errLog = "Unknown"; 257139aa4f0SVijay Khemka } 258139aa4f0SVijay Khemka } 259139aa4f0SVijay Khemka 260139aa4f0SVijay Khemka static void logCritIrq(uint8_t* data, std::string& errLog) 261139aa4f0SVijay Khemka { 262139aa4f0SVijay Khemka 263139aa4f0SVijay Khemka if (data[0] == 0x0) 264139aa4f0SVijay Khemka { 265139aa4f0SVijay Khemka errLog = "NMI / Diagnostic Interrupt"; 266139aa4f0SVijay Khemka } 267139aa4f0SVijay Khemka else if (data[0] == 0x03) 268139aa4f0SVijay Khemka { 269139aa4f0SVijay Khemka errLog = "Software NMI"; 270139aa4f0SVijay Khemka } 271139aa4f0SVijay Khemka else 272139aa4f0SVijay Khemka { 273139aa4f0SVijay Khemka errLog = "Unknown"; 274139aa4f0SVijay Khemka } 275139aa4f0SVijay Khemka 276139aa4f0SVijay Khemka /* TODO: Call add_cri_sel for CRITICAL_IRQ */ 277139aa4f0SVijay Khemka } 278139aa4f0SVijay Khemka 279139aa4f0SVijay Khemka static void logPostErr(uint8_t* data, std::string& errLog) 280139aa4f0SVijay Khemka { 281139aa4f0SVijay Khemka 282139aa4f0SVijay Khemka if ((data[0] & 0x0F) == 0x0) 283139aa4f0SVijay Khemka { 284139aa4f0SVijay Khemka errLog = "System Firmware Error"; 285139aa4f0SVijay Khemka } 286139aa4f0SVijay Khemka else 287139aa4f0SVijay Khemka { 288139aa4f0SVijay Khemka errLog = "Unknown"; 289139aa4f0SVijay Khemka } 290139aa4f0SVijay Khemka 291139aa4f0SVijay Khemka if (((data[0] >> 6) & 0x03) == 0x3) 292139aa4f0SVijay Khemka { 293139aa4f0SVijay Khemka // TODO: Need to implement IPMI spec based Post Code 294139aa4f0SVijay Khemka errLog += ", IPMI Post Code"; 295139aa4f0SVijay Khemka } 296139aa4f0SVijay Khemka else if (((data[0] >> 6) & 0x03) == 0x2) 297139aa4f0SVijay Khemka { 298139aa4f0SVijay Khemka errLog += 299139aa4f0SVijay Khemka ", OEM Post Code 0x" + byteToStr(data[2]) + byteToStr(data[1]); 300139aa4f0SVijay Khemka 301139aa4f0SVijay Khemka switch ((data[2] << 8) | data[1]) 302139aa4f0SVijay Khemka { 303139aa4f0SVijay Khemka case 0xA105: 304139aa4f0SVijay Khemka errLog += ", BMC Failed (No Response)"; 305139aa4f0SVijay Khemka break; 306139aa4f0SVijay Khemka case 0xA106: 307139aa4f0SVijay Khemka errLog += ", BMC Failed (Self Test Fail)"; 308139aa4f0SVijay Khemka break; 309139aa4f0SVijay Khemka case 0xA10A: 310139aa4f0SVijay Khemka errLog += ", System Firmware Corruption Detected"; 311139aa4f0SVijay Khemka break; 312139aa4f0SVijay Khemka case 0xA10B: 313139aa4f0SVijay Khemka errLog += ", TPM Self-Test FAIL Detected"; 314139aa4f0SVijay Khemka } 315139aa4f0SVijay Khemka } 316139aa4f0SVijay Khemka } 317139aa4f0SVijay Khemka 318139aa4f0SVijay Khemka static void logMchChkErr(uint8_t* data, std::string& errLog) 319139aa4f0SVijay Khemka { 320139aa4f0SVijay Khemka /* TODO: Call add_cri_sel for CRITICAL_IRQ */ 321139aa4f0SVijay Khemka if ((data[0] & 0x0F) == 0x0B) 322139aa4f0SVijay Khemka { 323139aa4f0SVijay Khemka errLog = "Uncorrectable"; 324139aa4f0SVijay Khemka } 325139aa4f0SVijay Khemka else if ((data[0] & 0x0F) == 0x0C) 326139aa4f0SVijay Khemka { 327139aa4f0SVijay Khemka errLog = "Correctable"; 328139aa4f0SVijay Khemka } 329139aa4f0SVijay Khemka else 330139aa4f0SVijay Khemka { 331139aa4f0SVijay Khemka errLog = "Unknown"; 332139aa4f0SVijay Khemka } 333139aa4f0SVijay Khemka 334139aa4f0SVijay Khemka errLog += ", Machine Check bank Number " + std::to_string(data[1]) + 335139aa4f0SVijay Khemka ", CPU " + std::to_string(data[2] >> 5) + ", Core " + 336139aa4f0SVijay Khemka std::to_string(data[2] & 0x1F); 337139aa4f0SVijay Khemka } 338139aa4f0SVijay Khemka 339139aa4f0SVijay Khemka static void logPcieErr(uint8_t* data, std::string& errLog) 340139aa4f0SVijay Khemka { 341139aa4f0SVijay Khemka std::stringstream tmp1, tmp2; 342139aa4f0SVijay Khemka tmp1 << std::hex << std::uppercase << std::setfill('0'); 343139aa4f0SVijay Khemka tmp2 << std::hex << std::uppercase << std::setfill('0'); 344139aa4f0SVijay Khemka tmp1 << " (Bus " << std::setw(2) << (int)(data[2]) << " / Dev " 345139aa4f0SVijay Khemka << std::setw(2) << (int)(data[1] >> 3) << " / Fun " << std::setw(2) 346139aa4f0SVijay Khemka << (int)(data[1] & 0x7) << ")"; 347139aa4f0SVijay Khemka 348139aa4f0SVijay Khemka switch (data[0] & 0xF) 349139aa4f0SVijay Khemka { 350139aa4f0SVijay Khemka case 0x4: 351139aa4f0SVijay Khemka errLog = "PCI PERR" + tmp1.str(); 352139aa4f0SVijay Khemka break; 353139aa4f0SVijay Khemka case 0x5: 354139aa4f0SVijay Khemka errLog = "PCI SERR" + tmp1.str(); 355139aa4f0SVijay Khemka break; 356139aa4f0SVijay Khemka case 0x7: 357139aa4f0SVijay Khemka errLog = "Correctable" + tmp1.str(); 358139aa4f0SVijay Khemka break; 359139aa4f0SVijay Khemka case 0x8: 360139aa4f0SVijay Khemka errLog = "Uncorrectable" + tmp1.str(); 361139aa4f0SVijay Khemka break; 362139aa4f0SVijay Khemka case 0xA: 363139aa4f0SVijay Khemka errLog = "Bus Fatal" + tmp1.str(); 364139aa4f0SVijay Khemka break; 365*d1194024SVijay Khemka case 0xD: 366*d1194024SVijay Khemka { 367139aa4f0SVijay Khemka uint32_t venId = (uint32_t)data[1] << 8 | (uint32_t)data[2]; 368139aa4f0SVijay Khemka tmp2 << "Vendor ID: 0x" << std::setw(4) << venId; 369139aa4f0SVijay Khemka errLog = tmp2.str(); 370139aa4f0SVijay Khemka } 371139aa4f0SVijay Khemka break; 372*d1194024SVijay Khemka case 0xE: 373*d1194024SVijay Khemka { 374139aa4f0SVijay Khemka uint32_t devId = (uint32_t)data[1] << 8 | (uint32_t)data[2]; 375139aa4f0SVijay Khemka tmp2 << "Device ID: 0x" << std::setw(4) << devId; 376139aa4f0SVijay Khemka errLog = tmp2.str(); 377139aa4f0SVijay Khemka } 378139aa4f0SVijay Khemka break; 379139aa4f0SVijay Khemka case 0xF: 380139aa4f0SVijay Khemka tmp2 << "Error ID from downstream: 0x" << std::setw(2) 381139aa4f0SVijay Khemka << (int)(data[1]) << std::setw(2) << (int)(data[2]); 382139aa4f0SVijay Khemka errLog = tmp2.str(); 383139aa4f0SVijay Khemka break; 384139aa4f0SVijay Khemka default: 385139aa4f0SVijay Khemka errLog = "Unknown"; 386139aa4f0SVijay Khemka } 387139aa4f0SVijay Khemka } 388139aa4f0SVijay Khemka 389139aa4f0SVijay Khemka static void logIioErr(uint8_t* data, std::string& errLog) 390139aa4f0SVijay Khemka { 391139aa4f0SVijay Khemka std::vector<std::string> tmpStr = { 392139aa4f0SVijay Khemka "IRP0", "IRP1", " IIO-Core", "VT-d", "Intel Quick Data", 393139aa4f0SVijay Khemka "Misc", " DMA", "ITC", "OTC", "CI"}; 394139aa4f0SVijay Khemka 395139aa4f0SVijay Khemka if ((data[0] & 0xF) == 0) 396139aa4f0SVijay Khemka { 397139aa4f0SVijay Khemka errLog += "CPU " + std::to_string(data[2] >> 5) + ", Error ID 0x" + 398139aa4f0SVijay Khemka byteToStr(data[1]) + " - "; 399139aa4f0SVijay Khemka 400139aa4f0SVijay Khemka if ((data[2] & 0xF) <= 0x9) 401139aa4f0SVijay Khemka { 402139aa4f0SVijay Khemka errLog += tmpStr[(data[2] & 0xF)]; 403139aa4f0SVijay Khemka } 404139aa4f0SVijay Khemka else 405139aa4f0SVijay Khemka { 406139aa4f0SVijay Khemka errLog += "Reserved"; 407139aa4f0SVijay Khemka } 408139aa4f0SVijay Khemka } 409139aa4f0SVijay Khemka else 410139aa4f0SVijay Khemka { 411139aa4f0SVijay Khemka errLog = "Unknown"; 412139aa4f0SVijay Khemka } 413139aa4f0SVijay Khemka } 414139aa4f0SVijay Khemka 415139aa4f0SVijay Khemka static void logMemErr(uint8_t* dataPtr, std::string& errLog) 416139aa4f0SVijay Khemka { 417139aa4f0SVijay Khemka uint8_t snrType = dataPtr[0]; 418139aa4f0SVijay Khemka uint8_t snrNum = dataPtr[1]; 419139aa4f0SVijay Khemka uint8_t* data = &(dataPtr[3]); 420139aa4f0SVijay Khemka 421139aa4f0SVijay Khemka /* TODO: add pal_add_cri_sel */ 422139aa4f0SVijay Khemka 423139aa4f0SVijay Khemka if (snrNum == memoryEccError) 424139aa4f0SVijay Khemka { 425139aa4f0SVijay Khemka /* SEL from MEMORY_ECC_ERR Sensor */ 426139aa4f0SVijay Khemka switch (data[0] & 0x0F) 427139aa4f0SVijay Khemka { 428139aa4f0SVijay Khemka case 0x0: 429139aa4f0SVijay Khemka if (snrType == 0x0C) 430139aa4f0SVijay Khemka { 431139aa4f0SVijay Khemka errLog = "Correctable"; 432139aa4f0SVijay Khemka } 433139aa4f0SVijay Khemka else if (snrType == 0x10) 434139aa4f0SVijay Khemka { 435139aa4f0SVijay Khemka errLog = "Correctable ECC error Logging Disabled"; 436139aa4f0SVijay Khemka } 437139aa4f0SVijay Khemka break; 438139aa4f0SVijay Khemka case 0x1: 439139aa4f0SVijay Khemka errLog = "Uncorrectable"; 440139aa4f0SVijay Khemka break; 441139aa4f0SVijay Khemka case 0x5: 442139aa4f0SVijay Khemka errLog = "Correctable ECC error Logging Limit Disabled"; 443139aa4f0SVijay Khemka break; 444139aa4f0SVijay Khemka default: 445139aa4f0SVijay Khemka errLog = "Unknown"; 446139aa4f0SVijay Khemka } 447139aa4f0SVijay Khemka } 448139aa4f0SVijay Khemka else if (snrNum == memoryErrLogDIS) 449139aa4f0SVijay Khemka { 450139aa4f0SVijay Khemka // SEL from MEMORY_ERR_LOG_DIS Sensor 451139aa4f0SVijay Khemka if ((data[0] & 0x0F) == 0x0) 452139aa4f0SVijay Khemka { 453139aa4f0SVijay Khemka errLog = "Correctable Memory Error Logging Disabled"; 454139aa4f0SVijay Khemka } 455139aa4f0SVijay Khemka else 456139aa4f0SVijay Khemka { 457139aa4f0SVijay Khemka errLog = "Unknown"; 458139aa4f0SVijay Khemka } 459139aa4f0SVijay Khemka } 460139aa4f0SVijay Khemka else 461139aa4f0SVijay Khemka { 462139aa4f0SVijay Khemka errLog = "Unknown"; 463139aa4f0SVijay Khemka return; 464139aa4f0SVijay Khemka } 465139aa4f0SVijay Khemka 466139aa4f0SVijay Khemka /* Common routine for both MEM_ECC_ERR and MEMORY_ERR_LOG_DIS */ 467139aa4f0SVijay Khemka 468139aa4f0SVijay Khemka errLog += " (DIMM " + byteToStr(data[2]) + ") Logical Rank " + 469139aa4f0SVijay Khemka std::to_string(data[1] & 0x03); 470139aa4f0SVijay Khemka 471139aa4f0SVijay Khemka /* DIMM number (data[2]): 472139aa4f0SVijay Khemka * Bit[7:5]: Socket number (Range: 0-7) 473139aa4f0SVijay Khemka * Bit[4:3]: Channel number (Range: 0-3) 474139aa4f0SVijay Khemka * Bit[2:0]: DIMM number (Range: 0-7) 475139aa4f0SVijay Khemka */ 476139aa4f0SVijay Khemka 477139aa4f0SVijay Khemka /* TODO: Verify these bits */ 478139aa4f0SVijay Khemka std::string cpuStr = "CPU# " + std::to_string((data[2] & 0xE0) >> 5); 479139aa4f0SVijay Khemka std::string chStr = "CHN# " + std::to_string((data[2] & 0x18) >> 3); 480139aa4f0SVijay Khemka std::string dimmStr = "DIMM# " + std::to_string(data[2] & 0x7); 481139aa4f0SVijay Khemka 482139aa4f0SVijay Khemka switch ((data[1] & 0xC) >> 2) 483139aa4f0SVijay Khemka { 484*d1194024SVijay Khemka case 0x0: 485*d1194024SVijay Khemka { 486139aa4f0SVijay Khemka 487139aa4f0SVijay Khemka /* All Info Valid */ 488139aa4f0SVijay Khemka uint8_t chnNum = (data[2] & 0x1C) >> 2; 489139aa4f0SVijay Khemka uint8_t dimmNum = data[2] & 0x3; 490139aa4f0SVijay Khemka 491139aa4f0SVijay Khemka /* TODO: If critical SEL logging is available, do it */ 492139aa4f0SVijay Khemka if (snrType == 0x0C) 493139aa4f0SVijay Khemka { 494139aa4f0SVijay Khemka if ((data[0] & 0x0F) == 0x0) 495139aa4f0SVijay Khemka { 496139aa4f0SVijay Khemka /* TODO: add_cri_sel */ 497139aa4f0SVijay Khemka /* "DIMM"+ 'A'+ chnNum + dimmNum + " ECC err,FRU:1" 498139aa4f0SVijay Khemka */ 499139aa4f0SVijay Khemka } 500139aa4f0SVijay Khemka else if ((data[0] & 0x0F) == 0x1) 501139aa4f0SVijay Khemka { 502139aa4f0SVijay Khemka /* TODO: add_cri_sel */ 503139aa4f0SVijay Khemka /* "DIMM"+ 'A'+ chnNum + dimmNum + " UECC err,FRU:1" 504139aa4f0SVijay Khemka */ 505139aa4f0SVijay Khemka } 506139aa4f0SVijay Khemka } 507139aa4f0SVijay Khemka /* Continue to parse the error into a string. All Info Valid 508139aa4f0SVijay Khemka */ 509139aa4f0SVijay Khemka errLog += " (" + cpuStr + ", " + chStr + ", " + dimmStr + ")"; 510139aa4f0SVijay Khemka } 511139aa4f0SVijay Khemka 512139aa4f0SVijay Khemka break; 513139aa4f0SVijay Khemka case 0x1: 514139aa4f0SVijay Khemka 515139aa4f0SVijay Khemka /* DIMM info not valid */ 516139aa4f0SVijay Khemka errLog += " (" + cpuStr + ", " + chStr + ")"; 517139aa4f0SVijay Khemka break; 518139aa4f0SVijay Khemka case 0x2: 519139aa4f0SVijay Khemka 520139aa4f0SVijay Khemka /* CHN info not valid */ 521139aa4f0SVijay Khemka errLog += " (" + cpuStr + ", " + dimmStr + ")"; 522139aa4f0SVijay Khemka break; 523139aa4f0SVijay Khemka case 0x3: 524139aa4f0SVijay Khemka 525139aa4f0SVijay Khemka /* CPU info not valid */ 526139aa4f0SVijay Khemka errLog += " (" + chStr + ", " + dimmStr + ")"; 527139aa4f0SVijay Khemka break; 528139aa4f0SVijay Khemka } 529139aa4f0SVijay Khemka } 530139aa4f0SVijay Khemka 531139aa4f0SVijay Khemka static void logPwrErr(uint8_t* data, std::string& errLog) 532139aa4f0SVijay Khemka { 533139aa4f0SVijay Khemka 534139aa4f0SVijay Khemka if (data[0] == 0x1) 535139aa4f0SVijay Khemka { 536139aa4f0SVijay Khemka errLog = "SYS_PWROK failure"; 537139aa4f0SVijay Khemka /* Also try logging to Critial log file, if available */ 538139aa4f0SVijay Khemka /* "SYS_PWROK failure,FRU:1" */ 539139aa4f0SVijay Khemka } 540139aa4f0SVijay Khemka else if (data[0] == 0x2) 541139aa4f0SVijay Khemka { 542139aa4f0SVijay Khemka errLog = "PCH_PWROK failure"; 543139aa4f0SVijay Khemka /* Also try logging to Critial log file, if available */ 544139aa4f0SVijay Khemka /* "PCH_PWROK failure,FRU:1" */ 545139aa4f0SVijay Khemka } 546139aa4f0SVijay Khemka else 547139aa4f0SVijay Khemka { 548139aa4f0SVijay Khemka errLog = "Unknown"; 549139aa4f0SVijay Khemka } 550139aa4f0SVijay Khemka } 551139aa4f0SVijay Khemka 552139aa4f0SVijay Khemka static void logCatErr(uint8_t* data, std::string& errLog) 553139aa4f0SVijay Khemka { 554139aa4f0SVijay Khemka 555139aa4f0SVijay Khemka if (data[0] == 0x0) 556139aa4f0SVijay Khemka { 557139aa4f0SVijay Khemka errLog = "IERR/CATERR"; 558139aa4f0SVijay Khemka /* Also try logging to Critial log file, if available */ 559139aa4f0SVijay Khemka /* "IERR,FRU:1 */ 560139aa4f0SVijay Khemka } 561139aa4f0SVijay Khemka else if (data[0] == 0xB) 562139aa4f0SVijay Khemka { 563139aa4f0SVijay Khemka errLog = "MCERR/CATERR"; 564139aa4f0SVijay Khemka /* Also try logging to Critial log file, if available */ 565139aa4f0SVijay Khemka /* "MCERR,FRU:1 */ 566139aa4f0SVijay Khemka } 567139aa4f0SVijay Khemka else 568139aa4f0SVijay Khemka { 569139aa4f0SVijay Khemka errLog = "Unknown"; 570139aa4f0SVijay Khemka } 571139aa4f0SVijay Khemka } 572139aa4f0SVijay Khemka 573139aa4f0SVijay Khemka static void logDimmHot(uint8_t* data, std::string& errLog) 574139aa4f0SVijay Khemka { 575139aa4f0SVijay Khemka if ((data[0] << 16 | data[1] << 8 | data[2]) == 0x01FFFF) 576139aa4f0SVijay Khemka { 577139aa4f0SVijay Khemka errLog = "SOC MEMHOT"; 578139aa4f0SVijay Khemka } 579139aa4f0SVijay Khemka else 580139aa4f0SVijay Khemka { 581139aa4f0SVijay Khemka errLog = "Unknown"; 582139aa4f0SVijay Khemka /* Also try logging to Critial log file, if available */ 583139aa4f0SVijay Khemka /* ""CPU_DIMM_HOT %s,FRU:1" */ 584139aa4f0SVijay Khemka } 585139aa4f0SVijay Khemka } 586139aa4f0SVijay Khemka 587139aa4f0SVijay Khemka static void logSwNMI(uint8_t* data, std::string& errLog) 588139aa4f0SVijay Khemka { 589139aa4f0SVijay Khemka if ((data[0] << 16 | data[1] << 8 | data[2]) == 0x03FFFF) 590139aa4f0SVijay Khemka { 591139aa4f0SVijay Khemka errLog = "Software NMI"; 592139aa4f0SVijay Khemka } 593139aa4f0SVijay Khemka else 594139aa4f0SVijay Khemka { 595139aa4f0SVijay Khemka errLog = "Unknown SW NMI"; 596139aa4f0SVijay Khemka } 597139aa4f0SVijay Khemka } 598139aa4f0SVijay Khemka 599139aa4f0SVijay Khemka static void logCPUThermalSts(uint8_t* data, std::string& errLog) 600139aa4f0SVijay Khemka { 601139aa4f0SVijay Khemka switch (data[0]) 602139aa4f0SVijay Khemka { 603139aa4f0SVijay Khemka case 0x0: 604139aa4f0SVijay Khemka errLog = "CPU Critical Temperature"; 605139aa4f0SVijay Khemka break; 606139aa4f0SVijay Khemka case 0x1: 607139aa4f0SVijay Khemka errLog = "PROCHOT#"; 608139aa4f0SVijay Khemka break; 609139aa4f0SVijay Khemka case 0x2: 610139aa4f0SVijay Khemka errLog = "TCC Activation"; 611139aa4f0SVijay Khemka break; 612139aa4f0SVijay Khemka default: 613139aa4f0SVijay Khemka errLog = "Unknown"; 614139aa4f0SVijay Khemka } 615139aa4f0SVijay Khemka } 616139aa4f0SVijay Khemka 617139aa4f0SVijay Khemka static void logMEPwrState(uint8_t* data, std::string& errLog) 618139aa4f0SVijay Khemka { 619139aa4f0SVijay Khemka switch (data[0]) 620139aa4f0SVijay Khemka { 621139aa4f0SVijay Khemka case 0: 622139aa4f0SVijay Khemka errLog = "RUNNING"; 623139aa4f0SVijay Khemka break; 624139aa4f0SVijay Khemka case 2: 625139aa4f0SVijay Khemka errLog = "POWER_OFF"; 626139aa4f0SVijay Khemka break; 627139aa4f0SVijay Khemka default: 628139aa4f0SVijay Khemka errLog = "Unknown[" + std::to_string(data[0]) + "]"; 629139aa4f0SVijay Khemka break; 630139aa4f0SVijay Khemka } 631139aa4f0SVijay Khemka } 632139aa4f0SVijay Khemka 633139aa4f0SVijay Khemka static void logSPSFwHealth(uint8_t* data, std::string& errLog) 634139aa4f0SVijay Khemka { 635139aa4f0SVijay Khemka if ((data[0] & 0x0F) == 0x00) 636139aa4f0SVijay Khemka { 637139aa4f0SVijay Khemka const std::vector<std::string> tmpStr = { 638139aa4f0SVijay Khemka "Recovery GPIO forced", 639139aa4f0SVijay Khemka "Image execution failed", 640139aa4f0SVijay Khemka "Flash erase error", 641139aa4f0SVijay Khemka "Flash state information", 642139aa4f0SVijay Khemka "Internal error", 643139aa4f0SVijay Khemka "BMC did not respond", 644139aa4f0SVijay Khemka "Direct Flash update", 645139aa4f0SVijay Khemka "Manufacturing error", 646139aa4f0SVijay Khemka "Automatic Restore to Factory Presets", 647139aa4f0SVijay Khemka "Firmware Exception", 648139aa4f0SVijay Khemka "Flash Wear-Out Protection Warning", 649139aa4f0SVijay Khemka "Unknown", 650139aa4f0SVijay Khemka "Unknown", 651139aa4f0SVijay Khemka "DMI interface error", 652139aa4f0SVijay Khemka "MCTP interface error", 653139aa4f0SVijay Khemka "Auto-configuration finished", 654139aa4f0SVijay Khemka "Unsupported Segment Defined Feature", 655139aa4f0SVijay Khemka "Unknown", 656139aa4f0SVijay Khemka "CPU Debug Capability Disabled", 657139aa4f0SVijay Khemka "UMA operation error"}; 658139aa4f0SVijay Khemka 659139aa4f0SVijay Khemka if (data[1] < 0x14) 660139aa4f0SVijay Khemka { 661139aa4f0SVijay Khemka errLog = tmpStr[data[1]]; 662139aa4f0SVijay Khemka } 663139aa4f0SVijay Khemka else 664139aa4f0SVijay Khemka { 665139aa4f0SVijay Khemka errLog = "Unknown"; 666139aa4f0SVijay Khemka } 667139aa4f0SVijay Khemka } 668139aa4f0SVijay Khemka else if ((data[0] & 0x0F) == 0x01) 669139aa4f0SVijay Khemka { 670139aa4f0SVijay Khemka errLog = "SMBus link failure"; 671139aa4f0SVijay Khemka } 672139aa4f0SVijay Khemka else 673139aa4f0SVijay Khemka { 674139aa4f0SVijay Khemka errLog = "Unknown"; 675139aa4f0SVijay Khemka } 676139aa4f0SVijay Khemka } 677139aa4f0SVijay Khemka 678139aa4f0SVijay Khemka static void logNmExcA(uint8_t* data, std::string& errLog) 679139aa4f0SVijay Khemka { 680139aa4f0SVijay Khemka /*NM4.0 #550710, Revision 1.95, and turn to p.155*/ 681139aa4f0SVijay Khemka if (data[0] == 0xA8) 682139aa4f0SVijay Khemka { 683139aa4f0SVijay Khemka errLog = "Policy Correction Time Exceeded"; 684139aa4f0SVijay Khemka } 685139aa4f0SVijay Khemka else 686139aa4f0SVijay Khemka { 687139aa4f0SVijay Khemka errLog = "Unknown"; 688139aa4f0SVijay Khemka } 689139aa4f0SVijay Khemka } 690139aa4f0SVijay Khemka 691139aa4f0SVijay Khemka static void logPCHThermal(uint8_t* data, std::string& errLog) 692139aa4f0SVijay Khemka { 693139aa4f0SVijay Khemka const std::vector<std::string> thresEvtName = {"Lower Non-critical", 694139aa4f0SVijay Khemka "Unknown", 695139aa4f0SVijay Khemka "Lower Critical", 696139aa4f0SVijay Khemka "Unknown", 697139aa4f0SVijay Khemka "Lower Non-recoverable", 698139aa4f0SVijay Khemka "Unknown", 699139aa4f0SVijay Khemka "Unknown", 700139aa4f0SVijay Khemka "Upper Non-critical", 701139aa4f0SVijay Khemka "Unknown", 702139aa4f0SVijay Khemka "Upper Critical", 703139aa4f0SVijay Khemka "Unknown", 704139aa4f0SVijay Khemka "Upper Non-recoverable"}; 705139aa4f0SVijay Khemka 706139aa4f0SVijay Khemka if ((data[0] & 0x0f) < 12) 707139aa4f0SVijay Khemka { 708139aa4f0SVijay Khemka errLog = thresEvtName[(data[0] & 0x0f)]; 709139aa4f0SVijay Khemka } 710139aa4f0SVijay Khemka else 711139aa4f0SVijay Khemka { 712139aa4f0SVijay Khemka errLog = "Unknown"; 713139aa4f0SVijay Khemka } 714139aa4f0SVijay Khemka 715139aa4f0SVijay Khemka errLog += ", curr_val: " + std::to_string(data[1]) + 716139aa4f0SVijay Khemka " C, thresh_val: " + std::to_string(data[2]) + " C"; 717139aa4f0SVijay Khemka } 718139aa4f0SVijay Khemka 719139aa4f0SVijay Khemka static void logNmHealth(uint8_t* data, std::string& errLog) 720139aa4f0SVijay Khemka { 721139aa4f0SVijay Khemka std::vector<std::string> nmErrType = { 722139aa4f0SVijay Khemka "Unknown", 723139aa4f0SVijay Khemka "Unknown", 724139aa4f0SVijay Khemka "Unknown", 725139aa4f0SVijay Khemka "Unknown", 726139aa4f0SVijay Khemka "Unknown", 727139aa4f0SVijay Khemka "Unknown", 728139aa4f0SVijay Khemka "Unknown", 729139aa4f0SVijay Khemka "Extended Telemetry Device Reading Failure", 730139aa4f0SVijay Khemka "Outlet Temperature Reading Failure", 731139aa4f0SVijay Khemka "Volumetric Airflow Reading Failure", 732139aa4f0SVijay Khemka "Policy Misconfiguration", 733139aa4f0SVijay Khemka "Power Sensor Reading Failure", 734139aa4f0SVijay Khemka "Inlet Temperature Reading Failure", 735139aa4f0SVijay Khemka "Host Communication Error", 736139aa4f0SVijay Khemka "Real-time Clock Synchronization Failure", 737139aa4f0SVijay Khemka "Platform Shutdown Initiated by Intel NM Policy", 738139aa4f0SVijay Khemka "Unknown"}; 739139aa4f0SVijay Khemka uint8_t nmTypeIdx = (data[0] & 0xf); 740139aa4f0SVijay Khemka uint8_t domIdx = (data[1] & 0xf); 741139aa4f0SVijay Khemka uint8_t errIdx = ((data[1] >> 4) & 0xf); 742139aa4f0SVijay Khemka 743139aa4f0SVijay Khemka if (nmTypeIdx == 2) 744139aa4f0SVijay Khemka { 745139aa4f0SVijay Khemka errLog = "SensorIntelNM"; 746139aa4f0SVijay Khemka } 747139aa4f0SVijay Khemka else 748139aa4f0SVijay Khemka { 749139aa4f0SVijay Khemka errLog = "Unknown"; 750139aa4f0SVijay Khemka } 751139aa4f0SVijay Khemka 752139aa4f0SVijay Khemka errLog += ", Domain:" + nmDomName[domIdx] + 753139aa4f0SVijay Khemka ", ErrType:" + nmErrType[errIdx] + ", Err:0x" + 754139aa4f0SVijay Khemka byteToStr(data[2]); 755139aa4f0SVijay Khemka } 756139aa4f0SVijay Khemka 757139aa4f0SVijay Khemka static void logNmCap(uint8_t* data, std::string& errLog) 758139aa4f0SVijay Khemka { 759139aa4f0SVijay Khemka 760139aa4f0SVijay Khemka const std::vector<std::string> nmCapStsStr = {"Not Available", "Available"}; 761139aa4f0SVijay Khemka if (data[0] & 0x7) // BIT1=policy, BIT2=monitoring, BIT3=pwr 762139aa4f0SVijay Khemka // limit and the others are reserved 763139aa4f0SVijay Khemka { 764139aa4f0SVijay Khemka errLog = "PolicyInterface:" + nmCapStsStr[BIT(data[0], 0)] + 765139aa4f0SVijay Khemka ",Monitoring:" + nmCapStsStr[BIT(data[0], 1)] + 766139aa4f0SVijay Khemka ",PowerLimit:" + nmCapStsStr[BIT(data[0], 2)]; 767139aa4f0SVijay Khemka } 768139aa4f0SVijay Khemka else 769139aa4f0SVijay Khemka { 770139aa4f0SVijay Khemka errLog = "Unknown"; 771139aa4f0SVijay Khemka } 772139aa4f0SVijay Khemka } 773139aa4f0SVijay Khemka 774139aa4f0SVijay Khemka static void logNmThreshold(uint8_t* data, std::string& errLog) 775139aa4f0SVijay Khemka { 776139aa4f0SVijay Khemka uint8_t thresNum = (data[0] & 0x3); 777139aa4f0SVijay Khemka uint8_t domIdx = (data[1] & 0xf); 778139aa4f0SVijay Khemka uint8_t polId = data[2]; 779139aa4f0SVijay Khemka uint8_t polEvtIdx = BIT(data[0], 3); 780139aa4f0SVijay Khemka const std::vector<std::string> polEvtStr = { 781139aa4f0SVijay Khemka "Threshold Exceeded", "Policy Correction Time Exceeded"}; 782139aa4f0SVijay Khemka 783139aa4f0SVijay Khemka errLog = "Threshold Number:" + std::to_string(thresNum) + "-" + 784139aa4f0SVijay Khemka polEvtStr[polEvtIdx] + ", Domain:" + nmDomName[domIdx] + 785139aa4f0SVijay Khemka ", PolicyID:0x" + byteToStr(polId); 786139aa4f0SVijay Khemka } 787139aa4f0SVijay Khemka 788139aa4f0SVijay Khemka static void logPwrThreshold(uint8_t* data, std::string& errLog) 789139aa4f0SVijay Khemka { 790139aa4f0SVijay Khemka if (data[0] == 0x00) 791139aa4f0SVijay Khemka { 792139aa4f0SVijay Khemka errLog = "Limit Not Exceeded"; 793139aa4f0SVijay Khemka } 794139aa4f0SVijay Khemka else if (data[0] == 0x01) 795139aa4f0SVijay Khemka { 796139aa4f0SVijay Khemka errLog = "Limit Exceeded"; 797139aa4f0SVijay Khemka } 798139aa4f0SVijay Khemka else 799139aa4f0SVijay Khemka { 800139aa4f0SVijay Khemka errLog = "Unknown"; 801139aa4f0SVijay Khemka } 802139aa4f0SVijay Khemka } 803139aa4f0SVijay Khemka 804139aa4f0SVijay Khemka static void logMSMI(uint8_t* data, std::string& errLog) 805139aa4f0SVijay Khemka { 806139aa4f0SVijay Khemka 807139aa4f0SVijay Khemka if (data[0] == 0x0) 808139aa4f0SVijay Khemka { 809139aa4f0SVijay Khemka errLog = "IERR/MSMI"; 810139aa4f0SVijay Khemka } 811139aa4f0SVijay Khemka else if (data[0] == 0x0B) 812139aa4f0SVijay Khemka { 813139aa4f0SVijay Khemka errLog = "MCERR/MSMI"; 814139aa4f0SVijay Khemka } 815139aa4f0SVijay Khemka else 816139aa4f0SVijay Khemka { 817139aa4f0SVijay Khemka errLog = "Unknown"; 818139aa4f0SVijay Khemka } 819139aa4f0SVijay Khemka } 820139aa4f0SVijay Khemka 821139aa4f0SVijay Khemka static void logHprWarn(uint8_t* data, std::string& errLog) 822139aa4f0SVijay Khemka { 823139aa4f0SVijay Khemka if (data[2] == 0x01) 824139aa4f0SVijay Khemka { 825139aa4f0SVijay Khemka if (data[1] == 0xFF) 826139aa4f0SVijay Khemka { 827139aa4f0SVijay Khemka errLog = "Infinite Time"; 828139aa4f0SVijay Khemka } 829139aa4f0SVijay Khemka else 830139aa4f0SVijay Khemka { 831139aa4f0SVijay Khemka errLog = std::to_string(data[1]) + " minutes"; 832139aa4f0SVijay Khemka } 833139aa4f0SVijay Khemka } 834139aa4f0SVijay Khemka else 835139aa4f0SVijay Khemka { 836139aa4f0SVijay Khemka errLog = "Unknown"; 837139aa4f0SVijay Khemka } 838139aa4f0SVijay Khemka } 839139aa4f0SVijay Khemka 840139aa4f0SVijay Khemka static const boost::container::flat_map< 841139aa4f0SVijay Khemka uint8_t, 842139aa4f0SVijay Khemka std::pair<std::string, std::function<void(uint8_t*, std::string&)>>> 843139aa4f0SVijay Khemka sensorNameTable = {{0xE9, {"SYSTEM_EVENT", logSysEvent}}, 844139aa4f0SVijay Khemka {0x7D, {"THERM_THRESH_EVT", logThermalEvent}}, 845139aa4f0SVijay Khemka {0xAA, {"BUTTON", logDefault}}, 846139aa4f0SVijay Khemka {0xAB, {"POWER_STATE", logDefault}}, 847139aa4f0SVijay Khemka {0xEA, {"CRITICAL_IRQ", logCritIrq}}, 848139aa4f0SVijay Khemka {0x2B, {"POST_ERROR", logPostErr}}, 849139aa4f0SVijay Khemka {0x40, {"MACHINE_CHK_ERR", logMchChkErr}}, 850139aa4f0SVijay Khemka {0x41, {"PCIE_ERR", logPcieErr}}, 851139aa4f0SVijay Khemka {0x43, {"IIO_ERR", logIioErr}}, 852139aa4f0SVijay Khemka {0X63, {"MEMORY_ECC_ERR", logDefault}}, 853139aa4f0SVijay Khemka {0X87, {"MEMORY_ERR_LOG_DIS", logDefault}}, 854139aa4f0SVijay Khemka {0X51, {"PROCHOT_EXT", logDefault}}, 855139aa4f0SVijay Khemka {0X56, {"PWR_ERR", logPwrErr}}, 856139aa4f0SVijay Khemka {0xE6, {"CATERR_A", logCatErr}}, 857139aa4f0SVijay Khemka {0xEB, {"CATERR_B", logCatErr}}, 858139aa4f0SVijay Khemka {0xB3, {"CPU_DIMM_HOT", logDimmHot}}, 859139aa4f0SVijay Khemka {0x90, {"SOFTWARE_NMI", logSwNMI}}, 860139aa4f0SVijay Khemka {0x1C, {"CPU0_THERM_STATUS", logCPUThermalSts}}, 861139aa4f0SVijay Khemka {0x1D, {"CPU1_THERM_STATUS", logCPUThermalSts}}, 862139aa4f0SVijay Khemka {0x16, {"ME_POWER_STATE", logMEPwrState}}, 863139aa4f0SVijay Khemka {0x17, {"SPS_FW_HEALTH", logSPSFwHealth}}, 864139aa4f0SVijay Khemka {0x18, {"NM_EXCEPTION_A", logNmExcA}}, 865139aa4f0SVijay Khemka {0x08, {"PCH_THERM_THRESHOLD", logPCHThermal}}, 866139aa4f0SVijay Khemka {0x19, {"NM_HEALTH", logNmHealth}}, 867139aa4f0SVijay Khemka {0x1A, {"NM_CAPABILITIES", logNmCap}}, 868139aa4f0SVijay Khemka {0x1B, {"NM_THRESHOLD", logNmThreshold}}, 869139aa4f0SVijay Khemka {0x3B, {"PWR_THRESH_EVT", logPwrThreshold}}, 870139aa4f0SVijay Khemka {0xE7, {"MSMI", logMSMI}}, 871139aa4f0SVijay Khemka {0xC5, {"HPR_WARNING", logHprWarn}}}; 872139aa4f0SVijay Khemka 873139aa4f0SVijay Khemka static void parseSelHelper(StdSELEntry* data, std::string& errStr) 874139aa4f0SVijay Khemka { 875139aa4f0SVijay Khemka 876139aa4f0SVijay Khemka /* Check if sensor type is OS_BOOT (0x1f) */ 877139aa4f0SVijay Khemka if (data->sensorType == 0x1F) 878139aa4f0SVijay Khemka { 879139aa4f0SVijay Khemka /* OS_BOOT used by OS */ 880139aa4f0SVijay Khemka switch (data->eventData1 & 0xF) 881139aa4f0SVijay Khemka { 882139aa4f0SVijay Khemka case 0x07: 883139aa4f0SVijay Khemka errStr = "Base OS/Hypervisor Installation started"; 884139aa4f0SVijay Khemka break; 885139aa4f0SVijay Khemka case 0x08: 886139aa4f0SVijay Khemka errStr = "Base OS/Hypervisor Installation completed"; 887139aa4f0SVijay Khemka break; 888139aa4f0SVijay Khemka case 0x09: 889139aa4f0SVijay Khemka errStr = "Base OS/Hypervisor Installation aborted"; 890139aa4f0SVijay Khemka break; 891139aa4f0SVijay Khemka case 0x0A: 892139aa4f0SVijay Khemka errStr = "Base OS/Hypervisor Installation failed"; 893139aa4f0SVijay Khemka break; 894139aa4f0SVijay Khemka default: 895139aa4f0SVijay Khemka errStr = "Unknown"; 896139aa4f0SVijay Khemka } 897139aa4f0SVijay Khemka return; 898139aa4f0SVijay Khemka } 899139aa4f0SVijay Khemka 900139aa4f0SVijay Khemka auto findSensorName = sensorNameTable.find(data->sensorNum); 901139aa4f0SVijay Khemka if (findSensorName == sensorNameTable.end()) 902139aa4f0SVijay Khemka { 903139aa4f0SVijay Khemka errStr = "Unknown"; 904139aa4f0SVijay Khemka return; 905139aa4f0SVijay Khemka } 906139aa4f0SVijay Khemka else 907139aa4f0SVijay Khemka { 908139aa4f0SVijay Khemka switch (data->sensorNum) 909139aa4f0SVijay Khemka { 910139aa4f0SVijay Khemka /* logMemErr function needs data from sensor type */ 911139aa4f0SVijay Khemka case memoryEccError: 912139aa4f0SVijay Khemka case memoryErrLogDIS: 913139aa4f0SVijay Khemka findSensorName->second.second(&(data->sensorType), errStr); 914139aa4f0SVijay Khemka break; 915139aa4f0SVijay Khemka /* Other sensor function needs only event data for parsing */ 916139aa4f0SVijay Khemka default: 917139aa4f0SVijay Khemka findSensorName->second.second(&(data->eventData1), errStr); 918139aa4f0SVijay Khemka } 919139aa4f0SVijay Khemka } 920139aa4f0SVijay Khemka 921139aa4f0SVijay Khemka if (((data->eventData3 & 0x80) >> 7) == 0) 922139aa4f0SVijay Khemka { 923139aa4f0SVijay Khemka errStr += " Assertion"; 924139aa4f0SVijay Khemka } 925139aa4f0SVijay Khemka else 926139aa4f0SVijay Khemka { 927139aa4f0SVijay Khemka errStr += " Deassertion"; 928139aa4f0SVijay Khemka } 929139aa4f0SVijay Khemka } 930139aa4f0SVijay 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: 973139aa4f0SVijay 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 { 1140139aa4f0SVijay 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 135215a7ae81SVijay Khemka static const std::string openBMCMessageRegistryVersion("0.1"); 135315a7ae81SVijay Khemka std::string messageID = 135415a7ae81SVijay Khemka "OpenBMC." + openBMCMessageRegistryVersion + ".SELEntryAdded"; 135515a7ae81SVijay Khemka 135611b9c3b1SVijay Khemka /* Log the Raw SEL message to the journal */ 135711b9c3b1SVijay Khemka std::string journalMsg = "SEL Entry Added: " + ipmiRaw; 1358f36f345fSVijay Khemka 135915a7ae81SVijay Khemka phosphor::logging::log<phosphor::logging::level::INFO>( 136015a7ae81SVijay Khemka journalMsg.c_str(), 136115a7ae81SVijay Khemka phosphor::logging::entry("IPMISEL_MESSAGE_ID=%s", messageID.c_str()), 136215a7ae81SVijay Khemka phosphor::logging::entry("IPMISEL_MESSAGE_ARGS=%s", logErr.c_str())); 136311b9c3b1SVijay Khemka 136411b9c3b1SVijay Khemka int responseID = selObj.addEntry(ipmiRaw.c_str()); 136511b9c3b1SVijay Khemka if (responseID < 0) 136611b9c3b1SVijay Khemka { 136711b9c3b1SVijay Khemka return ipmi::responseUnspecifiedError(); 136811b9c3b1SVijay Khemka } 136911b9c3b1SVijay Khemka return ipmi::responseSuccess((uint16_t)responseID); 137011b9c3b1SVijay Khemka } 137111b9c3b1SVijay Khemka 1372c1921c63SVijay Khemka ipmi::RspType<uint8_t> ipmiStorageClearSEL(uint16_t reservationID, 1373c1921c63SVijay Khemka const std::array<uint8_t, 3>& clr, 1374c1921c63SVijay Khemka uint8_t eraseOperation) 1375c1921c63SVijay Khemka { 1376c1921c63SVijay Khemka if (!checkSELReservation(reservationID)) 1377c1921c63SVijay Khemka { 1378c1921c63SVijay Khemka return ipmi::responseInvalidReservationId(); 1379c1921c63SVijay Khemka } 1380c1921c63SVijay Khemka 1381c1921c63SVijay Khemka static constexpr std::array<uint8_t, 3> clrExpected = {'C', 'L', 'R'}; 1382c1921c63SVijay Khemka if (clr != clrExpected) 1383c1921c63SVijay Khemka { 1384c1921c63SVijay Khemka return ipmi::responseInvalidFieldRequest(); 1385c1921c63SVijay Khemka } 1386c1921c63SVijay Khemka 1387c1921c63SVijay Khemka /* If there is no sel then return erase complete */ 1388c1921c63SVijay Khemka if (selObj.getCount() == 0) 1389c1921c63SVijay Khemka { 1390c1921c63SVijay Khemka return ipmi::responseSuccess(fb_oem::ipmi::sel::eraseComplete); 1391c1921c63SVijay Khemka } 1392c1921c63SVijay Khemka 1393c1921c63SVijay Khemka /* Erasure status cannot be fetched, so always return erasure 1394c1921c63SVijay Khemka * status as `erase completed`. 1395c1921c63SVijay Khemka */ 1396c1921c63SVijay Khemka if (eraseOperation == fb_oem::ipmi::sel::getEraseStatus) 1397c1921c63SVijay Khemka { 1398c1921c63SVijay Khemka return ipmi::responseSuccess(fb_oem::ipmi::sel::eraseComplete); 1399c1921c63SVijay Khemka } 1400c1921c63SVijay Khemka 1401c1921c63SVijay Khemka /* Check that initiate erase is correct */ 1402c1921c63SVijay Khemka if (eraseOperation != fb_oem::ipmi::sel::initiateErase) 1403c1921c63SVijay Khemka { 1404c1921c63SVijay Khemka return ipmi::responseInvalidFieldRequest(); 1405c1921c63SVijay Khemka } 1406c1921c63SVijay Khemka 1407c1921c63SVijay Khemka /* Per the IPMI spec, need to cancel any reservation when the 1408c1921c63SVijay Khemka * SEL is cleared 1409c1921c63SVijay Khemka */ 1410c1921c63SVijay Khemka cancelSELReservation(); 1411c1921c63SVijay Khemka 1412c1921c63SVijay Khemka /* Clear the complete Sel Json object */ 1413c1921c63SVijay Khemka if (selObj.clear() < 0) 1414c1921c63SVijay Khemka { 1415c1921c63SVijay Khemka return ipmi::responseUnspecifiedError(); 1416c1921c63SVijay Khemka } 1417c1921c63SVijay Khemka 1418c1921c63SVijay Khemka return ipmi::responseSuccess(fb_oem::ipmi::sel::eraseComplete); 1419c1921c63SVijay Khemka } 1420c1921c63SVijay Khemka 1421c1921c63SVijay Khemka ipmi::RspType<uint32_t> ipmiStorageGetSELTime() 1422c1921c63SVijay Khemka { 1423c1921c63SVijay Khemka struct timespec selTime = {}; 1424c1921c63SVijay Khemka 1425c1921c63SVijay Khemka if (clock_gettime(CLOCK_REALTIME, &selTime) < 0) 1426c1921c63SVijay Khemka { 1427c1921c63SVijay Khemka return ipmi::responseUnspecifiedError(); 1428c1921c63SVijay Khemka } 1429c1921c63SVijay Khemka 1430c1921c63SVijay Khemka return ipmi::responseSuccess(selTime.tv_sec); 1431c1921c63SVijay Khemka } 1432c1921c63SVijay Khemka 1433c1921c63SVijay Khemka ipmi::RspType<> ipmiStorageSetSELTime(uint32_t selTime) 1434c1921c63SVijay Khemka { 1435c1921c63SVijay Khemka // Set SEL Time is not supported 1436c1921c63SVijay Khemka return ipmi::responseInvalidCommand(); 1437c1921c63SVijay Khemka } 1438c1921c63SVijay Khemka 1439c1921c63SVijay Khemka ipmi::RspType<uint16_t> ipmiStorageGetSELTimeUtcOffset() 1440c1921c63SVijay Khemka { 1441c1921c63SVijay Khemka /* TODO: For now, the SEL time stamp is based on UTC time, 1442c1921c63SVijay Khemka * so return 0x0000 as offset. Might need to change once 1443c1921c63SVijay Khemka * supporting zones in SEL time stamps 1444c1921c63SVijay Khemka */ 1445c1921c63SVijay Khemka 1446c1921c63SVijay Khemka uint16_t utcOffset = 0x0000; 1447c1921c63SVijay Khemka return ipmi::responseSuccess(utcOffset); 1448c1921c63SVijay Khemka } 1449c1921c63SVijay Khemka 145011b9c3b1SVijay Khemka void registerSELFunctions() 145111b9c3b1SVijay Khemka { 145211b9c3b1SVijay Khemka // <Get SEL Info> 145311b9c3b1SVijay Khemka ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage, 145411b9c3b1SVijay Khemka ipmi::storage::cmdGetSelInfo, ipmi::Privilege::User, 145511b9c3b1SVijay Khemka ipmiStorageGetSELInfo); 145611b9c3b1SVijay Khemka 145711b9c3b1SVijay Khemka // <Get SEL Entry> 145811b9c3b1SVijay Khemka ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage, 145911b9c3b1SVijay Khemka ipmi::storage::cmdGetSelEntry, ipmi::Privilege::User, 146011b9c3b1SVijay Khemka ipmiStorageGetSELEntry); 146111b9c3b1SVijay Khemka 146211b9c3b1SVijay Khemka // <Add SEL Entry> 146311b9c3b1SVijay Khemka ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage, 146411b9c3b1SVijay Khemka ipmi::storage::cmdAddSelEntry, 146511b9c3b1SVijay Khemka ipmi::Privilege::Operator, ipmiStorageAddSELEntry); 146611b9c3b1SVijay Khemka 1467c1921c63SVijay Khemka // <Clear SEL> 1468c1921c63SVijay Khemka ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage, 1469c1921c63SVijay Khemka ipmi::storage::cmdClearSel, ipmi::Privilege::Operator, 1470c1921c63SVijay Khemka ipmiStorageClearSEL); 1471c1921c63SVijay Khemka 1472c1921c63SVijay Khemka // <Get SEL Time> 1473c1921c63SVijay Khemka ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage, 1474c1921c63SVijay Khemka ipmi::storage::cmdGetSelTime, ipmi::Privilege::User, 1475c1921c63SVijay Khemka ipmiStorageGetSELTime); 1476c1921c63SVijay Khemka 1477c1921c63SVijay Khemka // <Set SEL Time> 1478c1921c63SVijay Khemka ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage, 1479c1921c63SVijay Khemka ipmi::storage::cmdSetSelTime, 1480c1921c63SVijay Khemka ipmi::Privilege::Operator, ipmiStorageSetSELTime); 1481c1921c63SVijay Khemka 1482c1921c63SVijay Khemka // <Get SEL Time UTC Offset> 1483c1921c63SVijay Khemka ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage, 1484c1921c63SVijay Khemka ipmi::storage::cmdGetSelTimeUtcOffset, 1485c1921c63SVijay Khemka ipmi::Privilege::User, 1486c1921c63SVijay Khemka ipmiStorageGetSELTimeUtcOffset); 1487c1921c63SVijay Khemka 148811b9c3b1SVijay Khemka return; 148911b9c3b1SVijay Khemka } 149011b9c3b1SVijay Khemka 149111b9c3b1SVijay Khemka } // namespace storage 149211b9c3b1SVijay Khemka } // namespace ipmi 1493