xref: /openbmc/fb-ipmi-oem/src/selcommands.cpp (revision 7f97f7557cc90413de9e1fa097391071136fb7dd)
111b9c3b1SVijay Khemka /*
211b9c3b1SVijay Khemka  * Copyright (c)  2018 Intel Corporation.
311b9c3b1SVijay Khemka  * Copyright (c)  2018-present Facebook.
411b9c3b1SVijay Khemka  *
511b9c3b1SVijay Khemka  * Licensed under the Apache License, Version 2.0 (the "License");
611b9c3b1SVijay Khemka  * you may not use this file except in compliance with the License.
711b9c3b1SVijay Khemka  * You may obtain a copy of the License at
811b9c3b1SVijay Khemka  *
911b9c3b1SVijay Khemka  *      http://www.apache.org/licenses/LICENSE-2.0
1011b9c3b1SVijay Khemka  *
1111b9c3b1SVijay Khemka  * Unless required by applicable law or agreed to in writing, software
1211b9c3b1SVijay Khemka  * distributed under the License is distributed on an "AS IS" BASIS,
1311b9c3b1SVijay Khemka  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1411b9c3b1SVijay Khemka  * See the License for the specific language governing permissions and
1511b9c3b1SVijay Khemka  * limitations under the License.
1611b9c3b1SVijay Khemka  */
1711b9c3b1SVijay Khemka 
1811b9c3b1SVijay Khemka #include <boost/algorithm/string/join.hpp>
19020ff3e4SPatrick Williams #include <boost/container/flat_map.hpp>
2063c99be4SVijay Khemka #include <ipmid/api.hpp>
2111b9c3b1SVijay Khemka #include <nlohmann/json.hpp>
2211b9c3b1SVijay Khemka #include <phosphor-logging/log.hpp>
2311b9c3b1SVijay Khemka #include <sdbusplus/message/types.hpp>
2411b9c3b1SVijay Khemka #include <sdbusplus/timer.hpp>
2511b9c3b1SVijay Khemka #include <storagecommands.hpp>
2611b9c3b1SVijay Khemka 
2763c99be4SVijay Khemka #include <fstream>
2863c99be4SVijay Khemka #include <iostream>
2963c99be4SVijay Khemka #include <sstream>
30*7f97f755SPeter Yin #include <thread>
3163c99be4SVijay Khemka 
327451903cScchoux enum class MemErrType
337451903cScchoux {
347451903cScchoux     memTrainErr = 0,
357451903cScchoux     memPmicErr = 7
367451903cScchoux };
377451903cScchoux 
387451903cScchoux enum class PostEvtType
397451903cScchoux {
407451903cScchoux     pxeBootFail = 0,
417451903cScchoux     httpBootFail = 6,
427451903cScchoux     getCertFail = 7,
437451903cScchoux     amdAblFail = 10
447451903cScchoux };
457451903cScchoux 
467451903cScchoux enum class PcieEvtType
477451903cScchoux {
487451903cScchoux     dpc = 0
497451903cScchoux };
507451903cScchoux 
517451903cScchoux enum class MemEvtType
527451903cScchoux {
537451903cScchoux     ppr = 0,
547451903cScchoux     adddc = 5,
557451903cScchoux     noDimm = 7
567451903cScchoux };
577451903cScchoux 
5811b9c3b1SVijay Khemka //----------------------------------------------------------------------
5911b9c3b1SVijay Khemka // Platform specific functions for storing app data
6011b9c3b1SVijay Khemka //----------------------------------------------------------------------
6111b9c3b1SVijay Khemka 
byteToStr(uint8_t byte)62139aa4f0SVijay Khemka static std::string byteToStr(uint8_t byte)
63139aa4f0SVijay Khemka {
64139aa4f0SVijay Khemka     std::stringstream ss;
65139aa4f0SVijay Khemka 
66139aa4f0SVijay Khemka     ss << std::hex << std::uppercase << std::setfill('0');
67139aa4f0SVijay Khemka     ss << std::setw(2) << (int)byte;
68139aa4f0SVijay Khemka 
69139aa4f0SVijay Khemka     return ss.str();
70139aa4f0SVijay Khemka }
71139aa4f0SVijay Khemka 
toHexStr(std::vector<uint8_t> & bytes,std::string & hexStr)7211b9c3b1SVijay Khemka static void toHexStr(std::vector<uint8_t>& bytes, std::string& hexStr)
7311b9c3b1SVijay Khemka {
7411b9c3b1SVijay Khemka     std::stringstream stream;
7511b9c3b1SVijay Khemka     stream << std::hex << std::uppercase << std::setfill('0');
7611b9c3b1SVijay Khemka     for (const uint8_t byte : bytes)
7711b9c3b1SVijay Khemka     {
7811b9c3b1SVijay Khemka         stream << std::setw(2) << static_cast<int>(byte);
7911b9c3b1SVijay Khemka     }
8011b9c3b1SVijay Khemka     hexStr = stream.str();
8111b9c3b1SVijay Khemka }
8211b9c3b1SVijay Khemka 
fromHexStr(const std::string hexStr,std::vector<uint8_t> & data)8311b9c3b1SVijay Khemka static int fromHexStr(const std::string hexStr, std::vector<uint8_t>& data)
8411b9c3b1SVijay Khemka {
8511b9c3b1SVijay Khemka     for (unsigned int i = 0; i < hexStr.size(); i += 2)
8611b9c3b1SVijay Khemka     {
8711b9c3b1SVijay Khemka         try
8811b9c3b1SVijay Khemka         {
8911b9c3b1SVijay Khemka             data.push_back(static_cast<uint8_t>(
9011b9c3b1SVijay Khemka                 std::stoul(hexStr.substr(i, 2), nullptr, 16)));
9111b9c3b1SVijay Khemka         }
9235d12546SPatrick Williams         catch (const std::invalid_argument& e)
9311b9c3b1SVijay Khemka         {
9411b9c3b1SVijay Khemka             phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
9511b9c3b1SVijay Khemka             return -1;
9611b9c3b1SVijay Khemka         }
9735d12546SPatrick Williams         catch (const std::out_of_range& e)
9811b9c3b1SVijay Khemka         {
9911b9c3b1SVijay Khemka             phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
10011b9c3b1SVijay Khemka             return -1;
10111b9c3b1SVijay Khemka         }
10211b9c3b1SVijay Khemka     }
10311b9c3b1SVijay Khemka     return 0;
10411b9c3b1SVijay Khemka }
10511b9c3b1SVijay Khemka 
10611b9c3b1SVijay Khemka namespace fb_oem::ipmi::sel
10711b9c3b1SVijay Khemka {
10811b9c3b1SVijay Khemka 
10911b9c3b1SVijay Khemka class SELData
11011b9c3b1SVijay Khemka {
11111b9c3b1SVijay Khemka   private:
11211b9c3b1SVijay Khemka     nlohmann::json selDataObj;
11311b9c3b1SVijay Khemka 
flush()11411b9c3b1SVijay Khemka     void flush()
11511b9c3b1SVijay Khemka     {
11611b9c3b1SVijay Khemka         std::ofstream file(SEL_JSON_DATA_FILE);
11711b9c3b1SVijay Khemka         file << selDataObj;
11811b9c3b1SVijay Khemka         file.close();
11911b9c3b1SVijay Khemka     }
12011b9c3b1SVijay Khemka 
init()12111b9c3b1SVijay Khemka     void init()
12211b9c3b1SVijay Khemka     {
12311b9c3b1SVijay Khemka         selDataObj[KEY_SEL_VER] = 0x51;
12411b9c3b1SVijay Khemka         selDataObj[KEY_SEL_COUNT] = 0;
12511b9c3b1SVijay Khemka         selDataObj[KEY_ADD_TIME] = 0xFFFFFFFF;
12611b9c3b1SVijay Khemka         selDataObj[KEY_ERASE_TIME] = 0xFFFFFFFF;
12711b9c3b1SVijay Khemka         selDataObj[KEY_OPER_SUPP] = 0x02;
12811b9c3b1SVijay Khemka         /* Spec indicates that more than 64kB is free */
12911b9c3b1SVijay Khemka         selDataObj[KEY_FREE_SPACE] = 0xFFFF;
13011b9c3b1SVijay Khemka     }
13111b9c3b1SVijay Khemka 
writeEmptyJson()132ac597172SPeter Yin     void writeEmptyJson()
133ac597172SPeter Yin     {
134ac597172SPeter Yin         selDataObj = nlohmann::json::object(); // Create an empty JSON object
135ac597172SPeter Yin         std::ofstream outFile(SEL_JSON_DATA_FILE);
136ac597172SPeter Yin         if (outFile)
137ac597172SPeter Yin         {
138ac597172SPeter Yin             // Write empty JSON object to the file
139ac597172SPeter Yin             outFile << selDataObj.dump(4);
140ac597172SPeter Yin             outFile.close();
141ac597172SPeter Yin         }
142ac597172SPeter Yin         else
143ac597172SPeter Yin         {
144ac597172SPeter Yin             lg2::info("Failed to create SEL JSON file with empty JSON.");
145ac597172SPeter Yin         }
146ac597172SPeter Yin     }
147ac597172SPeter Yin 
14811b9c3b1SVijay Khemka   public:
SELData()14911b9c3b1SVijay Khemka     SELData()
15011b9c3b1SVijay Khemka     {
15111b9c3b1SVijay Khemka         /* Get App data stored in json file */
15211b9c3b1SVijay Khemka         std::ifstream file(SEL_JSON_DATA_FILE);
15311b9c3b1SVijay Khemka         if (file)
15411b9c3b1SVijay Khemka         {
155ac597172SPeter Yin             try
156ac597172SPeter Yin             {
15711b9c3b1SVijay Khemka                 file >> selDataObj;
158ac597172SPeter Yin             }
159ac597172SPeter Yin             catch (const nlohmann::json::parse_error& e)
160ac597172SPeter Yin             {
161ac597172SPeter Yin                 lg2::error("Error parsing SEL JSON file: {ERROR}", "ERROR", e);
162ac597172SPeter Yin                 writeEmptyJson();
163ac597172SPeter Yin                 init(); // Initialize to default values
164ac597172SPeter Yin             }
16511b9c3b1SVijay Khemka             file.close();
16611b9c3b1SVijay Khemka         }
167ac597172SPeter Yin         else
168ac597172SPeter Yin         {
169ac597172SPeter Yin             lg2::info("Failed to open SEL JSON file.");
170ac597172SPeter Yin             writeEmptyJson();
171ac597172SPeter Yin             init();
172ac597172SPeter Yin         }
17311b9c3b1SVijay Khemka 
17411b9c3b1SVijay Khemka         /* Initialize SelData object if no entries. */
17511b9c3b1SVijay Khemka         if (selDataObj.find(KEY_SEL_COUNT) == selDataObj.end())
17611b9c3b1SVijay Khemka         {
17711b9c3b1SVijay Khemka             init();
17811b9c3b1SVijay Khemka         }
17911b9c3b1SVijay Khemka     }
18011b9c3b1SVijay Khemka 
clear()18111b9c3b1SVijay Khemka     int clear()
18211b9c3b1SVijay Khemka     {
18311b9c3b1SVijay Khemka         /* Clear the complete Sel Json object */
18411b9c3b1SVijay Khemka         selDataObj.clear();
18511b9c3b1SVijay Khemka         /* Reinitialize it with basic data */
18611b9c3b1SVijay Khemka         init();
18711b9c3b1SVijay Khemka         /* Save the erase time */
18811b9c3b1SVijay Khemka         struct timespec selTime = {};
18911b9c3b1SVijay Khemka         if (clock_gettime(CLOCK_REALTIME, &selTime) < 0)
19011b9c3b1SVijay Khemka         {
19111b9c3b1SVijay Khemka             return -1;
19211b9c3b1SVijay Khemka         }
19311b9c3b1SVijay Khemka         selDataObj[KEY_ERASE_TIME] = selTime.tv_sec;
19411b9c3b1SVijay Khemka         flush();
19511b9c3b1SVijay Khemka         return 0;
19611b9c3b1SVijay Khemka     }
19711b9c3b1SVijay Khemka 
getCount()19811b9c3b1SVijay Khemka     uint32_t getCount()
19911b9c3b1SVijay Khemka     {
20011b9c3b1SVijay Khemka         return selDataObj[KEY_SEL_COUNT];
20111b9c3b1SVijay Khemka     }
20211b9c3b1SVijay Khemka 
getInfo(GetSELInfoData & info)20311b9c3b1SVijay Khemka     void getInfo(GetSELInfoData& info)
20411b9c3b1SVijay Khemka     {
20511b9c3b1SVijay Khemka         info.selVersion = selDataObj[KEY_SEL_VER];
20611b9c3b1SVijay Khemka         info.entries = selDataObj[KEY_SEL_COUNT];
20711b9c3b1SVijay Khemka         info.freeSpace = selDataObj[KEY_FREE_SPACE];
20811b9c3b1SVijay Khemka         info.addTimeStamp = selDataObj[KEY_ADD_TIME];
20911b9c3b1SVijay Khemka         info.eraseTimeStamp = selDataObj[KEY_ERASE_TIME];
21011b9c3b1SVijay Khemka         info.operationSupport = selDataObj[KEY_OPER_SUPP];
21111b9c3b1SVijay Khemka     }
21211b9c3b1SVijay Khemka 
getEntry(uint32_t index,std::string & rawStr)21311b9c3b1SVijay Khemka     int getEntry(uint32_t index, std::string& rawStr)
21411b9c3b1SVijay Khemka     {
21511b9c3b1SVijay Khemka         std::stringstream ss;
21611b9c3b1SVijay Khemka         ss << std::hex;
21711b9c3b1SVijay Khemka         ss << std::setw(2) << std::setfill('0') << index;
21811b9c3b1SVijay Khemka 
21911b9c3b1SVijay Khemka         /* Check or the requested SEL Entry, if record is available */
22011b9c3b1SVijay Khemka         if (selDataObj.find(ss.str()) == selDataObj.end())
22111b9c3b1SVijay Khemka         {
22211b9c3b1SVijay Khemka             return -1;
22311b9c3b1SVijay Khemka         }
22411b9c3b1SVijay Khemka 
22511b9c3b1SVijay Khemka         rawStr = selDataObj[ss.str()][KEY_SEL_ENTRY_RAW];
22611b9c3b1SVijay Khemka         return 0;
22711b9c3b1SVijay Khemka     }
22811b9c3b1SVijay Khemka 
addEntry(std::string keyStr)22911b9c3b1SVijay Khemka     int addEntry(std::string keyStr)
23011b9c3b1SVijay Khemka     {
23111b9c3b1SVijay Khemka         struct timespec selTime = {};
23211b9c3b1SVijay Khemka 
23311b9c3b1SVijay Khemka         if (clock_gettime(CLOCK_REALTIME, &selTime) < 0)
23411b9c3b1SVijay Khemka         {
23511b9c3b1SVijay Khemka             return -1;
23611b9c3b1SVijay Khemka         }
23711b9c3b1SVijay Khemka 
23811b9c3b1SVijay Khemka         selDataObj[KEY_ADD_TIME] = selTime.tv_sec;
23911b9c3b1SVijay Khemka 
24011b9c3b1SVijay Khemka         int selCount = selDataObj[KEY_SEL_COUNT];
24111b9c3b1SVijay Khemka         selDataObj[KEY_SEL_COUNT] = ++selCount;
24211b9c3b1SVijay Khemka 
24311b9c3b1SVijay Khemka         std::stringstream ss;
24411b9c3b1SVijay Khemka         ss << std::hex;
24511b9c3b1SVijay Khemka         ss << std::setw(2) << std::setfill('0') << selCount;
24611b9c3b1SVijay Khemka 
24711b9c3b1SVijay Khemka         selDataObj[ss.str()][KEY_SEL_ENTRY_RAW] = keyStr;
24811b9c3b1SVijay Khemka         flush();
24911b9c3b1SVijay Khemka         return selCount;
25011b9c3b1SVijay Khemka     }
25111b9c3b1SVijay Khemka };
25211b9c3b1SVijay Khemka 
253139aa4f0SVijay Khemka /*
254519530beSManojkiran Eda  * A Function to parse common SEL message, a helper function
255139aa4f0SVijay Khemka  * for parseStdSel.
256139aa4f0SVijay Khemka  *
257519530beSManojkiran Eda  * Note that this function __CANNOT__ be overridden.
258139aa4f0SVijay Khemka  * To add board specific routine, please override parseStdSel.
259139aa4f0SVijay Khemka  */
260139aa4f0SVijay Khemka 
261139aa4f0SVijay Khemka /*Used by decoding ME event*/
262139aa4f0SVijay Khemka std::vector<std::string> nmDomName = {
263139aa4f0SVijay Khemka     "Entire Platform",          "CPU Subsystem",
264139aa4f0SVijay Khemka     "Memory Subsystem",         "HW Protection",
265139aa4f0SVijay Khemka     "High Power I/O subsystem", "Unknown"};
266139aa4f0SVijay Khemka 
267139aa4f0SVijay Khemka /* Default log message for unknown type */
logDefault(uint8_t *,std::string & errLog)268e39f9393SWilly Tu static void logDefault(uint8_t*, std::string& errLog)
269139aa4f0SVijay Khemka {
270139aa4f0SVijay Khemka     errLog = "Unknown";
271139aa4f0SVijay Khemka }
272139aa4f0SVijay Khemka 
logSysEvent(uint8_t * data,std::string & errLog)273139aa4f0SVijay Khemka static void logSysEvent(uint8_t* data, std::string& errLog)
274139aa4f0SVijay Khemka {
275139aa4f0SVijay Khemka     if (data[0] == 0xE5)
276139aa4f0SVijay Khemka     {
277139aa4f0SVijay Khemka         errLog = "Cause of Time change - ";
278139aa4f0SVijay Khemka         switch (data[2])
279139aa4f0SVijay Khemka         {
280139aa4f0SVijay Khemka             case 0x00:
281139aa4f0SVijay Khemka                 errLog += "NTP";
282139aa4f0SVijay Khemka                 break;
283139aa4f0SVijay Khemka             case 0x01:
284139aa4f0SVijay Khemka                 errLog += "Host RTL";
285139aa4f0SVijay Khemka                 break;
286139aa4f0SVijay Khemka             case 0x02:
287139aa4f0SVijay Khemka                 errLog += "Set SEL time cmd";
288139aa4f0SVijay Khemka                 break;
289139aa4f0SVijay Khemka             case 0x03:
290139aa4f0SVijay Khemka                 errLog += "Set SEL time UTC offset cmd";
291139aa4f0SVijay Khemka                 break;
292139aa4f0SVijay Khemka             default:
293139aa4f0SVijay Khemka                 errLog += "Unknown";
294139aa4f0SVijay Khemka         }
295139aa4f0SVijay Khemka 
296139aa4f0SVijay Khemka         if (data[1] == 0x00)
297139aa4f0SVijay Khemka             errLog += " - First Time";
298139aa4f0SVijay Khemka         else if (data[1] == 0x80)
299139aa4f0SVijay Khemka             errLog += " - Second Time";
300139aa4f0SVijay Khemka     }
301139aa4f0SVijay Khemka     else
302139aa4f0SVijay Khemka     {
303139aa4f0SVijay Khemka         errLog = "Unknown";
304139aa4f0SVijay Khemka     }
305139aa4f0SVijay Khemka }
306139aa4f0SVijay Khemka 
logThermalEvent(uint8_t * data,std::string & errLog)307139aa4f0SVijay Khemka static void logThermalEvent(uint8_t* data, std::string& errLog)
308139aa4f0SVijay Khemka {
309139aa4f0SVijay Khemka     if (data[0] == 0x1)
310139aa4f0SVijay Khemka     {
311139aa4f0SVijay Khemka         errLog = "Limit Exceeded";
312139aa4f0SVijay Khemka     }
313139aa4f0SVijay Khemka     else
314139aa4f0SVijay Khemka     {
315139aa4f0SVijay Khemka         errLog = "Unknown";
316139aa4f0SVijay Khemka     }
317139aa4f0SVijay Khemka }
318139aa4f0SVijay Khemka 
logCritIrq(uint8_t * data,std::string & errLog)319139aa4f0SVijay Khemka static void logCritIrq(uint8_t* data, std::string& errLog)
320139aa4f0SVijay Khemka {
321139aa4f0SVijay Khemka     if (data[0] == 0x0)
322139aa4f0SVijay Khemka     {
323139aa4f0SVijay Khemka         errLog = "NMI / Diagnostic Interrupt";
324139aa4f0SVijay Khemka     }
325139aa4f0SVijay Khemka     else if (data[0] == 0x03)
326139aa4f0SVijay Khemka     {
327139aa4f0SVijay Khemka         errLog = "Software NMI";
328139aa4f0SVijay Khemka     }
329139aa4f0SVijay Khemka     else
330139aa4f0SVijay Khemka     {
331139aa4f0SVijay Khemka         errLog = "Unknown";
332139aa4f0SVijay Khemka     }
333139aa4f0SVijay Khemka 
334139aa4f0SVijay Khemka     /* TODO: Call add_cri_sel for CRITICAL_IRQ */
335139aa4f0SVijay Khemka }
336139aa4f0SVijay Khemka 
logPostErr(uint8_t * data,std::string & errLog)337139aa4f0SVijay Khemka static void logPostErr(uint8_t* data, std::string& errLog)
338139aa4f0SVijay Khemka {
339139aa4f0SVijay Khemka     if ((data[0] & 0x0F) == 0x0)
340139aa4f0SVijay Khemka     {
341139aa4f0SVijay Khemka         errLog = "System Firmware Error";
342139aa4f0SVijay Khemka     }
343139aa4f0SVijay Khemka     else
344139aa4f0SVijay Khemka     {
345139aa4f0SVijay Khemka         errLog = "Unknown";
346139aa4f0SVijay Khemka     }
347139aa4f0SVijay Khemka 
348139aa4f0SVijay Khemka     if (((data[0] >> 6) & 0x03) == 0x3)
349139aa4f0SVijay Khemka     {
350139aa4f0SVijay Khemka         // TODO: Need to implement IPMI spec based Post Code
351139aa4f0SVijay Khemka         errLog += ", IPMI Post Code";
352139aa4f0SVijay Khemka     }
353139aa4f0SVijay Khemka     else if (((data[0] >> 6) & 0x03) == 0x2)
354139aa4f0SVijay Khemka     {
3552405ae98SPatrick Williams         errLog += ", OEM Post Code 0x" + byteToStr(data[2]) +
3562405ae98SPatrick Williams                   byteToStr(data[1]);
357139aa4f0SVijay Khemka 
358139aa4f0SVijay Khemka         switch ((data[2] << 8) | data[1])
359139aa4f0SVijay Khemka         {
360139aa4f0SVijay Khemka             case 0xA105:
361139aa4f0SVijay Khemka                 errLog += ", BMC Failed (No Response)";
362139aa4f0SVijay Khemka                 break;
363139aa4f0SVijay Khemka             case 0xA106:
364139aa4f0SVijay Khemka                 errLog += ", BMC Failed (Self Test Fail)";
365139aa4f0SVijay Khemka                 break;
366139aa4f0SVijay Khemka             case 0xA10A:
367139aa4f0SVijay Khemka                 errLog += ", System Firmware Corruption Detected";
368139aa4f0SVijay Khemka                 break;
369139aa4f0SVijay Khemka             case 0xA10B:
370139aa4f0SVijay Khemka                 errLog += ", TPM Self-Test FAIL Detected";
371139aa4f0SVijay Khemka         }
372139aa4f0SVijay Khemka     }
373139aa4f0SVijay Khemka }
374139aa4f0SVijay Khemka 
logMchChkErr(uint8_t * data,std::string & errLog)375139aa4f0SVijay Khemka static void logMchChkErr(uint8_t* data, std::string& errLog)
376139aa4f0SVijay Khemka {
377139aa4f0SVijay Khemka     /* TODO: Call add_cri_sel for CRITICAL_IRQ */
378d17c356eSDaniel Hsu     switch (data[0] & 0x0F)
379139aa4f0SVijay Khemka     {
380d17c356eSDaniel Hsu         case 0x0B:
381d17c356eSDaniel Hsu             switch ((data[1] >> 5) & 0x03)
382d17c356eSDaniel Hsu             {
383d17c356eSDaniel Hsu                 case 0x00:
384d17c356eSDaniel Hsu                     errLog = "Uncorrected Recoverable Error";
385d17c356eSDaniel Hsu                     break;
386d17c356eSDaniel Hsu                 case 0x01:
387d17c356eSDaniel Hsu                     errLog = "Uncorrected Thread Fatal Error";
388d17c356eSDaniel Hsu                     break;
389d17c356eSDaniel Hsu                 case 0x02:
390d17c356eSDaniel Hsu                     errLog = "Uncorrected System Fatal Error";
391d17c356eSDaniel Hsu                     break;
392d17c356eSDaniel Hsu                 default:
393d17c356eSDaniel Hsu                     errLog = "Unknown";
394139aa4f0SVijay Khemka             }
395d17c356eSDaniel Hsu             break;
396d17c356eSDaniel Hsu         case 0x0C:
397d17c356eSDaniel Hsu             switch ((data[1] >> 5) & 0x03)
398139aa4f0SVijay Khemka             {
399d17c356eSDaniel Hsu                 case 0x00:
400d17c356eSDaniel Hsu                     errLog = "Correctable Error";
401d17c356eSDaniel Hsu                     break;
402d17c356eSDaniel Hsu                 case 0x01:
403d17c356eSDaniel Hsu                     errLog = "Deferred Error";
404d17c356eSDaniel Hsu                     break;
405d17c356eSDaniel Hsu                 default:
406d17c356eSDaniel Hsu                     errLog = "Unknown";
407139aa4f0SVijay Khemka             }
408d17c356eSDaniel Hsu             break;
409d17c356eSDaniel Hsu         default:
410139aa4f0SVijay Khemka             errLog = "Unknown";
411139aa4f0SVijay Khemka     }
412139aa4f0SVijay Khemka 
413139aa4f0SVijay Khemka     errLog += ", Machine Check bank Number " + std::to_string(data[1]) +
414139aa4f0SVijay Khemka               ", CPU " + std::to_string(data[2] >> 5) + ", Core " +
415139aa4f0SVijay Khemka               std::to_string(data[2] & 0x1F);
416139aa4f0SVijay Khemka }
417139aa4f0SVijay Khemka 
logPcieErr(uint8_t * data,std::string & errLog)418139aa4f0SVijay Khemka static void logPcieErr(uint8_t* data, std::string& errLog)
419139aa4f0SVijay Khemka {
420139aa4f0SVijay Khemka     std::stringstream tmp1, tmp2;
421139aa4f0SVijay Khemka     tmp1 << std::hex << std::uppercase << std::setfill('0');
422139aa4f0SVijay Khemka     tmp2 << std::hex << std::uppercase << std::setfill('0');
423139aa4f0SVijay Khemka     tmp1 << " (Bus " << std::setw(2) << (int)(data[2]) << " / Dev "
424139aa4f0SVijay Khemka          << std::setw(2) << (int)(data[1] >> 3) << " / Fun " << std::setw(2)
425139aa4f0SVijay Khemka          << (int)(data[1] & 0x7) << ")";
426139aa4f0SVijay Khemka 
427139aa4f0SVijay Khemka     switch (data[0] & 0xF)
428139aa4f0SVijay Khemka     {
429139aa4f0SVijay Khemka         case 0x4:
430139aa4f0SVijay Khemka             errLog = "PCI PERR" + tmp1.str();
431139aa4f0SVijay Khemka             break;
432139aa4f0SVijay Khemka         case 0x5:
433139aa4f0SVijay Khemka             errLog = "PCI SERR" + tmp1.str();
434139aa4f0SVijay Khemka             break;
435139aa4f0SVijay Khemka         case 0x7:
436139aa4f0SVijay Khemka             errLog = "Correctable" + tmp1.str();
437139aa4f0SVijay Khemka             break;
438139aa4f0SVijay Khemka         case 0x8:
439139aa4f0SVijay Khemka             errLog = "Uncorrectable" + tmp1.str();
440139aa4f0SVijay Khemka             break;
441139aa4f0SVijay Khemka         case 0xA:
442139aa4f0SVijay Khemka             errLog = "Bus Fatal" + tmp1.str();
443139aa4f0SVijay Khemka             break;
444d1194024SVijay Khemka         case 0xD:
445d1194024SVijay Khemka         {
446139aa4f0SVijay Khemka             uint32_t venId = (uint32_t)data[1] << 8 | (uint32_t)data[2];
447139aa4f0SVijay Khemka             tmp2 << "Vendor ID: 0x" << std::setw(4) << venId;
448139aa4f0SVijay Khemka             errLog = tmp2.str();
449139aa4f0SVijay Khemka         }
450139aa4f0SVijay Khemka         break;
451d1194024SVijay Khemka         case 0xE:
452d1194024SVijay Khemka         {
453139aa4f0SVijay Khemka             uint32_t devId = (uint32_t)data[1] << 8 | (uint32_t)data[2];
454139aa4f0SVijay Khemka             tmp2 << "Device ID: 0x" << std::setw(4) << devId;
455139aa4f0SVijay Khemka             errLog = tmp2.str();
456139aa4f0SVijay Khemka         }
457139aa4f0SVijay Khemka         break;
458139aa4f0SVijay Khemka         case 0xF:
459139aa4f0SVijay Khemka             tmp2 << "Error ID from downstream: 0x" << std::setw(2)
460139aa4f0SVijay Khemka                  << (int)(data[1]) << std::setw(2) << (int)(data[2]);
461139aa4f0SVijay Khemka             errLog = tmp2.str();
462139aa4f0SVijay Khemka             break;
463139aa4f0SVijay Khemka         default:
464139aa4f0SVijay Khemka             errLog = "Unknown";
465139aa4f0SVijay Khemka     }
466139aa4f0SVijay Khemka }
467139aa4f0SVijay Khemka 
logIioErr(uint8_t * data,std::string & errLog)468139aa4f0SVijay Khemka static void logIioErr(uint8_t* data, std::string& errLog)
469139aa4f0SVijay Khemka {
470139aa4f0SVijay Khemka     std::vector<std::string> tmpStr = {
471139aa4f0SVijay Khemka         "IRP0", "IRP1", " IIO-Core", "VT-d", "Intel Quick Data",
472139aa4f0SVijay Khemka         "Misc", " DMA", "ITC",       "OTC",  "CI"};
473139aa4f0SVijay Khemka 
474139aa4f0SVijay Khemka     if ((data[0] & 0xF) == 0)
475139aa4f0SVijay Khemka     {
476139aa4f0SVijay Khemka         errLog += "CPU " + std::to_string(data[2] >> 5) + ", Error ID 0x" +
477139aa4f0SVijay Khemka                   byteToStr(data[1]) + " - ";
478139aa4f0SVijay Khemka 
479139aa4f0SVijay Khemka         if ((data[2] & 0xF) <= 0x9)
480139aa4f0SVijay Khemka         {
481139aa4f0SVijay Khemka             errLog += tmpStr[(data[2] & 0xF)];
482139aa4f0SVijay Khemka         }
483139aa4f0SVijay Khemka         else
484139aa4f0SVijay Khemka         {
485139aa4f0SVijay Khemka             errLog += "Reserved";
486139aa4f0SVijay Khemka         }
487139aa4f0SVijay Khemka     }
488139aa4f0SVijay Khemka     else
489139aa4f0SVijay Khemka     {
490139aa4f0SVijay Khemka         errLog = "Unknown";
491139aa4f0SVijay Khemka     }
492139aa4f0SVijay Khemka }
493139aa4f0SVijay Khemka 
logMemErr(uint8_t * dataPtr,std::string & errLog)494e39f9393SWilly Tu [[maybe_unused]] static void logMemErr(uint8_t* dataPtr, std::string& errLog)
495139aa4f0SVijay Khemka {
496139aa4f0SVijay Khemka     uint8_t snrType = dataPtr[0];
497139aa4f0SVijay Khemka     uint8_t snrNum = dataPtr[1];
498139aa4f0SVijay Khemka     uint8_t* data = &(dataPtr[3]);
499139aa4f0SVijay Khemka 
500139aa4f0SVijay Khemka     /* TODO: add pal_add_cri_sel */
501139aa4f0SVijay Khemka 
502139aa4f0SVijay Khemka     if (snrNum == memoryEccError)
503139aa4f0SVijay Khemka     {
504139aa4f0SVijay Khemka         /* SEL from MEMORY_ECC_ERR Sensor */
505139aa4f0SVijay Khemka         switch (data[0] & 0x0F)
506139aa4f0SVijay Khemka         {
507139aa4f0SVijay Khemka             case 0x0:
508139aa4f0SVijay Khemka                 if (snrType == 0x0C)
509139aa4f0SVijay Khemka                 {
510139aa4f0SVijay Khemka                     errLog = "Correctable";
511139aa4f0SVijay Khemka                 }
512139aa4f0SVijay Khemka                 else if (snrType == 0x10)
513139aa4f0SVijay Khemka                 {
514139aa4f0SVijay Khemka                     errLog = "Correctable ECC error Logging Disabled";
515139aa4f0SVijay Khemka                 }
516139aa4f0SVijay Khemka                 break;
517139aa4f0SVijay Khemka             case 0x1:
518139aa4f0SVijay Khemka                 errLog = "Uncorrectable";
519139aa4f0SVijay Khemka                 break;
520139aa4f0SVijay Khemka             case 0x5:
521139aa4f0SVijay Khemka                 errLog = "Correctable ECC error Logging Limit Disabled";
522139aa4f0SVijay Khemka                 break;
523139aa4f0SVijay Khemka             default:
524139aa4f0SVijay Khemka                 errLog = "Unknown";
525139aa4f0SVijay Khemka         }
526139aa4f0SVijay Khemka     }
527139aa4f0SVijay Khemka     else if (snrNum == memoryErrLogDIS)
528139aa4f0SVijay Khemka     {
529139aa4f0SVijay Khemka         // SEL from MEMORY_ERR_LOG_DIS Sensor
530139aa4f0SVijay Khemka         if ((data[0] & 0x0F) == 0x0)
531139aa4f0SVijay Khemka         {
532139aa4f0SVijay Khemka             errLog = "Correctable Memory Error Logging Disabled";
533139aa4f0SVijay Khemka         }
534139aa4f0SVijay Khemka         else
535139aa4f0SVijay Khemka         {
536139aa4f0SVijay Khemka             errLog = "Unknown";
537139aa4f0SVijay Khemka         }
538139aa4f0SVijay Khemka     }
539139aa4f0SVijay Khemka     else
540139aa4f0SVijay Khemka     {
541139aa4f0SVijay Khemka         errLog = "Unknown";
542139aa4f0SVijay Khemka         return;
543139aa4f0SVijay Khemka     }
544139aa4f0SVijay Khemka 
545139aa4f0SVijay Khemka     /* Common routine for both MEM_ECC_ERR and MEMORY_ERR_LOG_DIS */
546139aa4f0SVijay Khemka 
547139aa4f0SVijay Khemka     errLog += " (DIMM " + byteToStr(data[2]) + ") Logical Rank " +
548139aa4f0SVijay Khemka               std::to_string(data[1] & 0x03);
549139aa4f0SVijay Khemka 
550139aa4f0SVijay Khemka     /* DIMM number (data[2]):
551139aa4f0SVijay Khemka      * Bit[7:5]: Socket number  (Range: 0-7)
552139aa4f0SVijay Khemka      * Bit[4:3]: Channel number (Range: 0-3)
553139aa4f0SVijay Khemka      * Bit[2:0]: DIMM number    (Range: 0-7)
554139aa4f0SVijay Khemka      */
555139aa4f0SVijay Khemka 
556139aa4f0SVijay Khemka     /* TODO: Verify these bits */
557139aa4f0SVijay Khemka     std::string cpuStr = "CPU# " + std::to_string((data[2] & 0xE0) >> 5);
558139aa4f0SVijay Khemka     std::string chStr = "CHN# " + std::to_string((data[2] & 0x18) >> 3);
559139aa4f0SVijay Khemka     std::string dimmStr = "DIMM#" + std::to_string(data[2] & 0x7);
560139aa4f0SVijay Khemka 
561139aa4f0SVijay Khemka     switch ((data[1] & 0xC) >> 2)
562139aa4f0SVijay Khemka     {
563d1194024SVijay Khemka         case 0x0:
564d1194024SVijay Khemka         {
565139aa4f0SVijay Khemka             /* All Info Valid */
566e39f9393SWilly Tu             [[maybe_unused]] uint8_t chnNum = (data[2] & 0x1C) >> 2;
567e39f9393SWilly Tu             [[maybe_unused]] uint8_t dimmNum = data[2] & 0x3;
568139aa4f0SVijay Khemka 
569139aa4f0SVijay Khemka             /* TODO: If critical SEL logging is available, do it */
570139aa4f0SVijay Khemka             if (snrType == 0x0C)
571139aa4f0SVijay Khemka             {
572139aa4f0SVijay Khemka                 if ((data[0] & 0x0F) == 0x0)
573139aa4f0SVijay Khemka                 {
574139aa4f0SVijay Khemka                     /* TODO: add_cri_sel */
575139aa4f0SVijay Khemka                     /* "DIMM"+ 'A'+ chnNum + dimmNum + " ECC err,FRU:1"
576139aa4f0SVijay Khemka                      */
577139aa4f0SVijay Khemka                 }
578139aa4f0SVijay Khemka                 else if ((data[0] & 0x0F) == 0x1)
579139aa4f0SVijay Khemka                 {
580139aa4f0SVijay Khemka                     /* TODO: add_cri_sel */
581139aa4f0SVijay Khemka                     /* "DIMM"+ 'A'+ chnNum + dimmNum + " UECC err,FRU:1"
582139aa4f0SVijay Khemka                      */
583139aa4f0SVijay Khemka                 }
584139aa4f0SVijay Khemka             }
585139aa4f0SVijay Khemka             /* Continue to parse the error into a string. All Info Valid
586139aa4f0SVijay Khemka              */
587139aa4f0SVijay Khemka             errLog += " (" + cpuStr + ", " + chStr + ", " + dimmStr + ")";
588139aa4f0SVijay Khemka         }
589139aa4f0SVijay Khemka 
590139aa4f0SVijay Khemka         break;
591139aa4f0SVijay Khemka         case 0x1:
592139aa4f0SVijay Khemka 
593139aa4f0SVijay Khemka             /* DIMM info not valid */
594139aa4f0SVijay Khemka             errLog += " (" + cpuStr + ", " + chStr + ")";
595139aa4f0SVijay Khemka             break;
596139aa4f0SVijay Khemka         case 0x2:
597139aa4f0SVijay Khemka 
598139aa4f0SVijay Khemka             /* CHN info not valid */
599139aa4f0SVijay Khemka             errLog += " (" + cpuStr + ", " + dimmStr + ")";
600139aa4f0SVijay Khemka             break;
601139aa4f0SVijay Khemka         case 0x3:
602139aa4f0SVijay Khemka 
603139aa4f0SVijay Khemka             /* CPU info not valid */
604139aa4f0SVijay Khemka             errLog += " (" + chStr + ", " + dimmStr + ")";
605139aa4f0SVijay Khemka             break;
606139aa4f0SVijay Khemka     }
607139aa4f0SVijay Khemka }
608139aa4f0SVijay Khemka 
logPwrErr(uint8_t * data,std::string & errLog)609139aa4f0SVijay Khemka static void logPwrErr(uint8_t* data, std::string& errLog)
610139aa4f0SVijay Khemka {
611139aa4f0SVijay Khemka     if (data[0] == 0x1)
612139aa4f0SVijay Khemka     {
613139aa4f0SVijay Khemka         errLog = "SYS_PWROK failure";
614519530beSManojkiran Eda         /* Also try logging to Critical log file, if available */
615139aa4f0SVijay Khemka         /* "SYS_PWROK failure,FRU:1" */
616139aa4f0SVijay Khemka     }
617139aa4f0SVijay Khemka     else if (data[0] == 0x2)
618139aa4f0SVijay Khemka     {
619139aa4f0SVijay Khemka         errLog = "PCH_PWROK failure";
620519530beSManojkiran Eda         /* Also try logging to Critical log file, if available */
621139aa4f0SVijay Khemka         /* "PCH_PWROK failure,FRU:1" */
622139aa4f0SVijay Khemka     }
623139aa4f0SVijay Khemka     else
624139aa4f0SVijay Khemka     {
625139aa4f0SVijay Khemka         errLog = "Unknown";
626139aa4f0SVijay Khemka     }
627139aa4f0SVijay Khemka }
628139aa4f0SVijay Khemka 
logCatErr(uint8_t * data,std::string & errLog)629139aa4f0SVijay Khemka static void logCatErr(uint8_t* data, std::string& errLog)
630139aa4f0SVijay Khemka {
631139aa4f0SVijay Khemka     if (data[0] == 0x0)
632139aa4f0SVijay Khemka     {
633139aa4f0SVijay Khemka         errLog = "IERR/CATERR";
634519530beSManojkiran Eda         /* Also try logging to Critical log file, if available */
635139aa4f0SVijay Khemka         /* "IERR,FRU:1 */
636139aa4f0SVijay Khemka     }
637139aa4f0SVijay Khemka     else if (data[0] == 0xB)
638139aa4f0SVijay Khemka     {
639139aa4f0SVijay Khemka         errLog = "MCERR/CATERR";
640519530beSManojkiran Eda         /* Also try logging to Critical log file, if available */
641139aa4f0SVijay Khemka         /* "MCERR,FRU:1 */
642139aa4f0SVijay Khemka     }
643139aa4f0SVijay Khemka     else
644139aa4f0SVijay Khemka     {
645139aa4f0SVijay Khemka         errLog = "Unknown";
646139aa4f0SVijay Khemka     }
647139aa4f0SVijay Khemka }
648139aa4f0SVijay Khemka 
logDimmHot(uint8_t * data,std::string & errLog)649139aa4f0SVijay Khemka static void logDimmHot(uint8_t* data, std::string& errLog)
650139aa4f0SVijay Khemka {
651139aa4f0SVijay Khemka     if ((data[0] << 16 | data[1] << 8 | data[2]) == 0x01FFFF)
652139aa4f0SVijay Khemka     {
653139aa4f0SVijay Khemka         errLog = "SOC MEMHOT";
654139aa4f0SVijay Khemka     }
655139aa4f0SVijay Khemka     else
656139aa4f0SVijay Khemka     {
657139aa4f0SVijay Khemka         errLog = "Unknown";
658519530beSManojkiran Eda         /* Also try logging to Critical log file, if available */
659139aa4f0SVijay Khemka         /* ""CPU_DIMM_HOT %s,FRU:1" */
660139aa4f0SVijay Khemka     }
661139aa4f0SVijay Khemka }
662139aa4f0SVijay Khemka 
logSwNMI(uint8_t * data,std::string & errLog)663139aa4f0SVijay Khemka static void logSwNMI(uint8_t* data, std::string& errLog)
664139aa4f0SVijay Khemka {
665139aa4f0SVijay Khemka     if ((data[0] << 16 | data[1] << 8 | data[2]) == 0x03FFFF)
666139aa4f0SVijay Khemka     {
667139aa4f0SVijay Khemka         errLog = "Software NMI";
668139aa4f0SVijay Khemka     }
669139aa4f0SVijay Khemka     else
670139aa4f0SVijay Khemka     {
671139aa4f0SVijay Khemka         errLog = "Unknown SW NMI";
672139aa4f0SVijay Khemka     }
673139aa4f0SVijay Khemka }
674139aa4f0SVijay Khemka 
logCPUThermalSts(uint8_t * data,std::string & errLog)675139aa4f0SVijay Khemka static void logCPUThermalSts(uint8_t* data, std::string& errLog)
676139aa4f0SVijay Khemka {
677139aa4f0SVijay Khemka     switch (data[0])
678139aa4f0SVijay Khemka     {
679139aa4f0SVijay Khemka         case 0x0:
680139aa4f0SVijay Khemka             errLog = "CPU Critical Temperature";
681139aa4f0SVijay Khemka             break;
682139aa4f0SVijay Khemka         case 0x1:
683139aa4f0SVijay Khemka             errLog = "PROCHOT#";
684139aa4f0SVijay Khemka             break;
685139aa4f0SVijay Khemka         case 0x2:
686139aa4f0SVijay Khemka             errLog = "TCC Activation";
687139aa4f0SVijay Khemka             break;
688139aa4f0SVijay Khemka         default:
689139aa4f0SVijay Khemka             errLog = "Unknown";
690139aa4f0SVijay Khemka     }
691139aa4f0SVijay Khemka }
692139aa4f0SVijay Khemka 
logMEPwrState(uint8_t * data,std::string & errLog)693139aa4f0SVijay Khemka static void logMEPwrState(uint8_t* data, std::string& errLog)
694139aa4f0SVijay Khemka {
695139aa4f0SVijay Khemka     switch (data[0])
696139aa4f0SVijay Khemka     {
697139aa4f0SVijay Khemka         case 0:
698139aa4f0SVijay Khemka             errLog = "RUNNING";
699139aa4f0SVijay Khemka             break;
700139aa4f0SVijay Khemka         case 2:
701139aa4f0SVijay Khemka             errLog = "POWER_OFF";
702139aa4f0SVijay Khemka             break;
703139aa4f0SVijay Khemka         default:
704139aa4f0SVijay Khemka             errLog = "Unknown[" + std::to_string(data[0]) + "]";
705139aa4f0SVijay Khemka             break;
706139aa4f0SVijay Khemka     }
707139aa4f0SVijay Khemka }
708139aa4f0SVijay Khemka 
logSPSFwHealth(uint8_t * data,std::string & errLog)709139aa4f0SVijay Khemka static void logSPSFwHealth(uint8_t* data, std::string& errLog)
710139aa4f0SVijay Khemka {
711139aa4f0SVijay Khemka     if ((data[0] & 0x0F) == 0x00)
712139aa4f0SVijay Khemka     {
713139aa4f0SVijay Khemka         const std::vector<std::string> tmpStr = {
714139aa4f0SVijay Khemka             "Recovery GPIO forced",
715139aa4f0SVijay Khemka             "Image execution failed",
716139aa4f0SVijay Khemka             "Flash erase error",
717139aa4f0SVijay Khemka             "Flash state information",
718139aa4f0SVijay Khemka             "Internal error",
719139aa4f0SVijay Khemka             "BMC did not respond",
720139aa4f0SVijay Khemka             "Direct Flash update",
721139aa4f0SVijay Khemka             "Manufacturing error",
722139aa4f0SVijay Khemka             "Automatic Restore to Factory Presets",
723139aa4f0SVijay Khemka             "Firmware Exception",
724139aa4f0SVijay Khemka             "Flash Wear-Out Protection Warning",
725139aa4f0SVijay Khemka             "Unknown",
726139aa4f0SVijay Khemka             "Unknown",
727139aa4f0SVijay Khemka             "DMI interface error",
728139aa4f0SVijay Khemka             "MCTP interface error",
729139aa4f0SVijay Khemka             "Auto-configuration finished",
730139aa4f0SVijay Khemka             "Unsupported Segment Defined Feature",
731139aa4f0SVijay Khemka             "Unknown",
732139aa4f0SVijay Khemka             "CPU Debug Capability Disabled",
733139aa4f0SVijay Khemka             "UMA operation error"};
734139aa4f0SVijay Khemka 
735139aa4f0SVijay Khemka         if (data[1] < 0x14)
736139aa4f0SVijay Khemka         {
737139aa4f0SVijay Khemka             errLog = tmpStr[data[1]];
738139aa4f0SVijay Khemka         }
739139aa4f0SVijay Khemka         else
740139aa4f0SVijay Khemka         {
741139aa4f0SVijay Khemka             errLog = "Unknown";
742139aa4f0SVijay Khemka         }
743139aa4f0SVijay Khemka     }
744139aa4f0SVijay Khemka     else if ((data[0] & 0x0F) == 0x01)
745139aa4f0SVijay Khemka     {
746139aa4f0SVijay Khemka         errLog = "SMBus link failure";
747139aa4f0SVijay Khemka     }
748139aa4f0SVijay Khemka     else
749139aa4f0SVijay Khemka     {
750139aa4f0SVijay Khemka         errLog = "Unknown";
751139aa4f0SVijay Khemka     }
752139aa4f0SVijay Khemka }
753139aa4f0SVijay Khemka 
logNmExcA(uint8_t * data,std::string & errLog)754139aa4f0SVijay Khemka static void logNmExcA(uint8_t* data, std::string& errLog)
755139aa4f0SVijay Khemka {
756139aa4f0SVijay Khemka     /*NM4.0 #550710, Revision 1.95, and turn to p.155*/
757139aa4f0SVijay Khemka     if (data[0] == 0xA8)
758139aa4f0SVijay Khemka     {
759139aa4f0SVijay Khemka         errLog = "Policy Correction Time Exceeded";
760139aa4f0SVijay Khemka     }
761139aa4f0SVijay Khemka     else
762139aa4f0SVijay Khemka     {
763139aa4f0SVijay Khemka         errLog = "Unknown";
764139aa4f0SVijay Khemka     }
765139aa4f0SVijay Khemka }
766139aa4f0SVijay Khemka 
logPCHThermal(uint8_t * data,std::string & errLog)767139aa4f0SVijay Khemka static void logPCHThermal(uint8_t* data, std::string& errLog)
768139aa4f0SVijay Khemka {
769010dee04SPatrick Williams     const std::vector<std::string> thresEvtName = {
770010dee04SPatrick Williams         "Lower Non-critical",
771139aa4f0SVijay Khemka         "Unknown",
772139aa4f0SVijay Khemka         "Lower Critical",
773139aa4f0SVijay Khemka         "Unknown",
774139aa4f0SVijay Khemka         "Lower Non-recoverable",
775139aa4f0SVijay Khemka         "Unknown",
776139aa4f0SVijay Khemka         "Unknown",
777139aa4f0SVijay Khemka         "Upper Non-critical",
778139aa4f0SVijay Khemka         "Unknown",
779139aa4f0SVijay Khemka         "Upper Critical",
780139aa4f0SVijay Khemka         "Unknown",
781139aa4f0SVijay Khemka         "Upper Non-recoverable"};
782139aa4f0SVijay Khemka 
783139aa4f0SVijay Khemka     if ((data[0] & 0x0f) < 12)
784139aa4f0SVijay Khemka     {
785139aa4f0SVijay Khemka         errLog = thresEvtName[(data[0] & 0x0f)];
786139aa4f0SVijay Khemka     }
787139aa4f0SVijay Khemka     else
788139aa4f0SVijay Khemka     {
789139aa4f0SVijay Khemka         errLog = "Unknown";
790139aa4f0SVijay Khemka     }
791139aa4f0SVijay Khemka 
792139aa4f0SVijay Khemka     errLog += ", curr_val: " + std::to_string(data[1]) +
793139aa4f0SVijay Khemka               " C, thresh_val: " + std::to_string(data[2]) + " C";
794139aa4f0SVijay Khemka }
795139aa4f0SVijay Khemka 
logNmHealth(uint8_t * data,std::string & errLog)796139aa4f0SVijay Khemka static void logNmHealth(uint8_t* data, std::string& errLog)
797139aa4f0SVijay Khemka {
798139aa4f0SVijay Khemka     std::vector<std::string> nmErrType = {
799139aa4f0SVijay Khemka         "Unknown",
800139aa4f0SVijay Khemka         "Unknown",
801139aa4f0SVijay Khemka         "Unknown",
802139aa4f0SVijay Khemka         "Unknown",
803139aa4f0SVijay Khemka         "Unknown",
804139aa4f0SVijay Khemka         "Unknown",
805139aa4f0SVijay Khemka         "Unknown",
806139aa4f0SVijay Khemka         "Extended Telemetry Device Reading Failure",
807139aa4f0SVijay Khemka         "Outlet Temperature Reading Failure",
808139aa4f0SVijay Khemka         "Volumetric Airflow Reading Failure",
809139aa4f0SVijay Khemka         "Policy Misconfiguration",
810139aa4f0SVijay Khemka         "Power Sensor Reading Failure",
811139aa4f0SVijay Khemka         "Inlet Temperature Reading Failure",
812139aa4f0SVijay Khemka         "Host Communication Error",
813139aa4f0SVijay Khemka         "Real-time Clock Synchronization Failure",
814139aa4f0SVijay Khemka         "Platform Shutdown Initiated by Intel NM Policy",
815139aa4f0SVijay Khemka         "Unknown"};
816139aa4f0SVijay Khemka     uint8_t nmTypeIdx = (data[0] & 0xf);
817139aa4f0SVijay Khemka     uint8_t domIdx = (data[1] & 0xf);
818139aa4f0SVijay Khemka     uint8_t errIdx = ((data[1] >> 4) & 0xf);
819139aa4f0SVijay Khemka 
820139aa4f0SVijay Khemka     if (nmTypeIdx == 2)
821139aa4f0SVijay Khemka     {
822139aa4f0SVijay Khemka         errLog = "SensorIntelNM";
823139aa4f0SVijay Khemka     }
824139aa4f0SVijay Khemka     else
825139aa4f0SVijay Khemka     {
826139aa4f0SVijay Khemka         errLog = "Unknown";
827139aa4f0SVijay Khemka     }
828139aa4f0SVijay Khemka 
829010dee04SPatrick Williams     errLog += ", Domain:" + nmDomName[domIdx] + ", ErrType:" +
830010dee04SPatrick Williams               nmErrType[errIdx] + ", Err:0x" + byteToStr(data[2]);
831139aa4f0SVijay Khemka }
832139aa4f0SVijay Khemka 
logNmCap(uint8_t * data,std::string & errLog)833139aa4f0SVijay Khemka static void logNmCap(uint8_t* data, std::string& errLog)
834139aa4f0SVijay Khemka {
835139aa4f0SVijay Khemka     const std::vector<std::string> nmCapStsStr = {"Not Available", "Available"};
836139aa4f0SVijay Khemka     if (data[0] & 0x7) // BIT1=policy, BIT2=monitoring, BIT3=pwr
837139aa4f0SVijay Khemka                        // limit and the others are reserved
838139aa4f0SVijay Khemka     {
839139aa4f0SVijay Khemka         errLog = "PolicyInterface:" + nmCapStsStr[BIT(data[0], 0)] +
840139aa4f0SVijay Khemka                  ",Monitoring:" + nmCapStsStr[BIT(data[0], 1)] +
841139aa4f0SVijay Khemka                  ",PowerLimit:" + nmCapStsStr[BIT(data[0], 2)];
842139aa4f0SVijay Khemka     }
843139aa4f0SVijay Khemka     else
844139aa4f0SVijay Khemka     {
845139aa4f0SVijay Khemka         errLog = "Unknown";
846139aa4f0SVijay Khemka     }
847139aa4f0SVijay Khemka }
848139aa4f0SVijay Khemka 
logNmThreshold(uint8_t * data,std::string & errLog)849139aa4f0SVijay Khemka static void logNmThreshold(uint8_t* data, std::string& errLog)
850139aa4f0SVijay Khemka {
851139aa4f0SVijay Khemka     uint8_t thresNum = (data[0] & 0x3);
852139aa4f0SVijay Khemka     uint8_t domIdx = (data[1] & 0xf);
853139aa4f0SVijay Khemka     uint8_t polId = data[2];
854139aa4f0SVijay Khemka     uint8_t polEvtIdx = BIT(data[0], 3);
855139aa4f0SVijay Khemka     const std::vector<std::string> polEvtStr = {
856139aa4f0SVijay Khemka         "Threshold Exceeded", "Policy Correction Time Exceeded"};
857139aa4f0SVijay Khemka 
858139aa4f0SVijay Khemka     errLog = "Threshold Number:" + std::to_string(thresNum) + "-" +
859139aa4f0SVijay Khemka              polEvtStr[polEvtIdx] + ", Domain:" + nmDomName[domIdx] +
860139aa4f0SVijay Khemka              ", PolicyID:0x" + byteToStr(polId);
861139aa4f0SVijay Khemka }
862139aa4f0SVijay Khemka 
logPwrThreshold(uint8_t * data,std::string & errLog)863139aa4f0SVijay Khemka static void logPwrThreshold(uint8_t* data, std::string& errLog)
864139aa4f0SVijay Khemka {
865139aa4f0SVijay Khemka     if (data[0] == 0x00)
866139aa4f0SVijay Khemka     {
867139aa4f0SVijay Khemka         errLog = "Limit Not Exceeded";
868139aa4f0SVijay Khemka     }
869139aa4f0SVijay Khemka     else if (data[0] == 0x01)
870139aa4f0SVijay Khemka     {
871139aa4f0SVijay Khemka         errLog = "Limit Exceeded";
872139aa4f0SVijay Khemka     }
873139aa4f0SVijay Khemka     else
874139aa4f0SVijay Khemka     {
875139aa4f0SVijay Khemka         errLog = "Unknown";
876139aa4f0SVijay Khemka     }
877139aa4f0SVijay Khemka }
878139aa4f0SVijay Khemka 
logMSMI(uint8_t * data,std::string & errLog)879139aa4f0SVijay Khemka static void logMSMI(uint8_t* data, std::string& errLog)
880139aa4f0SVijay Khemka {
881139aa4f0SVijay Khemka     if (data[0] == 0x0)
882139aa4f0SVijay Khemka     {
883139aa4f0SVijay Khemka         errLog = "IERR/MSMI";
884139aa4f0SVijay Khemka     }
885139aa4f0SVijay Khemka     else if (data[0] == 0x0B)
886139aa4f0SVijay Khemka     {
887139aa4f0SVijay Khemka         errLog = "MCERR/MSMI";
888139aa4f0SVijay Khemka     }
889139aa4f0SVijay Khemka     else
890139aa4f0SVijay Khemka     {
891139aa4f0SVijay Khemka         errLog = "Unknown";
892139aa4f0SVijay Khemka     }
893139aa4f0SVijay Khemka }
894139aa4f0SVijay Khemka 
logHprWarn(uint8_t * data,std::string & errLog)895139aa4f0SVijay Khemka static void logHprWarn(uint8_t* data, std::string& errLog)
896139aa4f0SVijay Khemka {
897139aa4f0SVijay Khemka     if (data[2] == 0x01)
898139aa4f0SVijay Khemka     {
899139aa4f0SVijay Khemka         if (data[1] == 0xFF)
900139aa4f0SVijay Khemka         {
901139aa4f0SVijay Khemka             errLog = "Infinite Time";
902139aa4f0SVijay Khemka         }
903139aa4f0SVijay Khemka         else
904139aa4f0SVijay Khemka         {
905139aa4f0SVijay Khemka             errLog = std::to_string(data[1]) + " minutes";
906139aa4f0SVijay Khemka         }
907139aa4f0SVijay Khemka     }
908139aa4f0SVijay Khemka     else
909139aa4f0SVijay Khemka     {
910139aa4f0SVijay Khemka         errLog = "Unknown";
911139aa4f0SVijay Khemka     }
912139aa4f0SVijay Khemka }
913139aa4f0SVijay Khemka 
914139aa4f0SVijay Khemka static const boost::container::flat_map<
915139aa4f0SVijay Khemka     uint8_t,
916139aa4f0SVijay Khemka     std::pair<std::string, std::function<void(uint8_t*, std::string&)>>>
917010dee04SPatrick Williams     sensorNameTable = {
918010dee04SPatrick Williams         {0xE9, {"SYSTEM_EVENT", logSysEvent}},
919139aa4f0SVijay Khemka         {0x7D, {"THERM_THRESH_EVT", logThermalEvent}},
920139aa4f0SVijay Khemka         {0xAA, {"BUTTON", logDefault}},
921139aa4f0SVijay Khemka         {0xAB, {"POWER_STATE", logDefault}},
922139aa4f0SVijay Khemka         {0xEA, {"CRITICAL_IRQ", logCritIrq}},
923139aa4f0SVijay Khemka         {0x2B, {"POST_ERROR", logPostErr}},
924139aa4f0SVijay Khemka         {0x40, {"MACHINE_CHK_ERR", logMchChkErr}},
925139aa4f0SVijay Khemka         {0x41, {"PCIE_ERR", logPcieErr}},
926139aa4f0SVijay Khemka         {0x43, {"IIO_ERR", logIioErr}},
927139aa4f0SVijay Khemka         {0X63, {"MEMORY_ECC_ERR", logDefault}},
928139aa4f0SVijay Khemka         {0X87, {"MEMORY_ERR_LOG_DIS", logDefault}},
929139aa4f0SVijay Khemka         {0X51, {"PROCHOT_EXT", logDefault}},
930139aa4f0SVijay Khemka         {0X56, {"PWR_ERR", logPwrErr}},
931139aa4f0SVijay Khemka         {0xE6, {"CATERR_A", logCatErr}},
932139aa4f0SVijay Khemka         {0xEB, {"CATERR_B", logCatErr}},
933139aa4f0SVijay Khemka         {0xB3, {"CPU_DIMM_HOT", logDimmHot}},
934139aa4f0SVijay Khemka         {0x90, {"SOFTWARE_NMI", logSwNMI}},
935139aa4f0SVijay Khemka         {0x1C, {"CPU0_THERM_STATUS", logCPUThermalSts}},
936139aa4f0SVijay Khemka         {0x1D, {"CPU1_THERM_STATUS", logCPUThermalSts}},
937139aa4f0SVijay Khemka         {0x16, {"ME_POWER_STATE", logMEPwrState}},
938139aa4f0SVijay Khemka         {0x17, {"SPS_FW_HEALTH", logSPSFwHealth}},
939139aa4f0SVijay Khemka         {0x18, {"NM_EXCEPTION_A", logNmExcA}},
940139aa4f0SVijay Khemka         {0x08, {"PCH_THERM_THRESHOLD", logPCHThermal}},
941139aa4f0SVijay Khemka         {0x19, {"NM_HEALTH", logNmHealth}},
942139aa4f0SVijay Khemka         {0x1A, {"NM_CAPABILITIES", logNmCap}},
943139aa4f0SVijay Khemka         {0x1B, {"NM_THRESHOLD", logNmThreshold}},
944139aa4f0SVijay Khemka         {0x3B, {"PWR_THRESH_EVT", logPwrThreshold}},
945139aa4f0SVijay Khemka         {0xE7, {"MSMI", logMSMI}},
946139aa4f0SVijay Khemka         {0xC5, {"HPR_WARNING", logHprWarn}}};
947139aa4f0SVijay Khemka 
parseSelHelper(StdSELEntry * data,std::string & errStr)948139aa4f0SVijay Khemka static void parseSelHelper(StdSELEntry* data, std::string& errStr)
949139aa4f0SVijay Khemka {
950139aa4f0SVijay Khemka     /* Check if sensor type is OS_BOOT (0x1f) */
951139aa4f0SVijay Khemka     if (data->sensorType == 0x1F)
952139aa4f0SVijay Khemka     {
953139aa4f0SVijay Khemka         /* OS_BOOT used by OS */
954139aa4f0SVijay Khemka         switch (data->eventData1 & 0xF)
955139aa4f0SVijay Khemka         {
956139aa4f0SVijay Khemka             case 0x07:
957139aa4f0SVijay Khemka                 errStr = "Base OS/Hypervisor Installation started";
958139aa4f0SVijay Khemka                 break;
959139aa4f0SVijay Khemka             case 0x08:
960139aa4f0SVijay Khemka                 errStr = "Base OS/Hypervisor Installation completed";
961139aa4f0SVijay Khemka                 break;
962139aa4f0SVijay Khemka             case 0x09:
963139aa4f0SVijay Khemka                 errStr = "Base OS/Hypervisor Installation aborted";
964139aa4f0SVijay Khemka                 break;
965139aa4f0SVijay Khemka             case 0x0A:
966139aa4f0SVijay Khemka                 errStr = "Base OS/Hypervisor Installation failed";
967139aa4f0SVijay Khemka                 break;
968139aa4f0SVijay Khemka             default:
969139aa4f0SVijay Khemka                 errStr = "Unknown";
970139aa4f0SVijay Khemka         }
971139aa4f0SVijay Khemka         return;
972139aa4f0SVijay Khemka     }
973139aa4f0SVijay Khemka 
974139aa4f0SVijay Khemka     auto findSensorName = sensorNameTable.find(data->sensorNum);
975139aa4f0SVijay Khemka     if (findSensorName == sensorNameTable.end())
976139aa4f0SVijay Khemka     {
977139aa4f0SVijay Khemka         errStr = "Unknown";
978139aa4f0SVijay Khemka         return;
979139aa4f0SVijay Khemka     }
980139aa4f0SVijay Khemka     else
981139aa4f0SVijay Khemka     {
982139aa4f0SVijay Khemka         switch (data->sensorNum)
983139aa4f0SVijay Khemka         {
984139aa4f0SVijay Khemka             /* logMemErr function needs data from sensor type */
985139aa4f0SVijay Khemka             case memoryEccError:
986139aa4f0SVijay Khemka             case memoryErrLogDIS:
987139aa4f0SVijay Khemka                 findSensorName->second.second(&(data->sensorType), errStr);
988139aa4f0SVijay Khemka                 break;
989139aa4f0SVijay Khemka             /* Other sensor function needs only event data for parsing */
990139aa4f0SVijay Khemka             default:
991139aa4f0SVijay Khemka                 findSensorName->second.second(&(data->eventData1), errStr);
992139aa4f0SVijay Khemka         }
993139aa4f0SVijay Khemka     }
994139aa4f0SVijay Khemka 
995139aa4f0SVijay Khemka     if (((data->eventData3 & 0x80) >> 7) == 0)
996139aa4f0SVijay Khemka     {
997139aa4f0SVijay Khemka         errStr += " Assertion";
998139aa4f0SVijay Khemka     }
999139aa4f0SVijay Khemka     else
1000139aa4f0SVijay Khemka     {
1001139aa4f0SVijay Khemka         errStr += " Deassertion";
1002139aa4f0SVijay Khemka     }
1003139aa4f0SVijay Khemka }
1004139aa4f0SVijay Khemka 
parseDimmPhyloc(StdSELEntry * data,std::string & errStr)1005c056dc00SManikandan Elumalai static void parseDimmPhyloc(StdSELEntry* data, std::string& errStr)
1006c056dc00SManikandan Elumalai {
1007c056dc00SManikandan Elumalai     // Log when " All info available"
1008c056dc00SManikandan Elumalai     uint8_t chNum = (data->eventData3 & 0x18) >> 3;
1009c056dc00SManikandan Elumalai     uint8_t dimmNum = data->eventData3 & 0x7;
1010c056dc00SManikandan Elumalai     uint8_t rankNum = data->eventData2 & 0x03;
1011c056dc00SManikandan Elumalai     uint8_t nodeNum = (data->eventData3 & 0xE0) >> 5;
1012c056dc00SManikandan Elumalai 
1013c056dc00SManikandan Elumalai     if (chNum == 3 && dimmNum == 0)
1014c056dc00SManikandan Elumalai     {
1015c056dc00SManikandan Elumalai         errStr += " Node: " + std::to_string(nodeNum) + "," +
1016c056dc00SManikandan Elumalai                   " Card: " + std::to_string(chNum) + "," +
1017c056dc00SManikandan Elumalai                   " Module: " + std::to_string(dimmNum) + "," +
1018c056dc00SManikandan Elumalai                   " Rank Number: " + std::to_string(rankNum) + "," +
1019c056dc00SManikandan Elumalai                   "  Location: DIMM A0";
1020c056dc00SManikandan Elumalai     }
1021c056dc00SManikandan Elumalai     else if (chNum == 2 && dimmNum == 0)
1022c056dc00SManikandan Elumalai     {
1023c056dc00SManikandan Elumalai         errStr += " Node: " + std::to_string(nodeNum) + "," +
1024c056dc00SManikandan Elumalai                   " Card: " + std::to_string(chNum) + "," +
1025c056dc00SManikandan Elumalai                   " Module: " + std::to_string(dimmNum) + "," +
1026c056dc00SManikandan Elumalai                   " Rank Number: " + std::to_string(rankNum) + "," +
1027c056dc00SManikandan Elumalai                   " Location: DIMM B0";
1028c056dc00SManikandan Elumalai     }
1029c056dc00SManikandan Elumalai     else if (chNum == 4 && dimmNum == 0)
1030c056dc00SManikandan Elumalai     {
1031c056dc00SManikandan Elumalai         errStr += " Node: " + std::to_string(nodeNum) + "," +
1032c056dc00SManikandan Elumalai                   " Card: " + std::to_string(chNum) + "," +
1033c056dc00SManikandan Elumalai                   " Module: " + std::to_string(dimmNum) + "," +
1034c056dc00SManikandan Elumalai                   " Rank Number: " + std::to_string(rankNum) + "," +
1035c056dc00SManikandan Elumalai                   " Location: DIMM C0 ";
1036c056dc00SManikandan Elumalai     }
1037c056dc00SManikandan Elumalai     else if (chNum == 5 && dimmNum == 0)
1038c056dc00SManikandan Elumalai     {
1039c056dc00SManikandan Elumalai         errStr += " Node: " + std::to_string(nodeNum) + "," +
1040c056dc00SManikandan Elumalai                   " Card: " + std::to_string(chNum) + "," +
1041c056dc00SManikandan Elumalai                   " Module: " + std::to_string(dimmNum) + "," +
1042c056dc00SManikandan Elumalai                   " Rank Number: " + std::to_string(rankNum) + "," +
1043c056dc00SManikandan Elumalai                   " Location: DIMM D0";
1044c056dc00SManikandan Elumalai     }
1045c056dc00SManikandan Elumalai     else
1046c056dc00SManikandan Elumalai     {
1047c056dc00SManikandan Elumalai         errStr += " Node: " + std::to_string(nodeNum) + "," +
1048c056dc00SManikandan Elumalai                   " Card: " + std::to_string(chNum) + "," +
1049c056dc00SManikandan Elumalai                   " Module: " + std::to_string(dimmNum) + "," +
1050c056dc00SManikandan Elumalai                   " Rank Number: " + std::to_string(rankNum) + "," +
1051519530beSManojkiran Eda                   " Location: DIMM Unknown";
1052c056dc00SManikandan Elumalai     }
1053c056dc00SManikandan Elumalai }
1054c056dc00SManikandan Elumalai 
parseStdSel(StdSELEntry * data,std::string & errStr)1055f36f345fSVijay Khemka static void parseStdSel(StdSELEntry* data, std::string& errStr)
1056f36f345fSVijay Khemka {
1057f36f345fSVijay Khemka     std::stringstream tmpStream;
1058f36f345fSVijay Khemka     tmpStream << std::hex << std::uppercase;
1059f36f345fSVijay Khemka 
1060f36f345fSVijay Khemka     /* TODO: add pal_add_cri_sel */
1061f36f345fSVijay Khemka     switch (data->sensorNum)
1062f36f345fSVijay Khemka     {
1063f36f345fSVijay Khemka         case memoryEccError:
1064f36f345fSVijay Khemka             switch (data->eventData1 & 0x0F)
1065f36f345fSVijay Khemka             {
1066f36f345fSVijay Khemka                 case 0x00:
1067f36f345fSVijay Khemka                     errStr = "Correctable";
1068f36f345fSVijay Khemka                     tmpStream << "DIMM" << std::setw(2) << std::setfill('0')
1069f36f345fSVijay Khemka                               << data->eventData3 << " ECC err";
1070c056dc00SManikandan Elumalai                     parseDimmPhyloc(data, errStr);
1071f36f345fSVijay Khemka                     break;
1072f36f345fSVijay Khemka                 case 0x01:
1073f36f345fSVijay Khemka                     errStr = "Uncorrectable";
1074f36f345fSVijay Khemka                     tmpStream << "DIMM" << std::setw(2) << std::setfill('0')
1075f36f345fSVijay Khemka                               << data->eventData3 << " UECC err";
1076c056dc00SManikandan Elumalai                     parseDimmPhyloc(data, errStr);
1077f36f345fSVijay Khemka                     break;
1078f36f345fSVijay Khemka                 case 0x02:
1079f36f345fSVijay Khemka                     errStr = "Parity";
1080f36f345fSVijay Khemka                     break;
1081f36f345fSVijay Khemka                 case 0x05:
1082f36f345fSVijay Khemka                     errStr = "Correctable ECC error Logging Limit Reached";
1083f36f345fSVijay Khemka                     break;
1084f36f345fSVijay Khemka                 default:
1085f36f345fSVijay Khemka                     errStr = "Unknown";
1086f36f345fSVijay Khemka             }
1087f36f345fSVijay Khemka             break;
1088f36f345fSVijay Khemka         case memoryErrLogDIS:
1089f36f345fSVijay Khemka             if ((data->eventData1 & 0x0F) == 0)
1090f36f345fSVijay Khemka             {
1091f36f345fSVijay Khemka                 errStr = "Correctable Memory Error Logging Disabled";
1092f36f345fSVijay Khemka             }
1093f36f345fSVijay Khemka             else
1094f36f345fSVijay Khemka             {
1095f36f345fSVijay Khemka                 errStr = "Unknown";
1096f36f345fSVijay Khemka             }
1097f36f345fSVijay Khemka             break;
1098f36f345fSVijay Khemka         default:
1099139aa4f0SVijay Khemka             parseSelHelper(data, errStr);
1100f36f345fSVijay Khemka             return;
1101f36f345fSVijay Khemka     }
1102f36f345fSVijay Khemka 
1103f36f345fSVijay Khemka     errStr += " (DIMM " + std::to_string(data->eventData3) + ")";
1104f36f345fSVijay Khemka     errStr += " Logical Rank " + std::to_string(data->eventData2 & 0x03);
1105f36f345fSVijay Khemka 
1106f36f345fSVijay Khemka     switch ((data->eventData2 & 0x0C) >> 2)
1107f36f345fSVijay Khemka     {
1108f36f345fSVijay Khemka         case 0x00:
1109f36f345fSVijay Khemka             // Ignore when " All info available"
1110f36f345fSVijay Khemka             break;
1111f36f345fSVijay Khemka         case 0x01:
1112f36f345fSVijay Khemka             errStr += " DIMM info not valid";
1113f36f345fSVijay Khemka             break;
1114f36f345fSVijay Khemka         case 0x02:
1115f36f345fSVijay Khemka             errStr += " CHN info not valid";
1116f36f345fSVijay Khemka             break;
1117f36f345fSVijay Khemka         case 0x03:
1118f36f345fSVijay Khemka             errStr += " CPU info not valid";
1119f36f345fSVijay Khemka             break;
1120f36f345fSVijay Khemka         default:
1121f36f345fSVijay Khemka             errStr += " Unknown";
1122f36f345fSVijay Khemka     }
1123f36f345fSVijay Khemka 
1124f36f345fSVijay Khemka     if (((data->eventType & 0x80) >> 7) == 0)
1125f36f345fSVijay Khemka     {
1126f36f345fSVijay Khemka         errStr += " Assertion";
1127f36f345fSVijay Khemka     }
1128f36f345fSVijay Khemka     else
1129f36f345fSVijay Khemka     {
1130f36f345fSVijay Khemka         errStr += " Deassertion";
1131f36f345fSVijay Khemka     }
1132f36f345fSVijay Khemka 
1133f36f345fSVijay Khemka     return;
1134f36f345fSVijay Khemka }
1135f36f345fSVijay Khemka 
parseOemSel(TsOemSELEntry * data,std::string & errStr)1136f36f345fSVijay Khemka static void parseOemSel(TsOemSELEntry* data, std::string& errStr)
1137f36f345fSVijay Khemka {
1138f36f345fSVijay Khemka     std::stringstream tmpStream;
1139f36f345fSVijay Khemka     tmpStream << std::hex << std::uppercase << std::setfill('0');
1140f36f345fSVijay Khemka 
1141f36f345fSVijay Khemka     switch (data->recordType)
1142f36f345fSVijay Khemka     {
1143f36f345fSVijay Khemka         case 0xC0:
1144f36f345fSVijay Khemka             tmpStream << "VID:0x" << std::setw(2) << (int)data->oemData[1]
1145f36f345fSVijay Khemka                       << std::setw(2) << (int)data->oemData[0] << " DID:0x"
1146f36f345fSVijay Khemka                       << std::setw(2) << (int)data->oemData[3] << std::setw(2)
1147f36f345fSVijay Khemka                       << (int)data->oemData[2] << " Slot:0x" << std::setw(2)
1148f36f345fSVijay Khemka                       << (int)data->oemData[4] << " Error ID:0x" << std::setw(2)
1149f36f345fSVijay Khemka                       << (int)data->oemData[5];
1150f36f345fSVijay Khemka             break;
1151f36f345fSVijay Khemka         case 0xC2:
1152f36f345fSVijay Khemka             tmpStream << "Extra info:0x" << std::setw(2)
1153f36f345fSVijay Khemka                       << (int)data->oemData[1] << " MSCOD:0x" << std::setw(2)
1154f36f345fSVijay Khemka                       << (int)data->oemData[3] << std::setw(2)
1155f36f345fSVijay Khemka                       << (int)data->oemData[2] << " MCACOD:0x" << std::setw(2)
1156f36f345fSVijay Khemka                       << (int)data->oemData[5] << std::setw(2)
1157f36f345fSVijay Khemka                       << (int)data->oemData[4];
1158f36f345fSVijay Khemka             break;
1159f36f345fSVijay Khemka         case 0xC3:
1160f36f345fSVijay Khemka             int bank = (data->oemData[1] & 0xf0) >> 4;
1161f36f345fSVijay Khemka             int col = ((data->oemData[1] & 0x0f) << 8) | data->oemData[2];
1162f36f345fSVijay Khemka 
1163f36f345fSVijay Khemka             tmpStream << "Fail Device:0x" << std::setw(2)
1164f36f345fSVijay Khemka                       << (int)data->oemData[0] << " Bank:0x" << std::setw(2)
1165f36f345fSVijay Khemka                       << bank << " Column:0x" << std::setw(2) << col
1166f36f345fSVijay Khemka                       << " Failed Row:0x" << std::setw(2)
1167f36f345fSVijay Khemka                       << (int)data->oemData[3] << std::setw(2)
1168f36f345fSVijay Khemka                       << (int)data->oemData[4] << std::setw(2)
1169f36f345fSVijay Khemka                       << (int)data->oemData[5];
1170f36f345fSVijay Khemka     }
1171f36f345fSVijay Khemka 
1172f36f345fSVijay Khemka     errStr = tmpStream.str();
1173f36f345fSVijay Khemka 
1174f36f345fSVijay Khemka     return;
1175f36f345fSVijay Khemka }
1176f36f345fSVijay Khemka 
dimmLocationStr(uint8_t socket,uint8_t channel,uint8_t slot)11777451903cScchoux static std::string dimmLocationStr(uint8_t socket, uint8_t channel,
11787451903cScchoux                                    uint8_t slot)
11797451903cScchoux {
11807451903cScchoux     uint8_t sled = (socket >> 4) & 0x3;
11817451903cScchoux 
11827451903cScchoux     socket &= 0xf;
11837451903cScchoux     if (channel == 0xFF && slot == 0xFF)
11847451903cScchoux     {
11857451903cScchoux         return std::format(
11867451903cScchoux             "DIMM Slot Location: Sled {:02}/Socket {:02}, Channel unknown"
11877451903cScchoux             ", Slot unknown, DIMM unknown",
11887451903cScchoux             sled, socket);
11897451903cScchoux     }
11907451903cScchoux     else
11917451903cScchoux     {
11927451903cScchoux         channel &= 0xf;
11937451903cScchoux         slot &= 0xf;
11947451903cScchoux         const char label[] = {'A', 'C', 'B', 'D'};
11957451903cScchoux         uint8_t idx = socket * 2 + slot;
11967451903cScchoux         return std::format("DIMM Slot Location: Sled {:02}/Socket {:02}"
11977451903cScchoux                            ", Channel {:02}, Slot {:02} DIMM {}",
11987451903cScchoux                            sled, socket, channel, slot,
11997451903cScchoux                            (idx < sizeof(label))
12007451903cScchoux                                ? label[idx] + std::to_string(channel)
12017451903cScchoux                                : "NA");
12027451903cScchoux     }
12037451903cScchoux }
12047451903cScchoux 
parseOemUnifiedSel(NtsOemSELEntry * data,std::string & errStr)120534a875f3SVijay Khemka static void parseOemUnifiedSel(NtsOemSELEntry* data, std::string& errStr)
120634a875f3SVijay Khemka {
120734a875f3SVijay Khemka     uint8_t* ptr = data->oemData;
12087451903cScchoux     uint8_t eventType = ptr[5] & 0xf;
120934a875f3SVijay Khemka     int genInfo = ptr[0];
121034a875f3SVijay Khemka     int errType = genInfo & 0x0f;
12117451903cScchoux     std::vector<std::string> dimmErr = {
12127451903cScchoux         "Memory training failure",
12137451903cScchoux         "Memory correctable error",
12147451903cScchoux         "Memory uncorrectable error",
12157451903cScchoux         "Memory correctable error (Patrol scrub)",
12167451903cScchoux         "Memory uncorrectable error (Patrol scrub)",
12177451903cScchoux         "Memory Parity Error (PCC=0)",
12187451903cScchoux         "Memory Parity Error (PCC=1)",
12197451903cScchoux         "Memory PMIC Error",
12207451903cScchoux         "CXL Memory training error",
12217451903cScchoux         "Reserved"};
12227451903cScchoux     std::vector<std::string> postEvent = {
12237451903cScchoux         "System PXE boot fail",
12247451903cScchoux         "CMOS/NVRAM configuration cleared",
12257451903cScchoux         "TPM Self-Test Fail",
12267451903cScchoux         "Boot Drive failure",
12277451903cScchoux         "Data Drive failure",
12287451903cScchoux         "Received invalid boot order request from BMC",
12297451903cScchoux         "System HTTP boot fail",
12307451903cScchoux         "BIOS fails to get the certificate from BMC",
12317451903cScchoux         "Password cleared by jumper",
12327451903cScchoux         "DXE FV check failure",
12337451903cScchoux         "AMD ABL failure",
12347451903cScchoux         "Reserved"};
12357451903cScchoux     std::vector<std::string> certErr = {
12367451903cScchoux         "No certificate at BMC", "IPMI transaction fail",
12377451903cScchoux         "Certificate data corrupted", "Reserved"};
1238010dee04SPatrick Williams     std::vector<std::string> pcieEvent = {
1239010dee04SPatrick Williams         "PCIe DPC Event",
12407451903cScchoux         "PCIe LER Event",
12417451903cScchoux         "PCIe Link Retraining and Recovery",
12427451903cScchoux         "PCIe Link CRC Error Check and Retry",
12437451903cScchoux         "PCIe Corrupt Data Containment",
12447451903cScchoux         "PCIe Express ECRC",
12457451903cScchoux         "Reserved"};
12467451903cScchoux     std::vector<std::string> memEvent = {
12477451903cScchoux         "Memory PPR event",
12487451903cScchoux         "Memory Correctable Error logging limit reached",
12497451903cScchoux         "Memory disable/map-out for FRB",
12507451903cScchoux         "Memory SDDC",
12517451903cScchoux         "Memory Address range/Partial mirroring",
12527451903cScchoux         "Memory ADDDC",
12537451903cScchoux         "Memory SMBus hang recovery",
12547451903cScchoux         "No DIMM in System",
12557451903cScchoux         "Reserved"};
12567451903cScchoux     std::vector<std::string> memPprTime = {"Boot time", "Autonomous",
12577451903cScchoux                                            "Run time", "Reserved"};
12587451903cScchoux     std::vector<std::string> memPpr = {"PPR success", "PPR fail", "PPR request",
12597451903cScchoux                                        "Reserved"};
1260010dee04SPatrick Williams     std::vector<std::string> memAdddc = {
1261010dee04SPatrick Williams         "Bank VLS", "r-Bank VLS + re-buddy", "r-Bank VLS + Rank VLS",
12627451903cScchoux         "r-Rank VLS + re-buddy", "Reserved"};
12637451903cScchoux     std::vector<std::string> pprEvent = {"PPR disable", "Soft PPR", "Hard PPR",
12647451903cScchoux                                          "Reserved"};
126534a875f3SVijay Khemka 
126634a875f3SVijay Khemka     std::stringstream tmpStream;
126734a875f3SVijay Khemka 
126834a875f3SVijay Khemka     switch (errType)
126934a875f3SVijay Khemka     {
127034a875f3SVijay Khemka         case unifiedPcieErr:
12717451903cScchoux             tmpStream << std::format(
12727451903cScchoux                 "GeneralInfo: x86/PCIeErr(0x{:02X})"
12737451903cScchoux                 ", Bus {:02X}/Dev {:02X}/Fun {:02X}, TotalErrID1Cnt: 0x{:04X}"
12747451903cScchoux                 ", ErrID2: 0x{:02X}, ErrID1: 0x{:02X}",
12757451903cScchoux                 genInfo, ptr[8], ptr[7] >> 3, ptr[7] & 0x7,
12767451903cScchoux                 (ptr[10] << 8) | ptr[9], ptr[11], ptr[12]);
127734a875f3SVijay Khemka             break;
127834a875f3SVijay Khemka         case unifiedMemErr:
12797451903cScchoux             eventType = ptr[9] & 0xf;
12807451903cScchoux             tmpStream << std::format(
12817451903cScchoux                 "GeneralInfo: MemErr(0x{:02X}), {}, DIMM Failure Event: {}",
12827451903cScchoux                 genInfo, dimmLocationStr(ptr[5], ptr[6], ptr[7]),
12837451903cScchoux                 dimmErr[std::min(eventType,
12847451903cScchoux                                  static_cast<uint8_t>(dimmErr.size() - 1))]);
128534a875f3SVijay Khemka 
12867451903cScchoux             if (static_cast<MemErrType>(eventType) == MemErrType::memTrainErr ||
12877451903cScchoux                 static_cast<MemErrType>(eventType) == MemErrType::memPmicErr)
12887451903cScchoux             {
12897451903cScchoux                 bool amd = ptr[9] & 0x80;
12907451903cScchoux                 tmpStream << std::format(
12917451903cScchoux                     ", Major Code: 0x{:02X}, Minor Code: 0x{:0{}X}", ptr[10],
12927451903cScchoux                     amd ? (ptr[12] << 8 | ptr[11]) : ptr[11], amd ? 4 : 2);
12937451903cScchoux             }
12947451903cScchoux             break;
12957451903cScchoux         case unifiedIioErr:
12967451903cScchoux             tmpStream << std::format(
12977451903cScchoux                 "GeneralInfo: IIOErr(0x{:02X})"
12987451903cScchoux                 ", IIO Port Location: Sled {:02}/Socket {:02}, Stack 0x{:02X}"
12997451903cScchoux                 ", Error Type: 0x{:02X}, Error Severity: 0x{:02X}"
13007451903cScchoux                 ", Error ID: 0x{:02X}",
13017451903cScchoux                 genInfo, (ptr[5] >> 4) & 0x3, ptr[5] & 0xf, ptr[6], ptr[10],
13027451903cScchoux                 ptr[11] & 0xf, ptr[12]);
13037451903cScchoux             break;
13047451903cScchoux         case unifiedPostEvt:
13057451903cScchoux             tmpStream << std::format(
13067451903cScchoux                 "GeneralInfo: POST(0x{:02X}), POST Failure Event: {}", genInfo,
13077451903cScchoux                 postEvent[std::min(
13087451903cScchoux                     eventType, static_cast<uint8_t>(postEvent.size() - 1))]);
13097451903cScchoux 
13107451903cScchoux             switch (static_cast<PostEvtType>(eventType))
13117451903cScchoux             {
13127451903cScchoux                 case PostEvtType::pxeBootFail:
13137451903cScchoux                 case PostEvtType::httpBootFail:
13147451903cScchoux                 {
13157451903cScchoux                     uint8_t failType = ptr[10] & 0xf;
13167451903cScchoux                     tmpStream
13177451903cScchoux                         << std::format(", Fail Type: {}, Error Code: 0x{:02X}",
13187451903cScchoux                                        (failType == 4 || failType == 6)
13197451903cScchoux                                            ? std::format("IPv{} fail", failType)
13207451903cScchoux                                            : std::format("0x{:02X}", ptr[10]),
13217451903cScchoux                                        ptr[11]);
13227451903cScchoux                     break;
13237451903cScchoux                 }
13247451903cScchoux                 case PostEvtType::getCertFail:
13257451903cScchoux                     tmpStream << std::format(
13267451903cScchoux                         ", Failure Detail: {}",
13277451903cScchoux                         certErr[std::min(
13287451903cScchoux                             ptr[9], static_cast<uint8_t>(certErr.size() - 1))]);
13297451903cScchoux                     break;
13307451903cScchoux                 case PostEvtType::amdAblFail:
13317451903cScchoux                     tmpStream << std::format(", ABL Error Code: 0x{:04X}",
13327451903cScchoux                                              (ptr[12] << 8) | ptr[11]);
13337451903cScchoux                     break;
13347451903cScchoux             }
13357451903cScchoux             break;
13367451903cScchoux         case unifiedPcieEvt:
13377451903cScchoux             tmpStream << std::format(
13387451903cScchoux                 "GeneralInfo: PCIeEvent(0x{:02X}), PCIe Failure Event: {}",
13397451903cScchoux                 genInfo,
13407451903cScchoux                 pcieEvent[std::min(
13417451903cScchoux                     eventType, static_cast<uint8_t>(pcieEvent.size() - 1))]);
13427451903cScchoux 
13437451903cScchoux             if (static_cast<PcieEvtType>(eventType) == PcieEvtType::dpc)
13447451903cScchoux             {
13457451903cScchoux                 tmpStream << std::format(
13467451903cScchoux                     ", Status: 0x{:04X}, Source ID: 0x{:04X}",
13477451903cScchoux                     (ptr[8] << 8) | ptr[7], (ptr[10] << 8) | ptr[9]);
13487451903cScchoux             }
13497451903cScchoux             break;
13507451903cScchoux         case unifiedMemEvt:
13517451903cScchoux             eventType = ptr[9] & 0xf;
1352010dee04SPatrick Williams             tmpStream
1353010dee04SPatrick Williams                 << std::format("GeneralInfo: MemEvent(0x{:02X})", genInfo)
1354010dee04SPatrick Williams                 << (static_cast<MemEvtType>(eventType) != MemEvtType::noDimm
1355010dee04SPatrick Williams                         ? std::format(", {}",
1356010dee04SPatrick Williams                                       dimmLocationStr(ptr[5], ptr[6], ptr[7]))
13577451903cScchoux                         : "")
13587451903cScchoux                 << ", DIMM Failure Event: ";
13597451903cScchoux 
13607451903cScchoux             switch (static_cast<MemEvtType>(eventType))
13617451903cScchoux             {
13627451903cScchoux                 case MemEvtType::ppr:
13637451903cScchoux                     tmpStream << std::format("{} {}",
13647451903cScchoux                                              memPprTime[(ptr[10] >> 2) & 0x3],
13657451903cScchoux                                              memPpr[ptr[10] & 0x3]);
13667451903cScchoux                     break;
13677451903cScchoux                 case MemEvtType::adddc:
13687451903cScchoux                     tmpStream << std::format(
13697451903cScchoux                         "{} {}",
13707451903cScchoux                         memEvent[std::min(eventType, static_cast<uint8_t>(
13717451903cScchoux                                                          memEvent.size() - 1))],
13727451903cScchoux                         memAdddc[std::min(
13737451903cScchoux                             static_cast<uint8_t>(ptr[11] & 0xf),
13747451903cScchoux                             static_cast<uint8_t>(memAdddc.size() - 1))]);
13757451903cScchoux                     break;
13767451903cScchoux                 default:
13777451903cScchoux                     tmpStream << std::format(
13787451903cScchoux                         "{}", memEvent[std::min(
13797451903cScchoux                                   eventType,
13807451903cScchoux                                   static_cast<uint8_t>(memEvent.size() - 1))]);
13817451903cScchoux                     break;
13827451903cScchoux             }
13837451903cScchoux             break;
13847451903cScchoux         case unifiedBootGuard:
13857451903cScchoux             tmpStream << std::format(
13867451903cScchoux                 "GeneralInfo: Boot Guard ACM Failure Events(0x{:02X})"
13877451903cScchoux                 ", Error Class: 0x{:02X}, Error Code: 0x{:02X}",
13887451903cScchoux                 genInfo, ptr[9], ptr[10]);
13897451903cScchoux             break;
13907451903cScchoux         case unifiedPprEvt:
13917451903cScchoux             tmpStream << std::format(
13927451903cScchoux                 "GeneralInfo: PPREvent(0x{:02X}), {}"
13937451903cScchoux                 ", DIMM Info: {:02X}{:02X}{:02X}{:02X}{:02X}{:02X}{:02X}",
13947451903cScchoux                 genInfo,
13957451903cScchoux                 pprEvent[std::min(eventType,
13967451903cScchoux                                   static_cast<uint8_t>(pprEvent.size() - 1))],
13977451903cScchoux                 ptr[6], ptr[7], ptr[8], ptr[9], ptr[10], ptr[11], ptr[12]);
139834a875f3SVijay Khemka             break;
139934a875f3SVijay Khemka         default:
140034a875f3SVijay Khemka             std::vector<uint8_t> oemData(ptr, ptr + 13);
140134a875f3SVijay Khemka             std::string oemDataStr;
140234a875f3SVijay Khemka             toHexStr(oemData, oemDataStr);
14037451903cScchoux             tmpStream << std::format("Undefined Error Type(0x{:02X}), Raw: {}",
14047451903cScchoux                                      errType, oemDataStr);
140534a875f3SVijay Khemka     }
140634a875f3SVijay Khemka 
140734a875f3SVijay Khemka     errStr = tmpStream.str();
140834a875f3SVijay Khemka 
140934a875f3SVijay Khemka     return;
141034a875f3SVijay Khemka }
141134a875f3SVijay Khemka 
parseSelData(uint8_t fruId,std::vector<uint8_t> & reqData,std::string & msgLog)1412c056dc00SManikandan Elumalai static void parseSelData(uint8_t fruId, std::vector<uint8_t>& reqData,
1413c056dc00SManikandan Elumalai                          std::string& msgLog)
1414f36f345fSVijay Khemka {
1415f36f345fSVijay Khemka     /* Get record type */
1416f36f345fSVijay Khemka     int recType = reqData[2];
1417f36f345fSVijay Khemka     std::string errType, errLog;
1418f36f345fSVijay Khemka 
1419f36f345fSVijay Khemka     uint8_t* ptr = NULL;
1420f36f345fSVijay Khemka 
1421f36f345fSVijay Khemka     std::stringstream recTypeStream;
1422f36f345fSVijay Khemka     recTypeStream << std::hex << std::uppercase << std::setfill('0')
1423f36f345fSVijay Khemka                   << std::setw(2) << recType;
1424f36f345fSVijay Khemka 
1425c056dc00SManikandan Elumalai     msgLog = "SEL Entry: FRU: " + std::to_string(fruId) + ", Record: ";
1426f36f345fSVijay Khemka 
1427f36f345fSVijay Khemka     if (recType == stdErrType)
1428f36f345fSVijay Khemka     {
1429f36f345fSVijay Khemka         StdSELEntry* data = reinterpret_cast<StdSELEntry*>(&reqData[0]);
1430f36f345fSVijay Khemka         std::string sensorName;
1431f36f345fSVijay Khemka 
1432f36f345fSVijay Khemka         errType = stdErr;
1433f36f345fSVijay Khemka         if (data->sensorType == 0x1F)
1434f36f345fSVijay Khemka         {
1435f36f345fSVijay Khemka             sensorName = "OS";
1436f36f345fSVijay Khemka         }
1437f36f345fSVijay Khemka         else
1438f36f345fSVijay Khemka         {
1439f36f345fSVijay Khemka             auto findSensorName = sensorNameTable.find(data->sensorNum);
1440f36f345fSVijay Khemka             if (findSensorName == sensorNameTable.end())
1441f36f345fSVijay Khemka             {
1442f36f345fSVijay Khemka                 sensorName = "Unknown";
1443f36f345fSVijay Khemka             }
1444f36f345fSVijay Khemka             else
1445f36f345fSVijay Khemka             {
1446139aa4f0SVijay Khemka                 sensorName = findSensorName->second.first;
1447f36f345fSVijay Khemka             }
1448f36f345fSVijay Khemka         }
1449f36f345fSVijay Khemka 
1450f36f345fSVijay Khemka         parseStdSel(data, errLog);
1451f36f345fSVijay Khemka         ptr = &(data->eventData1);
1452f36f345fSVijay Khemka         std::vector<uint8_t> evtData(ptr, ptr + 3);
1453f36f345fSVijay Khemka         std::string eventData;
1454f36f345fSVijay Khemka         toHexStr(evtData, eventData);
1455f36f345fSVijay Khemka 
1456f36f345fSVijay Khemka         std::stringstream senNumStream;
1457f36f345fSVijay Khemka         senNumStream << std::hex << std::uppercase << std::setfill('0')
1458f36f345fSVijay Khemka                      << std::setw(2) << (int)(data->sensorNum);
1459f36f345fSVijay Khemka 
1460f36f345fSVijay Khemka         msgLog += errType + " (0x" + recTypeStream.str() +
14610d053effSPeter Yin                   "), Sensor: " + sensorName + " (0x" + senNumStream.str() +
14620d053effSPeter Yin                   "), Event Data: (" + eventData + ") " + errLog;
1463f36f345fSVijay Khemka     }
1464f36f345fSVijay Khemka     else if ((recType >= oemTSErrTypeMin) && (recType <= oemTSErrTypeMax))
1465f36f345fSVijay Khemka     {
1466f36f345fSVijay Khemka         /* timestamped OEM SEL records */
1467f36f345fSVijay Khemka         TsOemSELEntry* data = reinterpret_cast<TsOemSELEntry*>(&reqData[0]);
1468f36f345fSVijay Khemka         ptr = data->mfrId;
1469f36f345fSVijay Khemka         std::vector<uint8_t> mfrIdData(ptr, ptr + 3);
1470f36f345fSVijay Khemka         std::string mfrIdStr;
1471f36f345fSVijay Khemka         toHexStr(mfrIdData, mfrIdStr);
1472f36f345fSVijay Khemka 
1473f36f345fSVijay Khemka         ptr = data->oemData;
1474f36f345fSVijay Khemka         std::vector<uint8_t> oemData(ptr, ptr + 6);
1475f36f345fSVijay Khemka         std::string oemDataStr;
1476f36f345fSVijay Khemka         toHexStr(oemData, oemDataStr);
1477f36f345fSVijay Khemka 
1478f36f345fSVijay Khemka         errType = oemTSErr;
1479f36f345fSVijay Khemka         parseOemSel(data, errLog);
1480f36f345fSVijay Khemka 
14810d053effSPeter Yin         msgLog += errType + " (0x" + recTypeStream.str() + "), MFG ID: " +
14820d053effSPeter Yin                   mfrIdStr + ", OEM Data: (" + oemDataStr + ") " + errLog;
1483f36f345fSVijay Khemka     }
148434a875f3SVijay Khemka     else if (recType == fbUniErrType)
148534a875f3SVijay Khemka     {
148634a875f3SVijay Khemka         NtsOemSELEntry* data = reinterpret_cast<NtsOemSELEntry*>(&reqData[0]);
148734a875f3SVijay Khemka         errType = fbUniSELErr;
148834a875f3SVijay Khemka         parseOemUnifiedSel(data, errLog);
148934a875f3SVijay Khemka         msgLog += errType + " (0x" + recTypeStream.str() + "), " + errLog;
149034a875f3SVijay Khemka     }
1491f36f345fSVijay Khemka     else if ((recType >= oemNTSErrTypeMin) && (recType <= oemNTSErrTypeMax))
1492f36f345fSVijay Khemka     {
1493f36f345fSVijay Khemka         /* Non timestamped OEM SEL records */
1494f36f345fSVijay Khemka         NtsOemSELEntry* data = reinterpret_cast<NtsOemSELEntry*>(&reqData[0]);
1495f36f345fSVijay Khemka         errType = oemNTSErr;
1496f36f345fSVijay Khemka 
1497f36f345fSVijay Khemka         ptr = data->oemData;
1498f36f345fSVijay Khemka         std::vector<uint8_t> oemData(ptr, ptr + 13);
1499f36f345fSVijay Khemka         std::string oemDataStr;
1500f36f345fSVijay Khemka         toHexStr(oemData, oemDataStr);
1501f36f345fSVijay Khemka 
1502f36f345fSVijay Khemka         parseOemSel((TsOemSELEntry*)data, errLog);
1503f36f345fSVijay Khemka         msgLog += errType + " (0x" + recTypeStream.str() + "), OEM Data: (" +
1504f36f345fSVijay Khemka                   oemDataStr + ") " + errLog;
1505f36f345fSVijay Khemka     }
1506f36f345fSVijay Khemka     else
1507f36f345fSVijay Khemka     {
1508f36f345fSVijay Khemka         errType = unknownErr;
1509f36f345fSVijay Khemka         toHexStr(reqData, errLog);
15102405ae98SPatrick Williams         msgLog += errType + " (0x" + recTypeStream.str() +
15112405ae98SPatrick Williams                   ") RawData: " + errLog;
1512f36f345fSVijay Khemka     }
1513f36f345fSVijay Khemka }
1514f36f345fSVijay Khemka 
151511b9c3b1SVijay Khemka } // namespace fb_oem::ipmi::sel
151611b9c3b1SVijay Khemka 
151711b9c3b1SVijay Khemka namespace ipmi
151811b9c3b1SVijay Khemka {
151911b9c3b1SVijay Khemka 
152011b9c3b1SVijay Khemka namespace storage
152111b9c3b1SVijay Khemka {
152211b9c3b1SVijay Khemka 
152311b9c3b1SVijay Khemka static void registerSELFunctions() __attribute__((constructor));
152411b9c3b1SVijay Khemka static fb_oem::ipmi::sel::SELData selObj __attribute__((init_priority(101)));
152511b9c3b1SVijay Khemka 
152611b9c3b1SVijay Khemka ipmi::RspType<uint8_t,  // SEL version
152711b9c3b1SVijay Khemka               uint16_t, // SEL entry count
152811b9c3b1SVijay Khemka               uint16_t, // free space
152911b9c3b1SVijay Khemka               uint32_t, // last add timestamp
153011b9c3b1SVijay Khemka               uint32_t, // last erase timestamp
153111b9c3b1SVijay Khemka               uint8_t>  // operation support
ipmiStorageGetSELInfo()153211b9c3b1SVijay Khemka     ipmiStorageGetSELInfo()
153311b9c3b1SVijay Khemka {
153411b9c3b1SVijay Khemka     fb_oem::ipmi::sel::GetSELInfoData info;
153511b9c3b1SVijay Khemka 
153611b9c3b1SVijay Khemka     selObj.getInfo(info);
153711b9c3b1SVijay Khemka     return ipmi::responseSuccess(info.selVersion, info.entries, info.freeSpace,
153811b9c3b1SVijay Khemka                                  info.addTimeStamp, info.eraseTimeStamp,
153911b9c3b1SVijay Khemka                                  info.operationSupport);
154011b9c3b1SVijay Khemka }
154111b9c3b1SVijay Khemka 
154211b9c3b1SVijay Khemka ipmi::RspType<uint16_t, std::vector<uint8_t>>
ipmiStorageGetSELEntry(std::vector<uint8_t> data)154311b9c3b1SVijay Khemka     ipmiStorageGetSELEntry(std::vector<uint8_t> data)
154411b9c3b1SVijay Khemka {
154511b9c3b1SVijay Khemka     if (data.size() != sizeof(fb_oem::ipmi::sel::GetSELEntryRequest))
154611b9c3b1SVijay Khemka     {
154711b9c3b1SVijay Khemka         return ipmi::responseReqDataLenInvalid();
154811b9c3b1SVijay Khemka     }
154911b9c3b1SVijay Khemka 
155011b9c3b1SVijay Khemka     fb_oem::ipmi::sel::GetSELEntryRequest* reqData =
155111b9c3b1SVijay Khemka         reinterpret_cast<fb_oem::ipmi::sel::GetSELEntryRequest*>(&data[0]);
155211b9c3b1SVijay Khemka 
155311b9c3b1SVijay Khemka     if (reqData->reservID != 0)
155411b9c3b1SVijay Khemka     {
155511b9c3b1SVijay Khemka         if (!checkSELReservation(reqData->reservID))
155611b9c3b1SVijay Khemka         {
155711b9c3b1SVijay Khemka             return ipmi::responseInvalidReservationId();
155811b9c3b1SVijay Khemka         }
155911b9c3b1SVijay Khemka     }
156011b9c3b1SVijay Khemka 
156111b9c3b1SVijay Khemka     uint16_t selCnt = selObj.getCount();
156211b9c3b1SVijay Khemka     if (selCnt == 0)
156311b9c3b1SVijay Khemka     {
156411b9c3b1SVijay Khemka         return ipmi::responseSensorInvalid();
156511b9c3b1SVijay Khemka     }
156611b9c3b1SVijay Khemka 
156711b9c3b1SVijay Khemka     /* If it is asked for first entry */
156811b9c3b1SVijay Khemka     if (reqData->recordID == fb_oem::ipmi::sel::firstEntry)
156911b9c3b1SVijay Khemka     {
157011b9c3b1SVijay Khemka         /* First Entry (0x0000) as per Spec */
157111b9c3b1SVijay Khemka         reqData->recordID = 1;
157211b9c3b1SVijay Khemka     }
157311b9c3b1SVijay Khemka     else if (reqData->recordID == fb_oem::ipmi::sel::lastEntry)
157411b9c3b1SVijay Khemka     {
157511b9c3b1SVijay Khemka         /* Last entry (0xFFFF) as per Spec */
157611b9c3b1SVijay Khemka         reqData->recordID = selCnt;
157711b9c3b1SVijay Khemka     }
157811b9c3b1SVijay Khemka 
157911b9c3b1SVijay Khemka     std::string ipmiRaw;
158011b9c3b1SVijay Khemka 
158111b9c3b1SVijay Khemka     if (selObj.getEntry(reqData->recordID, ipmiRaw) < 0)
158211b9c3b1SVijay Khemka     {
158311b9c3b1SVijay Khemka         return ipmi::responseSensorInvalid();
158411b9c3b1SVijay Khemka     }
158511b9c3b1SVijay Khemka 
158611b9c3b1SVijay Khemka     std::vector<uint8_t> recDataBytes;
158711b9c3b1SVijay Khemka     if (fromHexStr(ipmiRaw, recDataBytes) < 0)
158811b9c3b1SVijay Khemka     {
158911b9c3b1SVijay Khemka         return ipmi::responseUnspecifiedError();
159011b9c3b1SVijay Khemka     }
159111b9c3b1SVijay Khemka 
159211b9c3b1SVijay Khemka     /* Identify the next SEL record ID. If recordID is same as
159311b9c3b1SVijay Khemka      * total SeL count then next id should be last entry else
159411b9c3b1SVijay Khemka      * it should be incremented by 1 to current RecordID
159511b9c3b1SVijay Khemka      */
159611b9c3b1SVijay Khemka     uint16_t nextRecord;
159711b9c3b1SVijay Khemka     if (reqData->recordID == selCnt)
159811b9c3b1SVijay Khemka     {
159911b9c3b1SVijay Khemka         nextRecord = fb_oem::ipmi::sel::lastEntry;
160011b9c3b1SVijay Khemka     }
160111b9c3b1SVijay Khemka     else
160211b9c3b1SVijay Khemka     {
160311b9c3b1SVijay Khemka         nextRecord = reqData->recordID + 1;
160411b9c3b1SVijay Khemka     }
160511b9c3b1SVijay Khemka 
160611b9c3b1SVijay Khemka     if (reqData->readLen == fb_oem::ipmi::sel::entireRecord)
160711b9c3b1SVijay Khemka     {
160811b9c3b1SVijay Khemka         return ipmi::responseSuccess(nextRecord, recDataBytes);
160911b9c3b1SVijay Khemka     }
161011b9c3b1SVijay Khemka     else
161111b9c3b1SVijay Khemka     {
161211b9c3b1SVijay Khemka         if (reqData->offset >= fb_oem::ipmi::sel::selRecordSize ||
161311b9c3b1SVijay Khemka             reqData->readLen > fb_oem::ipmi::sel::selRecordSize)
161411b9c3b1SVijay Khemka         {
161511b9c3b1SVijay Khemka             return ipmi::responseUnspecifiedError();
161611b9c3b1SVijay Khemka         }
161711b9c3b1SVijay Khemka         std::vector<uint8_t> recPartData;
161811b9c3b1SVijay Khemka 
161911b9c3b1SVijay Khemka         auto diff = fb_oem::ipmi::sel::selRecordSize - reqData->offset;
162011b9c3b1SVijay Khemka         auto readLength = std::min(diff, static_cast<int>(reqData->readLen));
162111b9c3b1SVijay Khemka 
162211b9c3b1SVijay Khemka         for (int i = 0; i < readLength; i++)
162311b9c3b1SVijay Khemka         {
162411b9c3b1SVijay Khemka             recPartData.push_back(recDataBytes[i + reqData->offset]);
162511b9c3b1SVijay Khemka         }
162611b9c3b1SVijay Khemka         return ipmi::responseSuccess(nextRecord, recPartData);
162711b9c3b1SVijay Khemka     }
162811b9c3b1SVijay Khemka }
162911b9c3b1SVijay Khemka 
1630*7f97f755SPeter Yin // Retry function to log the SEL entry message and make D-Bus call
logWithRetry(const std::string & journalMsg,const std::string & messageID,const std::string & logErr,const std::string & severity,const std::map<std::string,std::string> & ad,int maxRetries=10,std::chrono::milliseconds waitTimeMs=std::chrono::milliseconds (100))1631*7f97f755SPeter Yin bool logWithRetry(
1632*7f97f755SPeter Yin     const std::string& journalMsg, const std::string& messageID,
1633*7f97f755SPeter Yin     const std::string& logErr, const std::string& severity,
1634*7f97f755SPeter Yin     const std::map<std::string, std::string>& ad, int maxRetries = 10,
1635*7f97f755SPeter Yin     std::chrono::milliseconds waitTimeMs = std::chrono::milliseconds(100))
1636*7f97f755SPeter Yin {
1637*7f97f755SPeter Yin     // Attempt to log the SEL entry message
1638*7f97f755SPeter Yin     lg2::info(
1639*7f97f755SPeter Yin         "SEL Entry Added: {IPMI_RAW}, IPMISEL_MESSAGE_ID={MESSAGE_ID}, IPMISEL_MESSAGE_ARGS={LOG_ERR}",
1640*7f97f755SPeter Yin         "IPMI_RAW", journalMsg, "MESSAGE_ID", messageID, "LOG_ERR", logErr);
1641*7f97f755SPeter Yin 
1642*7f97f755SPeter Yin     int attempts = 0;
1643*7f97f755SPeter Yin     while (attempts < maxRetries)
1644*7f97f755SPeter Yin     {
1645*7f97f755SPeter Yin         // Create D-Bus call
1646*7f97f755SPeter Yin         auto bus = sdbusplus::bus::new_default();
1647*7f97f755SPeter Yin         auto reqMsg = bus.new_method_call(
1648*7f97f755SPeter Yin             "xyz.openbmc_project.Logging", "/xyz/openbmc_project/logging",
1649*7f97f755SPeter Yin             "xyz.openbmc_project.Logging.Create", "Create");
1650*7f97f755SPeter Yin         reqMsg.append(logErr, severity, ad);
1651*7f97f755SPeter Yin 
1652*7f97f755SPeter Yin         try
1653*7f97f755SPeter Yin         {
1654*7f97f755SPeter Yin             // Attempt to make the D-Bus call
1655*7f97f755SPeter Yin             bus.call(reqMsg);
1656*7f97f755SPeter Yin             return true; // D-Bus call successful, exit the loop
1657*7f97f755SPeter Yin         }
1658*7f97f755SPeter Yin         catch (sdbusplus::exception_t& e)
1659*7f97f755SPeter Yin         {
1660*7f97f755SPeter Yin             lg2::error("D-Bus call failed: {ERROR}", "ERROR", e);
1661*7f97f755SPeter Yin         }
1662*7f97f755SPeter Yin 
1663*7f97f755SPeter Yin         // Wait before retrying
1664*7f97f755SPeter Yin         std::this_thread::sleep_for(std::chrono::milliseconds(waitTimeMs));
1665*7f97f755SPeter Yin         attempts++;
1666*7f97f755SPeter Yin     }
1667*7f97f755SPeter Yin 
1668*7f97f755SPeter Yin     return false; // Failed after max retries
1669*7f97f755SPeter Yin }
1670*7f97f755SPeter Yin 
1671*7f97f755SPeter Yin // Main function to add SEL entry
1672010dee04SPatrick Williams ipmi::RspType<uint16_t>
ipmiStorageAddSELEntry(ipmi::Context::ptr ctx,std::vector<uint8_t> data)1673010dee04SPatrick Williams     ipmiStorageAddSELEntry(ipmi::Context::ptr ctx, std::vector<uint8_t> data)
167411b9c3b1SVijay Khemka {
167511b9c3b1SVijay Khemka     /* Per the IPMI spec, need to cancel any reservation when a
167611b9c3b1SVijay Khemka      * SEL entry is added
167711b9c3b1SVijay Khemka      */
167811b9c3b1SVijay Khemka     cancelSELReservation();
167911b9c3b1SVijay Khemka 
168011b9c3b1SVijay Khemka     if (data.size() != fb_oem::ipmi::sel::selRecordSize)
168111b9c3b1SVijay Khemka     {
168211b9c3b1SVijay Khemka         return ipmi::responseReqDataLenInvalid();
168311b9c3b1SVijay Khemka     }
168411b9c3b1SVijay Khemka 
168511b9c3b1SVijay Khemka     std::string ipmiRaw, logErr;
168611b9c3b1SVijay Khemka     toHexStr(data, ipmiRaw);
168711b9c3b1SVijay Khemka 
1688f36f345fSVijay Khemka     /* Parse sel data and get an error log to be filed */
1689c056dc00SManikandan Elumalai     fb_oem::ipmi::sel::parseSelData((ctx->hostIdx + 1), data, logErr);
1690f36f345fSVijay Khemka 
169115a7ae81SVijay Khemka     static const std::string openBMCMessageRegistryVersion("0.1");
1692010dee04SPatrick Williams     std::string messageID =
1693010dee04SPatrick Williams         "OpenBMC." + openBMCMessageRegistryVersion + ".SELEntryAdded";
169415a7ae81SVijay Khemka 
169511b9c3b1SVijay Khemka     /* Log the Raw SEL message to the journal */
169611b9c3b1SVijay Khemka     std::string journalMsg = "SEL Entry Added: " + ipmiRaw;
1697f36f345fSVijay Khemka 
169821a79235SBonnieLo-wiwynn     std::map<std::string, std::string> ad;
169921a79235SBonnieLo-wiwynn     std::string severity = "xyz.openbmc_project.Logging.Entry.Level.Critical";
170021a79235SBonnieLo-wiwynn     ad.emplace("IPMI_RAW", ipmiRaw);
170121a79235SBonnieLo-wiwynn 
1702*7f97f755SPeter Yin     // Launch the logging thread
1703*7f97f755SPeter Yin     std::thread([=]() {
1704*7f97f755SPeter Yin         bool success =
1705*7f97f755SPeter Yin             logWithRetry(journalMsg, messageID, logErr, severity, ad);
1706*7f97f755SPeter Yin         if (!success)
170721a79235SBonnieLo-wiwynn         {
1708*7f97f755SPeter Yin             lg2::error("Failed to log SEL entry added event after retries.");
170921a79235SBonnieLo-wiwynn         }
1710*7f97f755SPeter Yin     }).detach();
171121a79235SBonnieLo-wiwynn 
171211b9c3b1SVijay Khemka     int responseID = selObj.addEntry(ipmiRaw.c_str());
171311b9c3b1SVijay Khemka     if (responseID < 0)
171411b9c3b1SVijay Khemka     {
171511b9c3b1SVijay Khemka         return ipmi::responseUnspecifiedError();
171611b9c3b1SVijay Khemka     }
1717*7f97f755SPeter Yin     return ipmi::responseSuccess(static_cast<uint16_t>(responseID));
171811b9c3b1SVijay Khemka }
171911b9c3b1SVijay Khemka 
ipmiStorageClearSEL(uint16_t reservationID,const std::array<uint8_t,3> & clr,uint8_t eraseOperation)1720c1921c63SVijay Khemka ipmi::RspType<uint8_t> ipmiStorageClearSEL(uint16_t reservationID,
1721c1921c63SVijay Khemka                                            const std::array<uint8_t, 3>& clr,
1722c1921c63SVijay Khemka                                            uint8_t eraseOperation)
1723c1921c63SVijay Khemka {
1724c1921c63SVijay Khemka     if (!checkSELReservation(reservationID))
1725c1921c63SVijay Khemka     {
1726c1921c63SVijay Khemka         return ipmi::responseInvalidReservationId();
1727c1921c63SVijay Khemka     }
1728c1921c63SVijay Khemka 
1729c1921c63SVijay Khemka     static constexpr std::array<uint8_t, 3> clrExpected = {'C', 'L', 'R'};
1730c1921c63SVijay Khemka     if (clr != clrExpected)
1731c1921c63SVijay Khemka     {
1732c1921c63SVijay Khemka         return ipmi::responseInvalidFieldRequest();
1733c1921c63SVijay Khemka     }
1734c1921c63SVijay Khemka 
1735c1921c63SVijay Khemka     /* If there is no sel then return erase complete */
1736c1921c63SVijay Khemka     if (selObj.getCount() == 0)
1737c1921c63SVijay Khemka     {
1738c1921c63SVijay Khemka         return ipmi::responseSuccess(fb_oem::ipmi::sel::eraseComplete);
1739c1921c63SVijay Khemka     }
1740c1921c63SVijay Khemka 
1741c1921c63SVijay Khemka     /* Erasure status cannot be fetched, so always return erasure
1742c1921c63SVijay Khemka      * status as `erase completed`.
1743c1921c63SVijay Khemka      */
1744c1921c63SVijay Khemka     if (eraseOperation == fb_oem::ipmi::sel::getEraseStatus)
1745c1921c63SVijay Khemka     {
1746c1921c63SVijay Khemka         return ipmi::responseSuccess(fb_oem::ipmi::sel::eraseComplete);
1747c1921c63SVijay Khemka     }
1748c1921c63SVijay Khemka 
1749c1921c63SVijay Khemka     /* Check that initiate erase is correct */
1750c1921c63SVijay Khemka     if (eraseOperation != fb_oem::ipmi::sel::initiateErase)
1751c1921c63SVijay Khemka     {
1752c1921c63SVijay Khemka         return ipmi::responseInvalidFieldRequest();
1753c1921c63SVijay Khemka     }
1754c1921c63SVijay Khemka 
1755c1921c63SVijay Khemka     /* Per the IPMI spec, need to cancel any reservation when the
1756c1921c63SVijay Khemka      * SEL is cleared
1757c1921c63SVijay Khemka      */
1758c1921c63SVijay Khemka     cancelSELReservation();
1759c1921c63SVijay Khemka 
1760c1921c63SVijay Khemka     /* Clear the complete Sel Json object */
1761c1921c63SVijay Khemka     if (selObj.clear() < 0)
1762c1921c63SVijay Khemka     {
1763c1921c63SVijay Khemka         return ipmi::responseUnspecifiedError();
1764c1921c63SVijay Khemka     }
1765c1921c63SVijay Khemka 
1766c1921c63SVijay Khemka     return ipmi::responseSuccess(fb_oem::ipmi::sel::eraseComplete);
1767c1921c63SVijay Khemka }
1768c1921c63SVijay Khemka 
ipmiStorageGetSELTime()1769c1921c63SVijay Khemka ipmi::RspType<uint32_t> ipmiStorageGetSELTime()
1770c1921c63SVijay Khemka {
1771c1921c63SVijay Khemka     struct timespec selTime = {};
1772c1921c63SVijay Khemka 
1773c1921c63SVijay Khemka     if (clock_gettime(CLOCK_REALTIME, &selTime) < 0)
1774c1921c63SVijay Khemka     {
1775c1921c63SVijay Khemka         return ipmi::responseUnspecifiedError();
1776c1921c63SVijay Khemka     }
1777c1921c63SVijay Khemka 
1778c1921c63SVijay Khemka     return ipmi::responseSuccess(selTime.tv_sec);
1779c1921c63SVijay Khemka }
1780c1921c63SVijay Khemka 
ipmiStorageSetSELTime(uint32_t)1781e39f9393SWilly Tu ipmi::RspType<> ipmiStorageSetSELTime(uint32_t)
1782c1921c63SVijay Khemka {
1783c1921c63SVijay Khemka     // Set SEL Time is not supported
1784c1921c63SVijay Khemka     return ipmi::responseInvalidCommand();
1785c1921c63SVijay Khemka }
1786c1921c63SVijay Khemka 
ipmiStorageGetSELTimeUtcOffset()1787c1921c63SVijay Khemka ipmi::RspType<uint16_t> ipmiStorageGetSELTimeUtcOffset()
1788c1921c63SVijay Khemka {
1789c1921c63SVijay Khemka     /* TODO: For now, the SEL time stamp is based on UTC time,
1790c1921c63SVijay Khemka      * so return 0x0000 as offset. Might need to change once
1791c1921c63SVijay Khemka      * supporting zones in SEL time stamps
1792c1921c63SVijay Khemka      */
1793c1921c63SVijay Khemka 
1794c1921c63SVijay Khemka     uint16_t utcOffset = 0x0000;
1795c1921c63SVijay Khemka     return ipmi::responseSuccess(utcOffset);
1796c1921c63SVijay Khemka }
1797c1921c63SVijay Khemka 
registerSELFunctions()179811b9c3b1SVijay Khemka void registerSELFunctions()
179911b9c3b1SVijay Khemka {
180011b9c3b1SVijay Khemka     // <Get SEL Info>
180111b9c3b1SVijay Khemka     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
180211b9c3b1SVijay Khemka                           ipmi::storage::cmdGetSelInfo, ipmi::Privilege::User,
180311b9c3b1SVijay Khemka                           ipmiStorageGetSELInfo);
180411b9c3b1SVijay Khemka 
180511b9c3b1SVijay Khemka     // <Get SEL Entry>
180611b9c3b1SVijay Khemka     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
180711b9c3b1SVijay Khemka                           ipmi::storage::cmdGetSelEntry, ipmi::Privilege::User,
180811b9c3b1SVijay Khemka                           ipmiStorageGetSELEntry);
180911b9c3b1SVijay Khemka 
181011b9c3b1SVijay Khemka     // <Add SEL Entry>
181111b9c3b1SVijay Khemka     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
181211b9c3b1SVijay Khemka                           ipmi::storage::cmdAddSelEntry,
181311b9c3b1SVijay Khemka                           ipmi::Privilege::Operator, ipmiStorageAddSELEntry);
181411b9c3b1SVijay Khemka 
1815c1921c63SVijay Khemka     // <Clear SEL>
1816c1921c63SVijay Khemka     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
1817c1921c63SVijay Khemka                           ipmi::storage::cmdClearSel, ipmi::Privilege::Operator,
1818c1921c63SVijay Khemka                           ipmiStorageClearSEL);
1819c1921c63SVijay Khemka 
1820c1921c63SVijay Khemka     // <Get SEL Time>
1821c1921c63SVijay Khemka     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
1822c1921c63SVijay Khemka                           ipmi::storage::cmdGetSelTime, ipmi::Privilege::User,
1823c1921c63SVijay Khemka                           ipmiStorageGetSELTime);
1824c1921c63SVijay Khemka 
1825c1921c63SVijay Khemka     // <Set SEL Time>
1826c1921c63SVijay Khemka     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
1827c1921c63SVijay Khemka                           ipmi::storage::cmdSetSelTime,
1828c1921c63SVijay Khemka                           ipmi::Privilege::Operator, ipmiStorageSetSELTime);
1829c1921c63SVijay Khemka 
1830c1921c63SVijay Khemka     // <Get SEL Time UTC Offset>
1831c1921c63SVijay Khemka     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
1832c1921c63SVijay Khemka                           ipmi::storage::cmdGetSelTimeUtcOffset,
1833c1921c63SVijay Khemka                           ipmi::Privilege::User,
1834c1921c63SVijay Khemka                           ipmiStorageGetSELTimeUtcOffset);
1835c1921c63SVijay Khemka 
183611b9c3b1SVijay Khemka     return;
183711b9c3b1SVijay Khemka }
183811b9c3b1SVijay Khemka 
183911b9c3b1SVijay Khemka } // namespace storage
184011b9c3b1SVijay Khemka } // namespace ipmi
1841