xref: /openbmc/fb-ipmi-oem/src/selcommands.cpp (revision 7451903cddb3c35b730ae629fd3a17c5ab1a0b66)
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 
31*7451903cScchoux enum class MemErrType
32*7451903cScchoux {
33*7451903cScchoux     memTrainErr = 0,
34*7451903cScchoux     memPmicErr = 7
35*7451903cScchoux };
36*7451903cScchoux 
37*7451903cScchoux enum class PostEvtType
38*7451903cScchoux {
39*7451903cScchoux     pxeBootFail = 0,
40*7451903cScchoux     httpBootFail = 6,
41*7451903cScchoux     getCertFail = 7,
42*7451903cScchoux     amdAblFail = 10
43*7451903cScchoux };
44*7451903cScchoux 
45*7451903cScchoux enum class PcieEvtType
46*7451903cScchoux {
47*7451903cScchoux     dpc = 0
48*7451903cScchoux };
49*7451903cScchoux 
50*7451903cScchoux enum class MemEvtType
51*7451903cScchoux {
52*7451903cScchoux     ppr = 0,
53*7451903cScchoux     adddc = 5,
54*7451903cScchoux     noDimm = 7
55*7451903cScchoux };
56*7451903cScchoux 
5711b9c3b1SVijay Khemka //----------------------------------------------------------------------
5811b9c3b1SVijay Khemka // Platform specific functions for storing app data
5911b9c3b1SVijay Khemka //----------------------------------------------------------------------
6011b9c3b1SVijay Khemka 
61139aa4f0SVijay Khemka static std::string byteToStr(uint8_t byte)
62139aa4f0SVijay Khemka {
63139aa4f0SVijay Khemka     std::stringstream ss;
64139aa4f0SVijay Khemka 
65139aa4f0SVijay Khemka     ss << std::hex << std::uppercase << std::setfill('0');
66139aa4f0SVijay Khemka     ss << std::setw(2) << (int)byte;
67139aa4f0SVijay Khemka 
68139aa4f0SVijay Khemka     return ss.str();
69139aa4f0SVijay Khemka }
70139aa4f0SVijay Khemka 
7111b9c3b1SVijay Khemka static void toHexStr(std::vector<uint8_t>& bytes, std::string& hexStr)
7211b9c3b1SVijay Khemka {
7311b9c3b1SVijay Khemka     std::stringstream stream;
7411b9c3b1SVijay Khemka     stream << std::hex << std::uppercase << std::setfill('0');
7511b9c3b1SVijay Khemka     for (const uint8_t byte : bytes)
7611b9c3b1SVijay Khemka     {
7711b9c3b1SVijay Khemka         stream << std::setw(2) << static_cast<int>(byte);
7811b9c3b1SVijay Khemka     }
7911b9c3b1SVijay Khemka     hexStr = stream.str();
8011b9c3b1SVijay Khemka }
8111b9c3b1SVijay Khemka 
8211b9c3b1SVijay Khemka static int fromHexStr(const std::string hexStr, std::vector<uint8_t>& data)
8311b9c3b1SVijay Khemka {
8411b9c3b1SVijay Khemka     for (unsigned int i = 0; i < hexStr.size(); i += 2)
8511b9c3b1SVijay Khemka     {
8611b9c3b1SVijay Khemka         try
8711b9c3b1SVijay Khemka         {
8811b9c3b1SVijay Khemka             data.push_back(static_cast<uint8_t>(
8911b9c3b1SVijay Khemka                 std::stoul(hexStr.substr(i, 2), nullptr, 16)));
9011b9c3b1SVijay Khemka         }
9135d12546SPatrick Williams         catch (const std::invalid_argument& e)
9211b9c3b1SVijay Khemka         {
9311b9c3b1SVijay Khemka             phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
9411b9c3b1SVijay Khemka             return -1;
9511b9c3b1SVijay Khemka         }
9635d12546SPatrick Williams         catch (const std::out_of_range& e)
9711b9c3b1SVijay Khemka         {
9811b9c3b1SVijay Khemka             phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
9911b9c3b1SVijay Khemka             return -1;
10011b9c3b1SVijay Khemka         }
10111b9c3b1SVijay Khemka     }
10211b9c3b1SVijay Khemka     return 0;
10311b9c3b1SVijay Khemka }
10411b9c3b1SVijay Khemka 
10511b9c3b1SVijay Khemka namespace fb_oem::ipmi::sel
10611b9c3b1SVijay Khemka {
10711b9c3b1SVijay Khemka 
10811b9c3b1SVijay Khemka class SELData
10911b9c3b1SVijay Khemka {
11011b9c3b1SVijay Khemka   private:
11111b9c3b1SVijay Khemka     nlohmann::json selDataObj;
11211b9c3b1SVijay Khemka 
11311b9c3b1SVijay Khemka     void flush()
11411b9c3b1SVijay Khemka     {
11511b9c3b1SVijay Khemka         std::ofstream file(SEL_JSON_DATA_FILE);
11611b9c3b1SVijay Khemka         file << selDataObj;
11711b9c3b1SVijay Khemka         file.close();
11811b9c3b1SVijay Khemka     }
11911b9c3b1SVijay Khemka 
12011b9c3b1SVijay Khemka     void init()
12111b9c3b1SVijay Khemka     {
12211b9c3b1SVijay Khemka         selDataObj[KEY_SEL_VER] = 0x51;
12311b9c3b1SVijay Khemka         selDataObj[KEY_SEL_COUNT] = 0;
12411b9c3b1SVijay Khemka         selDataObj[KEY_ADD_TIME] = 0xFFFFFFFF;
12511b9c3b1SVijay Khemka         selDataObj[KEY_ERASE_TIME] = 0xFFFFFFFF;
12611b9c3b1SVijay Khemka         selDataObj[KEY_OPER_SUPP] = 0x02;
12711b9c3b1SVijay Khemka         /* Spec indicates that more than 64kB is free */
12811b9c3b1SVijay Khemka         selDataObj[KEY_FREE_SPACE] = 0xFFFF;
12911b9c3b1SVijay Khemka     }
13011b9c3b1SVijay Khemka 
13111b9c3b1SVijay Khemka   public:
13211b9c3b1SVijay Khemka     SELData()
13311b9c3b1SVijay Khemka     {
13411b9c3b1SVijay Khemka         /* Get App data stored in json file */
13511b9c3b1SVijay Khemka         std::ifstream file(SEL_JSON_DATA_FILE);
13611b9c3b1SVijay Khemka         if (file)
13711b9c3b1SVijay Khemka         {
13811b9c3b1SVijay Khemka             file >> selDataObj;
13911b9c3b1SVijay Khemka             file.close();
14011b9c3b1SVijay Khemka         }
14111b9c3b1SVijay Khemka 
14211b9c3b1SVijay Khemka         /* Initialize SelData object if no entries. */
14311b9c3b1SVijay Khemka         if (selDataObj.find(KEY_SEL_COUNT) == selDataObj.end())
14411b9c3b1SVijay Khemka         {
14511b9c3b1SVijay Khemka             init();
14611b9c3b1SVijay Khemka         }
14711b9c3b1SVijay Khemka     }
14811b9c3b1SVijay Khemka 
14911b9c3b1SVijay Khemka     int clear()
15011b9c3b1SVijay Khemka     {
15111b9c3b1SVijay Khemka         /* Clear the complete Sel Json object */
15211b9c3b1SVijay Khemka         selDataObj.clear();
15311b9c3b1SVijay Khemka         /* Reinitialize it with basic data */
15411b9c3b1SVijay Khemka         init();
15511b9c3b1SVijay Khemka         /* Save the erase time */
15611b9c3b1SVijay Khemka         struct timespec selTime = {};
15711b9c3b1SVijay Khemka         if (clock_gettime(CLOCK_REALTIME, &selTime) < 0)
15811b9c3b1SVijay Khemka         {
15911b9c3b1SVijay Khemka             return -1;
16011b9c3b1SVijay Khemka         }
16111b9c3b1SVijay Khemka         selDataObj[KEY_ERASE_TIME] = selTime.tv_sec;
16211b9c3b1SVijay Khemka         flush();
16311b9c3b1SVijay Khemka         return 0;
16411b9c3b1SVijay Khemka     }
16511b9c3b1SVijay Khemka 
16611b9c3b1SVijay Khemka     uint32_t getCount()
16711b9c3b1SVijay Khemka     {
16811b9c3b1SVijay Khemka         return selDataObj[KEY_SEL_COUNT];
16911b9c3b1SVijay Khemka     }
17011b9c3b1SVijay Khemka 
17111b9c3b1SVijay Khemka     void getInfo(GetSELInfoData& info)
17211b9c3b1SVijay Khemka     {
17311b9c3b1SVijay Khemka         info.selVersion = selDataObj[KEY_SEL_VER];
17411b9c3b1SVijay Khemka         info.entries = selDataObj[KEY_SEL_COUNT];
17511b9c3b1SVijay Khemka         info.freeSpace = selDataObj[KEY_FREE_SPACE];
17611b9c3b1SVijay Khemka         info.addTimeStamp = selDataObj[KEY_ADD_TIME];
17711b9c3b1SVijay Khemka         info.eraseTimeStamp = selDataObj[KEY_ERASE_TIME];
17811b9c3b1SVijay Khemka         info.operationSupport = selDataObj[KEY_OPER_SUPP];
17911b9c3b1SVijay Khemka     }
18011b9c3b1SVijay Khemka 
18111b9c3b1SVijay Khemka     int getEntry(uint32_t index, std::string& rawStr)
18211b9c3b1SVijay Khemka     {
18311b9c3b1SVijay Khemka         std::stringstream ss;
18411b9c3b1SVijay Khemka         ss << std::hex;
18511b9c3b1SVijay Khemka         ss << std::setw(2) << std::setfill('0') << index;
18611b9c3b1SVijay Khemka 
18711b9c3b1SVijay Khemka         /* Check or the requested SEL Entry, if record is available */
18811b9c3b1SVijay Khemka         if (selDataObj.find(ss.str()) == selDataObj.end())
18911b9c3b1SVijay Khemka         {
19011b9c3b1SVijay Khemka             return -1;
19111b9c3b1SVijay Khemka         }
19211b9c3b1SVijay Khemka 
19311b9c3b1SVijay Khemka         rawStr = selDataObj[ss.str()][KEY_SEL_ENTRY_RAW];
19411b9c3b1SVijay Khemka         return 0;
19511b9c3b1SVijay Khemka     }
19611b9c3b1SVijay Khemka 
19711b9c3b1SVijay Khemka     int addEntry(std::string keyStr)
19811b9c3b1SVijay Khemka     {
19911b9c3b1SVijay Khemka         struct timespec selTime = {};
20011b9c3b1SVijay Khemka 
20111b9c3b1SVijay Khemka         if (clock_gettime(CLOCK_REALTIME, &selTime) < 0)
20211b9c3b1SVijay Khemka         {
20311b9c3b1SVijay Khemka             return -1;
20411b9c3b1SVijay Khemka         }
20511b9c3b1SVijay Khemka 
20611b9c3b1SVijay Khemka         selDataObj[KEY_ADD_TIME] = selTime.tv_sec;
20711b9c3b1SVijay Khemka 
20811b9c3b1SVijay Khemka         int selCount = selDataObj[KEY_SEL_COUNT];
20911b9c3b1SVijay Khemka         selDataObj[KEY_SEL_COUNT] = ++selCount;
21011b9c3b1SVijay Khemka 
21111b9c3b1SVijay Khemka         std::stringstream ss;
21211b9c3b1SVijay Khemka         ss << std::hex;
21311b9c3b1SVijay Khemka         ss << std::setw(2) << std::setfill('0') << selCount;
21411b9c3b1SVijay Khemka 
21511b9c3b1SVijay Khemka         selDataObj[ss.str()][KEY_SEL_ENTRY_RAW] = keyStr;
21611b9c3b1SVijay Khemka         flush();
21711b9c3b1SVijay Khemka         return selCount;
21811b9c3b1SVijay Khemka     }
21911b9c3b1SVijay Khemka };
22011b9c3b1SVijay Khemka 
221139aa4f0SVijay Khemka /*
222139aa4f0SVijay Khemka  * A Function to parse common SEL message, a helper funciton
223139aa4f0SVijay Khemka  * for parseStdSel.
224139aa4f0SVijay Khemka  *
225139aa4f0SVijay Khemka  * Note that this function __CANNOT__ be overriden.
226139aa4f0SVijay Khemka  * To add board specific routine, please override parseStdSel.
227139aa4f0SVijay Khemka  */
228139aa4f0SVijay Khemka 
229139aa4f0SVijay Khemka /*Used by decoding ME event*/
230139aa4f0SVijay Khemka std::vector<std::string> nmDomName = {
231139aa4f0SVijay Khemka     "Entire Platform",          "CPU Subsystem",
232139aa4f0SVijay Khemka     "Memory Subsystem",         "HW Protection",
233139aa4f0SVijay Khemka     "High Power I/O subsystem", "Unknown"};
234139aa4f0SVijay Khemka 
235139aa4f0SVijay Khemka /* Default log message for unknown type */
236e39f9393SWilly Tu static void logDefault(uint8_t*, std::string& errLog)
237139aa4f0SVijay Khemka {
238139aa4f0SVijay Khemka     errLog = "Unknown";
239139aa4f0SVijay Khemka }
240139aa4f0SVijay Khemka 
241139aa4f0SVijay Khemka static void logSysEvent(uint8_t* data, std::string& errLog)
242139aa4f0SVijay Khemka {
243139aa4f0SVijay Khemka     if (data[0] == 0xE5)
244139aa4f0SVijay Khemka     {
245139aa4f0SVijay Khemka         errLog = "Cause of Time change - ";
246139aa4f0SVijay Khemka         switch (data[2])
247139aa4f0SVijay Khemka         {
248139aa4f0SVijay Khemka             case 0x00:
249139aa4f0SVijay Khemka                 errLog += "NTP";
250139aa4f0SVijay Khemka                 break;
251139aa4f0SVijay Khemka             case 0x01:
252139aa4f0SVijay Khemka                 errLog += "Host RTL";
253139aa4f0SVijay Khemka                 break;
254139aa4f0SVijay Khemka             case 0x02:
255139aa4f0SVijay Khemka                 errLog += "Set SEL time cmd";
256139aa4f0SVijay Khemka                 break;
257139aa4f0SVijay Khemka             case 0x03:
258139aa4f0SVijay Khemka                 errLog += "Set SEL time UTC offset cmd";
259139aa4f0SVijay Khemka                 break;
260139aa4f0SVijay Khemka             default:
261139aa4f0SVijay Khemka                 errLog += "Unknown";
262139aa4f0SVijay Khemka         }
263139aa4f0SVijay Khemka 
264139aa4f0SVijay Khemka         if (data[1] == 0x00)
265139aa4f0SVijay Khemka             errLog += " - First Time";
266139aa4f0SVijay Khemka         else if (data[1] == 0x80)
267139aa4f0SVijay Khemka             errLog += " - Second Time";
268139aa4f0SVijay Khemka     }
269139aa4f0SVijay Khemka     else
270139aa4f0SVijay Khemka     {
271139aa4f0SVijay Khemka         errLog = "Unknown";
272139aa4f0SVijay Khemka     }
273139aa4f0SVijay Khemka }
274139aa4f0SVijay Khemka 
275139aa4f0SVijay Khemka static void logThermalEvent(uint8_t* data, std::string& errLog)
276139aa4f0SVijay Khemka {
277139aa4f0SVijay Khemka     if (data[0] == 0x1)
278139aa4f0SVijay Khemka     {
279139aa4f0SVijay Khemka         errLog = "Limit Exceeded";
280139aa4f0SVijay Khemka     }
281139aa4f0SVijay Khemka     else
282139aa4f0SVijay Khemka     {
283139aa4f0SVijay Khemka         errLog = "Unknown";
284139aa4f0SVijay Khemka     }
285139aa4f0SVijay Khemka }
286139aa4f0SVijay Khemka 
287139aa4f0SVijay Khemka static void logCritIrq(uint8_t* data, std::string& errLog)
288139aa4f0SVijay Khemka {
289139aa4f0SVijay Khemka     if (data[0] == 0x0)
290139aa4f0SVijay Khemka     {
291139aa4f0SVijay Khemka         errLog = "NMI / Diagnostic Interrupt";
292139aa4f0SVijay Khemka     }
293139aa4f0SVijay Khemka     else if (data[0] == 0x03)
294139aa4f0SVijay Khemka     {
295139aa4f0SVijay Khemka         errLog = "Software NMI";
296139aa4f0SVijay Khemka     }
297139aa4f0SVijay Khemka     else
298139aa4f0SVijay Khemka     {
299139aa4f0SVijay Khemka         errLog = "Unknown";
300139aa4f0SVijay Khemka     }
301139aa4f0SVijay Khemka 
302139aa4f0SVijay Khemka     /* TODO: Call add_cri_sel for CRITICAL_IRQ */
303139aa4f0SVijay Khemka }
304139aa4f0SVijay Khemka 
305139aa4f0SVijay Khemka static void logPostErr(uint8_t* data, std::string& errLog)
306139aa4f0SVijay Khemka {
307139aa4f0SVijay Khemka     if ((data[0] & 0x0F) == 0x0)
308139aa4f0SVijay Khemka     {
309139aa4f0SVijay Khemka         errLog = "System Firmware Error";
310139aa4f0SVijay Khemka     }
311139aa4f0SVijay Khemka     else
312139aa4f0SVijay Khemka     {
313139aa4f0SVijay Khemka         errLog = "Unknown";
314139aa4f0SVijay Khemka     }
315139aa4f0SVijay Khemka 
316139aa4f0SVijay Khemka     if (((data[0] >> 6) & 0x03) == 0x3)
317139aa4f0SVijay Khemka     {
318139aa4f0SVijay Khemka         // TODO: Need to implement IPMI spec based Post Code
319139aa4f0SVijay Khemka         errLog += ", IPMI Post Code";
320139aa4f0SVijay Khemka     }
321139aa4f0SVijay Khemka     else if (((data[0] >> 6) & 0x03) == 0x2)
322139aa4f0SVijay Khemka     {
3232405ae98SPatrick Williams         errLog += ", OEM Post Code 0x" + byteToStr(data[2]) +
3242405ae98SPatrick Williams                   byteToStr(data[1]);
325139aa4f0SVijay Khemka 
326139aa4f0SVijay Khemka         switch ((data[2] << 8) | data[1])
327139aa4f0SVijay Khemka         {
328139aa4f0SVijay Khemka             case 0xA105:
329139aa4f0SVijay Khemka                 errLog += ", BMC Failed (No Response)";
330139aa4f0SVijay Khemka                 break;
331139aa4f0SVijay Khemka             case 0xA106:
332139aa4f0SVijay Khemka                 errLog += ", BMC Failed (Self Test Fail)";
333139aa4f0SVijay Khemka                 break;
334139aa4f0SVijay Khemka             case 0xA10A:
335139aa4f0SVijay Khemka                 errLog += ", System Firmware Corruption Detected";
336139aa4f0SVijay Khemka                 break;
337139aa4f0SVijay Khemka             case 0xA10B:
338139aa4f0SVijay Khemka                 errLog += ", TPM Self-Test FAIL Detected";
339139aa4f0SVijay Khemka         }
340139aa4f0SVijay Khemka     }
341139aa4f0SVijay Khemka }
342139aa4f0SVijay Khemka 
343139aa4f0SVijay Khemka static void logMchChkErr(uint8_t* data, std::string& errLog)
344139aa4f0SVijay Khemka {
345139aa4f0SVijay Khemka     /* TODO: Call add_cri_sel for CRITICAL_IRQ */
346139aa4f0SVijay Khemka     if ((data[0] & 0x0F) == 0x0B)
347139aa4f0SVijay Khemka     {
348139aa4f0SVijay Khemka         errLog = "Uncorrectable";
349139aa4f0SVijay Khemka     }
350139aa4f0SVijay Khemka     else if ((data[0] & 0x0F) == 0x0C)
351139aa4f0SVijay Khemka     {
352139aa4f0SVijay Khemka         errLog = "Correctable";
353139aa4f0SVijay Khemka     }
354139aa4f0SVijay Khemka     else
355139aa4f0SVijay Khemka     {
356139aa4f0SVijay Khemka         errLog = "Unknown";
357139aa4f0SVijay Khemka     }
358139aa4f0SVijay Khemka 
359139aa4f0SVijay Khemka     errLog += ", Machine Check bank Number " + std::to_string(data[1]) +
360139aa4f0SVijay Khemka               ", CPU " + std::to_string(data[2] >> 5) + ", Core " +
361139aa4f0SVijay Khemka               std::to_string(data[2] & 0x1F);
362139aa4f0SVijay Khemka }
363139aa4f0SVijay Khemka 
364139aa4f0SVijay Khemka static void logPcieErr(uint8_t* data, std::string& errLog)
365139aa4f0SVijay Khemka {
366139aa4f0SVijay Khemka     std::stringstream tmp1, tmp2;
367139aa4f0SVijay Khemka     tmp1 << std::hex << std::uppercase << std::setfill('0');
368139aa4f0SVijay Khemka     tmp2 << std::hex << std::uppercase << std::setfill('0');
369139aa4f0SVijay Khemka     tmp1 << " (Bus " << std::setw(2) << (int)(data[2]) << " / Dev "
370139aa4f0SVijay Khemka          << std::setw(2) << (int)(data[1] >> 3) << " / Fun " << std::setw(2)
371139aa4f0SVijay Khemka          << (int)(data[1] & 0x7) << ")";
372139aa4f0SVijay Khemka 
373139aa4f0SVijay Khemka     switch (data[0] & 0xF)
374139aa4f0SVijay Khemka     {
375139aa4f0SVijay Khemka         case 0x4:
376139aa4f0SVijay Khemka             errLog = "PCI PERR" + tmp1.str();
377139aa4f0SVijay Khemka             break;
378139aa4f0SVijay Khemka         case 0x5:
379139aa4f0SVijay Khemka             errLog = "PCI SERR" + tmp1.str();
380139aa4f0SVijay Khemka             break;
381139aa4f0SVijay Khemka         case 0x7:
382139aa4f0SVijay Khemka             errLog = "Correctable" + tmp1.str();
383139aa4f0SVijay Khemka             break;
384139aa4f0SVijay Khemka         case 0x8:
385139aa4f0SVijay Khemka             errLog = "Uncorrectable" + tmp1.str();
386139aa4f0SVijay Khemka             break;
387139aa4f0SVijay Khemka         case 0xA:
388139aa4f0SVijay Khemka             errLog = "Bus Fatal" + tmp1.str();
389139aa4f0SVijay Khemka             break;
390d1194024SVijay Khemka         case 0xD:
391d1194024SVijay Khemka         {
392139aa4f0SVijay Khemka             uint32_t venId = (uint32_t)data[1] << 8 | (uint32_t)data[2];
393139aa4f0SVijay Khemka             tmp2 << "Vendor ID: 0x" << std::setw(4) << venId;
394139aa4f0SVijay Khemka             errLog = tmp2.str();
395139aa4f0SVijay Khemka         }
396139aa4f0SVijay Khemka         break;
397d1194024SVijay Khemka         case 0xE:
398d1194024SVijay Khemka         {
399139aa4f0SVijay Khemka             uint32_t devId = (uint32_t)data[1] << 8 | (uint32_t)data[2];
400139aa4f0SVijay Khemka             tmp2 << "Device ID: 0x" << std::setw(4) << devId;
401139aa4f0SVijay Khemka             errLog = tmp2.str();
402139aa4f0SVijay Khemka         }
403139aa4f0SVijay Khemka         break;
404139aa4f0SVijay Khemka         case 0xF:
405139aa4f0SVijay Khemka             tmp2 << "Error ID from downstream: 0x" << std::setw(2)
406139aa4f0SVijay Khemka                  << (int)(data[1]) << std::setw(2) << (int)(data[2]);
407139aa4f0SVijay Khemka             errLog = tmp2.str();
408139aa4f0SVijay Khemka             break;
409139aa4f0SVijay Khemka         default:
410139aa4f0SVijay Khemka             errLog = "Unknown";
411139aa4f0SVijay Khemka     }
412139aa4f0SVijay Khemka }
413139aa4f0SVijay Khemka 
414139aa4f0SVijay Khemka static void logIioErr(uint8_t* data, std::string& errLog)
415139aa4f0SVijay Khemka {
416139aa4f0SVijay Khemka     std::vector<std::string> tmpStr = {
417139aa4f0SVijay Khemka         "IRP0", "IRP1", " IIO-Core", "VT-d", "Intel Quick Data",
418139aa4f0SVijay Khemka         "Misc", " DMA", "ITC",       "OTC",  "CI"};
419139aa4f0SVijay Khemka 
420139aa4f0SVijay Khemka     if ((data[0] & 0xF) == 0)
421139aa4f0SVijay Khemka     {
422139aa4f0SVijay Khemka         errLog += "CPU " + std::to_string(data[2] >> 5) + ", Error ID 0x" +
423139aa4f0SVijay Khemka                   byteToStr(data[1]) + " - ";
424139aa4f0SVijay Khemka 
425139aa4f0SVijay Khemka         if ((data[2] & 0xF) <= 0x9)
426139aa4f0SVijay Khemka         {
427139aa4f0SVijay Khemka             errLog += tmpStr[(data[2] & 0xF)];
428139aa4f0SVijay Khemka         }
429139aa4f0SVijay Khemka         else
430139aa4f0SVijay Khemka         {
431139aa4f0SVijay Khemka             errLog += "Reserved";
432139aa4f0SVijay Khemka         }
433139aa4f0SVijay Khemka     }
434139aa4f0SVijay Khemka     else
435139aa4f0SVijay Khemka     {
436139aa4f0SVijay Khemka         errLog = "Unknown";
437139aa4f0SVijay Khemka     }
438139aa4f0SVijay Khemka }
439139aa4f0SVijay Khemka 
440e39f9393SWilly Tu [[maybe_unused]] static void logMemErr(uint8_t* dataPtr, std::string& errLog)
441139aa4f0SVijay Khemka {
442139aa4f0SVijay Khemka     uint8_t snrType = dataPtr[0];
443139aa4f0SVijay Khemka     uint8_t snrNum = dataPtr[1];
444139aa4f0SVijay Khemka     uint8_t* data = &(dataPtr[3]);
445139aa4f0SVijay Khemka 
446139aa4f0SVijay Khemka     /* TODO: add pal_add_cri_sel */
447139aa4f0SVijay Khemka 
448139aa4f0SVijay Khemka     if (snrNum == memoryEccError)
449139aa4f0SVijay Khemka     {
450139aa4f0SVijay Khemka         /* SEL from MEMORY_ECC_ERR Sensor */
451139aa4f0SVijay Khemka         switch (data[0] & 0x0F)
452139aa4f0SVijay Khemka         {
453139aa4f0SVijay Khemka             case 0x0:
454139aa4f0SVijay Khemka                 if (snrType == 0x0C)
455139aa4f0SVijay Khemka                 {
456139aa4f0SVijay Khemka                     errLog = "Correctable";
457139aa4f0SVijay Khemka                 }
458139aa4f0SVijay Khemka                 else if (snrType == 0x10)
459139aa4f0SVijay Khemka                 {
460139aa4f0SVijay Khemka                     errLog = "Correctable ECC error Logging Disabled";
461139aa4f0SVijay Khemka                 }
462139aa4f0SVijay Khemka                 break;
463139aa4f0SVijay Khemka             case 0x1:
464139aa4f0SVijay Khemka                 errLog = "Uncorrectable";
465139aa4f0SVijay Khemka                 break;
466139aa4f0SVijay Khemka             case 0x5:
467139aa4f0SVijay Khemka                 errLog = "Correctable ECC error Logging Limit Disabled";
468139aa4f0SVijay Khemka                 break;
469139aa4f0SVijay Khemka             default:
470139aa4f0SVijay Khemka                 errLog = "Unknown";
471139aa4f0SVijay Khemka         }
472139aa4f0SVijay Khemka     }
473139aa4f0SVijay Khemka     else if (snrNum == memoryErrLogDIS)
474139aa4f0SVijay Khemka     {
475139aa4f0SVijay Khemka         // SEL from MEMORY_ERR_LOG_DIS Sensor
476139aa4f0SVijay Khemka         if ((data[0] & 0x0F) == 0x0)
477139aa4f0SVijay Khemka         {
478139aa4f0SVijay Khemka             errLog = "Correctable Memory Error Logging Disabled";
479139aa4f0SVijay Khemka         }
480139aa4f0SVijay Khemka         else
481139aa4f0SVijay Khemka         {
482139aa4f0SVijay Khemka             errLog = "Unknown";
483139aa4f0SVijay Khemka         }
484139aa4f0SVijay Khemka     }
485139aa4f0SVijay Khemka     else
486139aa4f0SVijay Khemka     {
487139aa4f0SVijay Khemka         errLog = "Unknown";
488139aa4f0SVijay Khemka         return;
489139aa4f0SVijay Khemka     }
490139aa4f0SVijay Khemka 
491139aa4f0SVijay Khemka     /* Common routine for both MEM_ECC_ERR and MEMORY_ERR_LOG_DIS */
492139aa4f0SVijay Khemka 
493139aa4f0SVijay Khemka     errLog += " (DIMM " + byteToStr(data[2]) + ") Logical Rank " +
494139aa4f0SVijay Khemka               std::to_string(data[1] & 0x03);
495139aa4f0SVijay Khemka 
496139aa4f0SVijay Khemka     /* DIMM number (data[2]):
497139aa4f0SVijay Khemka      * Bit[7:5]: Socket number  (Range: 0-7)
498139aa4f0SVijay Khemka      * Bit[4:3]: Channel number (Range: 0-3)
499139aa4f0SVijay Khemka      * Bit[2:0]: DIMM number    (Range: 0-7)
500139aa4f0SVijay Khemka      */
501139aa4f0SVijay Khemka 
502139aa4f0SVijay Khemka     /* TODO: Verify these bits */
503139aa4f0SVijay Khemka     std::string cpuStr = "CPU# " + std::to_string((data[2] & 0xE0) >> 5);
504139aa4f0SVijay Khemka     std::string chStr = "CHN# " + std::to_string((data[2] & 0x18) >> 3);
505139aa4f0SVijay Khemka     std::string dimmStr = "DIMM#" + std::to_string(data[2] & 0x7);
506139aa4f0SVijay Khemka 
507139aa4f0SVijay Khemka     switch ((data[1] & 0xC) >> 2)
508139aa4f0SVijay Khemka     {
509d1194024SVijay Khemka         case 0x0:
510d1194024SVijay Khemka         {
511139aa4f0SVijay Khemka             /* All Info Valid */
512e39f9393SWilly Tu             [[maybe_unused]] uint8_t chnNum = (data[2] & 0x1C) >> 2;
513e39f9393SWilly Tu             [[maybe_unused]] uint8_t dimmNum = data[2] & 0x3;
514139aa4f0SVijay Khemka 
515139aa4f0SVijay Khemka             /* TODO: If critical SEL logging is available, do it */
516139aa4f0SVijay Khemka             if (snrType == 0x0C)
517139aa4f0SVijay Khemka             {
518139aa4f0SVijay Khemka                 if ((data[0] & 0x0F) == 0x0)
519139aa4f0SVijay Khemka                 {
520139aa4f0SVijay Khemka                     /* TODO: add_cri_sel */
521139aa4f0SVijay Khemka                     /* "DIMM"+ 'A'+ chnNum + dimmNum + " ECC err,FRU:1"
522139aa4f0SVijay Khemka                      */
523139aa4f0SVijay Khemka                 }
524139aa4f0SVijay Khemka                 else if ((data[0] & 0x0F) == 0x1)
525139aa4f0SVijay Khemka                 {
526139aa4f0SVijay Khemka                     /* TODO: add_cri_sel */
527139aa4f0SVijay Khemka                     /* "DIMM"+ 'A'+ chnNum + dimmNum + " UECC err,FRU:1"
528139aa4f0SVijay Khemka                      */
529139aa4f0SVijay Khemka                 }
530139aa4f0SVijay Khemka             }
531139aa4f0SVijay Khemka             /* Continue to parse the error into a string. All Info Valid
532139aa4f0SVijay Khemka              */
533139aa4f0SVijay Khemka             errLog += " (" + cpuStr + ", " + chStr + ", " + dimmStr + ")";
534139aa4f0SVijay Khemka         }
535139aa4f0SVijay Khemka 
536139aa4f0SVijay Khemka         break;
537139aa4f0SVijay Khemka         case 0x1:
538139aa4f0SVijay Khemka 
539139aa4f0SVijay Khemka             /* DIMM info not valid */
540139aa4f0SVijay Khemka             errLog += " (" + cpuStr + ", " + chStr + ")";
541139aa4f0SVijay Khemka             break;
542139aa4f0SVijay Khemka         case 0x2:
543139aa4f0SVijay Khemka 
544139aa4f0SVijay Khemka             /* CHN info not valid */
545139aa4f0SVijay Khemka             errLog += " (" + cpuStr + ", " + dimmStr + ")";
546139aa4f0SVijay Khemka             break;
547139aa4f0SVijay Khemka         case 0x3:
548139aa4f0SVijay Khemka 
549139aa4f0SVijay Khemka             /* CPU info not valid */
550139aa4f0SVijay Khemka             errLog += " (" + chStr + ", " + dimmStr + ")";
551139aa4f0SVijay Khemka             break;
552139aa4f0SVijay Khemka     }
553139aa4f0SVijay Khemka }
554139aa4f0SVijay Khemka 
555139aa4f0SVijay Khemka static void logPwrErr(uint8_t* data, std::string& errLog)
556139aa4f0SVijay Khemka {
557139aa4f0SVijay Khemka     if (data[0] == 0x1)
558139aa4f0SVijay Khemka     {
559139aa4f0SVijay Khemka         errLog = "SYS_PWROK failure";
560139aa4f0SVijay Khemka         /* Also try logging to Critial log file, if available */
561139aa4f0SVijay Khemka         /* "SYS_PWROK failure,FRU:1" */
562139aa4f0SVijay Khemka     }
563139aa4f0SVijay Khemka     else if (data[0] == 0x2)
564139aa4f0SVijay Khemka     {
565139aa4f0SVijay Khemka         errLog = "PCH_PWROK failure";
566139aa4f0SVijay Khemka         /* Also try logging to Critial log file, if available */
567139aa4f0SVijay Khemka         /* "PCH_PWROK failure,FRU:1" */
568139aa4f0SVijay Khemka     }
569139aa4f0SVijay Khemka     else
570139aa4f0SVijay Khemka     {
571139aa4f0SVijay Khemka         errLog = "Unknown";
572139aa4f0SVijay Khemka     }
573139aa4f0SVijay Khemka }
574139aa4f0SVijay Khemka 
575139aa4f0SVijay Khemka static void logCatErr(uint8_t* data, std::string& errLog)
576139aa4f0SVijay Khemka {
577139aa4f0SVijay Khemka     if (data[0] == 0x0)
578139aa4f0SVijay Khemka     {
579139aa4f0SVijay Khemka         errLog = "IERR/CATERR";
580139aa4f0SVijay Khemka         /* Also try logging to Critial log file, if available */
581139aa4f0SVijay Khemka         /* "IERR,FRU:1 */
582139aa4f0SVijay Khemka     }
583139aa4f0SVijay Khemka     else if (data[0] == 0xB)
584139aa4f0SVijay Khemka     {
585139aa4f0SVijay Khemka         errLog = "MCERR/CATERR";
586139aa4f0SVijay Khemka         /* Also try logging to Critial log file, if available */
587139aa4f0SVijay Khemka         /* "MCERR,FRU:1 */
588139aa4f0SVijay Khemka     }
589139aa4f0SVijay Khemka     else
590139aa4f0SVijay Khemka     {
591139aa4f0SVijay Khemka         errLog = "Unknown";
592139aa4f0SVijay Khemka     }
593139aa4f0SVijay Khemka }
594139aa4f0SVijay Khemka 
595139aa4f0SVijay Khemka static void logDimmHot(uint8_t* data, std::string& errLog)
596139aa4f0SVijay Khemka {
597139aa4f0SVijay Khemka     if ((data[0] << 16 | data[1] << 8 | data[2]) == 0x01FFFF)
598139aa4f0SVijay Khemka     {
599139aa4f0SVijay Khemka         errLog = "SOC MEMHOT";
600139aa4f0SVijay Khemka     }
601139aa4f0SVijay Khemka     else
602139aa4f0SVijay Khemka     {
603139aa4f0SVijay Khemka         errLog = "Unknown";
604139aa4f0SVijay Khemka         /* Also try logging to Critial log file, if available */
605139aa4f0SVijay Khemka         /* ""CPU_DIMM_HOT %s,FRU:1" */
606139aa4f0SVijay Khemka     }
607139aa4f0SVijay Khemka }
608139aa4f0SVijay Khemka 
609139aa4f0SVijay Khemka static void logSwNMI(uint8_t* data, std::string& errLog)
610139aa4f0SVijay Khemka {
611139aa4f0SVijay Khemka     if ((data[0] << 16 | data[1] << 8 | data[2]) == 0x03FFFF)
612139aa4f0SVijay Khemka     {
613139aa4f0SVijay Khemka         errLog = "Software NMI";
614139aa4f0SVijay Khemka     }
615139aa4f0SVijay Khemka     else
616139aa4f0SVijay Khemka     {
617139aa4f0SVijay Khemka         errLog = "Unknown SW NMI";
618139aa4f0SVijay Khemka     }
619139aa4f0SVijay Khemka }
620139aa4f0SVijay Khemka 
621139aa4f0SVijay Khemka static void logCPUThermalSts(uint8_t* data, std::string& errLog)
622139aa4f0SVijay Khemka {
623139aa4f0SVijay Khemka     switch (data[0])
624139aa4f0SVijay Khemka     {
625139aa4f0SVijay Khemka         case 0x0:
626139aa4f0SVijay Khemka             errLog = "CPU Critical Temperature";
627139aa4f0SVijay Khemka             break;
628139aa4f0SVijay Khemka         case 0x1:
629139aa4f0SVijay Khemka             errLog = "PROCHOT#";
630139aa4f0SVijay Khemka             break;
631139aa4f0SVijay Khemka         case 0x2:
632139aa4f0SVijay Khemka             errLog = "TCC Activation";
633139aa4f0SVijay Khemka             break;
634139aa4f0SVijay Khemka         default:
635139aa4f0SVijay Khemka             errLog = "Unknown";
636139aa4f0SVijay Khemka     }
637139aa4f0SVijay Khemka }
638139aa4f0SVijay Khemka 
639139aa4f0SVijay Khemka static void logMEPwrState(uint8_t* data, std::string& errLog)
640139aa4f0SVijay Khemka {
641139aa4f0SVijay Khemka     switch (data[0])
642139aa4f0SVijay Khemka     {
643139aa4f0SVijay Khemka         case 0:
644139aa4f0SVijay Khemka             errLog = "RUNNING";
645139aa4f0SVijay Khemka             break;
646139aa4f0SVijay Khemka         case 2:
647139aa4f0SVijay Khemka             errLog = "POWER_OFF";
648139aa4f0SVijay Khemka             break;
649139aa4f0SVijay Khemka         default:
650139aa4f0SVijay Khemka             errLog = "Unknown[" + std::to_string(data[0]) + "]";
651139aa4f0SVijay Khemka             break;
652139aa4f0SVijay Khemka     }
653139aa4f0SVijay Khemka }
654139aa4f0SVijay Khemka 
655139aa4f0SVijay Khemka static void logSPSFwHealth(uint8_t* data, std::string& errLog)
656139aa4f0SVijay Khemka {
657139aa4f0SVijay Khemka     if ((data[0] & 0x0F) == 0x00)
658139aa4f0SVijay Khemka     {
659139aa4f0SVijay Khemka         const std::vector<std::string> tmpStr = {
660139aa4f0SVijay Khemka             "Recovery GPIO forced",
661139aa4f0SVijay Khemka             "Image execution failed",
662139aa4f0SVijay Khemka             "Flash erase error",
663139aa4f0SVijay Khemka             "Flash state information",
664139aa4f0SVijay Khemka             "Internal error",
665139aa4f0SVijay Khemka             "BMC did not respond",
666139aa4f0SVijay Khemka             "Direct Flash update",
667139aa4f0SVijay Khemka             "Manufacturing error",
668139aa4f0SVijay Khemka             "Automatic Restore to Factory Presets",
669139aa4f0SVijay Khemka             "Firmware Exception",
670139aa4f0SVijay Khemka             "Flash Wear-Out Protection Warning",
671139aa4f0SVijay Khemka             "Unknown",
672139aa4f0SVijay Khemka             "Unknown",
673139aa4f0SVijay Khemka             "DMI interface error",
674139aa4f0SVijay Khemka             "MCTP interface error",
675139aa4f0SVijay Khemka             "Auto-configuration finished",
676139aa4f0SVijay Khemka             "Unsupported Segment Defined Feature",
677139aa4f0SVijay Khemka             "Unknown",
678139aa4f0SVijay Khemka             "CPU Debug Capability Disabled",
679139aa4f0SVijay Khemka             "UMA operation error"};
680139aa4f0SVijay Khemka 
681139aa4f0SVijay Khemka         if (data[1] < 0x14)
682139aa4f0SVijay Khemka         {
683139aa4f0SVijay Khemka             errLog = tmpStr[data[1]];
684139aa4f0SVijay Khemka         }
685139aa4f0SVijay Khemka         else
686139aa4f0SVijay Khemka         {
687139aa4f0SVijay Khemka             errLog = "Unknown";
688139aa4f0SVijay Khemka         }
689139aa4f0SVijay Khemka     }
690139aa4f0SVijay Khemka     else if ((data[0] & 0x0F) == 0x01)
691139aa4f0SVijay Khemka     {
692139aa4f0SVijay Khemka         errLog = "SMBus link failure";
693139aa4f0SVijay Khemka     }
694139aa4f0SVijay Khemka     else
695139aa4f0SVijay Khemka     {
696139aa4f0SVijay Khemka         errLog = "Unknown";
697139aa4f0SVijay Khemka     }
698139aa4f0SVijay Khemka }
699139aa4f0SVijay Khemka 
700139aa4f0SVijay Khemka static void logNmExcA(uint8_t* data, std::string& errLog)
701139aa4f0SVijay Khemka {
702139aa4f0SVijay Khemka     /*NM4.0 #550710, Revision 1.95, and turn to p.155*/
703139aa4f0SVijay Khemka     if (data[0] == 0xA8)
704139aa4f0SVijay Khemka     {
705139aa4f0SVijay Khemka         errLog = "Policy Correction Time Exceeded";
706139aa4f0SVijay Khemka     }
707139aa4f0SVijay Khemka     else
708139aa4f0SVijay Khemka     {
709139aa4f0SVijay Khemka         errLog = "Unknown";
710139aa4f0SVijay Khemka     }
711139aa4f0SVijay Khemka }
712139aa4f0SVijay Khemka 
713139aa4f0SVijay Khemka static void logPCHThermal(uint8_t* data, std::string& errLog)
714139aa4f0SVijay Khemka {
715139aa4f0SVijay Khemka     const std::vector<std::string> thresEvtName = {"Lower Non-critical",
716139aa4f0SVijay Khemka                                                    "Unknown",
717139aa4f0SVijay Khemka                                                    "Lower Critical",
718139aa4f0SVijay Khemka                                                    "Unknown",
719139aa4f0SVijay Khemka                                                    "Lower Non-recoverable",
720139aa4f0SVijay Khemka                                                    "Unknown",
721139aa4f0SVijay Khemka                                                    "Unknown",
722139aa4f0SVijay Khemka                                                    "Upper Non-critical",
723139aa4f0SVijay Khemka                                                    "Unknown",
724139aa4f0SVijay Khemka                                                    "Upper Critical",
725139aa4f0SVijay Khemka                                                    "Unknown",
726139aa4f0SVijay Khemka                                                    "Upper Non-recoverable"};
727139aa4f0SVijay Khemka 
728139aa4f0SVijay Khemka     if ((data[0] & 0x0f) < 12)
729139aa4f0SVijay Khemka     {
730139aa4f0SVijay Khemka         errLog = thresEvtName[(data[0] & 0x0f)];
731139aa4f0SVijay Khemka     }
732139aa4f0SVijay Khemka     else
733139aa4f0SVijay Khemka     {
734139aa4f0SVijay Khemka         errLog = "Unknown";
735139aa4f0SVijay Khemka     }
736139aa4f0SVijay Khemka 
737139aa4f0SVijay Khemka     errLog += ", curr_val: " + std::to_string(data[1]) +
738139aa4f0SVijay Khemka               " C, thresh_val: " + std::to_string(data[2]) + " C";
739139aa4f0SVijay Khemka }
740139aa4f0SVijay Khemka 
741139aa4f0SVijay Khemka static void logNmHealth(uint8_t* data, std::string& errLog)
742139aa4f0SVijay Khemka {
743139aa4f0SVijay Khemka     std::vector<std::string> nmErrType = {
744139aa4f0SVijay Khemka         "Unknown",
745139aa4f0SVijay Khemka         "Unknown",
746139aa4f0SVijay Khemka         "Unknown",
747139aa4f0SVijay Khemka         "Unknown",
748139aa4f0SVijay Khemka         "Unknown",
749139aa4f0SVijay Khemka         "Unknown",
750139aa4f0SVijay Khemka         "Unknown",
751139aa4f0SVijay Khemka         "Extended Telemetry Device Reading Failure",
752139aa4f0SVijay Khemka         "Outlet Temperature Reading Failure",
753139aa4f0SVijay Khemka         "Volumetric Airflow Reading Failure",
754139aa4f0SVijay Khemka         "Policy Misconfiguration",
755139aa4f0SVijay Khemka         "Power Sensor Reading Failure",
756139aa4f0SVijay Khemka         "Inlet Temperature Reading Failure",
757139aa4f0SVijay Khemka         "Host Communication Error",
758139aa4f0SVijay Khemka         "Real-time Clock Synchronization Failure",
759139aa4f0SVijay Khemka         "Platform Shutdown Initiated by Intel NM Policy",
760139aa4f0SVijay Khemka         "Unknown"};
761139aa4f0SVijay Khemka     uint8_t nmTypeIdx = (data[0] & 0xf);
762139aa4f0SVijay Khemka     uint8_t domIdx = (data[1] & 0xf);
763139aa4f0SVijay Khemka     uint8_t errIdx = ((data[1] >> 4) & 0xf);
764139aa4f0SVijay Khemka 
765139aa4f0SVijay Khemka     if (nmTypeIdx == 2)
766139aa4f0SVijay Khemka     {
767139aa4f0SVijay Khemka         errLog = "SensorIntelNM";
768139aa4f0SVijay Khemka     }
769139aa4f0SVijay Khemka     else
770139aa4f0SVijay Khemka     {
771139aa4f0SVijay Khemka         errLog = "Unknown";
772139aa4f0SVijay Khemka     }
773139aa4f0SVijay Khemka 
774139aa4f0SVijay Khemka     errLog += ", Domain:" + nmDomName[domIdx] +
775139aa4f0SVijay Khemka               ", ErrType:" + nmErrType[errIdx] + ", Err:0x" +
776139aa4f0SVijay Khemka               byteToStr(data[2]);
777139aa4f0SVijay Khemka }
778139aa4f0SVijay Khemka 
779139aa4f0SVijay Khemka static void logNmCap(uint8_t* data, std::string& errLog)
780139aa4f0SVijay Khemka {
781139aa4f0SVijay Khemka     const std::vector<std::string> nmCapStsStr = {"Not Available", "Available"};
782139aa4f0SVijay Khemka     if (data[0] & 0x7) // BIT1=policy, BIT2=monitoring, BIT3=pwr
783139aa4f0SVijay Khemka                        // limit and the others are reserved
784139aa4f0SVijay Khemka     {
785139aa4f0SVijay Khemka         errLog = "PolicyInterface:" + nmCapStsStr[BIT(data[0], 0)] +
786139aa4f0SVijay Khemka                  ",Monitoring:" + nmCapStsStr[BIT(data[0], 1)] +
787139aa4f0SVijay Khemka                  ",PowerLimit:" + nmCapStsStr[BIT(data[0], 2)];
788139aa4f0SVijay Khemka     }
789139aa4f0SVijay Khemka     else
790139aa4f0SVijay Khemka     {
791139aa4f0SVijay Khemka         errLog = "Unknown";
792139aa4f0SVijay Khemka     }
793139aa4f0SVijay Khemka }
794139aa4f0SVijay Khemka 
795139aa4f0SVijay Khemka static void logNmThreshold(uint8_t* data, std::string& errLog)
796139aa4f0SVijay Khemka {
797139aa4f0SVijay Khemka     uint8_t thresNum = (data[0] & 0x3);
798139aa4f0SVijay Khemka     uint8_t domIdx = (data[1] & 0xf);
799139aa4f0SVijay Khemka     uint8_t polId = data[2];
800139aa4f0SVijay Khemka     uint8_t polEvtIdx = BIT(data[0], 3);
801139aa4f0SVijay Khemka     const std::vector<std::string> polEvtStr = {
802139aa4f0SVijay Khemka         "Threshold Exceeded", "Policy Correction Time Exceeded"};
803139aa4f0SVijay Khemka 
804139aa4f0SVijay Khemka     errLog = "Threshold Number:" + std::to_string(thresNum) + "-" +
805139aa4f0SVijay Khemka              polEvtStr[polEvtIdx] + ", Domain:" + nmDomName[domIdx] +
806139aa4f0SVijay Khemka              ", PolicyID:0x" + byteToStr(polId);
807139aa4f0SVijay Khemka }
808139aa4f0SVijay Khemka 
809139aa4f0SVijay Khemka static void logPwrThreshold(uint8_t* data, std::string& errLog)
810139aa4f0SVijay Khemka {
811139aa4f0SVijay Khemka     if (data[0] == 0x00)
812139aa4f0SVijay Khemka     {
813139aa4f0SVijay Khemka         errLog = "Limit Not Exceeded";
814139aa4f0SVijay Khemka     }
815139aa4f0SVijay Khemka     else if (data[0] == 0x01)
816139aa4f0SVijay Khemka     {
817139aa4f0SVijay Khemka         errLog = "Limit Exceeded";
818139aa4f0SVijay Khemka     }
819139aa4f0SVijay Khemka     else
820139aa4f0SVijay Khemka     {
821139aa4f0SVijay Khemka         errLog = "Unknown";
822139aa4f0SVijay Khemka     }
823139aa4f0SVijay Khemka }
824139aa4f0SVijay Khemka 
825139aa4f0SVijay Khemka static void logMSMI(uint8_t* data, std::string& errLog)
826139aa4f0SVijay Khemka {
827139aa4f0SVijay Khemka     if (data[0] == 0x0)
828139aa4f0SVijay Khemka     {
829139aa4f0SVijay Khemka         errLog = "IERR/MSMI";
830139aa4f0SVijay Khemka     }
831139aa4f0SVijay Khemka     else if (data[0] == 0x0B)
832139aa4f0SVijay Khemka     {
833139aa4f0SVijay Khemka         errLog = "MCERR/MSMI";
834139aa4f0SVijay Khemka     }
835139aa4f0SVijay Khemka     else
836139aa4f0SVijay Khemka     {
837139aa4f0SVijay Khemka         errLog = "Unknown";
838139aa4f0SVijay Khemka     }
839139aa4f0SVijay Khemka }
840139aa4f0SVijay Khemka 
841139aa4f0SVijay Khemka static void logHprWarn(uint8_t* data, std::string& errLog)
842139aa4f0SVijay Khemka {
843139aa4f0SVijay Khemka     if (data[2] == 0x01)
844139aa4f0SVijay Khemka     {
845139aa4f0SVijay Khemka         if (data[1] == 0xFF)
846139aa4f0SVijay Khemka         {
847139aa4f0SVijay Khemka             errLog = "Infinite Time";
848139aa4f0SVijay Khemka         }
849139aa4f0SVijay Khemka         else
850139aa4f0SVijay Khemka         {
851139aa4f0SVijay Khemka             errLog = std::to_string(data[1]) + " minutes";
852139aa4f0SVijay Khemka         }
853139aa4f0SVijay Khemka     }
854139aa4f0SVijay Khemka     else
855139aa4f0SVijay Khemka     {
856139aa4f0SVijay Khemka         errLog = "Unknown";
857139aa4f0SVijay Khemka     }
858139aa4f0SVijay Khemka }
859139aa4f0SVijay Khemka 
860139aa4f0SVijay Khemka static const boost::container::flat_map<
861139aa4f0SVijay Khemka     uint8_t,
862139aa4f0SVijay Khemka     std::pair<std::string, std::function<void(uint8_t*, std::string&)>>>
863139aa4f0SVijay Khemka     sensorNameTable = {{0xE9, {"SYSTEM_EVENT", logSysEvent}},
864139aa4f0SVijay Khemka                        {0x7D, {"THERM_THRESH_EVT", logThermalEvent}},
865139aa4f0SVijay Khemka                        {0xAA, {"BUTTON", logDefault}},
866139aa4f0SVijay Khemka                        {0xAB, {"POWER_STATE", logDefault}},
867139aa4f0SVijay Khemka                        {0xEA, {"CRITICAL_IRQ", logCritIrq}},
868139aa4f0SVijay Khemka                        {0x2B, {"POST_ERROR", logPostErr}},
869139aa4f0SVijay Khemka                        {0x40, {"MACHINE_CHK_ERR", logMchChkErr}},
870139aa4f0SVijay Khemka                        {0x41, {"PCIE_ERR", logPcieErr}},
871139aa4f0SVijay Khemka                        {0x43, {"IIO_ERR", logIioErr}},
872139aa4f0SVijay Khemka                        {0X63, {"MEMORY_ECC_ERR", logDefault}},
873139aa4f0SVijay Khemka                        {0X87, {"MEMORY_ERR_LOG_DIS", logDefault}},
874139aa4f0SVijay Khemka                        {0X51, {"PROCHOT_EXT", logDefault}},
875139aa4f0SVijay Khemka                        {0X56, {"PWR_ERR", logPwrErr}},
876139aa4f0SVijay Khemka                        {0xE6, {"CATERR_A", logCatErr}},
877139aa4f0SVijay Khemka                        {0xEB, {"CATERR_B", logCatErr}},
878139aa4f0SVijay Khemka                        {0xB3, {"CPU_DIMM_HOT", logDimmHot}},
879139aa4f0SVijay Khemka                        {0x90, {"SOFTWARE_NMI", logSwNMI}},
880139aa4f0SVijay Khemka                        {0x1C, {"CPU0_THERM_STATUS", logCPUThermalSts}},
881139aa4f0SVijay Khemka                        {0x1D, {"CPU1_THERM_STATUS", logCPUThermalSts}},
882139aa4f0SVijay Khemka                        {0x16, {"ME_POWER_STATE", logMEPwrState}},
883139aa4f0SVijay Khemka                        {0x17, {"SPS_FW_HEALTH", logSPSFwHealth}},
884139aa4f0SVijay Khemka                        {0x18, {"NM_EXCEPTION_A", logNmExcA}},
885139aa4f0SVijay Khemka                        {0x08, {"PCH_THERM_THRESHOLD", logPCHThermal}},
886139aa4f0SVijay Khemka                        {0x19, {"NM_HEALTH", logNmHealth}},
887139aa4f0SVijay Khemka                        {0x1A, {"NM_CAPABILITIES", logNmCap}},
888139aa4f0SVijay Khemka                        {0x1B, {"NM_THRESHOLD", logNmThreshold}},
889139aa4f0SVijay Khemka                        {0x3B, {"PWR_THRESH_EVT", logPwrThreshold}},
890139aa4f0SVijay Khemka                        {0xE7, {"MSMI", logMSMI}},
891139aa4f0SVijay Khemka                        {0xC5, {"HPR_WARNING", logHprWarn}}};
892139aa4f0SVijay Khemka 
893139aa4f0SVijay Khemka static void parseSelHelper(StdSELEntry* data, std::string& errStr)
894139aa4f0SVijay Khemka {
895139aa4f0SVijay Khemka     /* Check if sensor type is OS_BOOT (0x1f) */
896139aa4f0SVijay Khemka     if (data->sensorType == 0x1F)
897139aa4f0SVijay Khemka     {
898139aa4f0SVijay Khemka         /* OS_BOOT used by OS */
899139aa4f0SVijay Khemka         switch (data->eventData1 & 0xF)
900139aa4f0SVijay Khemka         {
901139aa4f0SVijay Khemka             case 0x07:
902139aa4f0SVijay Khemka                 errStr = "Base OS/Hypervisor Installation started";
903139aa4f0SVijay Khemka                 break;
904139aa4f0SVijay Khemka             case 0x08:
905139aa4f0SVijay Khemka                 errStr = "Base OS/Hypervisor Installation completed";
906139aa4f0SVijay Khemka                 break;
907139aa4f0SVijay Khemka             case 0x09:
908139aa4f0SVijay Khemka                 errStr = "Base OS/Hypervisor Installation aborted";
909139aa4f0SVijay Khemka                 break;
910139aa4f0SVijay Khemka             case 0x0A:
911139aa4f0SVijay Khemka                 errStr = "Base OS/Hypervisor Installation failed";
912139aa4f0SVijay Khemka                 break;
913139aa4f0SVijay Khemka             default:
914139aa4f0SVijay Khemka                 errStr = "Unknown";
915139aa4f0SVijay Khemka         }
916139aa4f0SVijay Khemka         return;
917139aa4f0SVijay Khemka     }
918139aa4f0SVijay Khemka 
919139aa4f0SVijay Khemka     auto findSensorName = sensorNameTable.find(data->sensorNum);
920139aa4f0SVijay Khemka     if (findSensorName == sensorNameTable.end())
921139aa4f0SVijay Khemka     {
922139aa4f0SVijay Khemka         errStr = "Unknown";
923139aa4f0SVijay Khemka         return;
924139aa4f0SVijay Khemka     }
925139aa4f0SVijay Khemka     else
926139aa4f0SVijay Khemka     {
927139aa4f0SVijay Khemka         switch (data->sensorNum)
928139aa4f0SVijay Khemka         {
929139aa4f0SVijay Khemka             /* logMemErr function needs data from sensor type */
930139aa4f0SVijay Khemka             case memoryEccError:
931139aa4f0SVijay Khemka             case memoryErrLogDIS:
932139aa4f0SVijay Khemka                 findSensorName->second.second(&(data->sensorType), errStr);
933139aa4f0SVijay Khemka                 break;
934139aa4f0SVijay Khemka             /* Other sensor function needs only event data for parsing */
935139aa4f0SVijay Khemka             default:
936139aa4f0SVijay Khemka                 findSensorName->second.second(&(data->eventData1), errStr);
937139aa4f0SVijay Khemka         }
938139aa4f0SVijay Khemka     }
939139aa4f0SVijay Khemka 
940139aa4f0SVijay Khemka     if (((data->eventData3 & 0x80) >> 7) == 0)
941139aa4f0SVijay Khemka     {
942139aa4f0SVijay Khemka         errStr += " Assertion";
943139aa4f0SVijay Khemka     }
944139aa4f0SVijay Khemka     else
945139aa4f0SVijay Khemka     {
946139aa4f0SVijay Khemka         errStr += " Deassertion";
947139aa4f0SVijay Khemka     }
948139aa4f0SVijay Khemka }
949139aa4f0SVijay Khemka 
950c056dc00SManikandan Elumalai static void parseDimmPhyloc(StdSELEntry* data, std::string& errStr)
951c056dc00SManikandan Elumalai {
952c056dc00SManikandan Elumalai     // Log when " All info available"
953c056dc00SManikandan Elumalai     uint8_t chNum = (data->eventData3 & 0x18) >> 3;
954c056dc00SManikandan Elumalai     uint8_t dimmNum = data->eventData3 & 0x7;
955c056dc00SManikandan Elumalai     uint8_t rankNum = data->eventData2 & 0x03;
956c056dc00SManikandan Elumalai     uint8_t nodeNum = (data->eventData3 & 0xE0) >> 5;
957c056dc00SManikandan Elumalai 
958c056dc00SManikandan Elumalai     if (chNum == 3 && dimmNum == 0)
959c056dc00SManikandan Elumalai     {
960c056dc00SManikandan Elumalai         errStr += " Node: " + std::to_string(nodeNum) + "," +
961c056dc00SManikandan Elumalai                   " Card: " + std::to_string(chNum) + "," +
962c056dc00SManikandan Elumalai                   " Module: " + std::to_string(dimmNum) + "," +
963c056dc00SManikandan Elumalai                   " Rank Number: " + std::to_string(rankNum) + "," +
964c056dc00SManikandan Elumalai                   "  Location: DIMM A0";
965c056dc00SManikandan Elumalai     }
966c056dc00SManikandan Elumalai     else if (chNum == 2 && dimmNum == 0)
967c056dc00SManikandan Elumalai     {
968c056dc00SManikandan Elumalai         errStr += " Node: " + std::to_string(nodeNum) + "," +
969c056dc00SManikandan Elumalai                   " Card: " + std::to_string(chNum) + "," +
970c056dc00SManikandan Elumalai                   " Module: " + std::to_string(dimmNum) + "," +
971c056dc00SManikandan Elumalai                   " Rank Number: " + std::to_string(rankNum) + "," +
972c056dc00SManikandan Elumalai                   " Location: DIMM B0";
973c056dc00SManikandan Elumalai     }
974c056dc00SManikandan Elumalai     else if (chNum == 4 && dimmNum == 0)
975c056dc00SManikandan Elumalai     {
976c056dc00SManikandan Elumalai         errStr += " Node: " + std::to_string(nodeNum) + "," +
977c056dc00SManikandan Elumalai                   " Card: " + std::to_string(chNum) + "," +
978c056dc00SManikandan Elumalai                   " Module: " + std::to_string(dimmNum) + "," +
979c056dc00SManikandan Elumalai                   " Rank Number: " + std::to_string(rankNum) + "," +
980c056dc00SManikandan Elumalai                   " Location: DIMM C0 ";
981c056dc00SManikandan Elumalai     }
982c056dc00SManikandan Elumalai     else if (chNum == 5 && dimmNum == 0)
983c056dc00SManikandan Elumalai     {
984c056dc00SManikandan Elumalai         errStr += " Node: " + std::to_string(nodeNum) + "," +
985c056dc00SManikandan Elumalai                   " Card: " + std::to_string(chNum) + "," +
986c056dc00SManikandan Elumalai                   " Module: " + std::to_string(dimmNum) + "," +
987c056dc00SManikandan Elumalai                   " Rank Number: " + std::to_string(rankNum) + "," +
988c056dc00SManikandan Elumalai                   " Location: DIMM D0";
989c056dc00SManikandan Elumalai     }
990c056dc00SManikandan Elumalai     else
991c056dc00SManikandan Elumalai     {
992c056dc00SManikandan Elumalai         errStr += " Node: " + std::to_string(nodeNum) + "," +
993c056dc00SManikandan Elumalai                   " Card: " + std::to_string(chNum) + "," +
994c056dc00SManikandan Elumalai                   " Module: " + std::to_string(dimmNum) + "," +
995c056dc00SManikandan Elumalai                   " Rank Number: " + std::to_string(rankNum) + "," +
996c056dc00SManikandan Elumalai                   " Location: DIMM Unknow";
997c056dc00SManikandan Elumalai     }
998c056dc00SManikandan Elumalai }
999c056dc00SManikandan Elumalai 
1000f36f345fSVijay Khemka static void parseStdSel(StdSELEntry* data, std::string& errStr)
1001f36f345fSVijay Khemka {
1002f36f345fSVijay Khemka     std::stringstream tmpStream;
1003f36f345fSVijay Khemka     tmpStream << std::hex << std::uppercase;
1004f36f345fSVijay Khemka 
1005f36f345fSVijay Khemka     /* TODO: add pal_add_cri_sel */
1006f36f345fSVijay Khemka     switch (data->sensorNum)
1007f36f345fSVijay Khemka     {
1008f36f345fSVijay Khemka         case memoryEccError:
1009f36f345fSVijay Khemka             switch (data->eventData1 & 0x0F)
1010f36f345fSVijay Khemka             {
1011f36f345fSVijay Khemka                 case 0x00:
1012f36f345fSVijay Khemka                     errStr = "Correctable";
1013f36f345fSVijay Khemka                     tmpStream << "DIMM" << std::setw(2) << std::setfill('0')
1014f36f345fSVijay Khemka                               << data->eventData3 << " ECC err";
1015c056dc00SManikandan Elumalai                     parseDimmPhyloc(data, errStr);
1016f36f345fSVijay Khemka                     break;
1017f36f345fSVijay Khemka                 case 0x01:
1018f36f345fSVijay Khemka                     errStr = "Uncorrectable";
1019f36f345fSVijay Khemka                     tmpStream << "DIMM" << std::setw(2) << std::setfill('0')
1020f36f345fSVijay Khemka                               << data->eventData3 << " UECC err";
1021c056dc00SManikandan Elumalai                     parseDimmPhyloc(data, errStr);
1022f36f345fSVijay Khemka                     break;
1023f36f345fSVijay Khemka                 case 0x02:
1024f36f345fSVijay Khemka                     errStr = "Parity";
1025f36f345fSVijay Khemka                     break;
1026f36f345fSVijay Khemka                 case 0x05:
1027f36f345fSVijay Khemka                     errStr = "Correctable ECC error Logging Limit Reached";
1028f36f345fSVijay Khemka                     break;
1029f36f345fSVijay Khemka                 default:
1030f36f345fSVijay Khemka                     errStr = "Unknown";
1031f36f345fSVijay Khemka             }
1032f36f345fSVijay Khemka             break;
1033f36f345fSVijay Khemka         case memoryErrLogDIS:
1034f36f345fSVijay Khemka             if ((data->eventData1 & 0x0F) == 0)
1035f36f345fSVijay Khemka             {
1036f36f345fSVijay Khemka                 errStr = "Correctable Memory Error Logging Disabled";
1037f36f345fSVijay Khemka             }
1038f36f345fSVijay Khemka             else
1039f36f345fSVijay Khemka             {
1040f36f345fSVijay Khemka                 errStr = "Unknown";
1041f36f345fSVijay Khemka             }
1042f36f345fSVijay Khemka             break;
1043f36f345fSVijay Khemka         default:
1044139aa4f0SVijay Khemka             parseSelHelper(data, errStr);
1045f36f345fSVijay Khemka             return;
1046f36f345fSVijay Khemka     }
1047f36f345fSVijay Khemka 
1048f36f345fSVijay Khemka     errStr += " (DIMM " + std::to_string(data->eventData3) + ")";
1049f36f345fSVijay Khemka     errStr += " Logical Rank " + std::to_string(data->eventData2 & 0x03);
1050f36f345fSVijay Khemka 
1051f36f345fSVijay Khemka     switch ((data->eventData2 & 0x0C) >> 2)
1052f36f345fSVijay Khemka     {
1053f36f345fSVijay Khemka         case 0x00:
1054f36f345fSVijay Khemka             // Ignore when " All info available"
1055f36f345fSVijay Khemka             break;
1056f36f345fSVijay Khemka         case 0x01:
1057f36f345fSVijay Khemka             errStr += " DIMM info not valid";
1058f36f345fSVijay Khemka             break;
1059f36f345fSVijay Khemka         case 0x02:
1060f36f345fSVijay Khemka             errStr += " CHN info not valid";
1061f36f345fSVijay Khemka             break;
1062f36f345fSVijay Khemka         case 0x03:
1063f36f345fSVijay Khemka             errStr += " CPU info not valid";
1064f36f345fSVijay Khemka             break;
1065f36f345fSVijay Khemka         default:
1066f36f345fSVijay Khemka             errStr += " Unknown";
1067f36f345fSVijay Khemka     }
1068f36f345fSVijay Khemka 
1069f36f345fSVijay Khemka     if (((data->eventType & 0x80) >> 7) == 0)
1070f36f345fSVijay Khemka     {
1071f36f345fSVijay Khemka         errStr += " Assertion";
1072f36f345fSVijay Khemka     }
1073f36f345fSVijay Khemka     else
1074f36f345fSVijay Khemka     {
1075f36f345fSVijay Khemka         errStr += " Deassertion";
1076f36f345fSVijay Khemka     }
1077f36f345fSVijay Khemka 
1078f36f345fSVijay Khemka     return;
1079f36f345fSVijay Khemka }
1080f36f345fSVijay Khemka 
1081f36f345fSVijay Khemka static void parseOemSel(TsOemSELEntry* data, std::string& errStr)
1082f36f345fSVijay Khemka {
1083f36f345fSVijay Khemka     std::stringstream tmpStream;
1084f36f345fSVijay Khemka     tmpStream << std::hex << std::uppercase << std::setfill('0');
1085f36f345fSVijay Khemka 
1086f36f345fSVijay Khemka     switch (data->recordType)
1087f36f345fSVijay Khemka     {
1088f36f345fSVijay Khemka         case 0xC0:
1089f36f345fSVijay Khemka             tmpStream << "VID:0x" << std::setw(2) << (int)data->oemData[1]
1090f36f345fSVijay Khemka                       << std::setw(2) << (int)data->oemData[0] << " DID:0x"
1091f36f345fSVijay Khemka                       << std::setw(2) << (int)data->oemData[3] << std::setw(2)
1092f36f345fSVijay Khemka                       << (int)data->oemData[2] << " Slot:0x" << std::setw(2)
1093f36f345fSVijay Khemka                       << (int)data->oemData[4] << " Error ID:0x" << std::setw(2)
1094f36f345fSVijay Khemka                       << (int)data->oemData[5];
1095f36f345fSVijay Khemka             break;
1096f36f345fSVijay Khemka         case 0xC2:
1097f36f345fSVijay Khemka             tmpStream << "Extra info:0x" << std::setw(2)
1098f36f345fSVijay Khemka                       << (int)data->oemData[1] << " MSCOD:0x" << std::setw(2)
1099f36f345fSVijay Khemka                       << (int)data->oemData[3] << std::setw(2)
1100f36f345fSVijay Khemka                       << (int)data->oemData[2] << " MCACOD:0x" << std::setw(2)
1101f36f345fSVijay Khemka                       << (int)data->oemData[5] << std::setw(2)
1102f36f345fSVijay Khemka                       << (int)data->oemData[4];
1103f36f345fSVijay Khemka             break;
1104f36f345fSVijay Khemka         case 0xC3:
1105f36f345fSVijay Khemka             int bank = (data->oemData[1] & 0xf0) >> 4;
1106f36f345fSVijay Khemka             int col = ((data->oemData[1] & 0x0f) << 8) | data->oemData[2];
1107f36f345fSVijay Khemka 
1108f36f345fSVijay Khemka             tmpStream << "Fail Device:0x" << std::setw(2)
1109f36f345fSVijay Khemka                       << (int)data->oemData[0] << " Bank:0x" << std::setw(2)
1110f36f345fSVijay Khemka                       << bank << " Column:0x" << std::setw(2) << col
1111f36f345fSVijay Khemka                       << " Failed Row:0x" << std::setw(2)
1112f36f345fSVijay Khemka                       << (int)data->oemData[3] << std::setw(2)
1113f36f345fSVijay Khemka                       << (int)data->oemData[4] << std::setw(2)
1114f36f345fSVijay Khemka                       << (int)data->oemData[5];
1115f36f345fSVijay Khemka     }
1116f36f345fSVijay Khemka 
1117f36f345fSVijay Khemka     errStr = tmpStream.str();
1118f36f345fSVijay Khemka 
1119f36f345fSVijay Khemka     return;
1120f36f345fSVijay Khemka }
1121f36f345fSVijay Khemka 
1122*7451903cScchoux static std::string dimmLocationStr(uint8_t socket, uint8_t channel,
1123*7451903cScchoux                                    uint8_t slot)
1124*7451903cScchoux {
1125*7451903cScchoux     uint8_t sled = (socket >> 4) & 0x3;
1126*7451903cScchoux 
1127*7451903cScchoux     socket &= 0xf;
1128*7451903cScchoux     if (channel == 0xFF && slot == 0xFF)
1129*7451903cScchoux     {
1130*7451903cScchoux         return std::format(
1131*7451903cScchoux             "DIMM Slot Location: Sled {:02}/Socket {:02}, Channel unknown"
1132*7451903cScchoux             ", Slot unknown, DIMM unknown",
1133*7451903cScchoux             sled, socket);
1134*7451903cScchoux     }
1135*7451903cScchoux     else
1136*7451903cScchoux     {
1137*7451903cScchoux         channel &= 0xf;
1138*7451903cScchoux         slot &= 0xf;
1139*7451903cScchoux         const char label[] = {'A', 'C', 'B', 'D'};
1140*7451903cScchoux         uint8_t idx = socket * 2 + slot;
1141*7451903cScchoux         return std::format("DIMM Slot Location: Sled {:02}/Socket {:02}"
1142*7451903cScchoux                            ", Channel {:02}, Slot {:02} DIMM {}",
1143*7451903cScchoux                            sled, socket, channel, slot,
1144*7451903cScchoux                            (idx < sizeof(label))
1145*7451903cScchoux                                ? label[idx] + std::to_string(channel)
1146*7451903cScchoux                                : "NA");
1147*7451903cScchoux     }
1148*7451903cScchoux }
1149*7451903cScchoux 
115034a875f3SVijay Khemka static void parseOemUnifiedSel(NtsOemSELEntry* data, std::string& errStr)
115134a875f3SVijay Khemka {
115234a875f3SVijay Khemka     uint8_t* ptr = data->oemData;
1153*7451903cScchoux     uint8_t eventType = ptr[5] & 0xf;
115434a875f3SVijay Khemka     int genInfo = ptr[0];
115534a875f3SVijay Khemka     int errType = genInfo & 0x0f;
1156*7451903cScchoux     std::vector<std::string> dimmErr = {
1157*7451903cScchoux         "Memory training failure",
1158*7451903cScchoux         "Memory correctable error",
1159*7451903cScchoux         "Memory uncorrectable error",
1160*7451903cScchoux         "Memory correctable error (Patrol scrub)",
1161*7451903cScchoux         "Memory uncorrectable error (Patrol scrub)",
1162*7451903cScchoux         "Memory Parity Error (PCC=0)",
1163*7451903cScchoux         "Memory Parity Error (PCC=1)",
1164*7451903cScchoux         "Memory PMIC Error",
1165*7451903cScchoux         "CXL Memory training error",
1166*7451903cScchoux         "Reserved"};
1167*7451903cScchoux     std::vector<std::string> postEvent = {
1168*7451903cScchoux         "System PXE boot fail",
1169*7451903cScchoux         "CMOS/NVRAM configuration cleared",
1170*7451903cScchoux         "TPM Self-Test Fail",
1171*7451903cScchoux         "Boot Drive failure",
1172*7451903cScchoux         "Data Drive failure",
1173*7451903cScchoux         "Received invalid boot order request from BMC",
1174*7451903cScchoux         "System HTTP boot fail",
1175*7451903cScchoux         "BIOS fails to get the certificate from BMC",
1176*7451903cScchoux         "Password cleared by jumper",
1177*7451903cScchoux         "DXE FV check failure",
1178*7451903cScchoux         "AMD ABL failure",
1179*7451903cScchoux         "Reserved"};
1180*7451903cScchoux     std::vector<std::string> certErr = {
1181*7451903cScchoux         "No certificate at BMC", "IPMI transaction fail",
1182*7451903cScchoux         "Certificate data corrupted", "Reserved"};
1183*7451903cScchoux     std::vector<std::string> pcieEvent = {"PCIe DPC Event",
1184*7451903cScchoux                                           "PCIe LER Event",
1185*7451903cScchoux                                           "PCIe Link Retraining and Recovery",
1186*7451903cScchoux                                           "PCIe Link CRC Error Check and Retry",
1187*7451903cScchoux                                           "PCIe Corrupt Data Containment",
1188*7451903cScchoux                                           "PCIe Express ECRC",
1189*7451903cScchoux                                           "Reserved"};
1190*7451903cScchoux     std::vector<std::string> memEvent = {
1191*7451903cScchoux         "Memory PPR event",
1192*7451903cScchoux         "Memory Correctable Error logging limit reached",
1193*7451903cScchoux         "Memory disable/map-out for FRB",
1194*7451903cScchoux         "Memory SDDC",
1195*7451903cScchoux         "Memory Address range/Partial mirroring",
1196*7451903cScchoux         "Memory ADDDC",
1197*7451903cScchoux         "Memory SMBus hang recovery",
1198*7451903cScchoux         "No DIMM in System",
1199*7451903cScchoux         "Reserved"};
1200*7451903cScchoux     std::vector<std::string> memPprTime = {"Boot time", "Autonomous",
1201*7451903cScchoux                                            "Run time", "Reserved"};
1202*7451903cScchoux     std::vector<std::string> memPpr = {"PPR success", "PPR fail", "PPR request",
1203*7451903cScchoux                                        "Reserved"};
1204*7451903cScchoux     std::vector<std::string> memAdddc = {"Bank VLS", "r-Bank VLS + re-buddy",
1205*7451903cScchoux                                          "r-Bank VLS + Rank VLS",
1206*7451903cScchoux                                          "r-Rank VLS + re-buddy", "Reserved"};
1207*7451903cScchoux     std::vector<std::string> pprEvent = {"PPR disable", "Soft PPR", "Hard PPR",
1208*7451903cScchoux                                          "Reserved"};
120934a875f3SVijay Khemka 
121034a875f3SVijay Khemka     std::stringstream tmpStream;
121134a875f3SVijay Khemka 
121234a875f3SVijay Khemka     switch (errType)
121334a875f3SVijay Khemka     {
121434a875f3SVijay Khemka         case unifiedPcieErr:
1215*7451903cScchoux             tmpStream << std::format(
1216*7451903cScchoux                 "GeneralInfo: x86/PCIeErr(0x{:02X})"
1217*7451903cScchoux                 ", Bus {:02X}/Dev {:02X}/Fun {:02X}, TotalErrID1Cnt: 0x{:04X}"
1218*7451903cScchoux                 ", ErrID2: 0x{:02X}, ErrID1: 0x{:02X}",
1219*7451903cScchoux                 genInfo, ptr[8], ptr[7] >> 3, ptr[7] & 0x7,
1220*7451903cScchoux                 (ptr[10] << 8) | ptr[9], ptr[11], ptr[12]);
122134a875f3SVijay Khemka             break;
122234a875f3SVijay Khemka         case unifiedMemErr:
1223*7451903cScchoux             eventType = ptr[9] & 0xf;
1224*7451903cScchoux             tmpStream << std::format(
1225*7451903cScchoux                 "GeneralInfo: MemErr(0x{:02X}), {}, DIMM Failure Event: {}",
1226*7451903cScchoux                 genInfo, dimmLocationStr(ptr[5], ptr[6], ptr[7]),
1227*7451903cScchoux                 dimmErr[std::min(eventType,
1228*7451903cScchoux                                  static_cast<uint8_t>(dimmErr.size() - 1))]);
122934a875f3SVijay Khemka 
1230*7451903cScchoux             if (static_cast<MemErrType>(eventType) == MemErrType::memTrainErr ||
1231*7451903cScchoux                 static_cast<MemErrType>(eventType) == MemErrType::memPmicErr)
1232*7451903cScchoux             {
1233*7451903cScchoux                 bool amd = ptr[9] & 0x80;
1234*7451903cScchoux                 tmpStream << std::format(
1235*7451903cScchoux                     ", Major Code: 0x{:02X}, Minor Code: 0x{:0{}X}", ptr[10],
1236*7451903cScchoux                     amd ? (ptr[12] << 8 | ptr[11]) : ptr[11], amd ? 4 : 2);
1237*7451903cScchoux             }
1238*7451903cScchoux             break;
1239*7451903cScchoux         case unifiedIioErr:
1240*7451903cScchoux             tmpStream << std::format(
1241*7451903cScchoux                 "GeneralInfo: IIOErr(0x{:02X})"
1242*7451903cScchoux                 ", IIO Port Location: Sled {:02}/Socket {:02}, Stack 0x{:02X}"
1243*7451903cScchoux                 ", Error Type: 0x{:02X}, Error Severity: 0x{:02X}"
1244*7451903cScchoux                 ", Error ID: 0x{:02X}",
1245*7451903cScchoux                 genInfo, (ptr[5] >> 4) & 0x3, ptr[5] & 0xf, ptr[6], ptr[10],
1246*7451903cScchoux                 ptr[11] & 0xf, ptr[12]);
1247*7451903cScchoux             break;
1248*7451903cScchoux         case unifiedPostEvt:
1249*7451903cScchoux             tmpStream << std::format(
1250*7451903cScchoux                 "GeneralInfo: POST(0x{:02X}), POST Failure Event: {}", genInfo,
1251*7451903cScchoux                 postEvent[std::min(
1252*7451903cScchoux                     eventType, static_cast<uint8_t>(postEvent.size() - 1))]);
1253*7451903cScchoux 
1254*7451903cScchoux             switch (static_cast<PostEvtType>(eventType))
1255*7451903cScchoux             {
1256*7451903cScchoux                 case PostEvtType::pxeBootFail:
1257*7451903cScchoux                 case PostEvtType::httpBootFail:
1258*7451903cScchoux                 {
1259*7451903cScchoux                     uint8_t failType = ptr[10] & 0xf;
1260*7451903cScchoux                     tmpStream
1261*7451903cScchoux                         << std::format(", Fail Type: {}, Error Code: 0x{:02X}",
1262*7451903cScchoux                                        (failType == 4 || failType == 6)
1263*7451903cScchoux                                            ? std::format("IPv{} fail", failType)
1264*7451903cScchoux                                            : std::format("0x{:02X}", ptr[10]),
1265*7451903cScchoux                                        ptr[11]);
1266*7451903cScchoux                     break;
1267*7451903cScchoux                 }
1268*7451903cScchoux                 case PostEvtType::getCertFail:
1269*7451903cScchoux                     tmpStream << std::format(
1270*7451903cScchoux                         ", Failure Detail: {}",
1271*7451903cScchoux                         certErr[std::min(
1272*7451903cScchoux                             ptr[9], static_cast<uint8_t>(certErr.size() - 1))]);
1273*7451903cScchoux                     break;
1274*7451903cScchoux                 case PostEvtType::amdAblFail:
1275*7451903cScchoux                     tmpStream << std::format(", ABL Error Code: 0x{:04X}",
1276*7451903cScchoux                                              (ptr[12] << 8) | ptr[11]);
1277*7451903cScchoux                     break;
1278*7451903cScchoux             }
1279*7451903cScchoux             break;
1280*7451903cScchoux         case unifiedPcieEvt:
1281*7451903cScchoux             tmpStream << std::format(
1282*7451903cScchoux                 "GeneralInfo: PCIeEvent(0x{:02X}), PCIe Failure Event: {}",
1283*7451903cScchoux                 genInfo,
1284*7451903cScchoux                 pcieEvent[std::min(
1285*7451903cScchoux                     eventType, static_cast<uint8_t>(pcieEvent.size() - 1))]);
1286*7451903cScchoux 
1287*7451903cScchoux             if (static_cast<PcieEvtType>(eventType) == PcieEvtType::dpc)
1288*7451903cScchoux             {
1289*7451903cScchoux                 tmpStream << std::format(
1290*7451903cScchoux                     ", Status: 0x{:04X}, Source ID: 0x{:04X}",
1291*7451903cScchoux                     (ptr[8] << 8) | ptr[7], (ptr[10] << 8) | ptr[9]);
1292*7451903cScchoux             }
1293*7451903cScchoux             break;
1294*7451903cScchoux         case unifiedMemEvt:
1295*7451903cScchoux             eventType = ptr[9] & 0xf;
1296*7451903cScchoux             tmpStream << std::format("GeneralInfo: MemEvent(0x{:02X})", genInfo)
1297*7451903cScchoux                       << (static_cast<MemEvtType>(eventType) !=
1298*7451903cScchoux                                   MemEvtType::noDimm
1299*7451903cScchoux                               ? std::format(", {}", dimmLocationStr(
1300*7451903cScchoux                                                         ptr[5], ptr[6], ptr[7]))
1301*7451903cScchoux                               : "")
1302*7451903cScchoux                       << ", DIMM Failure Event: ";
1303*7451903cScchoux 
1304*7451903cScchoux             switch (static_cast<MemEvtType>(eventType))
1305*7451903cScchoux             {
1306*7451903cScchoux                 case MemEvtType::ppr:
1307*7451903cScchoux                     tmpStream << std::format("{} {}",
1308*7451903cScchoux                                              memPprTime[(ptr[10] >> 2) & 0x3],
1309*7451903cScchoux                                              memPpr[ptr[10] & 0x3]);
1310*7451903cScchoux                     break;
1311*7451903cScchoux                 case MemEvtType::adddc:
1312*7451903cScchoux                     tmpStream << std::format(
1313*7451903cScchoux                         "{} {}",
1314*7451903cScchoux                         memEvent[std::min(eventType, static_cast<uint8_t>(
1315*7451903cScchoux                                                          memEvent.size() - 1))],
1316*7451903cScchoux                         memAdddc[std::min(
1317*7451903cScchoux                             static_cast<uint8_t>(ptr[11] & 0xf),
1318*7451903cScchoux                             static_cast<uint8_t>(memAdddc.size() - 1))]);
1319*7451903cScchoux                     break;
1320*7451903cScchoux                 default:
1321*7451903cScchoux                     tmpStream << std::format(
1322*7451903cScchoux                         "{}", memEvent[std::min(
1323*7451903cScchoux                                   eventType,
1324*7451903cScchoux                                   static_cast<uint8_t>(memEvent.size() - 1))]);
1325*7451903cScchoux                     break;
1326*7451903cScchoux             }
1327*7451903cScchoux             break;
1328*7451903cScchoux         case unifiedBootGuard:
1329*7451903cScchoux             tmpStream << std::format(
1330*7451903cScchoux                 "GeneralInfo: Boot Guard ACM Failure Events(0x{:02X})"
1331*7451903cScchoux                 ", Error Class: 0x{:02X}, Error Code: 0x{:02X}",
1332*7451903cScchoux                 genInfo, ptr[9], ptr[10]);
1333*7451903cScchoux             break;
1334*7451903cScchoux         case unifiedPprEvt:
1335*7451903cScchoux             tmpStream << std::format(
1336*7451903cScchoux                 "GeneralInfo: PPREvent(0x{:02X}), {}"
1337*7451903cScchoux                 ", DIMM Info: {:02X}{:02X}{:02X}{:02X}{:02X}{:02X}{:02X}",
1338*7451903cScchoux                 genInfo,
1339*7451903cScchoux                 pprEvent[std::min(eventType,
1340*7451903cScchoux                                   static_cast<uint8_t>(pprEvent.size() - 1))],
1341*7451903cScchoux                 ptr[6], ptr[7], ptr[8], ptr[9], ptr[10], ptr[11], ptr[12]);
134234a875f3SVijay Khemka             break;
134334a875f3SVijay Khemka         default:
134434a875f3SVijay Khemka             std::vector<uint8_t> oemData(ptr, ptr + 13);
134534a875f3SVijay Khemka             std::string oemDataStr;
134634a875f3SVijay Khemka             toHexStr(oemData, oemDataStr);
1347*7451903cScchoux             tmpStream << std::format("Undefined Error Type(0x{:02X}), Raw: {}",
1348*7451903cScchoux                                      errType, oemDataStr);
134934a875f3SVijay Khemka     }
135034a875f3SVijay Khemka 
135134a875f3SVijay Khemka     errStr = tmpStream.str();
135234a875f3SVijay Khemka 
135334a875f3SVijay Khemka     return;
135434a875f3SVijay Khemka }
135534a875f3SVijay Khemka 
1356c056dc00SManikandan Elumalai static void parseSelData(uint8_t fruId, std::vector<uint8_t>& reqData,
1357c056dc00SManikandan Elumalai                          std::string& msgLog)
1358f36f345fSVijay Khemka {
1359f36f345fSVijay Khemka     /* Get record type */
1360f36f345fSVijay Khemka     int recType = reqData[2];
1361f36f345fSVijay Khemka     std::string errType, errLog;
1362f36f345fSVijay Khemka 
1363f36f345fSVijay Khemka     uint8_t* ptr = NULL;
1364f36f345fSVijay Khemka 
1365f36f345fSVijay Khemka     std::stringstream recTypeStream;
1366f36f345fSVijay Khemka     recTypeStream << std::hex << std::uppercase << std::setfill('0')
1367f36f345fSVijay Khemka                   << std::setw(2) << recType;
1368f36f345fSVijay Khemka 
1369c056dc00SManikandan Elumalai     msgLog = "SEL Entry: FRU: " + std::to_string(fruId) + ", Record: ";
1370f36f345fSVijay Khemka 
1371f36f345fSVijay Khemka     if (recType == stdErrType)
1372f36f345fSVijay Khemka     {
1373f36f345fSVijay Khemka         StdSELEntry* data = reinterpret_cast<StdSELEntry*>(&reqData[0]);
1374f36f345fSVijay Khemka         std::string sensorName;
1375f36f345fSVijay Khemka 
1376f36f345fSVijay Khemka         errType = stdErr;
1377f36f345fSVijay Khemka         if (data->sensorType == 0x1F)
1378f36f345fSVijay Khemka         {
1379f36f345fSVijay Khemka             sensorName = "OS";
1380f36f345fSVijay Khemka         }
1381f36f345fSVijay Khemka         else
1382f36f345fSVijay Khemka         {
1383f36f345fSVijay Khemka             auto findSensorName = sensorNameTable.find(data->sensorNum);
1384f36f345fSVijay Khemka             if (findSensorName == sensorNameTable.end())
1385f36f345fSVijay Khemka             {
1386f36f345fSVijay Khemka                 sensorName = "Unknown";
1387f36f345fSVijay Khemka             }
1388f36f345fSVijay Khemka             else
1389f36f345fSVijay Khemka             {
1390139aa4f0SVijay Khemka                 sensorName = findSensorName->second.first;
1391f36f345fSVijay Khemka             }
1392f36f345fSVijay Khemka         }
1393f36f345fSVijay Khemka 
13947480b2f1Scchoux         time_t timeStamp = static_cast<time_t>(data->timeStamp);
13957480b2f1Scchoux         std::string timeStr;
13967480b2f1Scchoux         std::tm ts;
13977480b2f1Scchoux         if (localtime_r(&timeStamp, &ts))
13987480b2f1Scchoux         {
13997480b2f1Scchoux             char buf[64];
14007480b2f1Scchoux             if (strftime(buf, sizeof(buf), "%c", &ts))
14017480b2f1Scchoux             {
14027480b2f1Scchoux                 timeStr = buf;
14037480b2f1Scchoux             }
14047480b2f1Scchoux         }
1405f36f345fSVijay Khemka 
1406f36f345fSVijay Khemka         parseStdSel(data, errLog);
1407f36f345fSVijay Khemka         ptr = &(data->eventData1);
1408f36f345fSVijay Khemka         std::vector<uint8_t> evtData(ptr, ptr + 3);
1409f36f345fSVijay Khemka         std::string eventData;
1410f36f345fSVijay Khemka         toHexStr(evtData, eventData);
1411f36f345fSVijay Khemka 
1412f36f345fSVijay Khemka         std::stringstream senNumStream;
1413f36f345fSVijay Khemka         senNumStream << std::hex << std::uppercase << std::setfill('0')
1414f36f345fSVijay Khemka                      << std::setw(2) << (int)(data->sensorNum);
1415f36f345fSVijay Khemka 
1416f36f345fSVijay Khemka         msgLog += errType + " (0x" + recTypeStream.str() +
1417f36f345fSVijay Khemka                   "), Time: " + timeStr + ", Sensor: " + sensorName + " (0x" +
1418f36f345fSVijay Khemka                   senNumStream.str() + "), Event Data: (" + eventData + ") " +
1419f36f345fSVijay Khemka                   errLog;
1420f36f345fSVijay Khemka     }
1421f36f345fSVijay Khemka     else if ((recType >= oemTSErrTypeMin) && (recType <= oemTSErrTypeMax))
1422f36f345fSVijay Khemka     {
1423f36f345fSVijay Khemka         /* timestamped OEM SEL records */
1424f36f345fSVijay Khemka         TsOemSELEntry* data = reinterpret_cast<TsOemSELEntry*>(&reqData[0]);
1425f36f345fSVijay Khemka         ptr = data->mfrId;
1426f36f345fSVijay Khemka         std::vector<uint8_t> mfrIdData(ptr, ptr + 3);
1427f36f345fSVijay Khemka         std::string mfrIdStr;
1428f36f345fSVijay Khemka         toHexStr(mfrIdData, mfrIdStr);
1429f36f345fSVijay Khemka 
1430f36f345fSVijay Khemka         ptr = data->oemData;
1431f36f345fSVijay Khemka         std::vector<uint8_t> oemData(ptr, ptr + 6);
1432f36f345fSVijay Khemka         std::string oemDataStr;
1433f36f345fSVijay Khemka         toHexStr(oemData, oemDataStr);
1434f36f345fSVijay Khemka 
14357480b2f1Scchoux         time_t timeStamp = static_cast<time_t>(data->timeStamp);
14367480b2f1Scchoux         std::string timeStr;
14377480b2f1Scchoux         std::tm ts;
14387480b2f1Scchoux         if (localtime_r(&timeStamp, &ts))
14397480b2f1Scchoux         {
14407480b2f1Scchoux             char buf[64];
14417480b2f1Scchoux             if (strftime(buf, sizeof(buf), "%c", &ts))
14427480b2f1Scchoux             {
14437480b2f1Scchoux                 timeStr = buf;
14447480b2f1Scchoux             }
14457480b2f1Scchoux         }
1446f36f345fSVijay Khemka 
1447f36f345fSVijay Khemka         errType = oemTSErr;
1448f36f345fSVijay Khemka         parseOemSel(data, errLog);
1449f36f345fSVijay Khemka 
1450f36f345fSVijay Khemka         msgLog += errType + " (0x" + recTypeStream.str() +
1451f36f345fSVijay Khemka                   "), Time: " + timeStr + ", MFG ID: " + mfrIdStr +
1452f36f345fSVijay Khemka                   ", OEM Data: (" + oemDataStr + ") " + errLog;
1453f36f345fSVijay Khemka     }
145434a875f3SVijay Khemka     else if (recType == fbUniErrType)
145534a875f3SVijay Khemka     {
145634a875f3SVijay Khemka         NtsOemSELEntry* data = reinterpret_cast<NtsOemSELEntry*>(&reqData[0]);
145734a875f3SVijay Khemka         errType = fbUniSELErr;
145834a875f3SVijay Khemka         parseOemUnifiedSel(data, errLog);
145934a875f3SVijay Khemka         msgLog += errType + " (0x" + recTypeStream.str() + "), " + errLog;
146034a875f3SVijay Khemka     }
1461f36f345fSVijay Khemka     else if ((recType >= oemNTSErrTypeMin) && (recType <= oemNTSErrTypeMax))
1462f36f345fSVijay Khemka     {
1463f36f345fSVijay Khemka         /* Non timestamped OEM SEL records */
1464f36f345fSVijay Khemka         NtsOemSELEntry* data = reinterpret_cast<NtsOemSELEntry*>(&reqData[0]);
1465f36f345fSVijay Khemka         errType = oemNTSErr;
1466f36f345fSVijay Khemka 
1467f36f345fSVijay Khemka         ptr = data->oemData;
1468f36f345fSVijay Khemka         std::vector<uint8_t> oemData(ptr, ptr + 13);
1469f36f345fSVijay Khemka         std::string oemDataStr;
1470f36f345fSVijay Khemka         toHexStr(oemData, oemDataStr);
1471f36f345fSVijay Khemka 
1472f36f345fSVijay Khemka         parseOemSel((TsOemSELEntry*)data, errLog);
1473f36f345fSVijay Khemka         msgLog += errType + " (0x" + recTypeStream.str() + "), OEM Data: (" +
1474f36f345fSVijay Khemka                   oemDataStr + ") " + errLog;
1475f36f345fSVijay Khemka     }
1476f36f345fSVijay Khemka     else
1477f36f345fSVijay Khemka     {
1478f36f345fSVijay Khemka         errType = unknownErr;
1479f36f345fSVijay Khemka         toHexStr(reqData, errLog);
14802405ae98SPatrick Williams         msgLog += errType + " (0x" + recTypeStream.str() +
14812405ae98SPatrick Williams                   ") RawData: " + errLog;
1482f36f345fSVijay Khemka     }
1483f36f345fSVijay Khemka }
1484f36f345fSVijay Khemka 
148511b9c3b1SVijay Khemka } // namespace fb_oem::ipmi::sel
148611b9c3b1SVijay Khemka 
148711b9c3b1SVijay Khemka namespace ipmi
148811b9c3b1SVijay Khemka {
148911b9c3b1SVijay Khemka 
149011b9c3b1SVijay Khemka namespace storage
149111b9c3b1SVijay Khemka {
149211b9c3b1SVijay Khemka 
149311b9c3b1SVijay Khemka static void registerSELFunctions() __attribute__((constructor));
149411b9c3b1SVijay Khemka static fb_oem::ipmi::sel::SELData selObj __attribute__((init_priority(101)));
149511b9c3b1SVijay Khemka 
149611b9c3b1SVijay Khemka ipmi::RspType<uint8_t,  // SEL version
149711b9c3b1SVijay Khemka               uint16_t, // SEL entry count
149811b9c3b1SVijay Khemka               uint16_t, // free space
149911b9c3b1SVijay Khemka               uint32_t, // last add timestamp
150011b9c3b1SVijay Khemka               uint32_t, // last erase timestamp
150111b9c3b1SVijay Khemka               uint8_t>  // operation support
150211b9c3b1SVijay Khemka     ipmiStorageGetSELInfo()
150311b9c3b1SVijay Khemka {
150411b9c3b1SVijay Khemka     fb_oem::ipmi::sel::GetSELInfoData info;
150511b9c3b1SVijay Khemka 
150611b9c3b1SVijay Khemka     selObj.getInfo(info);
150711b9c3b1SVijay Khemka     return ipmi::responseSuccess(info.selVersion, info.entries, info.freeSpace,
150811b9c3b1SVijay Khemka                                  info.addTimeStamp, info.eraseTimeStamp,
150911b9c3b1SVijay Khemka                                  info.operationSupport);
151011b9c3b1SVijay Khemka }
151111b9c3b1SVijay Khemka 
151211b9c3b1SVijay Khemka ipmi::RspType<uint16_t, std::vector<uint8_t>>
151311b9c3b1SVijay Khemka     ipmiStorageGetSELEntry(std::vector<uint8_t> data)
151411b9c3b1SVijay Khemka {
151511b9c3b1SVijay Khemka     if (data.size() != sizeof(fb_oem::ipmi::sel::GetSELEntryRequest))
151611b9c3b1SVijay Khemka     {
151711b9c3b1SVijay Khemka         return ipmi::responseReqDataLenInvalid();
151811b9c3b1SVijay Khemka     }
151911b9c3b1SVijay Khemka 
152011b9c3b1SVijay Khemka     fb_oem::ipmi::sel::GetSELEntryRequest* reqData =
152111b9c3b1SVijay Khemka         reinterpret_cast<fb_oem::ipmi::sel::GetSELEntryRequest*>(&data[0]);
152211b9c3b1SVijay Khemka 
152311b9c3b1SVijay Khemka     if (reqData->reservID != 0)
152411b9c3b1SVijay Khemka     {
152511b9c3b1SVijay Khemka         if (!checkSELReservation(reqData->reservID))
152611b9c3b1SVijay Khemka         {
152711b9c3b1SVijay Khemka             return ipmi::responseInvalidReservationId();
152811b9c3b1SVijay Khemka         }
152911b9c3b1SVijay Khemka     }
153011b9c3b1SVijay Khemka 
153111b9c3b1SVijay Khemka     uint16_t selCnt = selObj.getCount();
153211b9c3b1SVijay Khemka     if (selCnt == 0)
153311b9c3b1SVijay Khemka     {
153411b9c3b1SVijay Khemka         return ipmi::responseSensorInvalid();
153511b9c3b1SVijay Khemka     }
153611b9c3b1SVijay Khemka 
153711b9c3b1SVijay Khemka     /* If it is asked for first entry */
153811b9c3b1SVijay Khemka     if (reqData->recordID == fb_oem::ipmi::sel::firstEntry)
153911b9c3b1SVijay Khemka     {
154011b9c3b1SVijay Khemka         /* First Entry (0x0000) as per Spec */
154111b9c3b1SVijay Khemka         reqData->recordID = 1;
154211b9c3b1SVijay Khemka     }
154311b9c3b1SVijay Khemka     else if (reqData->recordID == fb_oem::ipmi::sel::lastEntry)
154411b9c3b1SVijay Khemka     {
154511b9c3b1SVijay Khemka         /* Last entry (0xFFFF) as per Spec */
154611b9c3b1SVijay Khemka         reqData->recordID = selCnt;
154711b9c3b1SVijay Khemka     }
154811b9c3b1SVijay Khemka 
154911b9c3b1SVijay Khemka     std::string ipmiRaw;
155011b9c3b1SVijay Khemka 
155111b9c3b1SVijay Khemka     if (selObj.getEntry(reqData->recordID, ipmiRaw) < 0)
155211b9c3b1SVijay Khemka     {
155311b9c3b1SVijay Khemka         return ipmi::responseSensorInvalid();
155411b9c3b1SVijay Khemka     }
155511b9c3b1SVijay Khemka 
155611b9c3b1SVijay Khemka     std::vector<uint8_t> recDataBytes;
155711b9c3b1SVijay Khemka     if (fromHexStr(ipmiRaw, recDataBytes) < 0)
155811b9c3b1SVijay Khemka     {
155911b9c3b1SVijay Khemka         return ipmi::responseUnspecifiedError();
156011b9c3b1SVijay Khemka     }
156111b9c3b1SVijay Khemka 
156211b9c3b1SVijay Khemka     /* Identify the next SEL record ID. If recordID is same as
156311b9c3b1SVijay Khemka      * total SeL count then next id should be last entry else
156411b9c3b1SVijay Khemka      * it should be incremented by 1 to current RecordID
156511b9c3b1SVijay Khemka      */
156611b9c3b1SVijay Khemka     uint16_t nextRecord;
156711b9c3b1SVijay Khemka     if (reqData->recordID == selCnt)
156811b9c3b1SVijay Khemka     {
156911b9c3b1SVijay Khemka         nextRecord = fb_oem::ipmi::sel::lastEntry;
157011b9c3b1SVijay Khemka     }
157111b9c3b1SVijay Khemka     else
157211b9c3b1SVijay Khemka     {
157311b9c3b1SVijay Khemka         nextRecord = reqData->recordID + 1;
157411b9c3b1SVijay Khemka     }
157511b9c3b1SVijay Khemka 
157611b9c3b1SVijay Khemka     if (reqData->readLen == fb_oem::ipmi::sel::entireRecord)
157711b9c3b1SVijay Khemka     {
157811b9c3b1SVijay Khemka         return ipmi::responseSuccess(nextRecord, recDataBytes);
157911b9c3b1SVijay Khemka     }
158011b9c3b1SVijay Khemka     else
158111b9c3b1SVijay Khemka     {
158211b9c3b1SVijay Khemka         if (reqData->offset >= fb_oem::ipmi::sel::selRecordSize ||
158311b9c3b1SVijay Khemka             reqData->readLen > fb_oem::ipmi::sel::selRecordSize)
158411b9c3b1SVijay Khemka         {
158511b9c3b1SVijay Khemka             return ipmi::responseUnspecifiedError();
158611b9c3b1SVijay Khemka         }
158711b9c3b1SVijay Khemka         std::vector<uint8_t> recPartData;
158811b9c3b1SVijay Khemka 
158911b9c3b1SVijay Khemka         auto diff = fb_oem::ipmi::sel::selRecordSize - reqData->offset;
159011b9c3b1SVijay Khemka         auto readLength = std::min(diff, static_cast<int>(reqData->readLen));
159111b9c3b1SVijay Khemka 
159211b9c3b1SVijay Khemka         for (int i = 0; i < readLength; i++)
159311b9c3b1SVijay Khemka         {
159411b9c3b1SVijay Khemka             recPartData.push_back(recDataBytes[i + reqData->offset]);
159511b9c3b1SVijay Khemka         }
159611b9c3b1SVijay Khemka         return ipmi::responseSuccess(nextRecord, recPartData);
159711b9c3b1SVijay Khemka     }
159811b9c3b1SVijay Khemka }
159911b9c3b1SVijay Khemka 
1600c056dc00SManikandan Elumalai ipmi::RspType<uint16_t> ipmiStorageAddSELEntry(ipmi::Context::ptr ctx,
1601c056dc00SManikandan Elumalai                                                std::vector<uint8_t> data)
160211b9c3b1SVijay Khemka {
160311b9c3b1SVijay Khemka     /* Per the IPMI spec, need to cancel any reservation when a
160411b9c3b1SVijay Khemka      * SEL entry is added
160511b9c3b1SVijay Khemka      */
160611b9c3b1SVijay Khemka     cancelSELReservation();
160711b9c3b1SVijay Khemka 
160811b9c3b1SVijay Khemka     if (data.size() != fb_oem::ipmi::sel::selRecordSize)
160911b9c3b1SVijay Khemka     {
161011b9c3b1SVijay Khemka         return ipmi::responseReqDataLenInvalid();
161111b9c3b1SVijay Khemka     }
161211b9c3b1SVijay Khemka 
161311b9c3b1SVijay Khemka     std::string ipmiRaw, logErr;
161411b9c3b1SVijay Khemka     toHexStr(data, ipmiRaw);
161511b9c3b1SVijay Khemka 
1616f36f345fSVijay Khemka     /* Parse sel data and get an error log to be filed */
1617c056dc00SManikandan Elumalai     fb_oem::ipmi::sel::parseSelData((ctx->hostIdx + 1), data, logErr);
1618f36f345fSVijay Khemka 
161915a7ae81SVijay Khemka     static const std::string openBMCMessageRegistryVersion("0.1");
16202405ae98SPatrick Williams     std::string messageID = "OpenBMC." + openBMCMessageRegistryVersion +
16212405ae98SPatrick Williams                             ".SELEntryAdded";
162215a7ae81SVijay Khemka 
162311b9c3b1SVijay Khemka     /* Log the Raw SEL message to the journal */
162411b9c3b1SVijay Khemka     std::string journalMsg = "SEL Entry Added: " + ipmiRaw;
1625f36f345fSVijay Khemka 
162615a7ae81SVijay Khemka     phosphor::logging::log<phosphor::logging::level::INFO>(
162715a7ae81SVijay Khemka         journalMsg.c_str(),
162815a7ae81SVijay Khemka         phosphor::logging::entry("IPMISEL_MESSAGE_ID=%s", messageID.c_str()),
162915a7ae81SVijay Khemka         phosphor::logging::entry("IPMISEL_MESSAGE_ARGS=%s", logErr.c_str()));
163011b9c3b1SVijay Khemka 
163121a79235SBonnieLo-wiwynn     std::map<std::string, std::string> ad;
163221a79235SBonnieLo-wiwynn     std::string severity = "xyz.openbmc_project.Logging.Entry.Level.Critical";
163321a79235SBonnieLo-wiwynn     ad.emplace("IPMI_RAW", ipmiRaw);
163421a79235SBonnieLo-wiwynn 
163521a79235SBonnieLo-wiwynn     auto bus = sdbusplus::bus::new_default();
163621a79235SBonnieLo-wiwynn     auto reqMsg = bus.new_method_call(
163721a79235SBonnieLo-wiwynn         "xyz.openbmc_project.Logging", "/xyz/openbmc_project/logging",
163821a79235SBonnieLo-wiwynn         "xyz.openbmc_project.Logging.Create", "Create");
163921a79235SBonnieLo-wiwynn     reqMsg.append(logErr, severity, ad);
164021a79235SBonnieLo-wiwynn 
164121a79235SBonnieLo-wiwynn     try
164221a79235SBonnieLo-wiwynn     {
164321a79235SBonnieLo-wiwynn         bus.call(reqMsg);
164421a79235SBonnieLo-wiwynn     }
164521a79235SBonnieLo-wiwynn     catch (sdbusplus::exception_t& e)
164621a79235SBonnieLo-wiwynn     {
164721a79235SBonnieLo-wiwynn         phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
164821a79235SBonnieLo-wiwynn     }
164921a79235SBonnieLo-wiwynn 
165011b9c3b1SVijay Khemka     int responseID = selObj.addEntry(ipmiRaw.c_str());
165111b9c3b1SVijay Khemka     if (responseID < 0)
165211b9c3b1SVijay Khemka     {
165311b9c3b1SVijay Khemka         return ipmi::responseUnspecifiedError();
165411b9c3b1SVijay Khemka     }
165511b9c3b1SVijay Khemka     return ipmi::responseSuccess((uint16_t)responseID);
165611b9c3b1SVijay Khemka }
165711b9c3b1SVijay Khemka 
1658c1921c63SVijay Khemka ipmi::RspType<uint8_t> ipmiStorageClearSEL(uint16_t reservationID,
1659c1921c63SVijay Khemka                                            const std::array<uint8_t, 3>& clr,
1660c1921c63SVijay Khemka                                            uint8_t eraseOperation)
1661c1921c63SVijay Khemka {
1662c1921c63SVijay Khemka     if (!checkSELReservation(reservationID))
1663c1921c63SVijay Khemka     {
1664c1921c63SVijay Khemka         return ipmi::responseInvalidReservationId();
1665c1921c63SVijay Khemka     }
1666c1921c63SVijay Khemka 
1667c1921c63SVijay Khemka     static constexpr std::array<uint8_t, 3> clrExpected = {'C', 'L', 'R'};
1668c1921c63SVijay Khemka     if (clr != clrExpected)
1669c1921c63SVijay Khemka     {
1670c1921c63SVijay Khemka         return ipmi::responseInvalidFieldRequest();
1671c1921c63SVijay Khemka     }
1672c1921c63SVijay Khemka 
1673c1921c63SVijay Khemka     /* If there is no sel then return erase complete */
1674c1921c63SVijay Khemka     if (selObj.getCount() == 0)
1675c1921c63SVijay Khemka     {
1676c1921c63SVijay Khemka         return ipmi::responseSuccess(fb_oem::ipmi::sel::eraseComplete);
1677c1921c63SVijay Khemka     }
1678c1921c63SVijay Khemka 
1679c1921c63SVijay Khemka     /* Erasure status cannot be fetched, so always return erasure
1680c1921c63SVijay Khemka      * status as `erase completed`.
1681c1921c63SVijay Khemka      */
1682c1921c63SVijay Khemka     if (eraseOperation == fb_oem::ipmi::sel::getEraseStatus)
1683c1921c63SVijay Khemka     {
1684c1921c63SVijay Khemka         return ipmi::responseSuccess(fb_oem::ipmi::sel::eraseComplete);
1685c1921c63SVijay Khemka     }
1686c1921c63SVijay Khemka 
1687c1921c63SVijay Khemka     /* Check that initiate erase is correct */
1688c1921c63SVijay Khemka     if (eraseOperation != fb_oem::ipmi::sel::initiateErase)
1689c1921c63SVijay Khemka     {
1690c1921c63SVijay Khemka         return ipmi::responseInvalidFieldRequest();
1691c1921c63SVijay Khemka     }
1692c1921c63SVijay Khemka 
1693c1921c63SVijay Khemka     /* Per the IPMI spec, need to cancel any reservation when the
1694c1921c63SVijay Khemka      * SEL is cleared
1695c1921c63SVijay Khemka      */
1696c1921c63SVijay Khemka     cancelSELReservation();
1697c1921c63SVijay Khemka 
1698c1921c63SVijay Khemka     /* Clear the complete Sel Json object */
1699c1921c63SVijay Khemka     if (selObj.clear() < 0)
1700c1921c63SVijay Khemka     {
1701c1921c63SVijay Khemka         return ipmi::responseUnspecifiedError();
1702c1921c63SVijay Khemka     }
1703c1921c63SVijay Khemka 
1704c1921c63SVijay Khemka     return ipmi::responseSuccess(fb_oem::ipmi::sel::eraseComplete);
1705c1921c63SVijay Khemka }
1706c1921c63SVijay Khemka 
1707c1921c63SVijay Khemka ipmi::RspType<uint32_t> ipmiStorageGetSELTime()
1708c1921c63SVijay Khemka {
1709c1921c63SVijay Khemka     struct timespec selTime = {};
1710c1921c63SVijay Khemka 
1711c1921c63SVijay Khemka     if (clock_gettime(CLOCK_REALTIME, &selTime) < 0)
1712c1921c63SVijay Khemka     {
1713c1921c63SVijay Khemka         return ipmi::responseUnspecifiedError();
1714c1921c63SVijay Khemka     }
1715c1921c63SVijay Khemka 
1716c1921c63SVijay Khemka     return ipmi::responseSuccess(selTime.tv_sec);
1717c1921c63SVijay Khemka }
1718c1921c63SVijay Khemka 
1719e39f9393SWilly Tu ipmi::RspType<> ipmiStorageSetSELTime(uint32_t)
1720c1921c63SVijay Khemka {
1721c1921c63SVijay Khemka     // Set SEL Time is not supported
1722c1921c63SVijay Khemka     return ipmi::responseInvalidCommand();
1723c1921c63SVijay Khemka }
1724c1921c63SVijay Khemka 
1725c1921c63SVijay Khemka ipmi::RspType<uint16_t> ipmiStorageGetSELTimeUtcOffset()
1726c1921c63SVijay Khemka {
1727c1921c63SVijay Khemka     /* TODO: For now, the SEL time stamp is based on UTC time,
1728c1921c63SVijay Khemka      * so return 0x0000 as offset. Might need to change once
1729c1921c63SVijay Khemka      * supporting zones in SEL time stamps
1730c1921c63SVijay Khemka      */
1731c1921c63SVijay Khemka 
1732c1921c63SVijay Khemka     uint16_t utcOffset = 0x0000;
1733c1921c63SVijay Khemka     return ipmi::responseSuccess(utcOffset);
1734c1921c63SVijay Khemka }
1735c1921c63SVijay Khemka 
173611b9c3b1SVijay Khemka void registerSELFunctions()
173711b9c3b1SVijay Khemka {
173811b9c3b1SVijay Khemka     // <Get SEL Info>
173911b9c3b1SVijay Khemka     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
174011b9c3b1SVijay Khemka                           ipmi::storage::cmdGetSelInfo, ipmi::Privilege::User,
174111b9c3b1SVijay Khemka                           ipmiStorageGetSELInfo);
174211b9c3b1SVijay Khemka 
174311b9c3b1SVijay Khemka     // <Get SEL Entry>
174411b9c3b1SVijay Khemka     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
174511b9c3b1SVijay Khemka                           ipmi::storage::cmdGetSelEntry, ipmi::Privilege::User,
174611b9c3b1SVijay Khemka                           ipmiStorageGetSELEntry);
174711b9c3b1SVijay Khemka 
174811b9c3b1SVijay Khemka     // <Add SEL Entry>
174911b9c3b1SVijay Khemka     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
175011b9c3b1SVijay Khemka                           ipmi::storage::cmdAddSelEntry,
175111b9c3b1SVijay Khemka                           ipmi::Privilege::Operator, ipmiStorageAddSELEntry);
175211b9c3b1SVijay Khemka 
1753c1921c63SVijay Khemka     // <Clear SEL>
1754c1921c63SVijay Khemka     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
1755c1921c63SVijay Khemka                           ipmi::storage::cmdClearSel, ipmi::Privilege::Operator,
1756c1921c63SVijay Khemka                           ipmiStorageClearSEL);
1757c1921c63SVijay Khemka 
1758c1921c63SVijay Khemka     // <Get SEL Time>
1759c1921c63SVijay Khemka     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
1760c1921c63SVijay Khemka                           ipmi::storage::cmdGetSelTime, ipmi::Privilege::User,
1761c1921c63SVijay Khemka                           ipmiStorageGetSELTime);
1762c1921c63SVijay Khemka 
1763c1921c63SVijay Khemka     // <Set SEL Time>
1764c1921c63SVijay Khemka     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
1765c1921c63SVijay Khemka                           ipmi::storage::cmdSetSelTime,
1766c1921c63SVijay Khemka                           ipmi::Privilege::Operator, ipmiStorageSetSELTime);
1767c1921c63SVijay Khemka 
1768c1921c63SVijay Khemka     // <Get SEL Time UTC Offset>
1769c1921c63SVijay Khemka     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
1770c1921c63SVijay Khemka                           ipmi::storage::cmdGetSelTimeUtcOffset,
1771c1921c63SVijay Khemka                           ipmi::Privilege::User,
1772c1921c63SVijay Khemka                           ipmiStorageGetSELTimeUtcOffset);
1773c1921c63SVijay Khemka 
177411b9c3b1SVijay Khemka     return;
177511b9c3b1SVijay Khemka }
177611b9c3b1SVijay Khemka 
177711b9c3b1SVijay Khemka } // namespace storage
177811b9c3b1SVijay Khemka } // namespace ipmi
1779