xref: /openbmc/fb-ipmi-oem/src/selcommands.cpp (revision 139aa4f0db3d0a8f4498da56448d101643ff8a3f)
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 <ipmid/api.hpp>
1911b9c3b1SVijay Khemka 
2011b9c3b1SVijay Khemka #include <boost/algorithm/string/join.hpp>
2111b9c3b1SVijay Khemka #include <nlohmann/json.hpp>
2211b9c3b1SVijay Khemka #include <iostream>
2311b9c3b1SVijay Khemka #include <sstream>
2411b9c3b1SVijay Khemka #include <fstream>
2511b9c3b1SVijay Khemka #include <phosphor-logging/log.hpp>
2611b9c3b1SVijay Khemka #include <sdbusplus/message/types.hpp>
2711b9c3b1SVijay Khemka #include <sdbusplus/timer.hpp>
2811b9c3b1SVijay Khemka #include <storagecommands.hpp>
2911b9c3b1SVijay Khemka 
3011b9c3b1SVijay Khemka //----------------------------------------------------------------------
3111b9c3b1SVijay Khemka // Platform specific functions for storing app data
3211b9c3b1SVijay Khemka //----------------------------------------------------------------------
3311b9c3b1SVijay Khemka 
34*139aa4f0SVijay Khemka static std::string byteToStr(uint8_t byte)
35*139aa4f0SVijay Khemka {
36*139aa4f0SVijay Khemka     std::stringstream ss;
37*139aa4f0SVijay Khemka 
38*139aa4f0SVijay Khemka     ss << std::hex << std::uppercase << std::setfill('0');
39*139aa4f0SVijay Khemka     ss << std::setw(2) << (int)byte;
40*139aa4f0SVijay Khemka 
41*139aa4f0SVijay Khemka     return ss.str();
42*139aa4f0SVijay Khemka }
43*139aa4f0SVijay Khemka 
4411b9c3b1SVijay Khemka static void toHexStr(std::vector<uint8_t> &bytes, std::string &hexStr)
4511b9c3b1SVijay Khemka {
4611b9c3b1SVijay Khemka     std::stringstream stream;
4711b9c3b1SVijay Khemka     stream << std::hex << std::uppercase << std::setfill('0');
4811b9c3b1SVijay Khemka     for (const uint8_t byte : bytes)
4911b9c3b1SVijay Khemka     {
5011b9c3b1SVijay Khemka         stream << std::setw(2) << static_cast<int>(byte);
5111b9c3b1SVijay Khemka     }
5211b9c3b1SVijay Khemka     hexStr = stream.str();
5311b9c3b1SVijay Khemka }
5411b9c3b1SVijay Khemka 
5511b9c3b1SVijay Khemka static int fromHexStr(const std::string hexStr, std::vector<uint8_t> &data)
5611b9c3b1SVijay Khemka {
5711b9c3b1SVijay Khemka     for (unsigned int i = 0; i < hexStr.size(); i += 2)
5811b9c3b1SVijay Khemka     {
5911b9c3b1SVijay Khemka         try
6011b9c3b1SVijay Khemka         {
6111b9c3b1SVijay Khemka             data.push_back(static_cast<uint8_t>(
6211b9c3b1SVijay Khemka                 std::stoul(hexStr.substr(i, 2), nullptr, 16)));
6311b9c3b1SVijay Khemka         }
6411b9c3b1SVijay Khemka         catch (std::invalid_argument &e)
6511b9c3b1SVijay Khemka         {
6611b9c3b1SVijay Khemka             phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
6711b9c3b1SVijay Khemka             return -1;
6811b9c3b1SVijay Khemka         }
6911b9c3b1SVijay Khemka         catch (std::out_of_range &e)
7011b9c3b1SVijay Khemka         {
7111b9c3b1SVijay Khemka             phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
7211b9c3b1SVijay Khemka             return -1;
7311b9c3b1SVijay Khemka         }
7411b9c3b1SVijay Khemka     }
7511b9c3b1SVijay Khemka     return 0;
7611b9c3b1SVijay Khemka }
7711b9c3b1SVijay Khemka 
7811b9c3b1SVijay Khemka namespace fb_oem::ipmi::sel
7911b9c3b1SVijay Khemka {
8011b9c3b1SVijay Khemka 
8111b9c3b1SVijay Khemka class SELData
8211b9c3b1SVijay Khemka {
8311b9c3b1SVijay Khemka   private:
8411b9c3b1SVijay Khemka     nlohmann::json selDataObj;
8511b9c3b1SVijay Khemka 
8611b9c3b1SVijay Khemka     void flush()
8711b9c3b1SVijay Khemka     {
8811b9c3b1SVijay Khemka         std::ofstream file(SEL_JSON_DATA_FILE);
8911b9c3b1SVijay Khemka         file << selDataObj;
9011b9c3b1SVijay Khemka         file.close();
9111b9c3b1SVijay Khemka     }
9211b9c3b1SVijay Khemka 
9311b9c3b1SVijay Khemka     void init()
9411b9c3b1SVijay Khemka     {
9511b9c3b1SVijay Khemka         selDataObj[KEY_SEL_VER] = 0x51;
9611b9c3b1SVijay Khemka         selDataObj[KEY_SEL_COUNT] = 0;
9711b9c3b1SVijay Khemka         selDataObj[KEY_ADD_TIME] = 0xFFFFFFFF;
9811b9c3b1SVijay Khemka         selDataObj[KEY_ERASE_TIME] = 0xFFFFFFFF;
9911b9c3b1SVijay Khemka         selDataObj[KEY_OPER_SUPP] = 0x02;
10011b9c3b1SVijay Khemka         /* Spec indicates that more than 64kB is free */
10111b9c3b1SVijay Khemka         selDataObj[KEY_FREE_SPACE] = 0xFFFF;
10211b9c3b1SVijay Khemka     }
10311b9c3b1SVijay Khemka 
10411b9c3b1SVijay Khemka   public:
10511b9c3b1SVijay Khemka     SELData()
10611b9c3b1SVijay Khemka     {
10711b9c3b1SVijay Khemka         /* Get App data stored in json file */
10811b9c3b1SVijay Khemka         std::ifstream file(SEL_JSON_DATA_FILE);
10911b9c3b1SVijay Khemka         if (file)
11011b9c3b1SVijay Khemka         {
11111b9c3b1SVijay Khemka             file >> selDataObj;
11211b9c3b1SVijay Khemka             file.close();
11311b9c3b1SVijay Khemka         }
11411b9c3b1SVijay Khemka 
11511b9c3b1SVijay Khemka         /* Initialize SelData object if no entries. */
11611b9c3b1SVijay Khemka         if (selDataObj.find(KEY_SEL_COUNT) == selDataObj.end())
11711b9c3b1SVijay Khemka         {
11811b9c3b1SVijay Khemka             init();
11911b9c3b1SVijay Khemka         }
12011b9c3b1SVijay Khemka     }
12111b9c3b1SVijay Khemka 
12211b9c3b1SVijay Khemka     int clear()
12311b9c3b1SVijay Khemka     {
12411b9c3b1SVijay Khemka         /* Clear the complete Sel Json object */
12511b9c3b1SVijay Khemka         selDataObj.clear();
12611b9c3b1SVijay Khemka         /* Reinitialize it with basic data */
12711b9c3b1SVijay Khemka         init();
12811b9c3b1SVijay Khemka         /* Save the erase time */
12911b9c3b1SVijay Khemka         struct timespec selTime = {};
13011b9c3b1SVijay Khemka         if (clock_gettime(CLOCK_REALTIME, &selTime) < 0)
13111b9c3b1SVijay Khemka         {
13211b9c3b1SVijay Khemka             return -1;
13311b9c3b1SVijay Khemka         }
13411b9c3b1SVijay Khemka         selDataObj[KEY_ERASE_TIME] = selTime.tv_sec;
13511b9c3b1SVijay Khemka         flush();
13611b9c3b1SVijay Khemka         return 0;
13711b9c3b1SVijay Khemka     }
13811b9c3b1SVijay Khemka 
13911b9c3b1SVijay Khemka     uint32_t getCount()
14011b9c3b1SVijay Khemka     {
14111b9c3b1SVijay Khemka         return selDataObj[KEY_SEL_COUNT];
14211b9c3b1SVijay Khemka     }
14311b9c3b1SVijay Khemka 
14411b9c3b1SVijay Khemka     void getInfo(GetSELInfoData &info)
14511b9c3b1SVijay Khemka     {
14611b9c3b1SVijay Khemka         info.selVersion = selDataObj[KEY_SEL_VER];
14711b9c3b1SVijay Khemka         info.entries = selDataObj[KEY_SEL_COUNT];
14811b9c3b1SVijay Khemka         info.freeSpace = selDataObj[KEY_FREE_SPACE];
14911b9c3b1SVijay Khemka         info.addTimeStamp = selDataObj[KEY_ADD_TIME];
15011b9c3b1SVijay Khemka         info.eraseTimeStamp = selDataObj[KEY_ERASE_TIME];
15111b9c3b1SVijay Khemka         info.operationSupport = selDataObj[KEY_OPER_SUPP];
15211b9c3b1SVijay Khemka     }
15311b9c3b1SVijay Khemka 
15411b9c3b1SVijay Khemka     int getEntry(uint32_t index, std::string &rawStr)
15511b9c3b1SVijay Khemka     {
15611b9c3b1SVijay Khemka         std::stringstream ss;
15711b9c3b1SVijay Khemka         ss << std::hex;
15811b9c3b1SVijay Khemka         ss << std::setw(2) << std::setfill('0') << index;
15911b9c3b1SVijay Khemka 
16011b9c3b1SVijay Khemka         /* Check or the requested SEL Entry, if record is available */
16111b9c3b1SVijay Khemka         if (selDataObj.find(ss.str()) == selDataObj.end())
16211b9c3b1SVijay Khemka         {
16311b9c3b1SVijay Khemka             return -1;
16411b9c3b1SVijay Khemka         }
16511b9c3b1SVijay Khemka 
16611b9c3b1SVijay Khemka         rawStr = selDataObj[ss.str()][KEY_SEL_ENTRY_RAW];
16711b9c3b1SVijay Khemka         return 0;
16811b9c3b1SVijay Khemka     }
16911b9c3b1SVijay Khemka 
17011b9c3b1SVijay Khemka     int addEntry(std::string keyStr)
17111b9c3b1SVijay Khemka     {
17211b9c3b1SVijay Khemka         struct timespec selTime = {};
17311b9c3b1SVijay Khemka 
17411b9c3b1SVijay Khemka         if (clock_gettime(CLOCK_REALTIME, &selTime) < 0)
17511b9c3b1SVijay Khemka         {
17611b9c3b1SVijay Khemka             return -1;
17711b9c3b1SVijay Khemka         }
17811b9c3b1SVijay Khemka 
17911b9c3b1SVijay Khemka         selDataObj[KEY_ADD_TIME] = selTime.tv_sec;
18011b9c3b1SVijay Khemka 
18111b9c3b1SVijay Khemka         int selCount = selDataObj[KEY_SEL_COUNT];
18211b9c3b1SVijay Khemka         selDataObj[KEY_SEL_COUNT] = ++selCount;
18311b9c3b1SVijay Khemka 
18411b9c3b1SVijay Khemka         std::stringstream ss;
18511b9c3b1SVijay Khemka         ss << std::hex;
18611b9c3b1SVijay Khemka         ss << std::setw(2) << std::setfill('0') << selCount;
18711b9c3b1SVijay Khemka 
18811b9c3b1SVijay Khemka         selDataObj[ss.str()][KEY_SEL_ENTRY_RAW] = keyStr;
18911b9c3b1SVijay Khemka         flush();
19011b9c3b1SVijay Khemka         return selCount;
19111b9c3b1SVijay Khemka     }
19211b9c3b1SVijay Khemka };
19311b9c3b1SVijay Khemka 
194*139aa4f0SVijay Khemka /*
195*139aa4f0SVijay Khemka  * A Function to parse common SEL message, a helper funciton
196*139aa4f0SVijay Khemka  * for parseStdSel.
197*139aa4f0SVijay Khemka  *
198*139aa4f0SVijay Khemka  * Note that this function __CANNOT__ be overriden.
199*139aa4f0SVijay Khemka  * To add board specific routine, please override parseStdSel.
200*139aa4f0SVijay Khemka  */
201*139aa4f0SVijay Khemka 
202*139aa4f0SVijay Khemka /*Used by decoding ME event*/
203*139aa4f0SVijay Khemka std::vector<std::string> nmDomName = {
204*139aa4f0SVijay Khemka     "Entire Platform",          "CPU Subsystem",
205*139aa4f0SVijay Khemka     "Memory Subsystem",         "HW Protection",
206*139aa4f0SVijay Khemka     "High Power I/O subsystem", "Unknown"};
207*139aa4f0SVijay Khemka 
208*139aa4f0SVijay Khemka /* Default log message for unknown type */
209*139aa4f0SVijay Khemka static void logDefault(uint8_t *data, std::string &errLog)
210*139aa4f0SVijay Khemka {
211*139aa4f0SVijay Khemka     errLog = "Unknown";
212*139aa4f0SVijay Khemka }
213*139aa4f0SVijay Khemka 
214*139aa4f0SVijay Khemka static void logSysEvent(uint8_t *data, std::string &errLog)
215*139aa4f0SVijay Khemka {
216*139aa4f0SVijay Khemka     if (data[0] == 0xE5)
217*139aa4f0SVijay Khemka     {
218*139aa4f0SVijay Khemka         errLog = "Cause of Time change - ";
219*139aa4f0SVijay Khemka         switch (data[2])
220*139aa4f0SVijay Khemka         {
221*139aa4f0SVijay Khemka             case 0x00:
222*139aa4f0SVijay Khemka                 errLog += "NTP";
223*139aa4f0SVijay Khemka                 break;
224*139aa4f0SVijay Khemka             case 0x01:
225*139aa4f0SVijay Khemka                 errLog += "Host RTL";
226*139aa4f0SVijay Khemka                 break;
227*139aa4f0SVijay Khemka             case 0x02:
228*139aa4f0SVijay Khemka                 errLog += "Set SEL time cmd";
229*139aa4f0SVijay Khemka                 break;
230*139aa4f0SVijay Khemka             case 0x03:
231*139aa4f0SVijay Khemka                 errLog += "Set SEL time UTC offset cmd";
232*139aa4f0SVijay Khemka                 break;
233*139aa4f0SVijay Khemka             default:
234*139aa4f0SVijay Khemka                 errLog += "Unknown";
235*139aa4f0SVijay Khemka         }
236*139aa4f0SVijay Khemka 
237*139aa4f0SVijay Khemka         if (data[1] == 0x00)
238*139aa4f0SVijay Khemka             errLog += " - First Time";
239*139aa4f0SVijay Khemka         else if (data[1] == 0x80)
240*139aa4f0SVijay Khemka             errLog += " - Second Time";
241*139aa4f0SVijay Khemka     }
242*139aa4f0SVijay Khemka     else
243*139aa4f0SVijay Khemka     {
244*139aa4f0SVijay Khemka         errLog = "Unknown";
245*139aa4f0SVijay Khemka     }
246*139aa4f0SVijay Khemka }
247*139aa4f0SVijay Khemka 
248*139aa4f0SVijay Khemka static void logThermalEvent(uint8_t *data, std::string &errLog)
249*139aa4f0SVijay Khemka {
250*139aa4f0SVijay Khemka     if (data[0] == 0x1)
251*139aa4f0SVijay Khemka     {
252*139aa4f0SVijay Khemka         errLog = "Limit Exceeded";
253*139aa4f0SVijay Khemka     }
254*139aa4f0SVijay Khemka     else
255*139aa4f0SVijay Khemka     {
256*139aa4f0SVijay Khemka         errLog = "Unknown";
257*139aa4f0SVijay Khemka     }
258*139aa4f0SVijay Khemka }
259*139aa4f0SVijay Khemka 
260*139aa4f0SVijay Khemka static void logCritIrq(uint8_t *data, std::string &errLog)
261*139aa4f0SVijay Khemka {
262*139aa4f0SVijay Khemka 
263*139aa4f0SVijay Khemka     if (data[0] == 0x0)
264*139aa4f0SVijay Khemka     {
265*139aa4f0SVijay Khemka         errLog = "NMI / Diagnostic Interrupt";
266*139aa4f0SVijay Khemka     }
267*139aa4f0SVijay Khemka     else if (data[0] == 0x03)
268*139aa4f0SVijay Khemka     {
269*139aa4f0SVijay Khemka         errLog = "Software NMI";
270*139aa4f0SVijay Khemka     }
271*139aa4f0SVijay Khemka     else
272*139aa4f0SVijay Khemka     {
273*139aa4f0SVijay Khemka         errLog = "Unknown";
274*139aa4f0SVijay Khemka     }
275*139aa4f0SVijay Khemka 
276*139aa4f0SVijay Khemka     /* TODO: Call add_cri_sel for CRITICAL_IRQ */
277*139aa4f0SVijay Khemka }
278*139aa4f0SVijay Khemka 
279*139aa4f0SVijay Khemka static void logPostErr(uint8_t *data, std::string &errLog)
280*139aa4f0SVijay Khemka {
281*139aa4f0SVijay Khemka 
282*139aa4f0SVijay Khemka     if ((data[0] & 0x0F) == 0x0)
283*139aa4f0SVijay Khemka     {
284*139aa4f0SVijay Khemka         errLog = "System Firmware Error";
285*139aa4f0SVijay Khemka     }
286*139aa4f0SVijay Khemka     else
287*139aa4f0SVijay Khemka     {
288*139aa4f0SVijay Khemka         errLog = "Unknown";
289*139aa4f0SVijay Khemka     }
290*139aa4f0SVijay Khemka 
291*139aa4f0SVijay Khemka     if (((data[0] >> 6) & 0x03) == 0x3)
292*139aa4f0SVijay Khemka     {
293*139aa4f0SVijay Khemka         // TODO: Need to implement IPMI spec based Post Code
294*139aa4f0SVijay Khemka         errLog += ", IPMI Post Code";
295*139aa4f0SVijay Khemka     }
296*139aa4f0SVijay Khemka     else if (((data[0] >> 6) & 0x03) == 0x2)
297*139aa4f0SVijay Khemka     {
298*139aa4f0SVijay Khemka         errLog +=
299*139aa4f0SVijay Khemka             ", OEM Post Code 0x" + byteToStr(data[2]) + byteToStr(data[1]);
300*139aa4f0SVijay Khemka 
301*139aa4f0SVijay Khemka         switch ((data[2] << 8) | data[1])
302*139aa4f0SVijay Khemka         {
303*139aa4f0SVijay Khemka             case 0xA105:
304*139aa4f0SVijay Khemka                 errLog += ", BMC Failed (No Response)";
305*139aa4f0SVijay Khemka                 break;
306*139aa4f0SVijay Khemka             case 0xA106:
307*139aa4f0SVijay Khemka                 errLog += ", BMC Failed (Self Test Fail)";
308*139aa4f0SVijay Khemka                 break;
309*139aa4f0SVijay Khemka             case 0xA10A:
310*139aa4f0SVijay Khemka                 errLog += ", System Firmware Corruption Detected";
311*139aa4f0SVijay Khemka                 break;
312*139aa4f0SVijay Khemka             case 0xA10B:
313*139aa4f0SVijay Khemka                 errLog += ", TPM Self-Test FAIL Detected";
314*139aa4f0SVijay Khemka         }
315*139aa4f0SVijay Khemka     }
316*139aa4f0SVijay Khemka }
317*139aa4f0SVijay Khemka 
318*139aa4f0SVijay Khemka static void logMchChkErr(uint8_t *data, std::string &errLog)
319*139aa4f0SVijay Khemka {
320*139aa4f0SVijay Khemka     /* TODO: Call add_cri_sel for CRITICAL_IRQ */
321*139aa4f0SVijay Khemka     if ((data[0] & 0x0F) == 0x0B)
322*139aa4f0SVijay Khemka     {
323*139aa4f0SVijay Khemka         errLog = "Uncorrectable";
324*139aa4f0SVijay Khemka     }
325*139aa4f0SVijay Khemka     else if ((data[0] & 0x0F) == 0x0C)
326*139aa4f0SVijay Khemka     {
327*139aa4f0SVijay Khemka         errLog = "Correctable";
328*139aa4f0SVijay Khemka     }
329*139aa4f0SVijay Khemka     else
330*139aa4f0SVijay Khemka     {
331*139aa4f0SVijay Khemka         errLog = "Unknown";
332*139aa4f0SVijay Khemka     }
333*139aa4f0SVijay Khemka 
334*139aa4f0SVijay Khemka     errLog += ", Machine Check bank Number " + std::to_string(data[1]) +
335*139aa4f0SVijay Khemka               ", CPU " + std::to_string(data[2] >> 5) + ", Core " +
336*139aa4f0SVijay Khemka               std::to_string(data[2] & 0x1F);
337*139aa4f0SVijay Khemka }
338*139aa4f0SVijay Khemka 
339*139aa4f0SVijay Khemka static void logPcieErr(uint8_t *data, std::string &errLog)
340*139aa4f0SVijay Khemka {
341*139aa4f0SVijay Khemka     std::stringstream tmp1, tmp2;
342*139aa4f0SVijay Khemka     tmp1 << std::hex << std::uppercase << std::setfill('0');
343*139aa4f0SVijay Khemka     tmp2 << std::hex << std::uppercase << std::setfill('0');
344*139aa4f0SVijay Khemka     tmp1 << " (Bus " << std::setw(2) << (int)(data[2]) << " / Dev "
345*139aa4f0SVijay Khemka          << std::setw(2) << (int)(data[1] >> 3) << " / Fun " << std::setw(2)
346*139aa4f0SVijay Khemka          << (int)(data[1] & 0x7) << ")";
347*139aa4f0SVijay Khemka 
348*139aa4f0SVijay Khemka     switch (data[0] & 0xF)
349*139aa4f0SVijay Khemka     {
350*139aa4f0SVijay Khemka         case 0x4:
351*139aa4f0SVijay Khemka             errLog = "PCI PERR" + tmp1.str();
352*139aa4f0SVijay Khemka             break;
353*139aa4f0SVijay Khemka         case 0x5:
354*139aa4f0SVijay Khemka             errLog = "PCI SERR" + tmp1.str();
355*139aa4f0SVijay Khemka             break;
356*139aa4f0SVijay Khemka         case 0x7:
357*139aa4f0SVijay Khemka             errLog = "Correctable" + tmp1.str();
358*139aa4f0SVijay Khemka             break;
359*139aa4f0SVijay Khemka         case 0x8:
360*139aa4f0SVijay Khemka             errLog = "Uncorrectable" + tmp1.str();
361*139aa4f0SVijay Khemka             break;
362*139aa4f0SVijay Khemka         case 0xA:
363*139aa4f0SVijay Khemka             errLog = "Bus Fatal" + tmp1.str();
364*139aa4f0SVijay Khemka             break;
365*139aa4f0SVijay Khemka         case 0xD:
366*139aa4f0SVijay Khemka         {
367*139aa4f0SVijay Khemka             uint32_t venId = (uint32_t)data[1] << 8 | (uint32_t)data[2];
368*139aa4f0SVijay Khemka             tmp2 << "Vendor ID: 0x" << std::setw(4) << venId;
369*139aa4f0SVijay Khemka             errLog = tmp2.str();
370*139aa4f0SVijay Khemka         }
371*139aa4f0SVijay Khemka         break;
372*139aa4f0SVijay Khemka         case 0xE:
373*139aa4f0SVijay Khemka         {
374*139aa4f0SVijay Khemka             uint32_t devId = (uint32_t)data[1] << 8 | (uint32_t)data[2];
375*139aa4f0SVijay Khemka             tmp2 << "Device ID: 0x" << std::setw(4) << devId;
376*139aa4f0SVijay Khemka             errLog = tmp2.str();
377*139aa4f0SVijay Khemka         }
378*139aa4f0SVijay Khemka         break;
379*139aa4f0SVijay Khemka         case 0xF:
380*139aa4f0SVijay Khemka             tmp2 << "Error ID from downstream: 0x" << std::setw(2)
381*139aa4f0SVijay Khemka                  << (int)(data[1]) << std::setw(2) << (int)(data[2]);
382*139aa4f0SVijay Khemka             errLog = tmp2.str();
383*139aa4f0SVijay Khemka             break;
384*139aa4f0SVijay Khemka         default:
385*139aa4f0SVijay Khemka             errLog = "Unknown";
386*139aa4f0SVijay Khemka     }
387*139aa4f0SVijay Khemka }
388*139aa4f0SVijay Khemka 
389*139aa4f0SVijay Khemka static void logIioErr(uint8_t *data, std::string &errLog)
390*139aa4f0SVijay Khemka {
391*139aa4f0SVijay Khemka     std::vector<std::string> tmpStr = {
392*139aa4f0SVijay Khemka         "IRP0", "IRP1", " IIO-Core", "VT-d", "Intel Quick Data",
393*139aa4f0SVijay Khemka         "Misc", " DMA", "ITC",       "OTC",  "CI"};
394*139aa4f0SVijay Khemka 
395*139aa4f0SVijay Khemka     if ((data[0] & 0xF) == 0)
396*139aa4f0SVijay Khemka     {
397*139aa4f0SVijay Khemka         errLog += "CPU " + std::to_string(data[2] >> 5) + ", Error ID 0x" +
398*139aa4f0SVijay Khemka                   byteToStr(data[1]) + " - ";
399*139aa4f0SVijay Khemka 
400*139aa4f0SVijay Khemka         if ((data[2] & 0xF) <= 0x9)
401*139aa4f0SVijay Khemka         {
402*139aa4f0SVijay Khemka             errLog += tmpStr[(data[2] & 0xF)];
403*139aa4f0SVijay Khemka         }
404*139aa4f0SVijay Khemka         else
405*139aa4f0SVijay Khemka         {
406*139aa4f0SVijay Khemka             errLog += "Reserved";
407*139aa4f0SVijay Khemka         }
408*139aa4f0SVijay Khemka     }
409*139aa4f0SVijay Khemka     else
410*139aa4f0SVijay Khemka     {
411*139aa4f0SVijay Khemka         errLog = "Unknown";
412*139aa4f0SVijay Khemka     }
413*139aa4f0SVijay Khemka }
414*139aa4f0SVijay Khemka 
415*139aa4f0SVijay Khemka static void logMemErr(uint8_t *dataPtr, std::string &errLog)
416*139aa4f0SVijay Khemka {
417*139aa4f0SVijay Khemka     uint8_t snrType = dataPtr[0];
418*139aa4f0SVijay Khemka     uint8_t snrNum = dataPtr[1];
419*139aa4f0SVijay Khemka     uint8_t *data = &(dataPtr[3]);
420*139aa4f0SVijay Khemka 
421*139aa4f0SVijay Khemka     /* TODO: add pal_add_cri_sel */
422*139aa4f0SVijay Khemka 
423*139aa4f0SVijay Khemka     if (snrNum == memoryEccError)
424*139aa4f0SVijay Khemka     {
425*139aa4f0SVijay Khemka         /* SEL from MEMORY_ECC_ERR Sensor */
426*139aa4f0SVijay Khemka         switch (data[0] & 0x0F)
427*139aa4f0SVijay Khemka         {
428*139aa4f0SVijay Khemka             case 0x0:
429*139aa4f0SVijay Khemka                 if (snrType == 0x0C)
430*139aa4f0SVijay Khemka                 {
431*139aa4f0SVijay Khemka                     errLog = "Correctable";
432*139aa4f0SVijay Khemka                 }
433*139aa4f0SVijay Khemka                 else if (snrType == 0x10)
434*139aa4f0SVijay Khemka                 {
435*139aa4f0SVijay Khemka                     errLog = "Correctable ECC error Logging Disabled";
436*139aa4f0SVijay Khemka                 }
437*139aa4f0SVijay Khemka                 break;
438*139aa4f0SVijay Khemka             case 0x1:
439*139aa4f0SVijay Khemka                 errLog = "Uncorrectable";
440*139aa4f0SVijay Khemka                 break;
441*139aa4f0SVijay Khemka             case 0x5:
442*139aa4f0SVijay Khemka                 errLog = "Correctable ECC error Logging Limit Disabled";
443*139aa4f0SVijay Khemka                 break;
444*139aa4f0SVijay Khemka             default:
445*139aa4f0SVijay Khemka                 errLog = "Unknown";
446*139aa4f0SVijay Khemka         }
447*139aa4f0SVijay Khemka     }
448*139aa4f0SVijay Khemka     else if (snrNum == memoryErrLogDIS)
449*139aa4f0SVijay Khemka     {
450*139aa4f0SVijay Khemka         // SEL from MEMORY_ERR_LOG_DIS Sensor
451*139aa4f0SVijay Khemka         if ((data[0] & 0x0F) == 0x0)
452*139aa4f0SVijay Khemka         {
453*139aa4f0SVijay Khemka             errLog = "Correctable Memory Error Logging Disabled";
454*139aa4f0SVijay Khemka         }
455*139aa4f0SVijay Khemka         else
456*139aa4f0SVijay Khemka         {
457*139aa4f0SVijay Khemka             errLog = "Unknown";
458*139aa4f0SVijay Khemka         }
459*139aa4f0SVijay Khemka     }
460*139aa4f0SVijay Khemka     else
461*139aa4f0SVijay Khemka     {
462*139aa4f0SVijay Khemka         errLog = "Unknown";
463*139aa4f0SVijay Khemka         return;
464*139aa4f0SVijay Khemka     }
465*139aa4f0SVijay Khemka 
466*139aa4f0SVijay Khemka     /* Common routine for both MEM_ECC_ERR and MEMORY_ERR_LOG_DIS */
467*139aa4f0SVijay Khemka 
468*139aa4f0SVijay Khemka     errLog += " (DIMM " + byteToStr(data[2]) + ") Logical Rank " +
469*139aa4f0SVijay Khemka               std::to_string(data[1] & 0x03);
470*139aa4f0SVijay Khemka 
471*139aa4f0SVijay Khemka     /* DIMM number (data[2]):
472*139aa4f0SVijay Khemka      * Bit[7:5]: Socket number  (Range: 0-7)
473*139aa4f0SVijay Khemka      * Bit[4:3]: Channel number (Range: 0-3)
474*139aa4f0SVijay Khemka      * Bit[2:0]: DIMM number    (Range: 0-7)
475*139aa4f0SVijay Khemka      */
476*139aa4f0SVijay Khemka 
477*139aa4f0SVijay Khemka     /* TODO: Verify these bits */
478*139aa4f0SVijay Khemka     std::string cpuStr = "CPU# " + std::to_string((data[2] & 0xE0) >> 5);
479*139aa4f0SVijay Khemka     std::string chStr = "CHN# " + std::to_string((data[2] & 0x18) >> 3);
480*139aa4f0SVijay Khemka     std::string dimmStr = "DIMM# " + std::to_string(data[2] & 0x7);
481*139aa4f0SVijay Khemka 
482*139aa4f0SVijay Khemka     switch ((data[1] & 0xC) >> 2)
483*139aa4f0SVijay Khemka     {
484*139aa4f0SVijay Khemka         case 0x0:
485*139aa4f0SVijay Khemka         {
486*139aa4f0SVijay Khemka 
487*139aa4f0SVijay Khemka             /* All Info Valid */
488*139aa4f0SVijay Khemka             uint8_t chnNum = (data[2] & 0x1C) >> 2;
489*139aa4f0SVijay Khemka             uint8_t dimmNum = data[2] & 0x3;
490*139aa4f0SVijay Khemka 
491*139aa4f0SVijay Khemka             /* TODO: If critical SEL logging is available, do it */
492*139aa4f0SVijay Khemka             if (snrType == 0x0C)
493*139aa4f0SVijay Khemka             {
494*139aa4f0SVijay Khemka                 if ((data[0] & 0x0F) == 0x0)
495*139aa4f0SVijay Khemka                 {
496*139aa4f0SVijay Khemka                     /* TODO: add_cri_sel */
497*139aa4f0SVijay Khemka                     /* "DIMM"+ 'A'+ chnNum + dimmNum + " ECC err,FRU:1"
498*139aa4f0SVijay Khemka                      */
499*139aa4f0SVijay Khemka                 }
500*139aa4f0SVijay Khemka                 else if ((data[0] & 0x0F) == 0x1)
501*139aa4f0SVijay Khemka                 {
502*139aa4f0SVijay Khemka                     /* TODO: add_cri_sel */
503*139aa4f0SVijay Khemka                     /* "DIMM"+ 'A'+ chnNum + dimmNum + " UECC err,FRU:1"
504*139aa4f0SVijay Khemka                      */
505*139aa4f0SVijay Khemka                 }
506*139aa4f0SVijay Khemka             }
507*139aa4f0SVijay Khemka             /* Continue to parse the error into a string. All Info Valid
508*139aa4f0SVijay Khemka              */
509*139aa4f0SVijay Khemka             errLog += " (" + cpuStr + ", " + chStr + ", " + dimmStr + ")";
510*139aa4f0SVijay Khemka         }
511*139aa4f0SVijay Khemka 
512*139aa4f0SVijay Khemka         break;
513*139aa4f0SVijay Khemka         case 0x1:
514*139aa4f0SVijay Khemka 
515*139aa4f0SVijay Khemka             /* DIMM info not valid */
516*139aa4f0SVijay Khemka             errLog += " (" + cpuStr + ", " + chStr + ")";
517*139aa4f0SVijay Khemka             break;
518*139aa4f0SVijay Khemka         case 0x2:
519*139aa4f0SVijay Khemka 
520*139aa4f0SVijay Khemka             /* CHN info not valid */
521*139aa4f0SVijay Khemka             errLog += " (" + cpuStr + ", " + dimmStr + ")";
522*139aa4f0SVijay Khemka             break;
523*139aa4f0SVijay Khemka         case 0x3:
524*139aa4f0SVijay Khemka 
525*139aa4f0SVijay Khemka             /* CPU info not valid */
526*139aa4f0SVijay Khemka             errLog += " (" + chStr + ", " + dimmStr + ")";
527*139aa4f0SVijay Khemka             break;
528*139aa4f0SVijay Khemka     }
529*139aa4f0SVijay Khemka }
530*139aa4f0SVijay Khemka 
531*139aa4f0SVijay Khemka static void logPwrErr(uint8_t *data, std::string &errLog)
532*139aa4f0SVijay Khemka {
533*139aa4f0SVijay Khemka 
534*139aa4f0SVijay Khemka     if (data[0] == 0x1)
535*139aa4f0SVijay Khemka     {
536*139aa4f0SVijay Khemka         errLog = "SYS_PWROK failure";
537*139aa4f0SVijay Khemka         /* Also try logging to Critial log file, if available */
538*139aa4f0SVijay Khemka         /* "SYS_PWROK failure,FRU:1" */
539*139aa4f0SVijay Khemka     }
540*139aa4f0SVijay Khemka     else if (data[0] == 0x2)
541*139aa4f0SVijay Khemka     {
542*139aa4f0SVijay Khemka         errLog = "PCH_PWROK failure";
543*139aa4f0SVijay Khemka         /* Also try logging to Critial log file, if available */
544*139aa4f0SVijay Khemka         /* "PCH_PWROK failure,FRU:1" */
545*139aa4f0SVijay Khemka     }
546*139aa4f0SVijay Khemka     else
547*139aa4f0SVijay Khemka     {
548*139aa4f0SVijay Khemka         errLog = "Unknown";
549*139aa4f0SVijay Khemka     }
550*139aa4f0SVijay Khemka }
551*139aa4f0SVijay Khemka 
552*139aa4f0SVijay Khemka static void logCatErr(uint8_t *data, std::string &errLog)
553*139aa4f0SVijay Khemka {
554*139aa4f0SVijay Khemka 
555*139aa4f0SVijay Khemka     if (data[0] == 0x0)
556*139aa4f0SVijay Khemka     {
557*139aa4f0SVijay Khemka         errLog = "IERR/CATERR";
558*139aa4f0SVijay Khemka         /* Also try logging to Critial log file, if available */
559*139aa4f0SVijay Khemka         /* "IERR,FRU:1 */
560*139aa4f0SVijay Khemka     }
561*139aa4f0SVijay Khemka     else if (data[0] == 0xB)
562*139aa4f0SVijay Khemka     {
563*139aa4f0SVijay Khemka         errLog = "MCERR/CATERR";
564*139aa4f0SVijay Khemka         /* Also try logging to Critial log file, if available */
565*139aa4f0SVijay Khemka         /* "MCERR,FRU:1 */
566*139aa4f0SVijay Khemka     }
567*139aa4f0SVijay Khemka     else
568*139aa4f0SVijay Khemka     {
569*139aa4f0SVijay Khemka         errLog = "Unknown";
570*139aa4f0SVijay Khemka     }
571*139aa4f0SVijay Khemka }
572*139aa4f0SVijay Khemka 
573*139aa4f0SVijay Khemka static void logDimmHot(uint8_t *data, std::string &errLog)
574*139aa4f0SVijay Khemka {
575*139aa4f0SVijay Khemka     if ((data[0] << 16 | data[1] << 8 | data[2]) == 0x01FFFF)
576*139aa4f0SVijay Khemka     {
577*139aa4f0SVijay Khemka         errLog = "SOC MEMHOT";
578*139aa4f0SVijay Khemka     }
579*139aa4f0SVijay Khemka     else
580*139aa4f0SVijay Khemka     {
581*139aa4f0SVijay Khemka         errLog = "Unknown";
582*139aa4f0SVijay Khemka         /* Also try logging to Critial log file, if available */
583*139aa4f0SVijay Khemka         /* ""CPU_DIMM_HOT %s,FRU:1" */
584*139aa4f0SVijay Khemka     }
585*139aa4f0SVijay Khemka }
586*139aa4f0SVijay Khemka 
587*139aa4f0SVijay Khemka static void logSwNMI(uint8_t *data, std::string &errLog)
588*139aa4f0SVijay Khemka {
589*139aa4f0SVijay Khemka     if ((data[0] << 16 | data[1] << 8 | data[2]) == 0x03FFFF)
590*139aa4f0SVijay Khemka     {
591*139aa4f0SVijay Khemka         errLog = "Software NMI";
592*139aa4f0SVijay Khemka     }
593*139aa4f0SVijay Khemka     else
594*139aa4f0SVijay Khemka     {
595*139aa4f0SVijay Khemka         errLog = "Unknown SW NMI";
596*139aa4f0SVijay Khemka     }
597*139aa4f0SVijay Khemka }
598*139aa4f0SVijay Khemka 
599*139aa4f0SVijay Khemka static void logCPUThermalSts(uint8_t *data, std::string &errLog)
600*139aa4f0SVijay Khemka {
601*139aa4f0SVijay Khemka     switch (data[0])
602*139aa4f0SVijay Khemka     {
603*139aa4f0SVijay Khemka         case 0x0:
604*139aa4f0SVijay Khemka             errLog = "CPU Critical Temperature";
605*139aa4f0SVijay Khemka             break;
606*139aa4f0SVijay Khemka         case 0x1:
607*139aa4f0SVijay Khemka             errLog = "PROCHOT#";
608*139aa4f0SVijay Khemka             break;
609*139aa4f0SVijay Khemka         case 0x2:
610*139aa4f0SVijay Khemka             errLog = "TCC Activation";
611*139aa4f0SVijay Khemka             break;
612*139aa4f0SVijay Khemka         default:
613*139aa4f0SVijay Khemka             errLog = "Unknown";
614*139aa4f0SVijay Khemka     }
615*139aa4f0SVijay Khemka }
616*139aa4f0SVijay Khemka 
617*139aa4f0SVijay Khemka static void logMEPwrState(uint8_t *data, std::string &errLog)
618*139aa4f0SVijay Khemka {
619*139aa4f0SVijay Khemka     switch (data[0])
620*139aa4f0SVijay Khemka     {
621*139aa4f0SVijay Khemka         case 0:
622*139aa4f0SVijay Khemka             errLog = "RUNNING";
623*139aa4f0SVijay Khemka             break;
624*139aa4f0SVijay Khemka         case 2:
625*139aa4f0SVijay Khemka             errLog = "POWER_OFF";
626*139aa4f0SVijay Khemka             break;
627*139aa4f0SVijay Khemka         default:
628*139aa4f0SVijay Khemka             errLog = "Unknown[" + std::to_string(data[0]) + "]";
629*139aa4f0SVijay Khemka             break;
630*139aa4f0SVijay Khemka     }
631*139aa4f0SVijay Khemka }
632*139aa4f0SVijay Khemka 
633*139aa4f0SVijay Khemka static void logSPSFwHealth(uint8_t *data, std::string &errLog)
634*139aa4f0SVijay Khemka {
635*139aa4f0SVijay Khemka     if ((data[0] & 0x0F) == 0x00)
636*139aa4f0SVijay Khemka     {
637*139aa4f0SVijay Khemka         const std::vector<std::string> tmpStr = {
638*139aa4f0SVijay Khemka             "Recovery GPIO forced",
639*139aa4f0SVijay Khemka             "Image execution failed",
640*139aa4f0SVijay Khemka             "Flash erase error",
641*139aa4f0SVijay Khemka             "Flash state information",
642*139aa4f0SVijay Khemka             "Internal error",
643*139aa4f0SVijay Khemka             "BMC did not respond",
644*139aa4f0SVijay Khemka             "Direct Flash update",
645*139aa4f0SVijay Khemka             "Manufacturing error",
646*139aa4f0SVijay Khemka             "Automatic Restore to Factory Presets",
647*139aa4f0SVijay Khemka             "Firmware Exception",
648*139aa4f0SVijay Khemka             "Flash Wear-Out Protection Warning",
649*139aa4f0SVijay Khemka             "Unknown",
650*139aa4f0SVijay Khemka             "Unknown",
651*139aa4f0SVijay Khemka             "DMI interface error",
652*139aa4f0SVijay Khemka             "MCTP interface error",
653*139aa4f0SVijay Khemka             "Auto-configuration finished",
654*139aa4f0SVijay Khemka             "Unsupported Segment Defined Feature",
655*139aa4f0SVijay Khemka             "Unknown",
656*139aa4f0SVijay Khemka             "CPU Debug Capability Disabled",
657*139aa4f0SVijay Khemka             "UMA operation error"};
658*139aa4f0SVijay Khemka 
659*139aa4f0SVijay Khemka         if (data[1] < 0x14)
660*139aa4f0SVijay Khemka         {
661*139aa4f0SVijay Khemka             errLog = tmpStr[data[1]];
662*139aa4f0SVijay Khemka         }
663*139aa4f0SVijay Khemka         else
664*139aa4f0SVijay Khemka         {
665*139aa4f0SVijay Khemka             errLog = "Unknown";
666*139aa4f0SVijay Khemka         }
667*139aa4f0SVijay Khemka     }
668*139aa4f0SVijay Khemka     else if ((data[0] & 0x0F) == 0x01)
669*139aa4f0SVijay Khemka     {
670*139aa4f0SVijay Khemka         errLog = "SMBus link failure";
671*139aa4f0SVijay Khemka     }
672*139aa4f0SVijay Khemka     else
673*139aa4f0SVijay Khemka     {
674*139aa4f0SVijay Khemka         errLog = "Unknown";
675*139aa4f0SVijay Khemka     }
676*139aa4f0SVijay Khemka }
677*139aa4f0SVijay Khemka 
678*139aa4f0SVijay Khemka static void logNmExcA(uint8_t *data, std::string &errLog)
679*139aa4f0SVijay Khemka {
680*139aa4f0SVijay Khemka     /*NM4.0 #550710, Revision 1.95, and turn to p.155*/
681*139aa4f0SVijay Khemka     if (data[0] == 0xA8)
682*139aa4f0SVijay Khemka     {
683*139aa4f0SVijay Khemka         errLog = "Policy Correction Time Exceeded";
684*139aa4f0SVijay Khemka     }
685*139aa4f0SVijay Khemka     else
686*139aa4f0SVijay Khemka     {
687*139aa4f0SVijay Khemka         errLog = "Unknown";
688*139aa4f0SVijay Khemka     }
689*139aa4f0SVijay Khemka }
690*139aa4f0SVijay Khemka 
691*139aa4f0SVijay Khemka static void logPCHThermal(uint8_t *data, std::string &errLog)
692*139aa4f0SVijay Khemka {
693*139aa4f0SVijay Khemka     const std::vector<std::string> thresEvtName = {"Lower Non-critical",
694*139aa4f0SVijay Khemka                                                    "Unknown",
695*139aa4f0SVijay Khemka                                                    "Lower Critical",
696*139aa4f0SVijay Khemka                                                    "Unknown",
697*139aa4f0SVijay Khemka                                                    "Lower Non-recoverable",
698*139aa4f0SVijay Khemka                                                    "Unknown",
699*139aa4f0SVijay Khemka                                                    "Unknown",
700*139aa4f0SVijay Khemka                                                    "Upper Non-critical",
701*139aa4f0SVijay Khemka                                                    "Unknown",
702*139aa4f0SVijay Khemka                                                    "Upper Critical",
703*139aa4f0SVijay Khemka                                                    "Unknown",
704*139aa4f0SVijay Khemka                                                    "Upper Non-recoverable"};
705*139aa4f0SVijay Khemka 
706*139aa4f0SVijay Khemka     if ((data[0] & 0x0f) < 12)
707*139aa4f0SVijay Khemka     {
708*139aa4f0SVijay Khemka         errLog = thresEvtName[(data[0] & 0x0f)];
709*139aa4f0SVijay Khemka     }
710*139aa4f0SVijay Khemka     else
711*139aa4f0SVijay Khemka     {
712*139aa4f0SVijay Khemka         errLog = "Unknown";
713*139aa4f0SVijay Khemka     }
714*139aa4f0SVijay Khemka 
715*139aa4f0SVijay Khemka     errLog += ", curr_val: " + std::to_string(data[1]) +
716*139aa4f0SVijay Khemka               " C, thresh_val: " + std::to_string(data[2]) + " C";
717*139aa4f0SVijay Khemka }
718*139aa4f0SVijay Khemka 
719*139aa4f0SVijay Khemka static void logNmHealth(uint8_t *data, std::string &errLog)
720*139aa4f0SVijay Khemka {
721*139aa4f0SVijay Khemka     std::vector<std::string> nmErrType = {
722*139aa4f0SVijay Khemka         "Unknown",
723*139aa4f0SVijay Khemka         "Unknown",
724*139aa4f0SVijay Khemka         "Unknown",
725*139aa4f0SVijay Khemka         "Unknown",
726*139aa4f0SVijay Khemka         "Unknown",
727*139aa4f0SVijay Khemka         "Unknown",
728*139aa4f0SVijay Khemka         "Unknown",
729*139aa4f0SVijay Khemka         "Extended Telemetry Device Reading Failure",
730*139aa4f0SVijay Khemka         "Outlet Temperature Reading Failure",
731*139aa4f0SVijay Khemka         "Volumetric Airflow Reading Failure",
732*139aa4f0SVijay Khemka         "Policy Misconfiguration",
733*139aa4f0SVijay Khemka         "Power Sensor Reading Failure",
734*139aa4f0SVijay Khemka         "Inlet Temperature Reading Failure",
735*139aa4f0SVijay Khemka         "Host Communication Error",
736*139aa4f0SVijay Khemka         "Real-time Clock Synchronization Failure",
737*139aa4f0SVijay Khemka         "Platform Shutdown Initiated by Intel NM Policy",
738*139aa4f0SVijay Khemka         "Unknown"};
739*139aa4f0SVijay Khemka     uint8_t nmTypeIdx = (data[0] & 0xf);
740*139aa4f0SVijay Khemka     uint8_t domIdx = (data[1] & 0xf);
741*139aa4f0SVijay Khemka     uint8_t errIdx = ((data[1] >> 4) & 0xf);
742*139aa4f0SVijay Khemka 
743*139aa4f0SVijay Khemka     if (nmTypeIdx == 2)
744*139aa4f0SVijay Khemka     {
745*139aa4f0SVijay Khemka         errLog = "SensorIntelNM";
746*139aa4f0SVijay Khemka     }
747*139aa4f0SVijay Khemka     else
748*139aa4f0SVijay Khemka     {
749*139aa4f0SVijay Khemka         errLog = "Unknown";
750*139aa4f0SVijay Khemka     }
751*139aa4f0SVijay Khemka 
752*139aa4f0SVijay Khemka     errLog += ", Domain:" + nmDomName[domIdx] +
753*139aa4f0SVijay Khemka               ", ErrType:" + nmErrType[errIdx] + ", Err:0x" +
754*139aa4f0SVijay Khemka               byteToStr(data[2]);
755*139aa4f0SVijay Khemka }
756*139aa4f0SVijay Khemka 
757*139aa4f0SVijay Khemka static void logNmCap(uint8_t *data, std::string &errLog)
758*139aa4f0SVijay Khemka {
759*139aa4f0SVijay Khemka 
760*139aa4f0SVijay Khemka     const std::vector<std::string> nmCapStsStr = {"Not Available", "Available"};
761*139aa4f0SVijay Khemka     if (data[0] & 0x7) // BIT1=policy, BIT2=monitoring, BIT3=pwr
762*139aa4f0SVijay Khemka                        // limit and the others are reserved
763*139aa4f0SVijay Khemka     {
764*139aa4f0SVijay Khemka         errLog = "PolicyInterface:" + nmCapStsStr[BIT(data[0], 0)] +
765*139aa4f0SVijay Khemka                  ",Monitoring:" + nmCapStsStr[BIT(data[0], 1)] +
766*139aa4f0SVijay Khemka                  ",PowerLimit:" + nmCapStsStr[BIT(data[0], 2)];
767*139aa4f0SVijay Khemka     }
768*139aa4f0SVijay Khemka     else
769*139aa4f0SVijay Khemka     {
770*139aa4f0SVijay Khemka         errLog = "Unknown";
771*139aa4f0SVijay Khemka     }
772*139aa4f0SVijay Khemka }
773*139aa4f0SVijay Khemka 
774*139aa4f0SVijay Khemka static void logNmThreshold(uint8_t *data, std::string &errLog)
775*139aa4f0SVijay Khemka {
776*139aa4f0SVijay Khemka     uint8_t thresNum = (data[0] & 0x3);
777*139aa4f0SVijay Khemka     uint8_t domIdx = (data[1] & 0xf);
778*139aa4f0SVijay Khemka     uint8_t polId = data[2];
779*139aa4f0SVijay Khemka     uint8_t polEvtIdx = BIT(data[0], 3);
780*139aa4f0SVijay Khemka     const std::vector<std::string> polEvtStr = {
781*139aa4f0SVijay Khemka         "Threshold Exceeded", "Policy Correction Time Exceeded"};
782*139aa4f0SVijay Khemka 
783*139aa4f0SVijay Khemka     errLog = "Threshold Number:" + std::to_string(thresNum) + "-" +
784*139aa4f0SVijay Khemka              polEvtStr[polEvtIdx] + ", Domain:" + nmDomName[domIdx] +
785*139aa4f0SVijay Khemka              ", PolicyID:0x" + byteToStr(polId);
786*139aa4f0SVijay Khemka }
787*139aa4f0SVijay Khemka 
788*139aa4f0SVijay Khemka static void logPwrThreshold(uint8_t *data, std::string &errLog)
789*139aa4f0SVijay Khemka {
790*139aa4f0SVijay Khemka     if (data[0] == 0x00)
791*139aa4f0SVijay Khemka     {
792*139aa4f0SVijay Khemka         errLog = "Limit Not Exceeded";
793*139aa4f0SVijay Khemka     }
794*139aa4f0SVijay Khemka     else if (data[0] == 0x01)
795*139aa4f0SVijay Khemka     {
796*139aa4f0SVijay Khemka         errLog = "Limit Exceeded";
797*139aa4f0SVijay Khemka     }
798*139aa4f0SVijay Khemka     else
799*139aa4f0SVijay Khemka     {
800*139aa4f0SVijay Khemka         errLog = "Unknown";
801*139aa4f0SVijay Khemka     }
802*139aa4f0SVijay Khemka }
803*139aa4f0SVijay Khemka 
804*139aa4f0SVijay Khemka static void logMSMI(uint8_t *data, std::string &errLog)
805*139aa4f0SVijay Khemka {
806*139aa4f0SVijay Khemka 
807*139aa4f0SVijay Khemka     if (data[0] == 0x0)
808*139aa4f0SVijay Khemka     {
809*139aa4f0SVijay Khemka         errLog = "IERR/MSMI";
810*139aa4f0SVijay Khemka     }
811*139aa4f0SVijay Khemka     else if (data[0] == 0x0B)
812*139aa4f0SVijay Khemka     {
813*139aa4f0SVijay Khemka         errLog = "MCERR/MSMI";
814*139aa4f0SVijay Khemka     }
815*139aa4f0SVijay Khemka     else
816*139aa4f0SVijay Khemka     {
817*139aa4f0SVijay Khemka         errLog = "Unknown";
818*139aa4f0SVijay Khemka     }
819*139aa4f0SVijay Khemka }
820*139aa4f0SVijay Khemka 
821*139aa4f0SVijay Khemka static void logHprWarn(uint8_t *data, std::string &errLog)
822*139aa4f0SVijay Khemka {
823*139aa4f0SVijay Khemka     if (data[2] == 0x01)
824*139aa4f0SVijay Khemka     {
825*139aa4f0SVijay Khemka         if (data[1] == 0xFF)
826*139aa4f0SVijay Khemka         {
827*139aa4f0SVijay Khemka             errLog = "Infinite Time";
828*139aa4f0SVijay Khemka         }
829*139aa4f0SVijay Khemka         else
830*139aa4f0SVijay Khemka         {
831*139aa4f0SVijay Khemka             errLog = std::to_string(data[1]) + " minutes";
832*139aa4f0SVijay Khemka         }
833*139aa4f0SVijay Khemka     }
834*139aa4f0SVijay Khemka     else
835*139aa4f0SVijay Khemka     {
836*139aa4f0SVijay Khemka         errLog = "Unknown";
837*139aa4f0SVijay Khemka     }
838*139aa4f0SVijay Khemka }
839*139aa4f0SVijay Khemka 
840*139aa4f0SVijay Khemka static const boost::container::flat_map<
841*139aa4f0SVijay Khemka     uint8_t,
842*139aa4f0SVijay Khemka     std::pair<std::string, std::function<void(uint8_t *, std::string &)>>>
843*139aa4f0SVijay Khemka     sensorNameTable = {{0xE9, {"SYSTEM_EVENT", logSysEvent}},
844*139aa4f0SVijay Khemka                        {0x7D, {"THERM_THRESH_EVT", logThermalEvent}},
845*139aa4f0SVijay Khemka                        {0xAA, {"BUTTON", logDefault}},
846*139aa4f0SVijay Khemka                        {0xAB, {"POWER_STATE", logDefault}},
847*139aa4f0SVijay Khemka                        {0xEA, {"CRITICAL_IRQ", logCritIrq}},
848*139aa4f0SVijay Khemka                        {0x2B, {"POST_ERROR", logPostErr}},
849*139aa4f0SVijay Khemka                        {0x40, {"MACHINE_CHK_ERR", logMchChkErr}},
850*139aa4f0SVijay Khemka                        {0x41, {"PCIE_ERR", logPcieErr}},
851*139aa4f0SVijay Khemka                        {0x43, {"IIO_ERR", logIioErr}},
852*139aa4f0SVijay Khemka                        {0X63, {"MEMORY_ECC_ERR", logDefault}},
853*139aa4f0SVijay Khemka                        {0X87, {"MEMORY_ERR_LOG_DIS", logDefault}},
854*139aa4f0SVijay Khemka                        {0X51, {"PROCHOT_EXT", logDefault}},
855*139aa4f0SVijay Khemka                        {0X56, {"PWR_ERR", logPwrErr}},
856*139aa4f0SVijay Khemka                        {0xE6, {"CATERR_A", logCatErr}},
857*139aa4f0SVijay Khemka                        {0xEB, {"CATERR_B", logCatErr}},
858*139aa4f0SVijay Khemka                        {0xB3, {"CPU_DIMM_HOT", logDimmHot}},
859*139aa4f0SVijay Khemka                        {0x90, {"SOFTWARE_NMI", logSwNMI}},
860*139aa4f0SVijay Khemka                        {0x1C, {"CPU0_THERM_STATUS", logCPUThermalSts}},
861*139aa4f0SVijay Khemka                        {0x1D, {"CPU1_THERM_STATUS", logCPUThermalSts}},
862*139aa4f0SVijay Khemka                        {0x16, {"ME_POWER_STATE", logMEPwrState}},
863*139aa4f0SVijay Khemka                        {0x17, {"SPS_FW_HEALTH", logSPSFwHealth}},
864*139aa4f0SVijay Khemka                        {0x18, {"NM_EXCEPTION_A", logNmExcA}},
865*139aa4f0SVijay Khemka                        {0x08, {"PCH_THERM_THRESHOLD", logPCHThermal}},
866*139aa4f0SVijay Khemka                        {0x19, {"NM_HEALTH", logNmHealth}},
867*139aa4f0SVijay Khemka                        {0x1A, {"NM_CAPABILITIES", logNmCap}},
868*139aa4f0SVijay Khemka                        {0x1B, {"NM_THRESHOLD", logNmThreshold}},
869*139aa4f0SVijay Khemka                        {0x3B, {"PWR_THRESH_EVT", logPwrThreshold}},
870*139aa4f0SVijay Khemka                        {0xE7, {"MSMI", logMSMI}},
871*139aa4f0SVijay Khemka                        {0xC5, {"HPR_WARNING", logHprWarn}}};
872*139aa4f0SVijay Khemka 
873*139aa4f0SVijay Khemka static void parseSelHelper(StdSELEntry *data, std::string &errStr)
874*139aa4f0SVijay Khemka {
875*139aa4f0SVijay Khemka 
876*139aa4f0SVijay Khemka     /* Check if sensor type is OS_BOOT (0x1f) */
877*139aa4f0SVijay Khemka     if (data->sensorType == 0x1F)
878*139aa4f0SVijay Khemka     {
879*139aa4f0SVijay Khemka         /* OS_BOOT used by OS */
880*139aa4f0SVijay Khemka         switch (data->eventData1 & 0xF)
881*139aa4f0SVijay Khemka         {
882*139aa4f0SVijay Khemka             case 0x07:
883*139aa4f0SVijay Khemka                 errStr = "Base OS/Hypervisor Installation started";
884*139aa4f0SVijay Khemka                 break;
885*139aa4f0SVijay Khemka             case 0x08:
886*139aa4f0SVijay Khemka                 errStr = "Base OS/Hypervisor Installation completed";
887*139aa4f0SVijay Khemka                 break;
888*139aa4f0SVijay Khemka             case 0x09:
889*139aa4f0SVijay Khemka                 errStr = "Base OS/Hypervisor Installation aborted";
890*139aa4f0SVijay Khemka                 break;
891*139aa4f0SVijay Khemka             case 0x0A:
892*139aa4f0SVijay Khemka                 errStr = "Base OS/Hypervisor Installation failed";
893*139aa4f0SVijay Khemka                 break;
894*139aa4f0SVijay Khemka             default:
895*139aa4f0SVijay Khemka                 errStr = "Unknown";
896*139aa4f0SVijay Khemka         }
897*139aa4f0SVijay Khemka         return;
898*139aa4f0SVijay Khemka     }
899*139aa4f0SVijay Khemka 
900*139aa4f0SVijay Khemka     auto findSensorName = sensorNameTable.find(data->sensorNum);
901*139aa4f0SVijay Khemka     if (findSensorName == sensorNameTable.end())
902*139aa4f0SVijay Khemka     {
903*139aa4f0SVijay Khemka         errStr = "Unknown";
904*139aa4f0SVijay Khemka         return;
905*139aa4f0SVijay Khemka     }
906*139aa4f0SVijay Khemka     else
907*139aa4f0SVijay Khemka     {
908*139aa4f0SVijay Khemka         switch (data->sensorNum)
909*139aa4f0SVijay Khemka         {
910*139aa4f0SVijay Khemka             /* logMemErr function needs data from sensor type */
911*139aa4f0SVijay Khemka             case memoryEccError:
912*139aa4f0SVijay Khemka             case memoryErrLogDIS:
913*139aa4f0SVijay Khemka                 findSensorName->second.second(&(data->sensorType), errStr);
914*139aa4f0SVijay Khemka                 break;
915*139aa4f0SVijay Khemka             /* Other sensor function needs only event data for parsing */
916*139aa4f0SVijay Khemka             default:
917*139aa4f0SVijay Khemka                 findSensorName->second.second(&(data->eventData1), errStr);
918*139aa4f0SVijay Khemka         }
919*139aa4f0SVijay Khemka     }
920*139aa4f0SVijay Khemka 
921*139aa4f0SVijay Khemka     if (((data->eventData3 & 0x80) >> 7) == 0)
922*139aa4f0SVijay Khemka     {
923*139aa4f0SVijay Khemka         errStr += " Assertion";
924*139aa4f0SVijay Khemka     }
925*139aa4f0SVijay Khemka     else
926*139aa4f0SVijay Khemka     {
927*139aa4f0SVijay Khemka         errStr += " Deassertion";
928*139aa4f0SVijay Khemka     }
929*139aa4f0SVijay Khemka }
930*139aa4f0SVijay Khemka 
931f36f345fSVijay Khemka static void parseStdSel(StdSELEntry *data, std::string &errStr)
932f36f345fSVijay Khemka {
933f36f345fSVijay Khemka     std::stringstream tmpStream;
934f36f345fSVijay Khemka     tmpStream << std::hex << std::uppercase;
935f36f345fSVijay Khemka 
936f36f345fSVijay Khemka     /* TODO: add pal_add_cri_sel */
937f36f345fSVijay Khemka     switch (data->sensorNum)
938f36f345fSVijay Khemka     {
939f36f345fSVijay Khemka         case memoryEccError:
940f36f345fSVijay Khemka             switch (data->eventData1 & 0x0F)
941f36f345fSVijay Khemka             {
942f36f345fSVijay Khemka                 case 0x00:
943f36f345fSVijay Khemka                     errStr = "Correctable";
944f36f345fSVijay Khemka                     tmpStream << "DIMM" << std::setw(2) << std::setfill('0')
945f36f345fSVijay Khemka                               << data->eventData3 << " ECC err";
946f36f345fSVijay Khemka                     break;
947f36f345fSVijay Khemka                 case 0x01:
948f36f345fSVijay Khemka                     errStr = "Uncorrectable";
949f36f345fSVijay Khemka                     tmpStream << "DIMM" << std::setw(2) << std::setfill('0')
950f36f345fSVijay Khemka                               << data->eventData3 << " UECC err";
951f36f345fSVijay Khemka                     break;
952f36f345fSVijay Khemka                 case 0x02:
953f36f345fSVijay Khemka                     errStr = "Parity";
954f36f345fSVijay Khemka                     break;
955f36f345fSVijay Khemka                 case 0x05:
956f36f345fSVijay Khemka                     errStr = "Correctable ECC error Logging Limit Reached";
957f36f345fSVijay Khemka                     break;
958f36f345fSVijay Khemka                 default:
959f36f345fSVijay Khemka                     errStr = "Unknown";
960f36f345fSVijay Khemka             }
961f36f345fSVijay Khemka             break;
962f36f345fSVijay Khemka         case memoryErrLogDIS:
963f36f345fSVijay Khemka             if ((data->eventData1 & 0x0F) == 0)
964f36f345fSVijay Khemka             {
965f36f345fSVijay Khemka                 errStr = "Correctable Memory Error Logging Disabled";
966f36f345fSVijay Khemka             }
967f36f345fSVijay Khemka             else
968f36f345fSVijay Khemka             {
969f36f345fSVijay Khemka                 errStr = "Unknown";
970f36f345fSVijay Khemka             }
971f36f345fSVijay Khemka             break;
972f36f345fSVijay Khemka         default:
973*139aa4f0SVijay Khemka             parseSelHelper(data, errStr);
974f36f345fSVijay Khemka             return;
975f36f345fSVijay Khemka     }
976f36f345fSVijay Khemka 
977f36f345fSVijay Khemka     errStr += " (DIMM " + std::to_string(data->eventData3) + ")";
978f36f345fSVijay Khemka     errStr += " Logical Rank " + std::to_string(data->eventData2 & 0x03);
979f36f345fSVijay Khemka 
980f36f345fSVijay Khemka     switch ((data->eventData2 & 0x0C) >> 2)
981f36f345fSVijay Khemka     {
982f36f345fSVijay Khemka         case 0x00:
983f36f345fSVijay Khemka             // Ignore when " All info available"
984f36f345fSVijay Khemka             break;
985f36f345fSVijay Khemka         case 0x01:
986f36f345fSVijay Khemka             errStr += " DIMM info not valid";
987f36f345fSVijay Khemka             break;
988f36f345fSVijay Khemka         case 0x02:
989f36f345fSVijay Khemka             errStr += " CHN info not valid";
990f36f345fSVijay Khemka             break;
991f36f345fSVijay Khemka         case 0x03:
992f36f345fSVijay Khemka             errStr += " CPU info not valid";
993f36f345fSVijay Khemka             break;
994f36f345fSVijay Khemka         default:
995f36f345fSVijay Khemka             errStr += " Unknown";
996f36f345fSVijay Khemka     }
997f36f345fSVijay Khemka 
998f36f345fSVijay Khemka     if (((data->eventType & 0x80) >> 7) == 0)
999f36f345fSVijay Khemka     {
1000f36f345fSVijay Khemka         errStr += " Assertion";
1001f36f345fSVijay Khemka     }
1002f36f345fSVijay Khemka     else
1003f36f345fSVijay Khemka     {
1004f36f345fSVijay Khemka         errStr += " Deassertion";
1005f36f345fSVijay Khemka     }
1006f36f345fSVijay Khemka 
1007f36f345fSVijay Khemka     return;
1008f36f345fSVijay Khemka }
1009f36f345fSVijay Khemka 
1010f36f345fSVijay Khemka static void parseOemSel(TsOemSELEntry *data, std::string &errStr)
1011f36f345fSVijay Khemka {
1012f36f345fSVijay Khemka     std::stringstream tmpStream;
1013f36f345fSVijay Khemka     tmpStream << std::hex << std::uppercase << std::setfill('0');
1014f36f345fSVijay Khemka 
1015f36f345fSVijay Khemka     switch (data->recordType)
1016f36f345fSVijay Khemka     {
1017f36f345fSVijay Khemka         case 0xC0:
1018f36f345fSVijay Khemka             tmpStream << "VID:0x" << std::setw(2) << (int)data->oemData[1]
1019f36f345fSVijay Khemka                       << std::setw(2) << (int)data->oemData[0] << " DID:0x"
1020f36f345fSVijay Khemka                       << std::setw(2) << (int)data->oemData[3] << std::setw(2)
1021f36f345fSVijay Khemka                       << (int)data->oemData[2] << " Slot:0x" << std::setw(2)
1022f36f345fSVijay Khemka                       << (int)data->oemData[4] << " Error ID:0x" << std::setw(2)
1023f36f345fSVijay Khemka                       << (int)data->oemData[5];
1024f36f345fSVijay Khemka             break;
1025f36f345fSVijay Khemka         case 0xC2:
1026f36f345fSVijay Khemka             tmpStream << "Extra info:0x" << std::setw(2)
1027f36f345fSVijay Khemka                       << (int)data->oemData[1] << " MSCOD:0x" << std::setw(2)
1028f36f345fSVijay Khemka                       << (int)data->oemData[3] << std::setw(2)
1029f36f345fSVijay Khemka                       << (int)data->oemData[2] << " MCACOD:0x" << std::setw(2)
1030f36f345fSVijay Khemka                       << (int)data->oemData[5] << std::setw(2)
1031f36f345fSVijay Khemka                       << (int)data->oemData[4];
1032f36f345fSVijay Khemka             break;
1033f36f345fSVijay Khemka         case 0xC3:
1034f36f345fSVijay Khemka             int bank = (data->oemData[1] & 0xf0) >> 4;
1035f36f345fSVijay Khemka             int col = ((data->oemData[1] & 0x0f) << 8) | data->oemData[2];
1036f36f345fSVijay Khemka 
1037f36f345fSVijay Khemka             tmpStream << "Fail Device:0x" << std::setw(2)
1038f36f345fSVijay Khemka                       << (int)data->oemData[0] << " Bank:0x" << std::setw(2)
1039f36f345fSVijay Khemka                       << bank << " Column:0x" << std::setw(2) << col
1040f36f345fSVijay Khemka                       << " Failed Row:0x" << std::setw(2)
1041f36f345fSVijay Khemka                       << (int)data->oemData[3] << std::setw(2)
1042f36f345fSVijay Khemka                       << (int)data->oemData[4] << std::setw(2)
1043f36f345fSVijay Khemka                       << (int)data->oemData[5];
1044f36f345fSVijay Khemka     }
1045f36f345fSVijay Khemka 
1046f36f345fSVijay Khemka     errStr = tmpStream.str();
1047f36f345fSVijay Khemka 
1048f36f345fSVijay Khemka     return;
1049f36f345fSVijay Khemka }
1050f36f345fSVijay Khemka 
105134a875f3SVijay Khemka static void parseOemUnifiedSel(NtsOemSELEntry *data, std::string &errStr)
105234a875f3SVijay Khemka {
105334a875f3SVijay Khemka     uint8_t *ptr = data->oemData;
105434a875f3SVijay Khemka     int genInfo = ptr[0];
105534a875f3SVijay Khemka     int errType = genInfo & 0x0f;
105634a875f3SVijay Khemka     std::vector<std::string> dimmEvent = {
105734a875f3SVijay Khemka         "Memory training failure", "Memory correctable error",
105834a875f3SVijay Khemka         "Memory uncorrectable error", "Reserved"};
105934a875f3SVijay Khemka 
106034a875f3SVijay Khemka     std::stringstream tmpStream;
106134a875f3SVijay Khemka     tmpStream << std::hex << std::uppercase << std::setfill('0');
106234a875f3SVijay Khemka 
106334a875f3SVijay Khemka     switch (errType)
106434a875f3SVijay Khemka     {
106534a875f3SVijay Khemka         case unifiedPcieErr:
106634a875f3SVijay Khemka             if (((genInfo & 0x10) >> 4) == 0) // x86
106734a875f3SVijay Khemka             {
106834a875f3SVijay Khemka                 tmpStream << "GeneralInfo: x86/PCIeErr(0x" << std::setw(2)
106934a875f3SVijay Khemka                           << genInfo << "),";
107034a875f3SVijay Khemka             }
107134a875f3SVijay Khemka 
107234a875f3SVijay Khemka             tmpStream << " Bus " << std::setw(2) << (int)(ptr[8]) << "/Dev "
107334a875f3SVijay Khemka                       << std::setw(2) << (int)(ptr[7] >> 3) << "/Fun "
107434a875f3SVijay Khemka                       << std::setw(2) << (int)(ptr[7] & 0x7)
107534a875f3SVijay Khemka                       << ", TotalErrID1Cnt: 0x" << std::setw(4)
107634a875f3SVijay Khemka                       << (int)((ptr[10] << 8) | ptr[9]) << ", ErrID2: 0x"
107734a875f3SVijay Khemka                       << std::setw(2) << (int)(ptr[11]) << ", ErrID1: 0x"
107834a875f3SVijay Khemka                       << std::setw(2) << (int)(ptr[12]);
107934a875f3SVijay Khemka 
108034a875f3SVijay Khemka             break;
108134a875f3SVijay Khemka         case unifiedMemErr:
108234a875f3SVijay Khemka             tmpStream << "GeneralInfo: MemErr(0x" << std::setw(2) << genInfo
108334a875f3SVijay Khemka                       << "), DIMM Slot Location: Sled " << std::setw(2)
108434a875f3SVijay Khemka                       << (int)((ptr[5] >> 4) & 0x03) << "/Socket "
108534a875f3SVijay Khemka                       << std::setw(2) << (int)(ptr[5] & 0x0f) << ", Channel "
108634a875f3SVijay Khemka                       << std::setw(2) << (int)(ptr[6] & 0x0f) << ", Slot "
108734a875f3SVijay Khemka                       << std::setw(2) << (int)(ptr[7] & 0x0f)
108834a875f3SVijay Khemka                       << ", DIMM Failure Event: " << dimmEvent[(ptr[9] & 0x03)]
108934a875f3SVijay Khemka                       << ", Major Code: 0x" << std::setw(2) << (int)(ptr[10])
109034a875f3SVijay Khemka                       << ", Minor Code: 0x" << std::setw(2) << (int)(ptr[11]);
109134a875f3SVijay Khemka 
109234a875f3SVijay Khemka             break;
109334a875f3SVijay Khemka         default:
109434a875f3SVijay Khemka             std::vector<uint8_t> oemData(ptr, ptr + 13);
109534a875f3SVijay Khemka             std::string oemDataStr;
109634a875f3SVijay Khemka             toHexStr(oemData, oemDataStr);
109734a875f3SVijay Khemka             tmpStream << "Undefined Error Type(0x" << std::setw(2) << errType
109834a875f3SVijay Khemka                       << "), Raw: " << oemDataStr;
109934a875f3SVijay Khemka     }
110034a875f3SVijay Khemka 
110134a875f3SVijay Khemka     errStr = tmpStream.str();
110234a875f3SVijay Khemka 
110334a875f3SVijay Khemka     return;
110434a875f3SVijay Khemka }
110534a875f3SVijay Khemka 
1106f36f345fSVijay Khemka static void parseSelData(std::vector<uint8_t> &reqData, std::string &msgLog)
1107f36f345fSVijay Khemka {
1108f36f345fSVijay Khemka 
1109f36f345fSVijay Khemka     /* Get record type */
1110f36f345fSVijay Khemka     int recType = reqData[2];
1111f36f345fSVijay Khemka     std::string errType, errLog;
1112f36f345fSVijay Khemka 
1113f36f345fSVijay Khemka     uint8_t *ptr = NULL;
1114f36f345fSVijay Khemka 
1115f36f345fSVijay Khemka     std::stringstream recTypeStream;
1116f36f345fSVijay Khemka     recTypeStream << std::hex << std::uppercase << std::setfill('0')
1117f36f345fSVijay Khemka                   << std::setw(2) << recType;
1118f36f345fSVijay Khemka 
1119f36f345fSVijay Khemka     msgLog = "SEL Entry: FRU: 1, Record: ";
1120f36f345fSVijay Khemka 
1121f36f345fSVijay Khemka     if (recType == stdErrType)
1122f36f345fSVijay Khemka     {
1123f36f345fSVijay Khemka         StdSELEntry *data = reinterpret_cast<StdSELEntry *>(&reqData[0]);
1124f36f345fSVijay Khemka         std::string sensorName;
1125f36f345fSVijay Khemka 
1126f36f345fSVijay Khemka         errType = stdErr;
1127f36f345fSVijay Khemka         if (data->sensorType == 0x1F)
1128f36f345fSVijay Khemka         {
1129f36f345fSVijay Khemka             sensorName = "OS";
1130f36f345fSVijay Khemka         }
1131f36f345fSVijay Khemka         else
1132f36f345fSVijay Khemka         {
1133f36f345fSVijay Khemka             auto findSensorName = sensorNameTable.find(data->sensorNum);
1134f36f345fSVijay Khemka             if (findSensorName == sensorNameTable.end())
1135f36f345fSVijay Khemka             {
1136f36f345fSVijay Khemka                 sensorName = "Unknown";
1137f36f345fSVijay Khemka             }
1138f36f345fSVijay Khemka             else
1139f36f345fSVijay Khemka             {
1140*139aa4f0SVijay Khemka                 sensorName = findSensorName->second.first;
1141f36f345fSVijay Khemka             }
1142f36f345fSVijay Khemka         }
1143f36f345fSVijay Khemka 
1144f36f345fSVijay Khemka         std::tm *ts = localtime((time_t *)(&(data->timeStamp)));
1145f36f345fSVijay Khemka         std::string timeStr = std::asctime(ts);
1146f36f345fSVijay Khemka 
1147f36f345fSVijay Khemka         parseStdSel(data, errLog);
1148f36f345fSVijay Khemka         ptr = &(data->eventData1);
1149f36f345fSVijay Khemka         std::vector<uint8_t> evtData(ptr, ptr + 3);
1150f36f345fSVijay Khemka         std::string eventData;
1151f36f345fSVijay Khemka         toHexStr(evtData, eventData);
1152f36f345fSVijay Khemka 
1153f36f345fSVijay Khemka         std::stringstream senNumStream;
1154f36f345fSVijay Khemka         senNumStream << std::hex << std::uppercase << std::setfill('0')
1155f36f345fSVijay Khemka                      << std::setw(2) << (int)(data->sensorNum);
1156f36f345fSVijay Khemka 
1157f36f345fSVijay Khemka         msgLog += errType + " (0x" + recTypeStream.str() +
1158f36f345fSVijay Khemka                   "), Time: " + timeStr + ", Sensor: " + sensorName + " (0x" +
1159f36f345fSVijay Khemka                   senNumStream.str() + "), Event Data: (" + eventData + ") " +
1160f36f345fSVijay Khemka                   errLog;
1161f36f345fSVijay Khemka     }
1162f36f345fSVijay Khemka     else if ((recType >= oemTSErrTypeMin) && (recType <= oemTSErrTypeMax))
1163f36f345fSVijay Khemka     {
1164f36f345fSVijay Khemka         /* timestamped OEM SEL records */
1165f36f345fSVijay Khemka         TsOemSELEntry *data = reinterpret_cast<TsOemSELEntry *>(&reqData[0]);
1166f36f345fSVijay Khemka         ptr = data->mfrId;
1167f36f345fSVijay Khemka         std::vector<uint8_t> mfrIdData(ptr, ptr + 3);
1168f36f345fSVijay Khemka         std::string mfrIdStr;
1169f36f345fSVijay Khemka         toHexStr(mfrIdData, mfrIdStr);
1170f36f345fSVijay Khemka 
1171f36f345fSVijay Khemka         ptr = data->oemData;
1172f36f345fSVijay Khemka         std::vector<uint8_t> oemData(ptr, ptr + 6);
1173f36f345fSVijay Khemka         std::string oemDataStr;
1174f36f345fSVijay Khemka         toHexStr(oemData, oemDataStr);
1175f36f345fSVijay Khemka 
1176f36f345fSVijay Khemka         std::tm *ts = localtime((time_t *)(&(data->timeStamp)));
1177f36f345fSVijay Khemka         std::string timeStr = std::asctime(ts);
1178f36f345fSVijay Khemka 
1179f36f345fSVijay Khemka         errType = oemTSErr;
1180f36f345fSVijay Khemka         parseOemSel(data, errLog);
1181f36f345fSVijay Khemka 
1182f36f345fSVijay Khemka         msgLog += errType + " (0x" + recTypeStream.str() +
1183f36f345fSVijay Khemka                   "), Time: " + timeStr + ", MFG ID: " + mfrIdStr +
1184f36f345fSVijay Khemka                   ", OEM Data: (" + oemDataStr + ") " + errLog;
1185f36f345fSVijay Khemka     }
118634a875f3SVijay Khemka     else if (recType == fbUniErrType)
118734a875f3SVijay Khemka     {
118834a875f3SVijay Khemka         NtsOemSELEntry *data = reinterpret_cast<NtsOemSELEntry *>(&reqData[0]);
118934a875f3SVijay Khemka         errType = fbUniSELErr;
119034a875f3SVijay Khemka         parseOemUnifiedSel(data, errLog);
119134a875f3SVijay Khemka         msgLog += errType + " (0x" + recTypeStream.str() + "), " + errLog;
119234a875f3SVijay Khemka     }
1193f36f345fSVijay Khemka     else if ((recType >= oemNTSErrTypeMin) && (recType <= oemNTSErrTypeMax))
1194f36f345fSVijay Khemka     {
1195f36f345fSVijay Khemka         /* Non timestamped OEM SEL records */
1196f36f345fSVijay Khemka         NtsOemSELEntry *data = reinterpret_cast<NtsOemSELEntry *>(&reqData[0]);
1197f36f345fSVijay Khemka         errType = oemNTSErr;
1198f36f345fSVijay Khemka 
1199f36f345fSVijay Khemka         ptr = data->oemData;
1200f36f345fSVijay Khemka         std::vector<uint8_t> oemData(ptr, ptr + 13);
1201f36f345fSVijay Khemka         std::string oemDataStr;
1202f36f345fSVijay Khemka         toHexStr(oemData, oemDataStr);
1203f36f345fSVijay Khemka 
1204f36f345fSVijay Khemka         parseOemSel((TsOemSELEntry *)data, errLog);
1205f36f345fSVijay Khemka         msgLog += errType + " (0x" + recTypeStream.str() + "), OEM Data: (" +
1206f36f345fSVijay Khemka                   oemDataStr + ") " + errLog;
1207f36f345fSVijay Khemka     }
1208f36f345fSVijay Khemka     else
1209f36f345fSVijay Khemka     {
1210f36f345fSVijay Khemka         errType = unknownErr;
1211f36f345fSVijay Khemka         toHexStr(reqData, errLog);
1212f36f345fSVijay Khemka         msgLog +=
1213f36f345fSVijay Khemka             errType + " (0x" + recTypeStream.str() + ") RawData: " + errLog;
1214f36f345fSVijay Khemka     }
1215f36f345fSVijay Khemka }
1216f36f345fSVijay Khemka 
121711b9c3b1SVijay Khemka } // namespace fb_oem::ipmi::sel
121811b9c3b1SVijay Khemka 
121911b9c3b1SVijay Khemka namespace ipmi
122011b9c3b1SVijay Khemka {
122111b9c3b1SVijay Khemka 
122211b9c3b1SVijay Khemka namespace storage
122311b9c3b1SVijay Khemka {
122411b9c3b1SVijay Khemka 
122511b9c3b1SVijay Khemka static void registerSELFunctions() __attribute__((constructor));
122611b9c3b1SVijay Khemka static fb_oem::ipmi::sel::SELData selObj __attribute__((init_priority(101)));
122711b9c3b1SVijay Khemka 
122811b9c3b1SVijay Khemka ipmi::RspType<uint8_t,  // SEL version
122911b9c3b1SVijay Khemka               uint16_t, // SEL entry count
123011b9c3b1SVijay Khemka               uint16_t, // free space
123111b9c3b1SVijay Khemka               uint32_t, // last add timestamp
123211b9c3b1SVijay Khemka               uint32_t, // last erase timestamp
123311b9c3b1SVijay Khemka               uint8_t>  // operation support
123411b9c3b1SVijay Khemka     ipmiStorageGetSELInfo()
123511b9c3b1SVijay Khemka {
123611b9c3b1SVijay Khemka 
123711b9c3b1SVijay Khemka     fb_oem::ipmi::sel::GetSELInfoData info;
123811b9c3b1SVijay Khemka 
123911b9c3b1SVijay Khemka     selObj.getInfo(info);
124011b9c3b1SVijay Khemka     return ipmi::responseSuccess(info.selVersion, info.entries, info.freeSpace,
124111b9c3b1SVijay Khemka                                  info.addTimeStamp, info.eraseTimeStamp,
124211b9c3b1SVijay Khemka                                  info.operationSupport);
124311b9c3b1SVijay Khemka }
124411b9c3b1SVijay Khemka 
124511b9c3b1SVijay Khemka ipmi::RspType<uint16_t, std::vector<uint8_t>>
124611b9c3b1SVijay Khemka     ipmiStorageGetSELEntry(std::vector<uint8_t> data)
124711b9c3b1SVijay Khemka {
124811b9c3b1SVijay Khemka 
124911b9c3b1SVijay Khemka     if (data.size() != sizeof(fb_oem::ipmi::sel::GetSELEntryRequest))
125011b9c3b1SVijay Khemka     {
125111b9c3b1SVijay Khemka         return ipmi::responseReqDataLenInvalid();
125211b9c3b1SVijay Khemka     }
125311b9c3b1SVijay Khemka 
125411b9c3b1SVijay Khemka     fb_oem::ipmi::sel::GetSELEntryRequest *reqData =
125511b9c3b1SVijay Khemka         reinterpret_cast<fb_oem::ipmi::sel::GetSELEntryRequest *>(&data[0]);
125611b9c3b1SVijay Khemka 
125711b9c3b1SVijay Khemka     if (reqData->reservID != 0)
125811b9c3b1SVijay Khemka     {
125911b9c3b1SVijay Khemka         if (!checkSELReservation(reqData->reservID))
126011b9c3b1SVijay Khemka         {
126111b9c3b1SVijay Khemka             return ipmi::responseInvalidReservationId();
126211b9c3b1SVijay Khemka         }
126311b9c3b1SVijay Khemka     }
126411b9c3b1SVijay Khemka 
126511b9c3b1SVijay Khemka     uint16_t selCnt = selObj.getCount();
126611b9c3b1SVijay Khemka     if (selCnt == 0)
126711b9c3b1SVijay Khemka     {
126811b9c3b1SVijay Khemka         return ipmi::responseSensorInvalid();
126911b9c3b1SVijay Khemka     }
127011b9c3b1SVijay Khemka 
127111b9c3b1SVijay Khemka     /* If it is asked for first entry */
127211b9c3b1SVijay Khemka     if (reqData->recordID == fb_oem::ipmi::sel::firstEntry)
127311b9c3b1SVijay Khemka     {
127411b9c3b1SVijay Khemka         /* First Entry (0x0000) as per Spec */
127511b9c3b1SVijay Khemka         reqData->recordID = 1;
127611b9c3b1SVijay Khemka     }
127711b9c3b1SVijay Khemka     else if (reqData->recordID == fb_oem::ipmi::sel::lastEntry)
127811b9c3b1SVijay Khemka     {
127911b9c3b1SVijay Khemka         /* Last entry (0xFFFF) as per Spec */
128011b9c3b1SVijay Khemka         reqData->recordID = selCnt;
128111b9c3b1SVijay Khemka     }
128211b9c3b1SVijay Khemka 
128311b9c3b1SVijay Khemka     std::string ipmiRaw;
128411b9c3b1SVijay Khemka 
128511b9c3b1SVijay Khemka     if (selObj.getEntry(reqData->recordID, ipmiRaw) < 0)
128611b9c3b1SVijay Khemka     {
128711b9c3b1SVijay Khemka         return ipmi::responseSensorInvalid();
128811b9c3b1SVijay Khemka     }
128911b9c3b1SVijay Khemka 
129011b9c3b1SVijay Khemka     std::vector<uint8_t> recDataBytes;
129111b9c3b1SVijay Khemka     if (fromHexStr(ipmiRaw, recDataBytes) < 0)
129211b9c3b1SVijay Khemka     {
129311b9c3b1SVijay Khemka         return ipmi::responseUnspecifiedError();
129411b9c3b1SVijay Khemka     }
129511b9c3b1SVijay Khemka 
129611b9c3b1SVijay Khemka     /* Identify the next SEL record ID. If recordID is same as
129711b9c3b1SVijay Khemka      * total SeL count then next id should be last entry else
129811b9c3b1SVijay Khemka      * it should be incremented by 1 to current RecordID
129911b9c3b1SVijay Khemka      */
130011b9c3b1SVijay Khemka     uint16_t nextRecord;
130111b9c3b1SVijay Khemka     if (reqData->recordID == selCnt)
130211b9c3b1SVijay Khemka     {
130311b9c3b1SVijay Khemka         nextRecord = fb_oem::ipmi::sel::lastEntry;
130411b9c3b1SVijay Khemka     }
130511b9c3b1SVijay Khemka     else
130611b9c3b1SVijay Khemka     {
130711b9c3b1SVijay Khemka         nextRecord = reqData->recordID + 1;
130811b9c3b1SVijay Khemka     }
130911b9c3b1SVijay Khemka 
131011b9c3b1SVijay Khemka     if (reqData->readLen == fb_oem::ipmi::sel::entireRecord)
131111b9c3b1SVijay Khemka     {
131211b9c3b1SVijay Khemka         return ipmi::responseSuccess(nextRecord, recDataBytes);
131311b9c3b1SVijay Khemka     }
131411b9c3b1SVijay Khemka     else
131511b9c3b1SVijay Khemka     {
131611b9c3b1SVijay Khemka         if (reqData->offset >= fb_oem::ipmi::sel::selRecordSize ||
131711b9c3b1SVijay Khemka             reqData->readLen > fb_oem::ipmi::sel::selRecordSize)
131811b9c3b1SVijay Khemka         {
131911b9c3b1SVijay Khemka             return ipmi::responseUnspecifiedError();
132011b9c3b1SVijay Khemka         }
132111b9c3b1SVijay Khemka         std::vector<uint8_t> recPartData;
132211b9c3b1SVijay Khemka 
132311b9c3b1SVijay Khemka         auto diff = fb_oem::ipmi::sel::selRecordSize - reqData->offset;
132411b9c3b1SVijay Khemka         auto readLength = std::min(diff, static_cast<int>(reqData->readLen));
132511b9c3b1SVijay Khemka 
132611b9c3b1SVijay Khemka         for (int i = 0; i < readLength; i++)
132711b9c3b1SVijay Khemka         {
132811b9c3b1SVijay Khemka             recPartData.push_back(recDataBytes[i + reqData->offset]);
132911b9c3b1SVijay Khemka         }
133011b9c3b1SVijay Khemka         return ipmi::responseSuccess(nextRecord, recPartData);
133111b9c3b1SVijay Khemka     }
133211b9c3b1SVijay Khemka }
133311b9c3b1SVijay Khemka 
133411b9c3b1SVijay Khemka ipmi::RspType<uint16_t> ipmiStorageAddSELEntry(std::vector<uint8_t> data)
133511b9c3b1SVijay Khemka {
133611b9c3b1SVijay Khemka     /* Per the IPMI spec, need to cancel any reservation when a
133711b9c3b1SVijay Khemka      * SEL entry is added
133811b9c3b1SVijay Khemka      */
133911b9c3b1SVijay Khemka     cancelSELReservation();
134011b9c3b1SVijay Khemka 
134111b9c3b1SVijay Khemka     if (data.size() != fb_oem::ipmi::sel::selRecordSize)
134211b9c3b1SVijay Khemka     {
134311b9c3b1SVijay Khemka         return ipmi::responseReqDataLenInvalid();
134411b9c3b1SVijay Khemka     }
134511b9c3b1SVijay Khemka 
134611b9c3b1SVijay Khemka     std::string ipmiRaw, logErr;
134711b9c3b1SVijay Khemka     toHexStr(data, ipmiRaw);
134811b9c3b1SVijay Khemka 
1349f36f345fSVijay Khemka     /* Parse sel data and get an error log to be filed */
1350f36f345fSVijay Khemka     fb_oem::ipmi::sel::parseSelData(data, logErr);
1351f36f345fSVijay Khemka 
135211b9c3b1SVijay Khemka     /* Log the Raw SEL message to the journal */
135311b9c3b1SVijay Khemka     std::string journalMsg = "SEL Entry Added: " + ipmiRaw;
1354f36f345fSVijay Khemka 
135511b9c3b1SVijay Khemka     phosphor::logging::log<phosphor::logging::level::INFO>(journalMsg.c_str());
1356f36f345fSVijay Khemka     phosphor::logging::log<phosphor::logging::level::INFO>(logErr.c_str());
135711b9c3b1SVijay Khemka 
135811b9c3b1SVijay Khemka     int responseID = selObj.addEntry(ipmiRaw.c_str());
135911b9c3b1SVijay Khemka     if (responseID < 0)
136011b9c3b1SVijay Khemka     {
136111b9c3b1SVijay Khemka         return ipmi::responseUnspecifiedError();
136211b9c3b1SVijay Khemka     }
136311b9c3b1SVijay Khemka     return ipmi::responseSuccess((uint16_t)responseID);
136411b9c3b1SVijay Khemka }
136511b9c3b1SVijay Khemka 
1366c1921c63SVijay Khemka ipmi::RspType<uint8_t> ipmiStorageClearSEL(uint16_t reservationID,
1367c1921c63SVijay Khemka                                            const std::array<uint8_t, 3> &clr,
1368c1921c63SVijay Khemka                                            uint8_t eraseOperation)
1369c1921c63SVijay Khemka {
1370c1921c63SVijay Khemka     if (!checkSELReservation(reservationID))
1371c1921c63SVijay Khemka     {
1372c1921c63SVijay Khemka         return ipmi::responseInvalidReservationId();
1373c1921c63SVijay Khemka     }
1374c1921c63SVijay Khemka 
1375c1921c63SVijay Khemka     static constexpr std::array<uint8_t, 3> clrExpected = {'C', 'L', 'R'};
1376c1921c63SVijay Khemka     if (clr != clrExpected)
1377c1921c63SVijay Khemka     {
1378c1921c63SVijay Khemka         return ipmi::responseInvalidFieldRequest();
1379c1921c63SVijay Khemka     }
1380c1921c63SVijay Khemka 
1381c1921c63SVijay Khemka     /* If there is no sel then return erase complete */
1382c1921c63SVijay Khemka     if (selObj.getCount() == 0)
1383c1921c63SVijay Khemka     {
1384c1921c63SVijay Khemka         return ipmi::responseSuccess(fb_oem::ipmi::sel::eraseComplete);
1385c1921c63SVijay Khemka     }
1386c1921c63SVijay Khemka 
1387c1921c63SVijay Khemka     /* Erasure status cannot be fetched, so always return erasure
1388c1921c63SVijay Khemka      * status as `erase completed`.
1389c1921c63SVijay Khemka      */
1390c1921c63SVijay Khemka     if (eraseOperation == fb_oem::ipmi::sel::getEraseStatus)
1391c1921c63SVijay Khemka     {
1392c1921c63SVijay Khemka         return ipmi::responseSuccess(fb_oem::ipmi::sel::eraseComplete);
1393c1921c63SVijay Khemka     }
1394c1921c63SVijay Khemka 
1395c1921c63SVijay Khemka     /* Check that initiate erase is correct */
1396c1921c63SVijay Khemka     if (eraseOperation != fb_oem::ipmi::sel::initiateErase)
1397c1921c63SVijay Khemka     {
1398c1921c63SVijay Khemka         return ipmi::responseInvalidFieldRequest();
1399c1921c63SVijay Khemka     }
1400c1921c63SVijay Khemka 
1401c1921c63SVijay Khemka     /* Per the IPMI spec, need to cancel any reservation when the
1402c1921c63SVijay Khemka      * SEL is cleared
1403c1921c63SVijay Khemka      */
1404c1921c63SVijay Khemka     cancelSELReservation();
1405c1921c63SVijay Khemka 
1406c1921c63SVijay Khemka     /* Clear the complete Sel Json object */
1407c1921c63SVijay Khemka     if (selObj.clear() < 0)
1408c1921c63SVijay Khemka     {
1409c1921c63SVijay Khemka         return ipmi::responseUnspecifiedError();
1410c1921c63SVijay Khemka     }
1411c1921c63SVijay Khemka 
1412c1921c63SVijay Khemka     return ipmi::responseSuccess(fb_oem::ipmi::sel::eraseComplete);
1413c1921c63SVijay Khemka }
1414c1921c63SVijay Khemka 
1415c1921c63SVijay Khemka ipmi::RspType<uint32_t> ipmiStorageGetSELTime()
1416c1921c63SVijay Khemka {
1417c1921c63SVijay Khemka     struct timespec selTime = {};
1418c1921c63SVijay Khemka 
1419c1921c63SVijay Khemka     if (clock_gettime(CLOCK_REALTIME, &selTime) < 0)
1420c1921c63SVijay Khemka     {
1421c1921c63SVijay Khemka         return ipmi::responseUnspecifiedError();
1422c1921c63SVijay Khemka     }
1423c1921c63SVijay Khemka 
1424c1921c63SVijay Khemka     return ipmi::responseSuccess(selTime.tv_sec);
1425c1921c63SVijay Khemka }
1426c1921c63SVijay Khemka 
1427c1921c63SVijay Khemka ipmi::RspType<> ipmiStorageSetSELTime(uint32_t selTime)
1428c1921c63SVijay Khemka {
1429c1921c63SVijay Khemka     // Set SEL Time is not supported
1430c1921c63SVijay Khemka     return ipmi::responseInvalidCommand();
1431c1921c63SVijay Khemka }
1432c1921c63SVijay Khemka 
1433c1921c63SVijay Khemka ipmi::RspType<uint16_t> ipmiStorageGetSELTimeUtcOffset()
1434c1921c63SVijay Khemka {
1435c1921c63SVijay Khemka     /* TODO: For now, the SEL time stamp is based on UTC time,
1436c1921c63SVijay Khemka      * so return 0x0000 as offset. Might need to change once
1437c1921c63SVijay Khemka      * supporting zones in SEL time stamps
1438c1921c63SVijay Khemka      */
1439c1921c63SVijay Khemka 
1440c1921c63SVijay Khemka     uint16_t utcOffset = 0x0000;
1441c1921c63SVijay Khemka     return ipmi::responseSuccess(utcOffset);
1442c1921c63SVijay Khemka }
1443c1921c63SVijay Khemka 
144411b9c3b1SVijay Khemka void registerSELFunctions()
144511b9c3b1SVijay Khemka {
144611b9c3b1SVijay Khemka     // <Get SEL Info>
144711b9c3b1SVijay Khemka     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
144811b9c3b1SVijay Khemka                           ipmi::storage::cmdGetSelInfo, ipmi::Privilege::User,
144911b9c3b1SVijay Khemka                           ipmiStorageGetSELInfo);
145011b9c3b1SVijay Khemka 
145111b9c3b1SVijay Khemka     // <Get SEL Entry>
145211b9c3b1SVijay Khemka     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
145311b9c3b1SVijay Khemka                           ipmi::storage::cmdGetSelEntry, ipmi::Privilege::User,
145411b9c3b1SVijay Khemka                           ipmiStorageGetSELEntry);
145511b9c3b1SVijay Khemka 
145611b9c3b1SVijay Khemka     // <Add SEL Entry>
145711b9c3b1SVijay Khemka     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
145811b9c3b1SVijay Khemka                           ipmi::storage::cmdAddSelEntry,
145911b9c3b1SVijay Khemka                           ipmi::Privilege::Operator, ipmiStorageAddSELEntry);
146011b9c3b1SVijay Khemka 
1461c1921c63SVijay Khemka     // <Clear SEL>
1462c1921c63SVijay Khemka     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
1463c1921c63SVijay Khemka                           ipmi::storage::cmdClearSel, ipmi::Privilege::Operator,
1464c1921c63SVijay Khemka                           ipmiStorageClearSEL);
1465c1921c63SVijay Khemka 
1466c1921c63SVijay Khemka     // <Get SEL Time>
1467c1921c63SVijay Khemka     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
1468c1921c63SVijay Khemka                           ipmi::storage::cmdGetSelTime, ipmi::Privilege::User,
1469c1921c63SVijay Khemka                           ipmiStorageGetSELTime);
1470c1921c63SVijay Khemka 
1471c1921c63SVijay Khemka     // <Set SEL Time>
1472c1921c63SVijay Khemka     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
1473c1921c63SVijay Khemka                           ipmi::storage::cmdSetSelTime,
1474c1921c63SVijay Khemka                           ipmi::Privilege::Operator, ipmiStorageSetSELTime);
1475c1921c63SVijay Khemka 
1476c1921c63SVijay Khemka     // <Get SEL Time UTC Offset>
1477c1921c63SVijay Khemka     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
1478c1921c63SVijay Khemka                           ipmi::storage::cmdGetSelTimeUtcOffset,
1479c1921c63SVijay Khemka                           ipmi::Privilege::User,
1480c1921c63SVijay Khemka                           ipmiStorageGetSELTimeUtcOffset);
1481c1921c63SVijay Khemka 
148211b9c3b1SVijay Khemka     return;
148311b9c3b1SVijay Khemka }
148411b9c3b1SVijay Khemka 
148511b9c3b1SVijay Khemka } // namespace storage
148611b9c3b1SVijay Khemka } // namespace ipmi
1487