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