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> 19*020ff3e4SPatrick 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 3111b9c3b1SVijay Khemka //---------------------------------------------------------------------- 3211b9c3b1SVijay Khemka // Platform specific functions for storing app data 3311b9c3b1SVijay Khemka //---------------------------------------------------------------------- 3411b9c3b1SVijay Khemka 35139aa4f0SVijay Khemka static std::string byteToStr(uint8_t byte) 36139aa4f0SVijay Khemka { 37139aa4f0SVijay Khemka std::stringstream ss; 38139aa4f0SVijay Khemka 39139aa4f0SVijay Khemka ss << std::hex << std::uppercase << std::setfill('0'); 40139aa4f0SVijay Khemka ss << std::setw(2) << (int)byte; 41139aa4f0SVijay Khemka 42139aa4f0SVijay Khemka return ss.str(); 43139aa4f0SVijay Khemka } 44139aa4f0SVijay Khemka 4511b9c3b1SVijay Khemka static void toHexStr(std::vector<uint8_t>& bytes, std::string& hexStr) 4611b9c3b1SVijay Khemka { 4711b9c3b1SVijay Khemka std::stringstream stream; 4811b9c3b1SVijay Khemka stream << std::hex << std::uppercase << std::setfill('0'); 4911b9c3b1SVijay Khemka for (const uint8_t byte : bytes) 5011b9c3b1SVijay Khemka { 5111b9c3b1SVijay Khemka stream << std::setw(2) << static_cast<int>(byte); 5211b9c3b1SVijay Khemka } 5311b9c3b1SVijay Khemka hexStr = stream.str(); 5411b9c3b1SVijay Khemka } 5511b9c3b1SVijay Khemka 5611b9c3b1SVijay Khemka static int fromHexStr(const std::string hexStr, std::vector<uint8_t>& data) 5711b9c3b1SVijay Khemka { 5811b9c3b1SVijay Khemka for (unsigned int i = 0; i < hexStr.size(); i += 2) 5911b9c3b1SVijay Khemka { 6011b9c3b1SVijay Khemka try 6111b9c3b1SVijay Khemka { 6211b9c3b1SVijay Khemka data.push_back(static_cast<uint8_t>( 6311b9c3b1SVijay Khemka std::stoul(hexStr.substr(i, 2), nullptr, 16))); 6411b9c3b1SVijay Khemka } 6535d12546SPatrick Williams catch (const std::invalid_argument& e) 6611b9c3b1SVijay Khemka { 6711b9c3b1SVijay Khemka phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); 6811b9c3b1SVijay Khemka return -1; 6911b9c3b1SVijay Khemka } 7035d12546SPatrick Williams catch (const std::out_of_range& e) 7111b9c3b1SVijay Khemka { 7211b9c3b1SVijay Khemka phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); 7311b9c3b1SVijay Khemka return -1; 7411b9c3b1SVijay Khemka } 7511b9c3b1SVijay Khemka } 7611b9c3b1SVijay Khemka return 0; 7711b9c3b1SVijay Khemka } 7811b9c3b1SVijay Khemka 7911b9c3b1SVijay Khemka namespace fb_oem::ipmi::sel 8011b9c3b1SVijay Khemka { 8111b9c3b1SVijay Khemka 8211b9c3b1SVijay Khemka class SELData 8311b9c3b1SVijay Khemka { 8411b9c3b1SVijay Khemka private: 8511b9c3b1SVijay Khemka nlohmann::json selDataObj; 8611b9c3b1SVijay Khemka 8711b9c3b1SVijay Khemka void flush() 8811b9c3b1SVijay Khemka { 8911b9c3b1SVijay Khemka std::ofstream file(SEL_JSON_DATA_FILE); 9011b9c3b1SVijay Khemka file << selDataObj; 9111b9c3b1SVijay Khemka file.close(); 9211b9c3b1SVijay Khemka } 9311b9c3b1SVijay Khemka 9411b9c3b1SVijay Khemka void init() 9511b9c3b1SVijay Khemka { 9611b9c3b1SVijay Khemka selDataObj[KEY_SEL_VER] = 0x51; 9711b9c3b1SVijay Khemka selDataObj[KEY_SEL_COUNT] = 0; 9811b9c3b1SVijay Khemka selDataObj[KEY_ADD_TIME] = 0xFFFFFFFF; 9911b9c3b1SVijay Khemka selDataObj[KEY_ERASE_TIME] = 0xFFFFFFFF; 10011b9c3b1SVijay Khemka selDataObj[KEY_OPER_SUPP] = 0x02; 10111b9c3b1SVijay Khemka /* Spec indicates that more than 64kB is free */ 10211b9c3b1SVijay Khemka selDataObj[KEY_FREE_SPACE] = 0xFFFF; 10311b9c3b1SVijay Khemka } 10411b9c3b1SVijay Khemka 10511b9c3b1SVijay Khemka public: 10611b9c3b1SVijay Khemka SELData() 10711b9c3b1SVijay Khemka { 10811b9c3b1SVijay Khemka /* Get App data stored in json file */ 10911b9c3b1SVijay Khemka std::ifstream file(SEL_JSON_DATA_FILE); 11011b9c3b1SVijay Khemka if (file) 11111b9c3b1SVijay Khemka { 11211b9c3b1SVijay Khemka file >> selDataObj; 11311b9c3b1SVijay Khemka file.close(); 11411b9c3b1SVijay Khemka } 11511b9c3b1SVijay Khemka 11611b9c3b1SVijay Khemka /* Initialize SelData object if no entries. */ 11711b9c3b1SVijay Khemka if (selDataObj.find(KEY_SEL_COUNT) == selDataObj.end()) 11811b9c3b1SVijay Khemka { 11911b9c3b1SVijay Khemka init(); 12011b9c3b1SVijay Khemka } 12111b9c3b1SVijay Khemka } 12211b9c3b1SVijay Khemka 12311b9c3b1SVijay Khemka int clear() 12411b9c3b1SVijay Khemka { 12511b9c3b1SVijay Khemka /* Clear the complete Sel Json object */ 12611b9c3b1SVijay Khemka selDataObj.clear(); 12711b9c3b1SVijay Khemka /* Reinitialize it with basic data */ 12811b9c3b1SVijay Khemka init(); 12911b9c3b1SVijay Khemka /* Save the erase time */ 13011b9c3b1SVijay Khemka struct timespec selTime = {}; 13111b9c3b1SVijay Khemka if (clock_gettime(CLOCK_REALTIME, &selTime) < 0) 13211b9c3b1SVijay Khemka { 13311b9c3b1SVijay Khemka return -1; 13411b9c3b1SVijay Khemka } 13511b9c3b1SVijay Khemka selDataObj[KEY_ERASE_TIME] = selTime.tv_sec; 13611b9c3b1SVijay Khemka flush(); 13711b9c3b1SVijay Khemka return 0; 13811b9c3b1SVijay Khemka } 13911b9c3b1SVijay Khemka 14011b9c3b1SVijay Khemka uint32_t getCount() 14111b9c3b1SVijay Khemka { 14211b9c3b1SVijay Khemka return selDataObj[KEY_SEL_COUNT]; 14311b9c3b1SVijay Khemka } 14411b9c3b1SVijay Khemka 14511b9c3b1SVijay Khemka void getInfo(GetSELInfoData& info) 14611b9c3b1SVijay Khemka { 14711b9c3b1SVijay Khemka info.selVersion = selDataObj[KEY_SEL_VER]; 14811b9c3b1SVijay Khemka info.entries = selDataObj[KEY_SEL_COUNT]; 14911b9c3b1SVijay Khemka info.freeSpace = selDataObj[KEY_FREE_SPACE]; 15011b9c3b1SVijay Khemka info.addTimeStamp = selDataObj[KEY_ADD_TIME]; 15111b9c3b1SVijay Khemka info.eraseTimeStamp = selDataObj[KEY_ERASE_TIME]; 15211b9c3b1SVijay Khemka info.operationSupport = selDataObj[KEY_OPER_SUPP]; 15311b9c3b1SVijay Khemka } 15411b9c3b1SVijay Khemka 15511b9c3b1SVijay Khemka int getEntry(uint32_t index, std::string& rawStr) 15611b9c3b1SVijay Khemka { 15711b9c3b1SVijay Khemka std::stringstream ss; 15811b9c3b1SVijay Khemka ss << std::hex; 15911b9c3b1SVijay Khemka ss << std::setw(2) << std::setfill('0') << index; 16011b9c3b1SVijay Khemka 16111b9c3b1SVijay Khemka /* Check or the requested SEL Entry, if record is available */ 16211b9c3b1SVijay Khemka if (selDataObj.find(ss.str()) == selDataObj.end()) 16311b9c3b1SVijay Khemka { 16411b9c3b1SVijay Khemka return -1; 16511b9c3b1SVijay Khemka } 16611b9c3b1SVijay Khemka 16711b9c3b1SVijay Khemka rawStr = selDataObj[ss.str()][KEY_SEL_ENTRY_RAW]; 16811b9c3b1SVijay Khemka return 0; 16911b9c3b1SVijay Khemka } 17011b9c3b1SVijay Khemka 17111b9c3b1SVijay Khemka int addEntry(std::string keyStr) 17211b9c3b1SVijay Khemka { 17311b9c3b1SVijay Khemka struct timespec selTime = {}; 17411b9c3b1SVijay Khemka 17511b9c3b1SVijay Khemka if (clock_gettime(CLOCK_REALTIME, &selTime) < 0) 17611b9c3b1SVijay Khemka { 17711b9c3b1SVijay Khemka return -1; 17811b9c3b1SVijay Khemka } 17911b9c3b1SVijay Khemka 18011b9c3b1SVijay Khemka selDataObj[KEY_ADD_TIME] = selTime.tv_sec; 18111b9c3b1SVijay Khemka 18211b9c3b1SVijay Khemka int selCount = selDataObj[KEY_SEL_COUNT]; 18311b9c3b1SVijay Khemka selDataObj[KEY_SEL_COUNT] = ++selCount; 18411b9c3b1SVijay Khemka 18511b9c3b1SVijay Khemka std::stringstream ss; 18611b9c3b1SVijay Khemka ss << std::hex; 18711b9c3b1SVijay Khemka ss << std::setw(2) << std::setfill('0') << selCount; 18811b9c3b1SVijay Khemka 18911b9c3b1SVijay Khemka selDataObj[ss.str()][KEY_SEL_ENTRY_RAW] = keyStr; 19011b9c3b1SVijay Khemka flush(); 19111b9c3b1SVijay Khemka return selCount; 19211b9c3b1SVijay Khemka } 19311b9c3b1SVijay Khemka }; 19411b9c3b1SVijay Khemka 195139aa4f0SVijay Khemka /* 196139aa4f0SVijay Khemka * A Function to parse common SEL message, a helper funciton 197139aa4f0SVijay Khemka * for parseStdSel. 198139aa4f0SVijay Khemka * 199139aa4f0SVijay Khemka * Note that this function __CANNOT__ be overriden. 200139aa4f0SVijay Khemka * To add board specific routine, please override parseStdSel. 201139aa4f0SVijay Khemka */ 202139aa4f0SVijay Khemka 203139aa4f0SVijay Khemka /*Used by decoding ME event*/ 204139aa4f0SVijay Khemka std::vector<std::string> nmDomName = { 205139aa4f0SVijay Khemka "Entire Platform", "CPU Subsystem", 206139aa4f0SVijay Khemka "Memory Subsystem", "HW Protection", 207139aa4f0SVijay Khemka "High Power I/O subsystem", "Unknown"}; 208139aa4f0SVijay Khemka 209139aa4f0SVijay Khemka /* Default log message for unknown type */ 210e39f9393SWilly Tu static void logDefault(uint8_t*, std::string& errLog) 211139aa4f0SVijay Khemka { 212139aa4f0SVijay Khemka errLog = "Unknown"; 213139aa4f0SVijay Khemka } 214139aa4f0SVijay Khemka 215139aa4f0SVijay Khemka static void logSysEvent(uint8_t* data, std::string& errLog) 216139aa4f0SVijay Khemka { 217139aa4f0SVijay Khemka if (data[0] == 0xE5) 218139aa4f0SVijay Khemka { 219139aa4f0SVijay Khemka errLog = "Cause of Time change - "; 220139aa4f0SVijay Khemka switch (data[2]) 221139aa4f0SVijay Khemka { 222139aa4f0SVijay Khemka case 0x00: 223139aa4f0SVijay Khemka errLog += "NTP"; 224139aa4f0SVijay Khemka break; 225139aa4f0SVijay Khemka case 0x01: 226139aa4f0SVijay Khemka errLog += "Host RTL"; 227139aa4f0SVijay Khemka break; 228139aa4f0SVijay Khemka case 0x02: 229139aa4f0SVijay Khemka errLog += "Set SEL time cmd"; 230139aa4f0SVijay Khemka break; 231139aa4f0SVijay Khemka case 0x03: 232139aa4f0SVijay Khemka errLog += "Set SEL time UTC offset cmd"; 233139aa4f0SVijay Khemka break; 234139aa4f0SVijay Khemka default: 235139aa4f0SVijay Khemka errLog += "Unknown"; 236139aa4f0SVijay Khemka } 237139aa4f0SVijay Khemka 238139aa4f0SVijay Khemka if (data[1] == 0x00) 239139aa4f0SVijay Khemka errLog += " - First Time"; 240139aa4f0SVijay Khemka else if (data[1] == 0x80) 241139aa4f0SVijay Khemka errLog += " - Second Time"; 242139aa4f0SVijay Khemka } 243139aa4f0SVijay Khemka else 244139aa4f0SVijay Khemka { 245139aa4f0SVijay Khemka errLog = "Unknown"; 246139aa4f0SVijay Khemka } 247139aa4f0SVijay Khemka } 248139aa4f0SVijay Khemka 249139aa4f0SVijay Khemka static void logThermalEvent(uint8_t* data, std::string& errLog) 250139aa4f0SVijay Khemka { 251139aa4f0SVijay Khemka if (data[0] == 0x1) 252139aa4f0SVijay Khemka { 253139aa4f0SVijay Khemka errLog = "Limit Exceeded"; 254139aa4f0SVijay Khemka } 255139aa4f0SVijay Khemka else 256139aa4f0SVijay Khemka { 257139aa4f0SVijay Khemka errLog = "Unknown"; 258139aa4f0SVijay Khemka } 259139aa4f0SVijay Khemka } 260139aa4f0SVijay Khemka 261139aa4f0SVijay Khemka static void logCritIrq(uint8_t* data, std::string& errLog) 262139aa4f0SVijay Khemka { 263139aa4f0SVijay Khemka 264139aa4f0SVijay Khemka if (data[0] == 0x0) 265139aa4f0SVijay Khemka { 266139aa4f0SVijay Khemka errLog = "NMI / Diagnostic Interrupt"; 267139aa4f0SVijay Khemka } 268139aa4f0SVijay Khemka else if (data[0] == 0x03) 269139aa4f0SVijay Khemka { 270139aa4f0SVijay Khemka errLog = "Software NMI"; 271139aa4f0SVijay Khemka } 272139aa4f0SVijay Khemka else 273139aa4f0SVijay Khemka { 274139aa4f0SVijay Khemka errLog = "Unknown"; 275139aa4f0SVijay Khemka } 276139aa4f0SVijay Khemka 277139aa4f0SVijay Khemka /* TODO: Call add_cri_sel for CRITICAL_IRQ */ 278139aa4f0SVijay Khemka } 279139aa4f0SVijay Khemka 280139aa4f0SVijay Khemka static void logPostErr(uint8_t* data, std::string& errLog) 281139aa4f0SVijay Khemka { 282139aa4f0SVijay Khemka 283139aa4f0SVijay Khemka if ((data[0] & 0x0F) == 0x0) 284139aa4f0SVijay Khemka { 285139aa4f0SVijay Khemka errLog = "System Firmware Error"; 286139aa4f0SVijay Khemka } 287139aa4f0SVijay Khemka else 288139aa4f0SVijay Khemka { 289139aa4f0SVijay Khemka errLog = "Unknown"; 290139aa4f0SVijay Khemka } 291139aa4f0SVijay Khemka 292139aa4f0SVijay Khemka if (((data[0] >> 6) & 0x03) == 0x3) 293139aa4f0SVijay Khemka { 294139aa4f0SVijay Khemka // TODO: Need to implement IPMI spec based Post Code 295139aa4f0SVijay Khemka errLog += ", IPMI Post Code"; 296139aa4f0SVijay Khemka } 297139aa4f0SVijay Khemka else if (((data[0] >> 6) & 0x03) == 0x2) 298139aa4f0SVijay Khemka { 299139aa4f0SVijay Khemka errLog += 300139aa4f0SVijay Khemka ", OEM Post Code 0x" + byteToStr(data[2]) + byteToStr(data[1]); 301139aa4f0SVijay Khemka 302139aa4f0SVijay Khemka switch ((data[2] << 8) | data[1]) 303139aa4f0SVijay Khemka { 304139aa4f0SVijay Khemka case 0xA105: 305139aa4f0SVijay Khemka errLog += ", BMC Failed (No Response)"; 306139aa4f0SVijay Khemka break; 307139aa4f0SVijay Khemka case 0xA106: 308139aa4f0SVijay Khemka errLog += ", BMC Failed (Self Test Fail)"; 309139aa4f0SVijay Khemka break; 310139aa4f0SVijay Khemka case 0xA10A: 311139aa4f0SVijay Khemka errLog += ", System Firmware Corruption Detected"; 312139aa4f0SVijay Khemka break; 313139aa4f0SVijay Khemka case 0xA10B: 314139aa4f0SVijay Khemka errLog += ", TPM Self-Test FAIL Detected"; 315139aa4f0SVijay Khemka } 316139aa4f0SVijay Khemka } 317139aa4f0SVijay Khemka } 318139aa4f0SVijay Khemka 319139aa4f0SVijay Khemka static void logMchChkErr(uint8_t* data, std::string& errLog) 320139aa4f0SVijay Khemka { 321139aa4f0SVijay Khemka /* TODO: Call add_cri_sel for CRITICAL_IRQ */ 322139aa4f0SVijay Khemka if ((data[0] & 0x0F) == 0x0B) 323139aa4f0SVijay Khemka { 324139aa4f0SVijay Khemka errLog = "Uncorrectable"; 325139aa4f0SVijay Khemka } 326139aa4f0SVijay Khemka else if ((data[0] & 0x0F) == 0x0C) 327139aa4f0SVijay Khemka { 328139aa4f0SVijay Khemka errLog = "Correctable"; 329139aa4f0SVijay Khemka } 330139aa4f0SVijay Khemka else 331139aa4f0SVijay Khemka { 332139aa4f0SVijay Khemka errLog = "Unknown"; 333139aa4f0SVijay Khemka } 334139aa4f0SVijay Khemka 335139aa4f0SVijay Khemka errLog += ", Machine Check bank Number " + std::to_string(data[1]) + 336139aa4f0SVijay Khemka ", CPU " + std::to_string(data[2] >> 5) + ", Core " + 337139aa4f0SVijay Khemka std::to_string(data[2] & 0x1F); 338139aa4f0SVijay Khemka } 339139aa4f0SVijay Khemka 340139aa4f0SVijay Khemka static void logPcieErr(uint8_t* data, std::string& errLog) 341139aa4f0SVijay Khemka { 342139aa4f0SVijay Khemka std::stringstream tmp1, tmp2; 343139aa4f0SVijay Khemka tmp1 << std::hex << std::uppercase << std::setfill('0'); 344139aa4f0SVijay Khemka tmp2 << std::hex << std::uppercase << std::setfill('0'); 345139aa4f0SVijay Khemka tmp1 << " (Bus " << std::setw(2) << (int)(data[2]) << " / Dev " 346139aa4f0SVijay Khemka << std::setw(2) << (int)(data[1] >> 3) << " / Fun " << std::setw(2) 347139aa4f0SVijay Khemka << (int)(data[1] & 0x7) << ")"; 348139aa4f0SVijay Khemka 349139aa4f0SVijay Khemka switch (data[0] & 0xF) 350139aa4f0SVijay Khemka { 351139aa4f0SVijay Khemka case 0x4: 352139aa4f0SVijay Khemka errLog = "PCI PERR" + tmp1.str(); 353139aa4f0SVijay Khemka break; 354139aa4f0SVijay Khemka case 0x5: 355139aa4f0SVijay Khemka errLog = "PCI SERR" + tmp1.str(); 356139aa4f0SVijay Khemka break; 357139aa4f0SVijay Khemka case 0x7: 358139aa4f0SVijay Khemka errLog = "Correctable" + tmp1.str(); 359139aa4f0SVijay Khemka break; 360139aa4f0SVijay Khemka case 0x8: 361139aa4f0SVijay Khemka errLog = "Uncorrectable" + tmp1.str(); 362139aa4f0SVijay Khemka break; 363139aa4f0SVijay Khemka case 0xA: 364139aa4f0SVijay Khemka errLog = "Bus Fatal" + tmp1.str(); 365139aa4f0SVijay Khemka break; 366d1194024SVijay Khemka case 0xD: 367d1194024SVijay Khemka { 368139aa4f0SVijay Khemka uint32_t venId = (uint32_t)data[1] << 8 | (uint32_t)data[2]; 369139aa4f0SVijay Khemka tmp2 << "Vendor ID: 0x" << std::setw(4) << venId; 370139aa4f0SVijay Khemka errLog = tmp2.str(); 371139aa4f0SVijay Khemka } 372139aa4f0SVijay Khemka break; 373d1194024SVijay Khemka case 0xE: 374d1194024SVijay Khemka { 375139aa4f0SVijay Khemka uint32_t devId = (uint32_t)data[1] << 8 | (uint32_t)data[2]; 376139aa4f0SVijay Khemka tmp2 << "Device ID: 0x" << std::setw(4) << devId; 377139aa4f0SVijay Khemka errLog = tmp2.str(); 378139aa4f0SVijay Khemka } 379139aa4f0SVijay Khemka break; 380139aa4f0SVijay Khemka case 0xF: 381139aa4f0SVijay Khemka tmp2 << "Error ID from downstream: 0x" << std::setw(2) 382139aa4f0SVijay Khemka << (int)(data[1]) << std::setw(2) << (int)(data[2]); 383139aa4f0SVijay Khemka errLog = tmp2.str(); 384139aa4f0SVijay Khemka break; 385139aa4f0SVijay Khemka default: 386139aa4f0SVijay Khemka errLog = "Unknown"; 387139aa4f0SVijay Khemka } 388139aa4f0SVijay Khemka } 389139aa4f0SVijay Khemka 390139aa4f0SVijay Khemka static void logIioErr(uint8_t* data, std::string& errLog) 391139aa4f0SVijay Khemka { 392139aa4f0SVijay Khemka std::vector<std::string> tmpStr = { 393139aa4f0SVijay Khemka "IRP0", "IRP1", " IIO-Core", "VT-d", "Intel Quick Data", 394139aa4f0SVijay Khemka "Misc", " DMA", "ITC", "OTC", "CI"}; 395139aa4f0SVijay Khemka 396139aa4f0SVijay Khemka if ((data[0] & 0xF) == 0) 397139aa4f0SVijay Khemka { 398139aa4f0SVijay Khemka errLog += "CPU " + std::to_string(data[2] >> 5) + ", Error ID 0x" + 399139aa4f0SVijay Khemka byteToStr(data[1]) + " - "; 400139aa4f0SVijay Khemka 401139aa4f0SVijay Khemka if ((data[2] & 0xF) <= 0x9) 402139aa4f0SVijay Khemka { 403139aa4f0SVijay Khemka errLog += tmpStr[(data[2] & 0xF)]; 404139aa4f0SVijay Khemka } 405139aa4f0SVijay Khemka else 406139aa4f0SVijay Khemka { 407139aa4f0SVijay Khemka errLog += "Reserved"; 408139aa4f0SVijay Khemka } 409139aa4f0SVijay Khemka } 410139aa4f0SVijay Khemka else 411139aa4f0SVijay Khemka { 412139aa4f0SVijay Khemka errLog = "Unknown"; 413139aa4f0SVijay Khemka } 414139aa4f0SVijay Khemka } 415139aa4f0SVijay Khemka 416e39f9393SWilly Tu [[maybe_unused]] static void logMemErr(uint8_t* dataPtr, std::string& errLog) 417139aa4f0SVijay Khemka { 418139aa4f0SVijay Khemka uint8_t snrType = dataPtr[0]; 419139aa4f0SVijay Khemka uint8_t snrNum = dataPtr[1]; 420139aa4f0SVijay Khemka uint8_t* data = &(dataPtr[3]); 421139aa4f0SVijay Khemka 422139aa4f0SVijay Khemka /* TODO: add pal_add_cri_sel */ 423139aa4f0SVijay Khemka 424139aa4f0SVijay Khemka if (snrNum == memoryEccError) 425139aa4f0SVijay Khemka { 426139aa4f0SVijay Khemka /* SEL from MEMORY_ECC_ERR Sensor */ 427139aa4f0SVijay Khemka switch (data[0] & 0x0F) 428139aa4f0SVijay Khemka { 429139aa4f0SVijay Khemka case 0x0: 430139aa4f0SVijay Khemka if (snrType == 0x0C) 431139aa4f0SVijay Khemka { 432139aa4f0SVijay Khemka errLog = "Correctable"; 433139aa4f0SVijay Khemka } 434139aa4f0SVijay Khemka else if (snrType == 0x10) 435139aa4f0SVijay Khemka { 436139aa4f0SVijay Khemka errLog = "Correctable ECC error Logging Disabled"; 437139aa4f0SVijay Khemka } 438139aa4f0SVijay Khemka break; 439139aa4f0SVijay Khemka case 0x1: 440139aa4f0SVijay Khemka errLog = "Uncorrectable"; 441139aa4f0SVijay Khemka break; 442139aa4f0SVijay Khemka case 0x5: 443139aa4f0SVijay Khemka errLog = "Correctable ECC error Logging Limit Disabled"; 444139aa4f0SVijay Khemka break; 445139aa4f0SVijay Khemka default: 446139aa4f0SVijay Khemka errLog = "Unknown"; 447139aa4f0SVijay Khemka } 448139aa4f0SVijay Khemka } 449139aa4f0SVijay Khemka else if (snrNum == memoryErrLogDIS) 450139aa4f0SVijay Khemka { 451139aa4f0SVijay Khemka // SEL from MEMORY_ERR_LOG_DIS Sensor 452139aa4f0SVijay Khemka if ((data[0] & 0x0F) == 0x0) 453139aa4f0SVijay Khemka { 454139aa4f0SVijay Khemka errLog = "Correctable Memory Error Logging Disabled"; 455139aa4f0SVijay Khemka } 456139aa4f0SVijay Khemka else 457139aa4f0SVijay Khemka { 458139aa4f0SVijay Khemka errLog = "Unknown"; 459139aa4f0SVijay Khemka } 460139aa4f0SVijay Khemka } 461139aa4f0SVijay Khemka else 462139aa4f0SVijay Khemka { 463139aa4f0SVijay Khemka errLog = "Unknown"; 464139aa4f0SVijay Khemka return; 465139aa4f0SVijay Khemka } 466139aa4f0SVijay Khemka 467139aa4f0SVijay Khemka /* Common routine for both MEM_ECC_ERR and MEMORY_ERR_LOG_DIS */ 468139aa4f0SVijay Khemka 469139aa4f0SVijay Khemka errLog += " (DIMM " + byteToStr(data[2]) + ") Logical Rank " + 470139aa4f0SVijay Khemka std::to_string(data[1] & 0x03); 471139aa4f0SVijay Khemka 472139aa4f0SVijay Khemka /* DIMM number (data[2]): 473139aa4f0SVijay Khemka * Bit[7:5]: Socket number (Range: 0-7) 474139aa4f0SVijay Khemka * Bit[4:3]: Channel number (Range: 0-3) 475139aa4f0SVijay Khemka * Bit[2:0]: DIMM number (Range: 0-7) 476139aa4f0SVijay Khemka */ 477139aa4f0SVijay Khemka 478139aa4f0SVijay Khemka /* TODO: Verify these bits */ 479139aa4f0SVijay Khemka std::string cpuStr = "CPU# " + std::to_string((data[2] & 0xE0) >> 5); 480139aa4f0SVijay Khemka std::string chStr = "CHN# " + std::to_string((data[2] & 0x18) >> 3); 481139aa4f0SVijay Khemka std::string dimmStr = "DIMM#" + std::to_string(data[2] & 0x7); 482139aa4f0SVijay Khemka 483139aa4f0SVijay Khemka switch ((data[1] & 0xC) >> 2) 484139aa4f0SVijay Khemka { 485d1194024SVijay Khemka case 0x0: 486d1194024SVijay Khemka { 487139aa4f0SVijay Khemka 488139aa4f0SVijay Khemka /* All Info Valid */ 489e39f9393SWilly Tu [[maybe_unused]] uint8_t chnNum = (data[2] & 0x1C) >> 2; 490e39f9393SWilly Tu [[maybe_unused]] uint8_t dimmNum = data[2] & 0x3; 491139aa4f0SVijay Khemka 492139aa4f0SVijay Khemka /* TODO: If critical SEL logging is available, do it */ 493139aa4f0SVijay Khemka if (snrType == 0x0C) 494139aa4f0SVijay Khemka { 495139aa4f0SVijay Khemka if ((data[0] & 0x0F) == 0x0) 496139aa4f0SVijay Khemka { 497139aa4f0SVijay Khemka /* TODO: add_cri_sel */ 498139aa4f0SVijay Khemka /* "DIMM"+ 'A'+ chnNum + dimmNum + " ECC err,FRU:1" 499139aa4f0SVijay Khemka */ 500139aa4f0SVijay Khemka } 501139aa4f0SVijay Khemka else if ((data[0] & 0x0F) == 0x1) 502139aa4f0SVijay Khemka { 503139aa4f0SVijay Khemka /* TODO: add_cri_sel */ 504139aa4f0SVijay Khemka /* "DIMM"+ 'A'+ chnNum + dimmNum + " UECC err,FRU:1" 505139aa4f0SVijay Khemka */ 506139aa4f0SVijay Khemka } 507139aa4f0SVijay Khemka } 508139aa4f0SVijay Khemka /* Continue to parse the error into a string. All Info Valid 509139aa4f0SVijay Khemka */ 510139aa4f0SVijay Khemka errLog += " (" + cpuStr + ", " + chStr + ", " + dimmStr + ")"; 511139aa4f0SVijay Khemka } 512139aa4f0SVijay Khemka 513139aa4f0SVijay Khemka break; 514139aa4f0SVijay Khemka case 0x1: 515139aa4f0SVijay Khemka 516139aa4f0SVijay Khemka /* DIMM info not valid */ 517139aa4f0SVijay Khemka errLog += " (" + cpuStr + ", " + chStr + ")"; 518139aa4f0SVijay Khemka break; 519139aa4f0SVijay Khemka case 0x2: 520139aa4f0SVijay Khemka 521139aa4f0SVijay Khemka /* CHN info not valid */ 522139aa4f0SVijay Khemka errLog += " (" + cpuStr + ", " + dimmStr + ")"; 523139aa4f0SVijay Khemka break; 524139aa4f0SVijay Khemka case 0x3: 525139aa4f0SVijay Khemka 526139aa4f0SVijay Khemka /* CPU info not valid */ 527139aa4f0SVijay Khemka errLog += " (" + chStr + ", " + dimmStr + ")"; 528139aa4f0SVijay Khemka break; 529139aa4f0SVijay Khemka } 530139aa4f0SVijay Khemka } 531139aa4f0SVijay Khemka 532139aa4f0SVijay Khemka static void logPwrErr(uint8_t* data, std::string& errLog) 533139aa4f0SVijay Khemka { 534139aa4f0SVijay Khemka 535139aa4f0SVijay Khemka if (data[0] == 0x1) 536139aa4f0SVijay Khemka { 537139aa4f0SVijay Khemka errLog = "SYS_PWROK failure"; 538139aa4f0SVijay Khemka /* Also try logging to Critial log file, if available */ 539139aa4f0SVijay Khemka /* "SYS_PWROK failure,FRU:1" */ 540139aa4f0SVijay Khemka } 541139aa4f0SVijay Khemka else if (data[0] == 0x2) 542139aa4f0SVijay Khemka { 543139aa4f0SVijay Khemka errLog = "PCH_PWROK failure"; 544139aa4f0SVijay Khemka /* Also try logging to Critial log file, if available */ 545139aa4f0SVijay Khemka /* "PCH_PWROK failure,FRU:1" */ 546139aa4f0SVijay Khemka } 547139aa4f0SVijay Khemka else 548139aa4f0SVijay Khemka { 549139aa4f0SVijay Khemka errLog = "Unknown"; 550139aa4f0SVijay Khemka } 551139aa4f0SVijay Khemka } 552139aa4f0SVijay Khemka 553139aa4f0SVijay Khemka static void logCatErr(uint8_t* data, std::string& errLog) 554139aa4f0SVijay Khemka { 555139aa4f0SVijay Khemka 556139aa4f0SVijay Khemka if (data[0] == 0x0) 557139aa4f0SVijay Khemka { 558139aa4f0SVijay Khemka errLog = "IERR/CATERR"; 559139aa4f0SVijay Khemka /* Also try logging to Critial log file, if available */ 560139aa4f0SVijay Khemka /* "IERR,FRU:1 */ 561139aa4f0SVijay Khemka } 562139aa4f0SVijay Khemka else if (data[0] == 0xB) 563139aa4f0SVijay Khemka { 564139aa4f0SVijay Khemka errLog = "MCERR/CATERR"; 565139aa4f0SVijay Khemka /* Also try logging to Critial log file, if available */ 566139aa4f0SVijay Khemka /* "MCERR,FRU:1 */ 567139aa4f0SVijay Khemka } 568139aa4f0SVijay Khemka else 569139aa4f0SVijay Khemka { 570139aa4f0SVijay Khemka errLog = "Unknown"; 571139aa4f0SVijay Khemka } 572139aa4f0SVijay Khemka } 573139aa4f0SVijay Khemka 574139aa4f0SVijay Khemka static void logDimmHot(uint8_t* data, std::string& errLog) 575139aa4f0SVijay Khemka { 576139aa4f0SVijay Khemka if ((data[0] << 16 | data[1] << 8 | data[2]) == 0x01FFFF) 577139aa4f0SVijay Khemka { 578139aa4f0SVijay Khemka errLog = "SOC MEMHOT"; 579139aa4f0SVijay Khemka } 580139aa4f0SVijay Khemka else 581139aa4f0SVijay Khemka { 582139aa4f0SVijay Khemka errLog = "Unknown"; 583139aa4f0SVijay Khemka /* Also try logging to Critial log file, if available */ 584139aa4f0SVijay Khemka /* ""CPU_DIMM_HOT %s,FRU:1" */ 585139aa4f0SVijay Khemka } 586139aa4f0SVijay Khemka } 587139aa4f0SVijay Khemka 588139aa4f0SVijay Khemka static void logSwNMI(uint8_t* data, std::string& errLog) 589139aa4f0SVijay Khemka { 590139aa4f0SVijay Khemka if ((data[0] << 16 | data[1] << 8 | data[2]) == 0x03FFFF) 591139aa4f0SVijay Khemka { 592139aa4f0SVijay Khemka errLog = "Software NMI"; 593139aa4f0SVijay Khemka } 594139aa4f0SVijay Khemka else 595139aa4f0SVijay Khemka { 596139aa4f0SVijay Khemka errLog = "Unknown SW NMI"; 597139aa4f0SVijay Khemka } 598139aa4f0SVijay Khemka } 599139aa4f0SVijay Khemka 600139aa4f0SVijay Khemka static void logCPUThermalSts(uint8_t* data, std::string& errLog) 601139aa4f0SVijay Khemka { 602139aa4f0SVijay Khemka switch (data[0]) 603139aa4f0SVijay Khemka { 604139aa4f0SVijay Khemka case 0x0: 605139aa4f0SVijay Khemka errLog = "CPU Critical Temperature"; 606139aa4f0SVijay Khemka break; 607139aa4f0SVijay Khemka case 0x1: 608139aa4f0SVijay Khemka errLog = "PROCHOT#"; 609139aa4f0SVijay Khemka break; 610139aa4f0SVijay Khemka case 0x2: 611139aa4f0SVijay Khemka errLog = "TCC Activation"; 612139aa4f0SVijay Khemka break; 613139aa4f0SVijay Khemka default: 614139aa4f0SVijay Khemka errLog = "Unknown"; 615139aa4f0SVijay Khemka } 616139aa4f0SVijay Khemka } 617139aa4f0SVijay Khemka 618139aa4f0SVijay Khemka static void logMEPwrState(uint8_t* data, std::string& errLog) 619139aa4f0SVijay Khemka { 620139aa4f0SVijay Khemka switch (data[0]) 621139aa4f0SVijay Khemka { 622139aa4f0SVijay Khemka case 0: 623139aa4f0SVijay Khemka errLog = "RUNNING"; 624139aa4f0SVijay Khemka break; 625139aa4f0SVijay Khemka case 2: 626139aa4f0SVijay Khemka errLog = "POWER_OFF"; 627139aa4f0SVijay Khemka break; 628139aa4f0SVijay Khemka default: 629139aa4f0SVijay Khemka errLog = "Unknown[" + std::to_string(data[0]) + "]"; 630139aa4f0SVijay Khemka break; 631139aa4f0SVijay Khemka } 632139aa4f0SVijay Khemka } 633139aa4f0SVijay Khemka 634139aa4f0SVijay Khemka static void logSPSFwHealth(uint8_t* data, std::string& errLog) 635139aa4f0SVijay Khemka { 636139aa4f0SVijay Khemka if ((data[0] & 0x0F) == 0x00) 637139aa4f0SVijay Khemka { 638139aa4f0SVijay Khemka const std::vector<std::string> tmpStr = { 639139aa4f0SVijay Khemka "Recovery GPIO forced", 640139aa4f0SVijay Khemka "Image execution failed", 641139aa4f0SVijay Khemka "Flash erase error", 642139aa4f0SVijay Khemka "Flash state information", 643139aa4f0SVijay Khemka "Internal error", 644139aa4f0SVijay Khemka "BMC did not respond", 645139aa4f0SVijay Khemka "Direct Flash update", 646139aa4f0SVijay Khemka "Manufacturing error", 647139aa4f0SVijay Khemka "Automatic Restore to Factory Presets", 648139aa4f0SVijay Khemka "Firmware Exception", 649139aa4f0SVijay Khemka "Flash Wear-Out Protection Warning", 650139aa4f0SVijay Khemka "Unknown", 651139aa4f0SVijay Khemka "Unknown", 652139aa4f0SVijay Khemka "DMI interface error", 653139aa4f0SVijay Khemka "MCTP interface error", 654139aa4f0SVijay Khemka "Auto-configuration finished", 655139aa4f0SVijay Khemka "Unsupported Segment Defined Feature", 656139aa4f0SVijay Khemka "Unknown", 657139aa4f0SVijay Khemka "CPU Debug Capability Disabled", 658139aa4f0SVijay Khemka "UMA operation error"}; 659139aa4f0SVijay Khemka 660139aa4f0SVijay Khemka if (data[1] < 0x14) 661139aa4f0SVijay Khemka { 662139aa4f0SVijay Khemka errLog = tmpStr[data[1]]; 663139aa4f0SVijay Khemka } 664139aa4f0SVijay Khemka else 665139aa4f0SVijay Khemka { 666139aa4f0SVijay Khemka errLog = "Unknown"; 667139aa4f0SVijay Khemka } 668139aa4f0SVijay Khemka } 669139aa4f0SVijay Khemka else if ((data[0] & 0x0F) == 0x01) 670139aa4f0SVijay Khemka { 671139aa4f0SVijay Khemka errLog = "SMBus link failure"; 672139aa4f0SVijay Khemka } 673139aa4f0SVijay Khemka else 674139aa4f0SVijay Khemka { 675139aa4f0SVijay Khemka errLog = "Unknown"; 676139aa4f0SVijay Khemka } 677139aa4f0SVijay Khemka } 678139aa4f0SVijay Khemka 679139aa4f0SVijay Khemka static void logNmExcA(uint8_t* data, std::string& errLog) 680139aa4f0SVijay Khemka { 681139aa4f0SVijay Khemka /*NM4.0 #550710, Revision 1.95, and turn to p.155*/ 682139aa4f0SVijay Khemka if (data[0] == 0xA8) 683139aa4f0SVijay Khemka { 684139aa4f0SVijay Khemka errLog = "Policy Correction Time Exceeded"; 685139aa4f0SVijay Khemka } 686139aa4f0SVijay Khemka else 687139aa4f0SVijay Khemka { 688139aa4f0SVijay Khemka errLog = "Unknown"; 689139aa4f0SVijay Khemka } 690139aa4f0SVijay Khemka } 691139aa4f0SVijay Khemka 692139aa4f0SVijay Khemka static void logPCHThermal(uint8_t* data, std::string& errLog) 693139aa4f0SVijay Khemka { 694139aa4f0SVijay Khemka const std::vector<std::string> thresEvtName = {"Lower Non-critical", 695139aa4f0SVijay Khemka "Unknown", 696139aa4f0SVijay Khemka "Lower Critical", 697139aa4f0SVijay Khemka "Unknown", 698139aa4f0SVijay Khemka "Lower Non-recoverable", 699139aa4f0SVijay Khemka "Unknown", 700139aa4f0SVijay Khemka "Unknown", 701139aa4f0SVijay Khemka "Upper Non-critical", 702139aa4f0SVijay Khemka "Unknown", 703139aa4f0SVijay Khemka "Upper Critical", 704139aa4f0SVijay Khemka "Unknown", 705139aa4f0SVijay Khemka "Upper Non-recoverable"}; 706139aa4f0SVijay Khemka 707139aa4f0SVijay Khemka if ((data[0] & 0x0f) < 12) 708139aa4f0SVijay Khemka { 709139aa4f0SVijay Khemka errLog = thresEvtName[(data[0] & 0x0f)]; 710139aa4f0SVijay Khemka } 711139aa4f0SVijay Khemka else 712139aa4f0SVijay Khemka { 713139aa4f0SVijay Khemka errLog = "Unknown"; 714139aa4f0SVijay Khemka } 715139aa4f0SVijay Khemka 716139aa4f0SVijay Khemka errLog += ", curr_val: " + std::to_string(data[1]) + 717139aa4f0SVijay Khemka " C, thresh_val: " + std::to_string(data[2]) + " C"; 718139aa4f0SVijay Khemka } 719139aa4f0SVijay Khemka 720139aa4f0SVijay Khemka static void logNmHealth(uint8_t* data, std::string& errLog) 721139aa4f0SVijay Khemka { 722139aa4f0SVijay Khemka std::vector<std::string> nmErrType = { 723139aa4f0SVijay Khemka "Unknown", 724139aa4f0SVijay Khemka "Unknown", 725139aa4f0SVijay Khemka "Unknown", 726139aa4f0SVijay Khemka "Unknown", 727139aa4f0SVijay Khemka "Unknown", 728139aa4f0SVijay Khemka "Unknown", 729139aa4f0SVijay Khemka "Unknown", 730139aa4f0SVijay Khemka "Extended Telemetry Device Reading Failure", 731139aa4f0SVijay Khemka "Outlet Temperature Reading Failure", 732139aa4f0SVijay Khemka "Volumetric Airflow Reading Failure", 733139aa4f0SVijay Khemka "Policy Misconfiguration", 734139aa4f0SVijay Khemka "Power Sensor Reading Failure", 735139aa4f0SVijay Khemka "Inlet Temperature Reading Failure", 736139aa4f0SVijay Khemka "Host Communication Error", 737139aa4f0SVijay Khemka "Real-time Clock Synchronization Failure", 738139aa4f0SVijay Khemka "Platform Shutdown Initiated by Intel NM Policy", 739139aa4f0SVijay Khemka "Unknown"}; 740139aa4f0SVijay Khemka uint8_t nmTypeIdx = (data[0] & 0xf); 741139aa4f0SVijay Khemka uint8_t domIdx = (data[1] & 0xf); 742139aa4f0SVijay Khemka uint8_t errIdx = ((data[1] >> 4) & 0xf); 743139aa4f0SVijay Khemka 744139aa4f0SVijay Khemka if (nmTypeIdx == 2) 745139aa4f0SVijay Khemka { 746139aa4f0SVijay Khemka errLog = "SensorIntelNM"; 747139aa4f0SVijay Khemka } 748139aa4f0SVijay Khemka else 749139aa4f0SVijay Khemka { 750139aa4f0SVijay Khemka errLog = "Unknown"; 751139aa4f0SVijay Khemka } 752139aa4f0SVijay Khemka 753139aa4f0SVijay Khemka errLog += ", Domain:" + nmDomName[domIdx] + 754139aa4f0SVijay Khemka ", ErrType:" + nmErrType[errIdx] + ", Err:0x" + 755139aa4f0SVijay Khemka byteToStr(data[2]); 756139aa4f0SVijay Khemka } 757139aa4f0SVijay Khemka 758139aa4f0SVijay Khemka static void logNmCap(uint8_t* data, std::string& errLog) 759139aa4f0SVijay Khemka { 760139aa4f0SVijay Khemka 761139aa4f0SVijay Khemka const std::vector<std::string> nmCapStsStr = {"Not Available", "Available"}; 762139aa4f0SVijay Khemka if (data[0] & 0x7) // BIT1=policy, BIT2=monitoring, BIT3=pwr 763139aa4f0SVijay Khemka // limit and the others are reserved 764139aa4f0SVijay Khemka { 765139aa4f0SVijay Khemka errLog = "PolicyInterface:" + nmCapStsStr[BIT(data[0], 0)] + 766139aa4f0SVijay Khemka ",Monitoring:" + nmCapStsStr[BIT(data[0], 1)] + 767139aa4f0SVijay Khemka ",PowerLimit:" + nmCapStsStr[BIT(data[0], 2)]; 768139aa4f0SVijay Khemka } 769139aa4f0SVijay Khemka else 770139aa4f0SVijay Khemka { 771139aa4f0SVijay Khemka errLog = "Unknown"; 772139aa4f0SVijay Khemka } 773139aa4f0SVijay Khemka } 774139aa4f0SVijay Khemka 775139aa4f0SVijay Khemka static void logNmThreshold(uint8_t* data, std::string& errLog) 776139aa4f0SVijay Khemka { 777139aa4f0SVijay Khemka uint8_t thresNum = (data[0] & 0x3); 778139aa4f0SVijay Khemka uint8_t domIdx = (data[1] & 0xf); 779139aa4f0SVijay Khemka uint8_t polId = data[2]; 780139aa4f0SVijay Khemka uint8_t polEvtIdx = BIT(data[0], 3); 781139aa4f0SVijay Khemka const std::vector<std::string> polEvtStr = { 782139aa4f0SVijay Khemka "Threshold Exceeded", "Policy Correction Time Exceeded"}; 783139aa4f0SVijay Khemka 784139aa4f0SVijay Khemka errLog = "Threshold Number:" + std::to_string(thresNum) + "-" + 785139aa4f0SVijay Khemka polEvtStr[polEvtIdx] + ", Domain:" + nmDomName[domIdx] + 786139aa4f0SVijay Khemka ", PolicyID:0x" + byteToStr(polId); 787139aa4f0SVijay Khemka } 788139aa4f0SVijay Khemka 789139aa4f0SVijay Khemka static void logPwrThreshold(uint8_t* data, std::string& errLog) 790139aa4f0SVijay Khemka { 791139aa4f0SVijay Khemka if (data[0] == 0x00) 792139aa4f0SVijay Khemka { 793139aa4f0SVijay Khemka errLog = "Limit Not Exceeded"; 794139aa4f0SVijay Khemka } 795139aa4f0SVijay Khemka else if (data[0] == 0x01) 796139aa4f0SVijay Khemka { 797139aa4f0SVijay Khemka errLog = "Limit Exceeded"; 798139aa4f0SVijay Khemka } 799139aa4f0SVijay Khemka else 800139aa4f0SVijay Khemka { 801139aa4f0SVijay Khemka errLog = "Unknown"; 802139aa4f0SVijay Khemka } 803139aa4f0SVijay Khemka } 804139aa4f0SVijay Khemka 805139aa4f0SVijay Khemka static void logMSMI(uint8_t* data, std::string& errLog) 806139aa4f0SVijay Khemka { 807139aa4f0SVijay Khemka 808139aa4f0SVijay Khemka if (data[0] == 0x0) 809139aa4f0SVijay Khemka { 810139aa4f0SVijay Khemka errLog = "IERR/MSMI"; 811139aa4f0SVijay Khemka } 812139aa4f0SVijay Khemka else if (data[0] == 0x0B) 813139aa4f0SVijay Khemka { 814139aa4f0SVijay Khemka errLog = "MCERR/MSMI"; 815139aa4f0SVijay Khemka } 816139aa4f0SVijay Khemka else 817139aa4f0SVijay Khemka { 818139aa4f0SVijay Khemka errLog = "Unknown"; 819139aa4f0SVijay Khemka } 820139aa4f0SVijay Khemka } 821139aa4f0SVijay Khemka 822139aa4f0SVijay Khemka static void logHprWarn(uint8_t* data, std::string& errLog) 823139aa4f0SVijay Khemka { 824139aa4f0SVijay Khemka if (data[2] == 0x01) 825139aa4f0SVijay Khemka { 826139aa4f0SVijay Khemka if (data[1] == 0xFF) 827139aa4f0SVijay Khemka { 828139aa4f0SVijay Khemka errLog = "Infinite Time"; 829139aa4f0SVijay Khemka } 830139aa4f0SVijay Khemka else 831139aa4f0SVijay Khemka { 832139aa4f0SVijay Khemka errLog = std::to_string(data[1]) + " minutes"; 833139aa4f0SVijay Khemka } 834139aa4f0SVijay Khemka } 835139aa4f0SVijay Khemka else 836139aa4f0SVijay Khemka { 837139aa4f0SVijay Khemka errLog = "Unknown"; 838139aa4f0SVijay Khemka } 839139aa4f0SVijay Khemka } 840139aa4f0SVijay Khemka 841139aa4f0SVijay Khemka static const boost::container::flat_map< 842139aa4f0SVijay Khemka uint8_t, 843139aa4f0SVijay Khemka std::pair<std::string, std::function<void(uint8_t*, std::string&)>>> 844139aa4f0SVijay Khemka sensorNameTable = {{0xE9, {"SYSTEM_EVENT", logSysEvent}}, 845139aa4f0SVijay Khemka {0x7D, {"THERM_THRESH_EVT", logThermalEvent}}, 846139aa4f0SVijay Khemka {0xAA, {"BUTTON", logDefault}}, 847139aa4f0SVijay Khemka {0xAB, {"POWER_STATE", logDefault}}, 848139aa4f0SVijay Khemka {0xEA, {"CRITICAL_IRQ", logCritIrq}}, 849139aa4f0SVijay Khemka {0x2B, {"POST_ERROR", logPostErr}}, 850139aa4f0SVijay Khemka {0x40, {"MACHINE_CHK_ERR", logMchChkErr}}, 851139aa4f0SVijay Khemka {0x41, {"PCIE_ERR", logPcieErr}}, 852139aa4f0SVijay Khemka {0x43, {"IIO_ERR", logIioErr}}, 853139aa4f0SVijay Khemka {0X63, {"MEMORY_ECC_ERR", logDefault}}, 854139aa4f0SVijay Khemka {0X87, {"MEMORY_ERR_LOG_DIS", logDefault}}, 855139aa4f0SVijay Khemka {0X51, {"PROCHOT_EXT", logDefault}}, 856139aa4f0SVijay Khemka {0X56, {"PWR_ERR", logPwrErr}}, 857139aa4f0SVijay Khemka {0xE6, {"CATERR_A", logCatErr}}, 858139aa4f0SVijay Khemka {0xEB, {"CATERR_B", logCatErr}}, 859139aa4f0SVijay Khemka {0xB3, {"CPU_DIMM_HOT", logDimmHot}}, 860139aa4f0SVijay Khemka {0x90, {"SOFTWARE_NMI", logSwNMI}}, 861139aa4f0SVijay Khemka {0x1C, {"CPU0_THERM_STATUS", logCPUThermalSts}}, 862139aa4f0SVijay Khemka {0x1D, {"CPU1_THERM_STATUS", logCPUThermalSts}}, 863139aa4f0SVijay Khemka {0x16, {"ME_POWER_STATE", logMEPwrState}}, 864139aa4f0SVijay Khemka {0x17, {"SPS_FW_HEALTH", logSPSFwHealth}}, 865139aa4f0SVijay Khemka {0x18, {"NM_EXCEPTION_A", logNmExcA}}, 866139aa4f0SVijay Khemka {0x08, {"PCH_THERM_THRESHOLD", logPCHThermal}}, 867139aa4f0SVijay Khemka {0x19, {"NM_HEALTH", logNmHealth}}, 868139aa4f0SVijay Khemka {0x1A, {"NM_CAPABILITIES", logNmCap}}, 869139aa4f0SVijay Khemka {0x1B, {"NM_THRESHOLD", logNmThreshold}}, 870139aa4f0SVijay Khemka {0x3B, {"PWR_THRESH_EVT", logPwrThreshold}}, 871139aa4f0SVijay Khemka {0xE7, {"MSMI", logMSMI}}, 872139aa4f0SVijay Khemka {0xC5, {"HPR_WARNING", logHprWarn}}}; 873139aa4f0SVijay Khemka 874139aa4f0SVijay Khemka static void parseSelHelper(StdSELEntry* data, std::string& errStr) 875139aa4f0SVijay Khemka { 876139aa4f0SVijay Khemka 877139aa4f0SVijay Khemka /* Check if sensor type is OS_BOOT (0x1f) */ 878139aa4f0SVijay Khemka if (data->sensorType == 0x1F) 879139aa4f0SVijay Khemka { 880139aa4f0SVijay Khemka /* OS_BOOT used by OS */ 881139aa4f0SVijay Khemka switch (data->eventData1 & 0xF) 882139aa4f0SVijay Khemka { 883139aa4f0SVijay Khemka case 0x07: 884139aa4f0SVijay Khemka errStr = "Base OS/Hypervisor Installation started"; 885139aa4f0SVijay Khemka break; 886139aa4f0SVijay Khemka case 0x08: 887139aa4f0SVijay Khemka errStr = "Base OS/Hypervisor Installation completed"; 888139aa4f0SVijay Khemka break; 889139aa4f0SVijay Khemka case 0x09: 890139aa4f0SVijay Khemka errStr = "Base OS/Hypervisor Installation aborted"; 891139aa4f0SVijay Khemka break; 892139aa4f0SVijay Khemka case 0x0A: 893139aa4f0SVijay Khemka errStr = "Base OS/Hypervisor Installation failed"; 894139aa4f0SVijay Khemka break; 895139aa4f0SVijay Khemka default: 896139aa4f0SVijay Khemka errStr = "Unknown"; 897139aa4f0SVijay Khemka } 898139aa4f0SVijay Khemka return; 899139aa4f0SVijay Khemka } 900139aa4f0SVijay Khemka 901139aa4f0SVijay Khemka auto findSensorName = sensorNameTable.find(data->sensorNum); 902139aa4f0SVijay Khemka if (findSensorName == sensorNameTable.end()) 903139aa4f0SVijay Khemka { 904139aa4f0SVijay Khemka errStr = "Unknown"; 905139aa4f0SVijay Khemka return; 906139aa4f0SVijay Khemka } 907139aa4f0SVijay Khemka else 908139aa4f0SVijay Khemka { 909139aa4f0SVijay Khemka switch (data->sensorNum) 910139aa4f0SVijay Khemka { 911139aa4f0SVijay Khemka /* logMemErr function needs data from sensor type */ 912139aa4f0SVijay Khemka case memoryEccError: 913139aa4f0SVijay Khemka case memoryErrLogDIS: 914139aa4f0SVijay Khemka findSensorName->second.second(&(data->sensorType), errStr); 915139aa4f0SVijay Khemka break; 916139aa4f0SVijay Khemka /* Other sensor function needs only event data for parsing */ 917139aa4f0SVijay Khemka default: 918139aa4f0SVijay Khemka findSensorName->second.second(&(data->eventData1), errStr); 919139aa4f0SVijay Khemka } 920139aa4f0SVijay Khemka } 921139aa4f0SVijay Khemka 922139aa4f0SVijay Khemka if (((data->eventData3 & 0x80) >> 7) == 0) 923139aa4f0SVijay Khemka { 924139aa4f0SVijay Khemka errStr += " Assertion"; 925139aa4f0SVijay Khemka } 926139aa4f0SVijay Khemka else 927139aa4f0SVijay Khemka { 928139aa4f0SVijay Khemka errStr += " Deassertion"; 929139aa4f0SVijay Khemka } 930139aa4f0SVijay Khemka } 931139aa4f0SVijay Khemka 932c056dc00SManikandan Elumalai static void parseDimmPhyloc(StdSELEntry* data, std::string& errStr) 933c056dc00SManikandan Elumalai { 934c056dc00SManikandan Elumalai // Log when " All info available" 935c056dc00SManikandan Elumalai uint8_t chNum = (data->eventData3 & 0x18) >> 3; 936c056dc00SManikandan Elumalai uint8_t dimmNum = data->eventData3 & 0x7; 937c056dc00SManikandan Elumalai uint8_t rankNum = data->eventData2 & 0x03; 938c056dc00SManikandan Elumalai uint8_t nodeNum = (data->eventData3 & 0xE0) >> 5; 939c056dc00SManikandan Elumalai 940c056dc00SManikandan Elumalai if (chNum == 3 && dimmNum == 0) 941c056dc00SManikandan Elumalai { 942c056dc00SManikandan Elumalai errStr += " Node: " + std::to_string(nodeNum) + "," + 943c056dc00SManikandan Elumalai " Card: " + std::to_string(chNum) + "," + 944c056dc00SManikandan Elumalai " Module: " + std::to_string(dimmNum) + "," + 945c056dc00SManikandan Elumalai " Rank Number: " + std::to_string(rankNum) + "," + 946c056dc00SManikandan Elumalai " Location: DIMM A0"; 947c056dc00SManikandan Elumalai } 948c056dc00SManikandan Elumalai else if (chNum == 2 && dimmNum == 0) 949c056dc00SManikandan Elumalai { 950c056dc00SManikandan Elumalai errStr += " Node: " + std::to_string(nodeNum) + "," + 951c056dc00SManikandan Elumalai " Card: " + std::to_string(chNum) + "," + 952c056dc00SManikandan Elumalai " Module: " + std::to_string(dimmNum) + "," + 953c056dc00SManikandan Elumalai " Rank Number: " + std::to_string(rankNum) + "," + 954c056dc00SManikandan Elumalai " Location: DIMM B0"; 955c056dc00SManikandan Elumalai } 956c056dc00SManikandan Elumalai else if (chNum == 4 && dimmNum == 0) 957c056dc00SManikandan Elumalai { 958c056dc00SManikandan Elumalai errStr += " Node: " + std::to_string(nodeNum) + "," + 959c056dc00SManikandan Elumalai " Card: " + std::to_string(chNum) + "," + 960c056dc00SManikandan Elumalai " Module: " + std::to_string(dimmNum) + "," + 961c056dc00SManikandan Elumalai " Rank Number: " + std::to_string(rankNum) + "," + 962c056dc00SManikandan Elumalai " Location: DIMM C0 "; 963c056dc00SManikandan Elumalai } 964c056dc00SManikandan Elumalai else if (chNum == 5 && dimmNum == 0) 965c056dc00SManikandan Elumalai { 966c056dc00SManikandan Elumalai errStr += " Node: " + std::to_string(nodeNum) + "," + 967c056dc00SManikandan Elumalai " Card: " + std::to_string(chNum) + "," + 968c056dc00SManikandan Elumalai " Module: " + std::to_string(dimmNum) + "," + 969c056dc00SManikandan Elumalai " Rank Number: " + std::to_string(rankNum) + "," + 970c056dc00SManikandan Elumalai " Location: DIMM D0"; 971c056dc00SManikandan Elumalai } 972c056dc00SManikandan Elumalai else 973c056dc00SManikandan Elumalai { 974c056dc00SManikandan Elumalai errStr += " Node: " + std::to_string(nodeNum) + "," + 975c056dc00SManikandan Elumalai " Card: " + std::to_string(chNum) + "," + 976c056dc00SManikandan Elumalai " Module: " + std::to_string(dimmNum) + "," + 977c056dc00SManikandan Elumalai " Rank Number: " + std::to_string(rankNum) + "," + 978c056dc00SManikandan Elumalai " Location: DIMM Unknow"; 979c056dc00SManikandan Elumalai } 980c056dc00SManikandan Elumalai } 981c056dc00SManikandan Elumalai 982f36f345fSVijay Khemka static void parseStdSel(StdSELEntry* data, std::string& errStr) 983f36f345fSVijay Khemka { 984f36f345fSVijay Khemka std::stringstream tmpStream; 985f36f345fSVijay Khemka tmpStream << std::hex << std::uppercase; 986f36f345fSVijay Khemka 987f36f345fSVijay Khemka /* TODO: add pal_add_cri_sel */ 988f36f345fSVijay Khemka switch (data->sensorNum) 989f36f345fSVijay Khemka { 990f36f345fSVijay Khemka case memoryEccError: 991f36f345fSVijay Khemka switch (data->eventData1 & 0x0F) 992f36f345fSVijay Khemka { 993f36f345fSVijay Khemka case 0x00: 994f36f345fSVijay Khemka errStr = "Correctable"; 995f36f345fSVijay Khemka tmpStream << "DIMM" << std::setw(2) << std::setfill('0') 996f36f345fSVijay Khemka << data->eventData3 << " ECC err"; 997c056dc00SManikandan Elumalai parseDimmPhyloc(data, errStr); 998f36f345fSVijay Khemka break; 999f36f345fSVijay Khemka case 0x01: 1000f36f345fSVijay Khemka errStr = "Uncorrectable"; 1001f36f345fSVijay Khemka tmpStream << "DIMM" << std::setw(2) << std::setfill('0') 1002f36f345fSVijay Khemka << data->eventData3 << " UECC err"; 1003c056dc00SManikandan Elumalai parseDimmPhyloc(data, errStr); 1004f36f345fSVijay Khemka break; 1005f36f345fSVijay Khemka case 0x02: 1006f36f345fSVijay Khemka errStr = "Parity"; 1007f36f345fSVijay Khemka break; 1008f36f345fSVijay Khemka case 0x05: 1009f36f345fSVijay Khemka errStr = "Correctable ECC error Logging Limit Reached"; 1010f36f345fSVijay Khemka break; 1011f36f345fSVijay Khemka default: 1012f36f345fSVijay Khemka errStr = "Unknown"; 1013f36f345fSVijay Khemka } 1014f36f345fSVijay Khemka break; 1015f36f345fSVijay Khemka case memoryErrLogDIS: 1016f36f345fSVijay Khemka if ((data->eventData1 & 0x0F) == 0) 1017f36f345fSVijay Khemka { 1018f36f345fSVijay Khemka errStr = "Correctable Memory Error Logging Disabled"; 1019f36f345fSVijay Khemka } 1020f36f345fSVijay Khemka else 1021f36f345fSVijay Khemka { 1022f36f345fSVijay Khemka errStr = "Unknown"; 1023f36f345fSVijay Khemka } 1024f36f345fSVijay Khemka break; 1025f36f345fSVijay Khemka default: 1026139aa4f0SVijay Khemka parseSelHelper(data, errStr); 1027f36f345fSVijay Khemka return; 1028f36f345fSVijay Khemka } 1029f36f345fSVijay Khemka 1030f36f345fSVijay Khemka errStr += " (DIMM " + std::to_string(data->eventData3) + ")"; 1031f36f345fSVijay Khemka errStr += " Logical Rank " + std::to_string(data->eventData2 & 0x03); 1032f36f345fSVijay Khemka 1033f36f345fSVijay Khemka switch ((data->eventData2 & 0x0C) >> 2) 1034f36f345fSVijay Khemka { 1035f36f345fSVijay Khemka case 0x00: 1036f36f345fSVijay Khemka // Ignore when " All info available" 1037f36f345fSVijay Khemka break; 1038f36f345fSVijay Khemka case 0x01: 1039f36f345fSVijay Khemka errStr += " DIMM info not valid"; 1040f36f345fSVijay Khemka break; 1041f36f345fSVijay Khemka case 0x02: 1042f36f345fSVijay Khemka errStr += " CHN info not valid"; 1043f36f345fSVijay Khemka break; 1044f36f345fSVijay Khemka case 0x03: 1045f36f345fSVijay Khemka errStr += " CPU info not valid"; 1046f36f345fSVijay Khemka break; 1047f36f345fSVijay Khemka default: 1048f36f345fSVijay Khemka errStr += " Unknown"; 1049f36f345fSVijay Khemka } 1050f36f345fSVijay Khemka 1051f36f345fSVijay Khemka if (((data->eventType & 0x80) >> 7) == 0) 1052f36f345fSVijay Khemka { 1053f36f345fSVijay Khemka errStr += " Assertion"; 1054f36f345fSVijay Khemka } 1055f36f345fSVijay Khemka else 1056f36f345fSVijay Khemka { 1057f36f345fSVijay Khemka errStr += " Deassertion"; 1058f36f345fSVijay Khemka } 1059f36f345fSVijay Khemka 1060f36f345fSVijay Khemka return; 1061f36f345fSVijay Khemka } 1062f36f345fSVijay Khemka 1063f36f345fSVijay Khemka static void parseOemSel(TsOemSELEntry* data, std::string& errStr) 1064f36f345fSVijay Khemka { 1065f36f345fSVijay Khemka std::stringstream tmpStream; 1066f36f345fSVijay Khemka tmpStream << std::hex << std::uppercase << std::setfill('0'); 1067f36f345fSVijay Khemka 1068f36f345fSVijay Khemka switch (data->recordType) 1069f36f345fSVijay Khemka { 1070f36f345fSVijay Khemka case 0xC0: 1071f36f345fSVijay Khemka tmpStream << "VID:0x" << std::setw(2) << (int)data->oemData[1] 1072f36f345fSVijay Khemka << std::setw(2) << (int)data->oemData[0] << " DID:0x" 1073f36f345fSVijay Khemka << std::setw(2) << (int)data->oemData[3] << std::setw(2) 1074f36f345fSVijay Khemka << (int)data->oemData[2] << " Slot:0x" << std::setw(2) 1075f36f345fSVijay Khemka << (int)data->oemData[4] << " Error ID:0x" << std::setw(2) 1076f36f345fSVijay Khemka << (int)data->oemData[5]; 1077f36f345fSVijay Khemka break; 1078f36f345fSVijay Khemka case 0xC2: 1079f36f345fSVijay Khemka tmpStream << "Extra info:0x" << std::setw(2) 1080f36f345fSVijay Khemka << (int)data->oemData[1] << " MSCOD:0x" << std::setw(2) 1081f36f345fSVijay Khemka << (int)data->oemData[3] << std::setw(2) 1082f36f345fSVijay Khemka << (int)data->oemData[2] << " MCACOD:0x" << std::setw(2) 1083f36f345fSVijay Khemka << (int)data->oemData[5] << std::setw(2) 1084f36f345fSVijay Khemka << (int)data->oemData[4]; 1085f36f345fSVijay Khemka break; 1086f36f345fSVijay Khemka case 0xC3: 1087f36f345fSVijay Khemka int bank = (data->oemData[1] & 0xf0) >> 4; 1088f36f345fSVijay Khemka int col = ((data->oemData[1] & 0x0f) << 8) | data->oemData[2]; 1089f36f345fSVijay Khemka 1090f36f345fSVijay Khemka tmpStream << "Fail Device:0x" << std::setw(2) 1091f36f345fSVijay Khemka << (int)data->oemData[0] << " Bank:0x" << std::setw(2) 1092f36f345fSVijay Khemka << bank << " Column:0x" << std::setw(2) << col 1093f36f345fSVijay Khemka << " Failed Row:0x" << std::setw(2) 1094f36f345fSVijay Khemka << (int)data->oemData[3] << std::setw(2) 1095f36f345fSVijay Khemka << (int)data->oemData[4] << std::setw(2) 1096f36f345fSVijay Khemka << (int)data->oemData[5]; 1097f36f345fSVijay Khemka } 1098f36f345fSVijay Khemka 1099f36f345fSVijay Khemka errStr = tmpStream.str(); 1100f36f345fSVijay Khemka 1101f36f345fSVijay Khemka return; 1102f36f345fSVijay Khemka } 1103f36f345fSVijay Khemka 110434a875f3SVijay Khemka static void parseOemUnifiedSel(NtsOemSELEntry* data, std::string& errStr) 110534a875f3SVijay Khemka { 110634a875f3SVijay Khemka uint8_t* ptr = data->oemData; 110734a875f3SVijay Khemka int genInfo = ptr[0]; 110834a875f3SVijay Khemka int errType = genInfo & 0x0f; 110934a875f3SVijay Khemka std::vector<std::string> dimmEvent = { 111034a875f3SVijay Khemka "Memory training failure", "Memory correctable error", 111134a875f3SVijay Khemka "Memory uncorrectable error", "Reserved"}; 111234a875f3SVijay Khemka 111334a875f3SVijay Khemka std::stringstream tmpStream; 111434a875f3SVijay Khemka tmpStream << std::hex << std::uppercase << std::setfill('0'); 111534a875f3SVijay Khemka 111634a875f3SVijay Khemka switch (errType) 111734a875f3SVijay Khemka { 111834a875f3SVijay Khemka case unifiedPcieErr: 111934a875f3SVijay Khemka if (((genInfo & 0x10) >> 4) == 0) // x86 112034a875f3SVijay Khemka { 112134a875f3SVijay Khemka tmpStream << "GeneralInfo: x86/PCIeErr(0x" << std::setw(2) 112234a875f3SVijay Khemka << genInfo << "),"; 112334a875f3SVijay Khemka } 112434a875f3SVijay Khemka 112534a875f3SVijay Khemka tmpStream << " Bus " << std::setw(2) << (int)(ptr[8]) << "/Dev " 112634a875f3SVijay Khemka << std::setw(2) << (int)(ptr[7] >> 3) << "/Fun " 112734a875f3SVijay Khemka << std::setw(2) << (int)(ptr[7] & 0x7) 112834a875f3SVijay Khemka << ", TotalErrID1Cnt: 0x" << std::setw(4) 112934a875f3SVijay Khemka << (int)((ptr[10] << 8) | ptr[9]) << ", ErrID2: 0x" 113034a875f3SVijay Khemka << std::setw(2) << (int)(ptr[11]) << ", ErrID1: 0x" 113134a875f3SVijay Khemka << std::setw(2) << (int)(ptr[12]); 113234a875f3SVijay Khemka 113334a875f3SVijay Khemka break; 113434a875f3SVijay Khemka case unifiedMemErr: 113534a875f3SVijay Khemka tmpStream << "GeneralInfo: MemErr(0x" << std::setw(2) << genInfo 113634a875f3SVijay Khemka << "), DIMM Slot Location: Sled " << std::setw(2) 113734a875f3SVijay Khemka << (int)((ptr[5] >> 4) & 0x03) << "/Socket " 113834a875f3SVijay Khemka << std::setw(2) << (int)(ptr[5] & 0x0f) << ", Channel " 113934a875f3SVijay Khemka << std::setw(2) << (int)(ptr[6] & 0x0f) << ", Slot " 114034a875f3SVijay Khemka << std::setw(2) << (int)(ptr[7] & 0x0f) 114134a875f3SVijay Khemka << ", DIMM Failure Event: " << dimmEvent[(ptr[9] & 0x03)] 114234a875f3SVijay Khemka << ", Major Code: 0x" << std::setw(2) << (int)(ptr[10]) 114334a875f3SVijay Khemka << ", Minor Code: 0x" << std::setw(2) << (int)(ptr[11]); 114434a875f3SVijay Khemka 114534a875f3SVijay Khemka break; 114634a875f3SVijay Khemka default: 114734a875f3SVijay Khemka std::vector<uint8_t> oemData(ptr, ptr + 13); 114834a875f3SVijay Khemka std::string oemDataStr; 114934a875f3SVijay Khemka toHexStr(oemData, oemDataStr); 115034a875f3SVijay Khemka tmpStream << "Undefined Error Type(0x" << std::setw(2) << errType 115134a875f3SVijay Khemka << "), Raw: " << oemDataStr; 115234a875f3SVijay Khemka } 115334a875f3SVijay Khemka 115434a875f3SVijay Khemka errStr = tmpStream.str(); 115534a875f3SVijay Khemka 115634a875f3SVijay Khemka return; 115734a875f3SVijay Khemka } 115834a875f3SVijay Khemka 1159c056dc00SManikandan Elumalai static void parseSelData(uint8_t fruId, std::vector<uint8_t>& reqData, 1160c056dc00SManikandan Elumalai std::string& msgLog) 1161f36f345fSVijay Khemka { 1162f36f345fSVijay Khemka 1163f36f345fSVijay Khemka /* Get record type */ 1164f36f345fSVijay Khemka int recType = reqData[2]; 1165f36f345fSVijay Khemka std::string errType, errLog; 1166f36f345fSVijay Khemka 1167f36f345fSVijay Khemka uint8_t* ptr = NULL; 1168f36f345fSVijay Khemka 1169f36f345fSVijay Khemka std::stringstream recTypeStream; 1170f36f345fSVijay Khemka recTypeStream << std::hex << std::uppercase << std::setfill('0') 1171f36f345fSVijay Khemka << std::setw(2) << recType; 1172f36f345fSVijay Khemka 1173c056dc00SManikandan Elumalai msgLog = "SEL Entry: FRU: " + std::to_string(fruId) + ", Record: "; 1174f36f345fSVijay Khemka 1175f36f345fSVijay Khemka if (recType == stdErrType) 1176f36f345fSVijay Khemka { 1177f36f345fSVijay Khemka StdSELEntry* data = reinterpret_cast<StdSELEntry*>(&reqData[0]); 1178f36f345fSVijay Khemka std::string sensorName; 1179f36f345fSVijay Khemka 1180f36f345fSVijay Khemka errType = stdErr; 1181f36f345fSVijay Khemka if (data->sensorType == 0x1F) 1182f36f345fSVijay Khemka { 1183f36f345fSVijay Khemka sensorName = "OS"; 1184f36f345fSVijay Khemka } 1185f36f345fSVijay Khemka else 1186f36f345fSVijay Khemka { 1187f36f345fSVijay Khemka auto findSensorName = sensorNameTable.find(data->sensorNum); 1188f36f345fSVijay Khemka if (findSensorName == sensorNameTable.end()) 1189f36f345fSVijay Khemka { 1190f36f345fSVijay Khemka sensorName = "Unknown"; 1191f36f345fSVijay Khemka } 1192f36f345fSVijay Khemka else 1193f36f345fSVijay Khemka { 1194139aa4f0SVijay Khemka sensorName = findSensorName->second.first; 1195f36f345fSVijay Khemka } 1196f36f345fSVijay Khemka } 1197f36f345fSVijay Khemka 1198e39f9393SWilly Tu uint32_t timeStamp = data->timeStamp; 1199e39f9393SWilly Tu std::tm* ts = localtime(reinterpret_cast<time_t*>(&timeStamp)); 1200f36f345fSVijay Khemka std::string timeStr = std::asctime(ts); 1201f36f345fSVijay Khemka 1202f36f345fSVijay Khemka parseStdSel(data, errLog); 1203f36f345fSVijay Khemka ptr = &(data->eventData1); 1204f36f345fSVijay Khemka std::vector<uint8_t> evtData(ptr, ptr + 3); 1205f36f345fSVijay Khemka std::string eventData; 1206f36f345fSVijay Khemka toHexStr(evtData, eventData); 1207f36f345fSVijay Khemka 1208f36f345fSVijay Khemka std::stringstream senNumStream; 1209f36f345fSVijay Khemka senNumStream << std::hex << std::uppercase << std::setfill('0') 1210f36f345fSVijay Khemka << std::setw(2) << (int)(data->sensorNum); 1211f36f345fSVijay Khemka 1212f36f345fSVijay Khemka msgLog += errType + " (0x" + recTypeStream.str() + 1213f36f345fSVijay Khemka "), Time: " + timeStr + ", Sensor: " + sensorName + " (0x" + 1214f36f345fSVijay Khemka senNumStream.str() + "), Event Data: (" + eventData + ") " + 1215f36f345fSVijay Khemka errLog; 1216f36f345fSVijay Khemka } 1217f36f345fSVijay Khemka else if ((recType >= oemTSErrTypeMin) && (recType <= oemTSErrTypeMax)) 1218f36f345fSVijay Khemka { 1219f36f345fSVijay Khemka /* timestamped OEM SEL records */ 1220f36f345fSVijay Khemka TsOemSELEntry* data = reinterpret_cast<TsOemSELEntry*>(&reqData[0]); 1221f36f345fSVijay Khemka ptr = data->mfrId; 1222f36f345fSVijay Khemka std::vector<uint8_t> mfrIdData(ptr, ptr + 3); 1223f36f345fSVijay Khemka std::string mfrIdStr; 1224f36f345fSVijay Khemka toHexStr(mfrIdData, mfrIdStr); 1225f36f345fSVijay Khemka 1226f36f345fSVijay Khemka ptr = data->oemData; 1227f36f345fSVijay Khemka std::vector<uint8_t> oemData(ptr, ptr + 6); 1228f36f345fSVijay Khemka std::string oemDataStr; 1229f36f345fSVijay Khemka toHexStr(oemData, oemDataStr); 1230f36f345fSVijay Khemka 1231e39f9393SWilly Tu uint32_t timeStamp = data->timeStamp; 1232e39f9393SWilly Tu std::tm* ts = localtime(reinterpret_cast<time_t*>(&timeStamp)); 1233f36f345fSVijay Khemka std::string timeStr = std::asctime(ts); 1234f36f345fSVijay Khemka 1235f36f345fSVijay Khemka errType = oemTSErr; 1236f36f345fSVijay Khemka parseOemSel(data, errLog); 1237f36f345fSVijay Khemka 1238f36f345fSVijay Khemka msgLog += errType + " (0x" + recTypeStream.str() + 1239f36f345fSVijay Khemka "), Time: " + timeStr + ", MFG ID: " + mfrIdStr + 1240f36f345fSVijay Khemka ", OEM Data: (" + oemDataStr + ") " + errLog; 1241f36f345fSVijay Khemka } 124234a875f3SVijay Khemka else if (recType == fbUniErrType) 124334a875f3SVijay Khemka { 124434a875f3SVijay Khemka NtsOemSELEntry* data = reinterpret_cast<NtsOemSELEntry*>(&reqData[0]); 124534a875f3SVijay Khemka errType = fbUniSELErr; 124634a875f3SVijay Khemka parseOemUnifiedSel(data, errLog); 124734a875f3SVijay Khemka msgLog += errType + " (0x" + recTypeStream.str() + "), " + errLog; 124834a875f3SVijay Khemka } 1249f36f345fSVijay Khemka else if ((recType >= oemNTSErrTypeMin) && (recType <= oemNTSErrTypeMax)) 1250f36f345fSVijay Khemka { 1251f36f345fSVijay Khemka /* Non timestamped OEM SEL records */ 1252f36f345fSVijay Khemka NtsOemSELEntry* data = reinterpret_cast<NtsOemSELEntry*>(&reqData[0]); 1253f36f345fSVijay Khemka errType = oemNTSErr; 1254f36f345fSVijay Khemka 1255f36f345fSVijay Khemka ptr = data->oemData; 1256f36f345fSVijay Khemka std::vector<uint8_t> oemData(ptr, ptr + 13); 1257f36f345fSVijay Khemka std::string oemDataStr; 1258f36f345fSVijay Khemka toHexStr(oemData, oemDataStr); 1259f36f345fSVijay Khemka 1260f36f345fSVijay Khemka parseOemSel((TsOemSELEntry*)data, errLog); 1261f36f345fSVijay Khemka msgLog += errType + " (0x" + recTypeStream.str() + "), OEM Data: (" + 1262f36f345fSVijay Khemka oemDataStr + ") " + errLog; 1263f36f345fSVijay Khemka } 1264f36f345fSVijay Khemka else 1265f36f345fSVijay Khemka { 1266f36f345fSVijay Khemka errType = unknownErr; 1267f36f345fSVijay Khemka toHexStr(reqData, errLog); 1268f36f345fSVijay Khemka msgLog += 1269f36f345fSVijay Khemka errType + " (0x" + recTypeStream.str() + ") RawData: " + errLog; 1270f36f345fSVijay Khemka } 1271f36f345fSVijay Khemka } 1272f36f345fSVijay Khemka 127311b9c3b1SVijay Khemka } // namespace fb_oem::ipmi::sel 127411b9c3b1SVijay Khemka 127511b9c3b1SVijay Khemka namespace ipmi 127611b9c3b1SVijay Khemka { 127711b9c3b1SVijay Khemka 127811b9c3b1SVijay Khemka namespace storage 127911b9c3b1SVijay Khemka { 128011b9c3b1SVijay Khemka 128111b9c3b1SVijay Khemka static void registerSELFunctions() __attribute__((constructor)); 128211b9c3b1SVijay Khemka static fb_oem::ipmi::sel::SELData selObj __attribute__((init_priority(101))); 128311b9c3b1SVijay Khemka 128411b9c3b1SVijay Khemka ipmi::RspType<uint8_t, // SEL version 128511b9c3b1SVijay Khemka uint16_t, // SEL entry count 128611b9c3b1SVijay Khemka uint16_t, // free space 128711b9c3b1SVijay Khemka uint32_t, // last add timestamp 128811b9c3b1SVijay Khemka uint32_t, // last erase timestamp 128911b9c3b1SVijay Khemka uint8_t> // operation support 129011b9c3b1SVijay Khemka ipmiStorageGetSELInfo() 129111b9c3b1SVijay Khemka { 129211b9c3b1SVijay Khemka 129311b9c3b1SVijay Khemka fb_oem::ipmi::sel::GetSELInfoData info; 129411b9c3b1SVijay Khemka 129511b9c3b1SVijay Khemka selObj.getInfo(info); 129611b9c3b1SVijay Khemka return ipmi::responseSuccess(info.selVersion, info.entries, info.freeSpace, 129711b9c3b1SVijay Khemka info.addTimeStamp, info.eraseTimeStamp, 129811b9c3b1SVijay Khemka info.operationSupport); 129911b9c3b1SVijay Khemka } 130011b9c3b1SVijay Khemka 130111b9c3b1SVijay Khemka ipmi::RspType<uint16_t, std::vector<uint8_t>> 130211b9c3b1SVijay Khemka ipmiStorageGetSELEntry(std::vector<uint8_t> data) 130311b9c3b1SVijay Khemka { 130411b9c3b1SVijay Khemka 130511b9c3b1SVijay Khemka if (data.size() != sizeof(fb_oem::ipmi::sel::GetSELEntryRequest)) 130611b9c3b1SVijay Khemka { 130711b9c3b1SVijay Khemka return ipmi::responseReqDataLenInvalid(); 130811b9c3b1SVijay Khemka } 130911b9c3b1SVijay Khemka 131011b9c3b1SVijay Khemka fb_oem::ipmi::sel::GetSELEntryRequest* reqData = 131111b9c3b1SVijay Khemka reinterpret_cast<fb_oem::ipmi::sel::GetSELEntryRequest*>(&data[0]); 131211b9c3b1SVijay Khemka 131311b9c3b1SVijay Khemka if (reqData->reservID != 0) 131411b9c3b1SVijay Khemka { 131511b9c3b1SVijay Khemka if (!checkSELReservation(reqData->reservID)) 131611b9c3b1SVijay Khemka { 131711b9c3b1SVijay Khemka return ipmi::responseInvalidReservationId(); 131811b9c3b1SVijay Khemka } 131911b9c3b1SVijay Khemka } 132011b9c3b1SVijay Khemka 132111b9c3b1SVijay Khemka uint16_t selCnt = selObj.getCount(); 132211b9c3b1SVijay Khemka if (selCnt == 0) 132311b9c3b1SVijay Khemka { 132411b9c3b1SVijay Khemka return ipmi::responseSensorInvalid(); 132511b9c3b1SVijay Khemka } 132611b9c3b1SVijay Khemka 132711b9c3b1SVijay Khemka /* If it is asked for first entry */ 132811b9c3b1SVijay Khemka if (reqData->recordID == fb_oem::ipmi::sel::firstEntry) 132911b9c3b1SVijay Khemka { 133011b9c3b1SVijay Khemka /* First Entry (0x0000) as per Spec */ 133111b9c3b1SVijay Khemka reqData->recordID = 1; 133211b9c3b1SVijay Khemka } 133311b9c3b1SVijay Khemka else if (reqData->recordID == fb_oem::ipmi::sel::lastEntry) 133411b9c3b1SVijay Khemka { 133511b9c3b1SVijay Khemka /* Last entry (0xFFFF) as per Spec */ 133611b9c3b1SVijay Khemka reqData->recordID = selCnt; 133711b9c3b1SVijay Khemka } 133811b9c3b1SVijay Khemka 133911b9c3b1SVijay Khemka std::string ipmiRaw; 134011b9c3b1SVijay Khemka 134111b9c3b1SVijay Khemka if (selObj.getEntry(reqData->recordID, ipmiRaw) < 0) 134211b9c3b1SVijay Khemka { 134311b9c3b1SVijay Khemka return ipmi::responseSensorInvalid(); 134411b9c3b1SVijay Khemka } 134511b9c3b1SVijay Khemka 134611b9c3b1SVijay Khemka std::vector<uint8_t> recDataBytes; 134711b9c3b1SVijay Khemka if (fromHexStr(ipmiRaw, recDataBytes) < 0) 134811b9c3b1SVijay Khemka { 134911b9c3b1SVijay Khemka return ipmi::responseUnspecifiedError(); 135011b9c3b1SVijay Khemka } 135111b9c3b1SVijay Khemka 135211b9c3b1SVijay Khemka /* Identify the next SEL record ID. If recordID is same as 135311b9c3b1SVijay Khemka * total SeL count then next id should be last entry else 135411b9c3b1SVijay Khemka * it should be incremented by 1 to current RecordID 135511b9c3b1SVijay Khemka */ 135611b9c3b1SVijay Khemka uint16_t nextRecord; 135711b9c3b1SVijay Khemka if (reqData->recordID == selCnt) 135811b9c3b1SVijay Khemka { 135911b9c3b1SVijay Khemka nextRecord = fb_oem::ipmi::sel::lastEntry; 136011b9c3b1SVijay Khemka } 136111b9c3b1SVijay Khemka else 136211b9c3b1SVijay Khemka { 136311b9c3b1SVijay Khemka nextRecord = reqData->recordID + 1; 136411b9c3b1SVijay Khemka } 136511b9c3b1SVijay Khemka 136611b9c3b1SVijay Khemka if (reqData->readLen == fb_oem::ipmi::sel::entireRecord) 136711b9c3b1SVijay Khemka { 136811b9c3b1SVijay Khemka return ipmi::responseSuccess(nextRecord, recDataBytes); 136911b9c3b1SVijay Khemka } 137011b9c3b1SVijay Khemka else 137111b9c3b1SVijay Khemka { 137211b9c3b1SVijay Khemka if (reqData->offset >= fb_oem::ipmi::sel::selRecordSize || 137311b9c3b1SVijay Khemka reqData->readLen > fb_oem::ipmi::sel::selRecordSize) 137411b9c3b1SVijay Khemka { 137511b9c3b1SVijay Khemka return ipmi::responseUnspecifiedError(); 137611b9c3b1SVijay Khemka } 137711b9c3b1SVijay Khemka std::vector<uint8_t> recPartData; 137811b9c3b1SVijay Khemka 137911b9c3b1SVijay Khemka auto diff = fb_oem::ipmi::sel::selRecordSize - reqData->offset; 138011b9c3b1SVijay Khemka auto readLength = std::min(diff, static_cast<int>(reqData->readLen)); 138111b9c3b1SVijay Khemka 138211b9c3b1SVijay Khemka for (int i = 0; i < readLength; i++) 138311b9c3b1SVijay Khemka { 138411b9c3b1SVijay Khemka recPartData.push_back(recDataBytes[i + reqData->offset]); 138511b9c3b1SVijay Khemka } 138611b9c3b1SVijay Khemka return ipmi::responseSuccess(nextRecord, recPartData); 138711b9c3b1SVijay Khemka } 138811b9c3b1SVijay Khemka } 138911b9c3b1SVijay Khemka 1390c056dc00SManikandan Elumalai ipmi::RspType<uint16_t> ipmiStorageAddSELEntry(ipmi::Context::ptr ctx, 1391c056dc00SManikandan Elumalai std::vector<uint8_t> data) 139211b9c3b1SVijay Khemka { 139311b9c3b1SVijay Khemka /* Per the IPMI spec, need to cancel any reservation when a 139411b9c3b1SVijay Khemka * SEL entry is added 139511b9c3b1SVijay Khemka */ 139611b9c3b1SVijay Khemka cancelSELReservation(); 139711b9c3b1SVijay Khemka 139811b9c3b1SVijay Khemka if (data.size() != fb_oem::ipmi::sel::selRecordSize) 139911b9c3b1SVijay Khemka { 140011b9c3b1SVijay Khemka return ipmi::responseReqDataLenInvalid(); 140111b9c3b1SVijay Khemka } 140211b9c3b1SVijay Khemka 140311b9c3b1SVijay Khemka std::string ipmiRaw, logErr; 140411b9c3b1SVijay Khemka toHexStr(data, ipmiRaw); 140511b9c3b1SVijay Khemka 1406f36f345fSVijay Khemka /* Parse sel data and get an error log to be filed */ 1407c056dc00SManikandan Elumalai fb_oem::ipmi::sel::parseSelData((ctx->hostIdx + 1), data, logErr); 1408f36f345fSVijay Khemka 140915a7ae81SVijay Khemka static const std::string openBMCMessageRegistryVersion("0.1"); 141015a7ae81SVijay Khemka std::string messageID = 141115a7ae81SVijay Khemka "OpenBMC." + openBMCMessageRegistryVersion + ".SELEntryAdded"; 141215a7ae81SVijay Khemka 141311b9c3b1SVijay Khemka /* Log the Raw SEL message to the journal */ 141411b9c3b1SVijay Khemka std::string journalMsg = "SEL Entry Added: " + ipmiRaw; 1415f36f345fSVijay Khemka 141615a7ae81SVijay Khemka phosphor::logging::log<phosphor::logging::level::INFO>( 141715a7ae81SVijay Khemka journalMsg.c_str(), 141815a7ae81SVijay Khemka phosphor::logging::entry("IPMISEL_MESSAGE_ID=%s", messageID.c_str()), 141915a7ae81SVijay Khemka phosphor::logging::entry("IPMISEL_MESSAGE_ARGS=%s", logErr.c_str())); 142011b9c3b1SVijay Khemka 142111b9c3b1SVijay Khemka int responseID = selObj.addEntry(ipmiRaw.c_str()); 142211b9c3b1SVijay Khemka if (responseID < 0) 142311b9c3b1SVijay Khemka { 142411b9c3b1SVijay Khemka return ipmi::responseUnspecifiedError(); 142511b9c3b1SVijay Khemka } 142611b9c3b1SVijay Khemka return ipmi::responseSuccess((uint16_t)responseID); 142711b9c3b1SVijay Khemka } 142811b9c3b1SVijay Khemka 1429c1921c63SVijay Khemka ipmi::RspType<uint8_t> ipmiStorageClearSEL(uint16_t reservationID, 1430c1921c63SVijay Khemka const std::array<uint8_t, 3>& clr, 1431c1921c63SVijay Khemka uint8_t eraseOperation) 1432c1921c63SVijay Khemka { 1433c1921c63SVijay Khemka if (!checkSELReservation(reservationID)) 1434c1921c63SVijay Khemka { 1435c1921c63SVijay Khemka return ipmi::responseInvalidReservationId(); 1436c1921c63SVijay Khemka } 1437c1921c63SVijay Khemka 1438c1921c63SVijay Khemka static constexpr std::array<uint8_t, 3> clrExpected = {'C', 'L', 'R'}; 1439c1921c63SVijay Khemka if (clr != clrExpected) 1440c1921c63SVijay Khemka { 1441c1921c63SVijay Khemka return ipmi::responseInvalidFieldRequest(); 1442c1921c63SVijay Khemka } 1443c1921c63SVijay Khemka 1444c1921c63SVijay Khemka /* If there is no sel then return erase complete */ 1445c1921c63SVijay Khemka if (selObj.getCount() == 0) 1446c1921c63SVijay Khemka { 1447c1921c63SVijay Khemka return ipmi::responseSuccess(fb_oem::ipmi::sel::eraseComplete); 1448c1921c63SVijay Khemka } 1449c1921c63SVijay Khemka 1450c1921c63SVijay Khemka /* Erasure status cannot be fetched, so always return erasure 1451c1921c63SVijay Khemka * status as `erase completed`. 1452c1921c63SVijay Khemka */ 1453c1921c63SVijay Khemka if (eraseOperation == fb_oem::ipmi::sel::getEraseStatus) 1454c1921c63SVijay Khemka { 1455c1921c63SVijay Khemka return ipmi::responseSuccess(fb_oem::ipmi::sel::eraseComplete); 1456c1921c63SVijay Khemka } 1457c1921c63SVijay Khemka 1458c1921c63SVijay Khemka /* Check that initiate erase is correct */ 1459c1921c63SVijay Khemka if (eraseOperation != fb_oem::ipmi::sel::initiateErase) 1460c1921c63SVijay Khemka { 1461c1921c63SVijay Khemka return ipmi::responseInvalidFieldRequest(); 1462c1921c63SVijay Khemka } 1463c1921c63SVijay Khemka 1464c1921c63SVijay Khemka /* Per the IPMI spec, need to cancel any reservation when the 1465c1921c63SVijay Khemka * SEL is cleared 1466c1921c63SVijay Khemka */ 1467c1921c63SVijay Khemka cancelSELReservation(); 1468c1921c63SVijay Khemka 1469c1921c63SVijay Khemka /* Clear the complete Sel Json object */ 1470c1921c63SVijay Khemka if (selObj.clear() < 0) 1471c1921c63SVijay Khemka { 1472c1921c63SVijay Khemka return ipmi::responseUnspecifiedError(); 1473c1921c63SVijay Khemka } 1474c1921c63SVijay Khemka 1475c1921c63SVijay Khemka return ipmi::responseSuccess(fb_oem::ipmi::sel::eraseComplete); 1476c1921c63SVijay Khemka } 1477c1921c63SVijay Khemka 1478c1921c63SVijay Khemka ipmi::RspType<uint32_t> ipmiStorageGetSELTime() 1479c1921c63SVijay Khemka { 1480c1921c63SVijay Khemka struct timespec selTime = {}; 1481c1921c63SVijay Khemka 1482c1921c63SVijay Khemka if (clock_gettime(CLOCK_REALTIME, &selTime) < 0) 1483c1921c63SVijay Khemka { 1484c1921c63SVijay Khemka return ipmi::responseUnspecifiedError(); 1485c1921c63SVijay Khemka } 1486c1921c63SVijay Khemka 1487c1921c63SVijay Khemka return ipmi::responseSuccess(selTime.tv_sec); 1488c1921c63SVijay Khemka } 1489c1921c63SVijay Khemka 1490e39f9393SWilly Tu ipmi::RspType<> ipmiStorageSetSELTime(uint32_t) 1491c1921c63SVijay Khemka { 1492c1921c63SVijay Khemka // Set SEL Time is not supported 1493c1921c63SVijay Khemka return ipmi::responseInvalidCommand(); 1494c1921c63SVijay Khemka } 1495c1921c63SVijay Khemka 1496c1921c63SVijay Khemka ipmi::RspType<uint16_t> ipmiStorageGetSELTimeUtcOffset() 1497c1921c63SVijay Khemka { 1498c1921c63SVijay Khemka /* TODO: For now, the SEL time stamp is based on UTC time, 1499c1921c63SVijay Khemka * so return 0x0000 as offset. Might need to change once 1500c1921c63SVijay Khemka * supporting zones in SEL time stamps 1501c1921c63SVijay Khemka */ 1502c1921c63SVijay Khemka 1503c1921c63SVijay Khemka uint16_t utcOffset = 0x0000; 1504c1921c63SVijay Khemka return ipmi::responseSuccess(utcOffset); 1505c1921c63SVijay Khemka } 1506c1921c63SVijay Khemka 150711b9c3b1SVijay Khemka void registerSELFunctions() 150811b9c3b1SVijay Khemka { 150911b9c3b1SVijay Khemka // <Get SEL Info> 151011b9c3b1SVijay Khemka ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage, 151111b9c3b1SVijay Khemka ipmi::storage::cmdGetSelInfo, ipmi::Privilege::User, 151211b9c3b1SVijay Khemka ipmiStorageGetSELInfo); 151311b9c3b1SVijay Khemka 151411b9c3b1SVijay Khemka // <Get SEL Entry> 151511b9c3b1SVijay Khemka ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage, 151611b9c3b1SVijay Khemka ipmi::storage::cmdGetSelEntry, ipmi::Privilege::User, 151711b9c3b1SVijay Khemka ipmiStorageGetSELEntry); 151811b9c3b1SVijay Khemka 151911b9c3b1SVijay Khemka // <Add SEL Entry> 152011b9c3b1SVijay Khemka ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage, 152111b9c3b1SVijay Khemka ipmi::storage::cmdAddSelEntry, 152211b9c3b1SVijay Khemka ipmi::Privilege::Operator, ipmiStorageAddSELEntry); 152311b9c3b1SVijay Khemka 1524c1921c63SVijay Khemka // <Clear SEL> 1525c1921c63SVijay Khemka ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage, 1526c1921c63SVijay Khemka ipmi::storage::cmdClearSel, ipmi::Privilege::Operator, 1527c1921c63SVijay Khemka ipmiStorageClearSEL); 1528c1921c63SVijay Khemka 1529c1921c63SVijay Khemka // <Get SEL Time> 1530c1921c63SVijay Khemka ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage, 1531c1921c63SVijay Khemka ipmi::storage::cmdGetSelTime, ipmi::Privilege::User, 1532c1921c63SVijay Khemka ipmiStorageGetSELTime); 1533c1921c63SVijay Khemka 1534c1921c63SVijay Khemka // <Set SEL Time> 1535c1921c63SVijay Khemka ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage, 1536c1921c63SVijay Khemka ipmi::storage::cmdSetSelTime, 1537c1921c63SVijay Khemka ipmi::Privilege::Operator, ipmiStorageSetSELTime); 1538c1921c63SVijay Khemka 1539c1921c63SVijay Khemka // <Get SEL Time UTC Offset> 1540c1921c63SVijay Khemka ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage, 1541c1921c63SVijay Khemka ipmi::storage::cmdGetSelTimeUtcOffset, 1542c1921c63SVijay Khemka ipmi::Privilege::User, 1543c1921c63SVijay Khemka ipmiStorageGetSELTimeUtcOffset); 1544c1921c63SVijay Khemka 154511b9c3b1SVijay Khemka return; 154611b9c3b1SVijay Khemka } 154711b9c3b1SVijay Khemka 154811b9c3b1SVijay Khemka } // namespace storage 154911b9c3b1SVijay Khemka } // namespace ipmi 1550