xref: /openbmc/fb-ipmi-oem/src/selcommands.cpp (revision 63c99be4ac026a326d6953d608376edb0e60007a)
111b9c3b1SVijay Khemka /*
211b9c3b1SVijay Khemka  * Copyright (c)  2018 Intel Corporation.
311b9c3b1SVijay Khemka  * Copyright (c)  2018-present Facebook.
411b9c3b1SVijay Khemka  *
511b9c3b1SVijay Khemka  * Licensed under the Apache License, Version 2.0 (the "License");
611b9c3b1SVijay Khemka  * you may not use this file except in compliance with the License.
711b9c3b1SVijay Khemka  * You may obtain a copy of the License at
811b9c3b1SVijay Khemka  *
911b9c3b1SVijay Khemka  *      http://www.apache.org/licenses/LICENSE-2.0
1011b9c3b1SVijay Khemka  *
1111b9c3b1SVijay Khemka  * Unless required by applicable law or agreed to in writing, software
1211b9c3b1SVijay Khemka  * distributed under the License is distributed on an "AS IS" BASIS,
1311b9c3b1SVijay Khemka  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1411b9c3b1SVijay Khemka  * See the License for the specific language governing permissions and
1511b9c3b1SVijay Khemka  * limitations under the License.
1611b9c3b1SVijay Khemka  */
1711b9c3b1SVijay Khemka 
1811b9c3b1SVijay Khemka #include <boost/algorithm/string/join.hpp>
19*63c99be4SVijay Khemka #include <ipmid/api.hpp>
2011b9c3b1SVijay Khemka #include <nlohmann/json.hpp>
2111b9c3b1SVijay Khemka #include <phosphor-logging/log.hpp>
2211b9c3b1SVijay Khemka #include <sdbusplus/message/types.hpp>
2311b9c3b1SVijay Khemka #include <sdbusplus/timer.hpp>
2411b9c3b1SVijay Khemka #include <storagecommands.hpp>
2511b9c3b1SVijay Khemka 
26*63c99be4SVijay Khemka #include <fstream>
27*63c99be4SVijay Khemka #include <iostream>
28*63c99be4SVijay Khemka #include <sstream>
29*63c99be4SVijay Khemka 
3011b9c3b1SVijay Khemka //----------------------------------------------------------------------
3111b9c3b1SVijay Khemka // Platform specific functions for storing app data
3211b9c3b1SVijay Khemka //----------------------------------------------------------------------
3311b9c3b1SVijay Khemka 
34139aa4f0SVijay Khemka static std::string byteToStr(uint8_t byte)
35139aa4f0SVijay Khemka {
36139aa4f0SVijay Khemka     std::stringstream ss;
37139aa4f0SVijay Khemka 
38139aa4f0SVijay Khemka     ss << std::hex << std::uppercase << std::setfill('0');
39139aa4f0SVijay Khemka     ss << std::setw(2) << (int)byte;
40139aa4f0SVijay Khemka 
41139aa4f0SVijay Khemka     return ss.str();
42139aa4f0SVijay Khemka }
43139aa4f0SVijay 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 
194139aa4f0SVijay Khemka /*
195139aa4f0SVijay Khemka  * A Function to parse common SEL message, a helper funciton
196139aa4f0SVijay Khemka  * for parseStdSel.
197139aa4f0SVijay Khemka  *
198139aa4f0SVijay Khemka  * Note that this function __CANNOT__ be overriden.
199139aa4f0SVijay Khemka  * To add board specific routine, please override parseStdSel.
200139aa4f0SVijay Khemka  */
201139aa4f0SVijay Khemka 
202139aa4f0SVijay Khemka /*Used by decoding ME event*/
203139aa4f0SVijay Khemka std::vector<std::string> nmDomName = {
204139aa4f0SVijay Khemka     "Entire Platform",          "CPU Subsystem",
205139aa4f0SVijay Khemka     "Memory Subsystem",         "HW Protection",
206139aa4f0SVijay Khemka     "High Power I/O subsystem", "Unknown"};
207139aa4f0SVijay Khemka 
208139aa4f0SVijay Khemka /* Default log message for unknown type */
209139aa4f0SVijay Khemka static void logDefault(uint8_t* data, std::string& errLog)
210139aa4f0SVijay Khemka {
211139aa4f0SVijay Khemka     errLog = "Unknown";
212139aa4f0SVijay Khemka }
213139aa4f0SVijay Khemka 
214139aa4f0SVijay Khemka static void logSysEvent(uint8_t* data, std::string& errLog)
215139aa4f0SVijay Khemka {
216139aa4f0SVijay Khemka     if (data[0] == 0xE5)
217139aa4f0SVijay Khemka     {
218139aa4f0SVijay Khemka         errLog = "Cause of Time change - ";
219139aa4f0SVijay Khemka         switch (data[2])
220139aa4f0SVijay Khemka         {
221139aa4f0SVijay Khemka             case 0x00:
222139aa4f0SVijay Khemka                 errLog += "NTP";
223139aa4f0SVijay Khemka                 break;
224139aa4f0SVijay Khemka             case 0x01:
225139aa4f0SVijay Khemka                 errLog += "Host RTL";
226139aa4f0SVijay Khemka                 break;
227139aa4f0SVijay Khemka             case 0x02:
228139aa4f0SVijay Khemka                 errLog += "Set SEL time cmd";
229139aa4f0SVijay Khemka                 break;
230139aa4f0SVijay Khemka             case 0x03:
231139aa4f0SVijay Khemka                 errLog += "Set SEL time UTC offset cmd";
232139aa4f0SVijay Khemka                 break;
233139aa4f0SVijay Khemka             default:
234139aa4f0SVijay Khemka                 errLog += "Unknown";
235139aa4f0SVijay Khemka         }
236139aa4f0SVijay Khemka 
237139aa4f0SVijay Khemka         if (data[1] == 0x00)
238139aa4f0SVijay Khemka             errLog += " - First Time";
239139aa4f0SVijay Khemka         else if (data[1] == 0x80)
240139aa4f0SVijay Khemka             errLog += " - Second Time";
241139aa4f0SVijay Khemka     }
242139aa4f0SVijay Khemka     else
243139aa4f0SVijay Khemka     {
244139aa4f0SVijay Khemka         errLog = "Unknown";
245139aa4f0SVijay Khemka     }
246139aa4f0SVijay Khemka }
247139aa4f0SVijay Khemka 
248139aa4f0SVijay Khemka static void logThermalEvent(uint8_t* data, std::string& errLog)
249139aa4f0SVijay Khemka {
250139aa4f0SVijay Khemka     if (data[0] == 0x1)
251139aa4f0SVijay Khemka     {
252139aa4f0SVijay Khemka         errLog = "Limit Exceeded";
253139aa4f0SVijay Khemka     }
254139aa4f0SVijay Khemka     else
255139aa4f0SVijay Khemka     {
256139aa4f0SVijay Khemka         errLog = "Unknown";
257139aa4f0SVijay Khemka     }
258139aa4f0SVijay Khemka }
259139aa4f0SVijay Khemka 
260139aa4f0SVijay Khemka static void logCritIrq(uint8_t* data, std::string& errLog)
261139aa4f0SVijay Khemka {
262139aa4f0SVijay Khemka 
263139aa4f0SVijay Khemka     if (data[0] == 0x0)
264139aa4f0SVijay Khemka     {
265139aa4f0SVijay Khemka         errLog = "NMI / Diagnostic Interrupt";
266139aa4f0SVijay Khemka     }
267139aa4f0SVijay Khemka     else if (data[0] == 0x03)
268139aa4f0SVijay Khemka     {
269139aa4f0SVijay Khemka         errLog = "Software NMI";
270139aa4f0SVijay Khemka     }
271139aa4f0SVijay Khemka     else
272139aa4f0SVijay Khemka     {
273139aa4f0SVijay Khemka         errLog = "Unknown";
274139aa4f0SVijay Khemka     }
275139aa4f0SVijay Khemka 
276139aa4f0SVijay Khemka     /* TODO: Call add_cri_sel for CRITICAL_IRQ */
277139aa4f0SVijay Khemka }
278139aa4f0SVijay Khemka 
279139aa4f0SVijay Khemka static void logPostErr(uint8_t* data, std::string& errLog)
280139aa4f0SVijay Khemka {
281139aa4f0SVijay Khemka 
282139aa4f0SVijay Khemka     if ((data[0] & 0x0F) == 0x0)
283139aa4f0SVijay Khemka     {
284139aa4f0SVijay Khemka         errLog = "System Firmware Error";
285139aa4f0SVijay Khemka     }
286139aa4f0SVijay Khemka     else
287139aa4f0SVijay Khemka     {
288139aa4f0SVijay Khemka         errLog = "Unknown";
289139aa4f0SVijay Khemka     }
290139aa4f0SVijay Khemka 
291139aa4f0SVijay Khemka     if (((data[0] >> 6) & 0x03) == 0x3)
292139aa4f0SVijay Khemka     {
293139aa4f0SVijay Khemka         // TODO: Need to implement IPMI spec based Post Code
294139aa4f0SVijay Khemka         errLog += ", IPMI Post Code";
295139aa4f0SVijay Khemka     }
296139aa4f0SVijay Khemka     else if (((data[0] >> 6) & 0x03) == 0x2)
297139aa4f0SVijay Khemka     {
298139aa4f0SVijay Khemka         errLog +=
299139aa4f0SVijay Khemka             ", OEM Post Code 0x" + byteToStr(data[2]) + byteToStr(data[1]);
300139aa4f0SVijay Khemka 
301139aa4f0SVijay Khemka         switch ((data[2] << 8) | data[1])
302139aa4f0SVijay Khemka         {
303139aa4f0SVijay Khemka             case 0xA105:
304139aa4f0SVijay Khemka                 errLog += ", BMC Failed (No Response)";
305139aa4f0SVijay Khemka                 break;
306139aa4f0SVijay Khemka             case 0xA106:
307139aa4f0SVijay Khemka                 errLog += ", BMC Failed (Self Test Fail)";
308139aa4f0SVijay Khemka                 break;
309139aa4f0SVijay Khemka             case 0xA10A:
310139aa4f0SVijay Khemka                 errLog += ", System Firmware Corruption Detected";
311139aa4f0SVijay Khemka                 break;
312139aa4f0SVijay Khemka             case 0xA10B:
313139aa4f0SVijay Khemka                 errLog += ", TPM Self-Test FAIL Detected";
314139aa4f0SVijay Khemka         }
315139aa4f0SVijay Khemka     }
316139aa4f0SVijay Khemka }
317139aa4f0SVijay Khemka 
318139aa4f0SVijay Khemka static void logMchChkErr(uint8_t* data, std::string& errLog)
319139aa4f0SVijay Khemka {
320139aa4f0SVijay Khemka     /* TODO: Call add_cri_sel for CRITICAL_IRQ */
321139aa4f0SVijay Khemka     if ((data[0] & 0x0F) == 0x0B)
322139aa4f0SVijay Khemka     {
323139aa4f0SVijay Khemka         errLog = "Uncorrectable";
324139aa4f0SVijay Khemka     }
325139aa4f0SVijay Khemka     else if ((data[0] & 0x0F) == 0x0C)
326139aa4f0SVijay Khemka     {
327139aa4f0SVijay Khemka         errLog = "Correctable";
328139aa4f0SVijay Khemka     }
329139aa4f0SVijay Khemka     else
330139aa4f0SVijay Khemka     {
331139aa4f0SVijay Khemka         errLog = "Unknown";
332139aa4f0SVijay Khemka     }
333139aa4f0SVijay Khemka 
334139aa4f0SVijay Khemka     errLog += ", Machine Check bank Number " + std::to_string(data[1]) +
335139aa4f0SVijay Khemka               ", CPU " + std::to_string(data[2] >> 5) + ", Core " +
336139aa4f0SVijay Khemka               std::to_string(data[2] & 0x1F);
337139aa4f0SVijay Khemka }
338139aa4f0SVijay Khemka 
339139aa4f0SVijay Khemka static void logPcieErr(uint8_t* data, std::string& errLog)
340139aa4f0SVijay Khemka {
341139aa4f0SVijay Khemka     std::stringstream tmp1, tmp2;
342139aa4f0SVijay Khemka     tmp1 << std::hex << std::uppercase << std::setfill('0');
343139aa4f0SVijay Khemka     tmp2 << std::hex << std::uppercase << std::setfill('0');
344139aa4f0SVijay Khemka     tmp1 << " (Bus " << std::setw(2) << (int)(data[2]) << " / Dev "
345139aa4f0SVijay Khemka          << std::setw(2) << (int)(data[1] >> 3) << " / Fun " << std::setw(2)
346139aa4f0SVijay Khemka          << (int)(data[1] & 0x7) << ")";
347139aa4f0SVijay Khemka 
348139aa4f0SVijay Khemka     switch (data[0] & 0xF)
349139aa4f0SVijay Khemka     {
350139aa4f0SVijay Khemka         case 0x4:
351139aa4f0SVijay Khemka             errLog = "PCI PERR" + tmp1.str();
352139aa4f0SVijay Khemka             break;
353139aa4f0SVijay Khemka         case 0x5:
354139aa4f0SVijay Khemka             errLog = "PCI SERR" + tmp1.str();
355139aa4f0SVijay Khemka             break;
356139aa4f0SVijay Khemka         case 0x7:
357139aa4f0SVijay Khemka             errLog = "Correctable" + tmp1.str();
358139aa4f0SVijay Khemka             break;
359139aa4f0SVijay Khemka         case 0x8:
360139aa4f0SVijay Khemka             errLog = "Uncorrectable" + tmp1.str();
361139aa4f0SVijay Khemka             break;
362139aa4f0SVijay Khemka         case 0xA:
363139aa4f0SVijay Khemka             errLog = "Bus Fatal" + tmp1.str();
364139aa4f0SVijay Khemka             break;
365*63c99be4SVijay Khemka         case 0xD: {
366139aa4f0SVijay Khemka             uint32_t venId = (uint32_t)data[1] << 8 | (uint32_t)data[2];
367139aa4f0SVijay Khemka             tmp2 << "Vendor ID: 0x" << std::setw(4) << venId;
368139aa4f0SVijay Khemka             errLog = tmp2.str();
369139aa4f0SVijay Khemka         }
370139aa4f0SVijay Khemka         break;
371*63c99be4SVijay Khemka         case 0xE: {
372139aa4f0SVijay Khemka             uint32_t devId = (uint32_t)data[1] << 8 | (uint32_t)data[2];
373139aa4f0SVijay Khemka             tmp2 << "Device ID: 0x" << std::setw(4) << devId;
374139aa4f0SVijay Khemka             errLog = tmp2.str();
375139aa4f0SVijay Khemka         }
376139aa4f0SVijay Khemka         break;
377139aa4f0SVijay Khemka         case 0xF:
378139aa4f0SVijay Khemka             tmp2 << "Error ID from downstream: 0x" << std::setw(2)
379139aa4f0SVijay Khemka                  << (int)(data[1]) << std::setw(2) << (int)(data[2]);
380139aa4f0SVijay Khemka             errLog = tmp2.str();
381139aa4f0SVijay Khemka             break;
382139aa4f0SVijay Khemka         default:
383139aa4f0SVijay Khemka             errLog = "Unknown";
384139aa4f0SVijay Khemka     }
385139aa4f0SVijay Khemka }
386139aa4f0SVijay Khemka 
387139aa4f0SVijay Khemka static void logIioErr(uint8_t* data, std::string& errLog)
388139aa4f0SVijay Khemka {
389139aa4f0SVijay Khemka     std::vector<std::string> tmpStr = {
390139aa4f0SVijay Khemka         "IRP0", "IRP1", " IIO-Core", "VT-d", "Intel Quick Data",
391139aa4f0SVijay Khemka         "Misc", " DMA", "ITC",       "OTC",  "CI"};
392139aa4f0SVijay Khemka 
393139aa4f0SVijay Khemka     if ((data[0] & 0xF) == 0)
394139aa4f0SVijay Khemka     {
395139aa4f0SVijay Khemka         errLog += "CPU " + std::to_string(data[2] >> 5) + ", Error ID 0x" +
396139aa4f0SVijay Khemka                   byteToStr(data[1]) + " - ";
397139aa4f0SVijay Khemka 
398139aa4f0SVijay Khemka         if ((data[2] & 0xF) <= 0x9)
399139aa4f0SVijay Khemka         {
400139aa4f0SVijay Khemka             errLog += tmpStr[(data[2] & 0xF)];
401139aa4f0SVijay Khemka         }
402139aa4f0SVijay Khemka         else
403139aa4f0SVijay Khemka         {
404139aa4f0SVijay Khemka             errLog += "Reserved";
405139aa4f0SVijay Khemka         }
406139aa4f0SVijay Khemka     }
407139aa4f0SVijay Khemka     else
408139aa4f0SVijay Khemka     {
409139aa4f0SVijay Khemka         errLog = "Unknown";
410139aa4f0SVijay Khemka     }
411139aa4f0SVijay Khemka }
412139aa4f0SVijay Khemka 
413139aa4f0SVijay Khemka static void logMemErr(uint8_t* dataPtr, std::string& errLog)
414139aa4f0SVijay Khemka {
415139aa4f0SVijay Khemka     uint8_t snrType = dataPtr[0];
416139aa4f0SVijay Khemka     uint8_t snrNum = dataPtr[1];
417139aa4f0SVijay Khemka     uint8_t* data = &(dataPtr[3]);
418139aa4f0SVijay Khemka 
419139aa4f0SVijay Khemka     /* TODO: add pal_add_cri_sel */
420139aa4f0SVijay Khemka 
421139aa4f0SVijay Khemka     if (snrNum == memoryEccError)
422139aa4f0SVijay Khemka     {
423139aa4f0SVijay Khemka         /* SEL from MEMORY_ECC_ERR Sensor */
424139aa4f0SVijay Khemka         switch (data[0] & 0x0F)
425139aa4f0SVijay Khemka         {
426139aa4f0SVijay Khemka             case 0x0:
427139aa4f0SVijay Khemka                 if (snrType == 0x0C)
428139aa4f0SVijay Khemka                 {
429139aa4f0SVijay Khemka                     errLog = "Correctable";
430139aa4f0SVijay Khemka                 }
431139aa4f0SVijay Khemka                 else if (snrType == 0x10)
432139aa4f0SVijay Khemka                 {
433139aa4f0SVijay Khemka                     errLog = "Correctable ECC error Logging Disabled";
434139aa4f0SVijay Khemka                 }
435139aa4f0SVijay Khemka                 break;
436139aa4f0SVijay Khemka             case 0x1:
437139aa4f0SVijay Khemka                 errLog = "Uncorrectable";
438139aa4f0SVijay Khemka                 break;
439139aa4f0SVijay Khemka             case 0x5:
440139aa4f0SVijay Khemka                 errLog = "Correctable ECC error Logging Limit Disabled";
441139aa4f0SVijay Khemka                 break;
442139aa4f0SVijay Khemka             default:
443139aa4f0SVijay Khemka                 errLog = "Unknown";
444139aa4f0SVijay Khemka         }
445139aa4f0SVijay Khemka     }
446139aa4f0SVijay Khemka     else if (snrNum == memoryErrLogDIS)
447139aa4f0SVijay Khemka     {
448139aa4f0SVijay Khemka         // SEL from MEMORY_ERR_LOG_DIS Sensor
449139aa4f0SVijay Khemka         if ((data[0] & 0x0F) == 0x0)
450139aa4f0SVijay Khemka         {
451139aa4f0SVijay Khemka             errLog = "Correctable Memory Error Logging Disabled";
452139aa4f0SVijay Khemka         }
453139aa4f0SVijay Khemka         else
454139aa4f0SVijay Khemka         {
455139aa4f0SVijay Khemka             errLog = "Unknown";
456139aa4f0SVijay Khemka         }
457139aa4f0SVijay Khemka     }
458139aa4f0SVijay Khemka     else
459139aa4f0SVijay Khemka     {
460139aa4f0SVijay Khemka         errLog = "Unknown";
461139aa4f0SVijay Khemka         return;
462139aa4f0SVijay Khemka     }
463139aa4f0SVijay Khemka 
464139aa4f0SVijay Khemka     /* Common routine for both MEM_ECC_ERR and MEMORY_ERR_LOG_DIS */
465139aa4f0SVijay Khemka 
466139aa4f0SVijay Khemka     errLog += " (DIMM " + byteToStr(data[2]) + ") Logical Rank " +
467139aa4f0SVijay Khemka               std::to_string(data[1] & 0x03);
468139aa4f0SVijay Khemka 
469139aa4f0SVijay Khemka     /* DIMM number (data[2]):
470139aa4f0SVijay Khemka      * Bit[7:5]: Socket number  (Range: 0-7)
471139aa4f0SVijay Khemka      * Bit[4:3]: Channel number (Range: 0-3)
472139aa4f0SVijay Khemka      * Bit[2:0]: DIMM number    (Range: 0-7)
473139aa4f0SVijay Khemka      */
474139aa4f0SVijay Khemka 
475139aa4f0SVijay Khemka     /* TODO: Verify these bits */
476139aa4f0SVijay Khemka     std::string cpuStr = "CPU# " + std::to_string((data[2] & 0xE0) >> 5);
477139aa4f0SVijay Khemka     std::string chStr = "CHN# " + std::to_string((data[2] & 0x18) >> 3);
478139aa4f0SVijay Khemka     std::string dimmStr = "DIMM# " + std::to_string(data[2] & 0x7);
479139aa4f0SVijay Khemka 
480139aa4f0SVijay Khemka     switch ((data[1] & 0xC) >> 2)
481139aa4f0SVijay Khemka     {
482*63c99be4SVijay Khemka         case 0x0: {
483139aa4f0SVijay Khemka 
484139aa4f0SVijay Khemka             /* All Info Valid */
485139aa4f0SVijay Khemka             uint8_t chnNum = (data[2] & 0x1C) >> 2;
486139aa4f0SVijay Khemka             uint8_t dimmNum = data[2] & 0x3;
487139aa4f0SVijay Khemka 
488139aa4f0SVijay Khemka             /* TODO: If critical SEL logging is available, do it */
489139aa4f0SVijay Khemka             if (snrType == 0x0C)
490139aa4f0SVijay Khemka             {
491139aa4f0SVijay Khemka                 if ((data[0] & 0x0F) == 0x0)
492139aa4f0SVijay Khemka                 {
493139aa4f0SVijay Khemka                     /* TODO: add_cri_sel */
494139aa4f0SVijay Khemka                     /* "DIMM"+ 'A'+ chnNum + dimmNum + " ECC err,FRU:1"
495139aa4f0SVijay Khemka                      */
496139aa4f0SVijay Khemka                 }
497139aa4f0SVijay Khemka                 else if ((data[0] & 0x0F) == 0x1)
498139aa4f0SVijay Khemka                 {
499139aa4f0SVijay Khemka                     /* TODO: add_cri_sel */
500139aa4f0SVijay Khemka                     /* "DIMM"+ 'A'+ chnNum + dimmNum + " UECC err,FRU:1"
501139aa4f0SVijay Khemka                      */
502139aa4f0SVijay Khemka                 }
503139aa4f0SVijay Khemka             }
504139aa4f0SVijay Khemka             /* Continue to parse the error into a string. All Info Valid
505139aa4f0SVijay Khemka              */
506139aa4f0SVijay Khemka             errLog += " (" + cpuStr + ", " + chStr + ", " + dimmStr + ")";
507139aa4f0SVijay Khemka         }
508139aa4f0SVijay Khemka 
509139aa4f0SVijay Khemka         break;
510139aa4f0SVijay Khemka         case 0x1:
511139aa4f0SVijay Khemka 
512139aa4f0SVijay Khemka             /* DIMM info not valid */
513139aa4f0SVijay Khemka             errLog += " (" + cpuStr + ", " + chStr + ")";
514139aa4f0SVijay Khemka             break;
515139aa4f0SVijay Khemka         case 0x2:
516139aa4f0SVijay Khemka 
517139aa4f0SVijay Khemka             /* CHN info not valid */
518139aa4f0SVijay Khemka             errLog += " (" + cpuStr + ", " + dimmStr + ")";
519139aa4f0SVijay Khemka             break;
520139aa4f0SVijay Khemka         case 0x3:
521139aa4f0SVijay Khemka 
522139aa4f0SVijay Khemka             /* CPU info not valid */
523139aa4f0SVijay Khemka             errLog += " (" + chStr + ", " + dimmStr + ")";
524139aa4f0SVijay Khemka             break;
525139aa4f0SVijay Khemka     }
526139aa4f0SVijay Khemka }
527139aa4f0SVijay Khemka 
528139aa4f0SVijay Khemka static void logPwrErr(uint8_t* data, std::string& errLog)
529139aa4f0SVijay Khemka {
530139aa4f0SVijay Khemka 
531139aa4f0SVijay Khemka     if (data[0] == 0x1)
532139aa4f0SVijay Khemka     {
533139aa4f0SVijay Khemka         errLog = "SYS_PWROK failure";
534139aa4f0SVijay Khemka         /* Also try logging to Critial log file, if available */
535139aa4f0SVijay Khemka         /* "SYS_PWROK failure,FRU:1" */
536139aa4f0SVijay Khemka     }
537139aa4f0SVijay Khemka     else if (data[0] == 0x2)
538139aa4f0SVijay Khemka     {
539139aa4f0SVijay Khemka         errLog = "PCH_PWROK failure";
540139aa4f0SVijay Khemka         /* Also try logging to Critial log file, if available */
541139aa4f0SVijay Khemka         /* "PCH_PWROK failure,FRU:1" */
542139aa4f0SVijay Khemka     }
543139aa4f0SVijay Khemka     else
544139aa4f0SVijay Khemka     {
545139aa4f0SVijay Khemka         errLog = "Unknown";
546139aa4f0SVijay Khemka     }
547139aa4f0SVijay Khemka }
548139aa4f0SVijay Khemka 
549139aa4f0SVijay Khemka static void logCatErr(uint8_t* data, std::string& errLog)
550139aa4f0SVijay Khemka {
551139aa4f0SVijay Khemka 
552139aa4f0SVijay Khemka     if (data[0] == 0x0)
553139aa4f0SVijay Khemka     {
554139aa4f0SVijay Khemka         errLog = "IERR/CATERR";
555139aa4f0SVijay Khemka         /* Also try logging to Critial log file, if available */
556139aa4f0SVijay Khemka         /* "IERR,FRU:1 */
557139aa4f0SVijay Khemka     }
558139aa4f0SVijay Khemka     else if (data[0] == 0xB)
559139aa4f0SVijay Khemka     {
560139aa4f0SVijay Khemka         errLog = "MCERR/CATERR";
561139aa4f0SVijay Khemka         /* Also try logging to Critial log file, if available */
562139aa4f0SVijay Khemka         /* "MCERR,FRU:1 */
563139aa4f0SVijay Khemka     }
564139aa4f0SVijay Khemka     else
565139aa4f0SVijay Khemka     {
566139aa4f0SVijay Khemka         errLog = "Unknown";
567139aa4f0SVijay Khemka     }
568139aa4f0SVijay Khemka }
569139aa4f0SVijay Khemka 
570139aa4f0SVijay Khemka static void logDimmHot(uint8_t* data, std::string& errLog)
571139aa4f0SVijay Khemka {
572139aa4f0SVijay Khemka     if ((data[0] << 16 | data[1] << 8 | data[2]) == 0x01FFFF)
573139aa4f0SVijay Khemka     {
574139aa4f0SVijay Khemka         errLog = "SOC MEMHOT";
575139aa4f0SVijay Khemka     }
576139aa4f0SVijay Khemka     else
577139aa4f0SVijay Khemka     {
578139aa4f0SVijay Khemka         errLog = "Unknown";
579139aa4f0SVijay Khemka         /* Also try logging to Critial log file, if available */
580139aa4f0SVijay Khemka         /* ""CPU_DIMM_HOT %s,FRU:1" */
581139aa4f0SVijay Khemka     }
582139aa4f0SVijay Khemka }
583139aa4f0SVijay Khemka 
584139aa4f0SVijay Khemka static void logSwNMI(uint8_t* data, std::string& errLog)
585139aa4f0SVijay Khemka {
586139aa4f0SVijay Khemka     if ((data[0] << 16 | data[1] << 8 | data[2]) == 0x03FFFF)
587139aa4f0SVijay Khemka     {
588139aa4f0SVijay Khemka         errLog = "Software NMI";
589139aa4f0SVijay Khemka     }
590139aa4f0SVijay Khemka     else
591139aa4f0SVijay Khemka     {
592139aa4f0SVijay Khemka         errLog = "Unknown SW NMI";
593139aa4f0SVijay Khemka     }
594139aa4f0SVijay Khemka }
595139aa4f0SVijay Khemka 
596139aa4f0SVijay Khemka static void logCPUThermalSts(uint8_t* data, std::string& errLog)
597139aa4f0SVijay Khemka {
598139aa4f0SVijay Khemka     switch (data[0])
599139aa4f0SVijay Khemka     {
600139aa4f0SVijay Khemka         case 0x0:
601139aa4f0SVijay Khemka             errLog = "CPU Critical Temperature";
602139aa4f0SVijay Khemka             break;
603139aa4f0SVijay Khemka         case 0x1:
604139aa4f0SVijay Khemka             errLog = "PROCHOT#";
605139aa4f0SVijay Khemka             break;
606139aa4f0SVijay Khemka         case 0x2:
607139aa4f0SVijay Khemka             errLog = "TCC Activation";
608139aa4f0SVijay Khemka             break;
609139aa4f0SVijay Khemka         default:
610139aa4f0SVijay Khemka             errLog = "Unknown";
611139aa4f0SVijay Khemka     }
612139aa4f0SVijay Khemka }
613139aa4f0SVijay Khemka 
614139aa4f0SVijay Khemka static void logMEPwrState(uint8_t* data, std::string& errLog)
615139aa4f0SVijay Khemka {
616139aa4f0SVijay Khemka     switch (data[0])
617139aa4f0SVijay Khemka     {
618139aa4f0SVijay Khemka         case 0:
619139aa4f0SVijay Khemka             errLog = "RUNNING";
620139aa4f0SVijay Khemka             break;
621139aa4f0SVijay Khemka         case 2:
622139aa4f0SVijay Khemka             errLog = "POWER_OFF";
623139aa4f0SVijay Khemka             break;
624139aa4f0SVijay Khemka         default:
625139aa4f0SVijay Khemka             errLog = "Unknown[" + std::to_string(data[0]) + "]";
626139aa4f0SVijay Khemka             break;
627139aa4f0SVijay Khemka     }
628139aa4f0SVijay Khemka }
629139aa4f0SVijay Khemka 
630139aa4f0SVijay Khemka static void logSPSFwHealth(uint8_t* data, std::string& errLog)
631139aa4f0SVijay Khemka {
632139aa4f0SVijay Khemka     if ((data[0] & 0x0F) == 0x00)
633139aa4f0SVijay Khemka     {
634139aa4f0SVijay Khemka         const std::vector<std::string> tmpStr = {
635139aa4f0SVijay Khemka             "Recovery GPIO forced",
636139aa4f0SVijay Khemka             "Image execution failed",
637139aa4f0SVijay Khemka             "Flash erase error",
638139aa4f0SVijay Khemka             "Flash state information",
639139aa4f0SVijay Khemka             "Internal error",
640139aa4f0SVijay Khemka             "BMC did not respond",
641139aa4f0SVijay Khemka             "Direct Flash update",
642139aa4f0SVijay Khemka             "Manufacturing error",
643139aa4f0SVijay Khemka             "Automatic Restore to Factory Presets",
644139aa4f0SVijay Khemka             "Firmware Exception",
645139aa4f0SVijay Khemka             "Flash Wear-Out Protection Warning",
646139aa4f0SVijay Khemka             "Unknown",
647139aa4f0SVijay Khemka             "Unknown",
648139aa4f0SVijay Khemka             "DMI interface error",
649139aa4f0SVijay Khemka             "MCTP interface error",
650139aa4f0SVijay Khemka             "Auto-configuration finished",
651139aa4f0SVijay Khemka             "Unsupported Segment Defined Feature",
652139aa4f0SVijay Khemka             "Unknown",
653139aa4f0SVijay Khemka             "CPU Debug Capability Disabled",
654139aa4f0SVijay Khemka             "UMA operation error"};
655139aa4f0SVijay Khemka 
656139aa4f0SVijay Khemka         if (data[1] < 0x14)
657139aa4f0SVijay Khemka         {
658139aa4f0SVijay Khemka             errLog = tmpStr[data[1]];
659139aa4f0SVijay Khemka         }
660139aa4f0SVijay Khemka         else
661139aa4f0SVijay Khemka         {
662139aa4f0SVijay Khemka             errLog = "Unknown";
663139aa4f0SVijay Khemka         }
664139aa4f0SVijay Khemka     }
665139aa4f0SVijay Khemka     else if ((data[0] & 0x0F) == 0x01)
666139aa4f0SVijay Khemka     {
667139aa4f0SVijay Khemka         errLog = "SMBus link failure";
668139aa4f0SVijay Khemka     }
669139aa4f0SVijay Khemka     else
670139aa4f0SVijay Khemka     {
671139aa4f0SVijay Khemka         errLog = "Unknown";
672139aa4f0SVijay Khemka     }
673139aa4f0SVijay Khemka }
674139aa4f0SVijay Khemka 
675139aa4f0SVijay Khemka static void logNmExcA(uint8_t* data, std::string& errLog)
676139aa4f0SVijay Khemka {
677139aa4f0SVijay Khemka     /*NM4.0 #550710, Revision 1.95, and turn to p.155*/
678139aa4f0SVijay Khemka     if (data[0] == 0xA8)
679139aa4f0SVijay Khemka     {
680139aa4f0SVijay Khemka         errLog = "Policy Correction Time Exceeded";
681139aa4f0SVijay Khemka     }
682139aa4f0SVijay Khemka     else
683139aa4f0SVijay Khemka     {
684139aa4f0SVijay Khemka         errLog = "Unknown";
685139aa4f0SVijay Khemka     }
686139aa4f0SVijay Khemka }
687139aa4f0SVijay Khemka 
688139aa4f0SVijay Khemka static void logPCHThermal(uint8_t* data, std::string& errLog)
689139aa4f0SVijay Khemka {
690139aa4f0SVijay Khemka     const std::vector<std::string> thresEvtName = {"Lower Non-critical",
691139aa4f0SVijay Khemka                                                    "Unknown",
692139aa4f0SVijay Khemka                                                    "Lower Critical",
693139aa4f0SVijay Khemka                                                    "Unknown",
694139aa4f0SVijay Khemka                                                    "Lower Non-recoverable",
695139aa4f0SVijay Khemka                                                    "Unknown",
696139aa4f0SVijay Khemka                                                    "Unknown",
697139aa4f0SVijay Khemka                                                    "Upper Non-critical",
698139aa4f0SVijay Khemka                                                    "Unknown",
699139aa4f0SVijay Khemka                                                    "Upper Critical",
700139aa4f0SVijay Khemka                                                    "Unknown",
701139aa4f0SVijay Khemka                                                    "Upper Non-recoverable"};
702139aa4f0SVijay Khemka 
703139aa4f0SVijay Khemka     if ((data[0] & 0x0f) < 12)
704139aa4f0SVijay Khemka     {
705139aa4f0SVijay Khemka         errLog = thresEvtName[(data[0] & 0x0f)];
706139aa4f0SVijay Khemka     }
707139aa4f0SVijay Khemka     else
708139aa4f0SVijay Khemka     {
709139aa4f0SVijay Khemka         errLog = "Unknown";
710139aa4f0SVijay Khemka     }
711139aa4f0SVijay Khemka 
712139aa4f0SVijay Khemka     errLog += ", curr_val: " + std::to_string(data[1]) +
713139aa4f0SVijay Khemka               " C, thresh_val: " + std::to_string(data[2]) + " C";
714139aa4f0SVijay Khemka }
715139aa4f0SVijay Khemka 
716139aa4f0SVijay Khemka static void logNmHealth(uint8_t* data, std::string& errLog)
717139aa4f0SVijay Khemka {
718139aa4f0SVijay Khemka     std::vector<std::string> nmErrType = {
719139aa4f0SVijay Khemka         "Unknown",
720139aa4f0SVijay Khemka         "Unknown",
721139aa4f0SVijay Khemka         "Unknown",
722139aa4f0SVijay Khemka         "Unknown",
723139aa4f0SVijay Khemka         "Unknown",
724139aa4f0SVijay Khemka         "Unknown",
725139aa4f0SVijay Khemka         "Unknown",
726139aa4f0SVijay Khemka         "Extended Telemetry Device Reading Failure",
727139aa4f0SVijay Khemka         "Outlet Temperature Reading Failure",
728139aa4f0SVijay Khemka         "Volumetric Airflow Reading Failure",
729139aa4f0SVijay Khemka         "Policy Misconfiguration",
730139aa4f0SVijay Khemka         "Power Sensor Reading Failure",
731139aa4f0SVijay Khemka         "Inlet Temperature Reading Failure",
732139aa4f0SVijay Khemka         "Host Communication Error",
733139aa4f0SVijay Khemka         "Real-time Clock Synchronization Failure",
734139aa4f0SVijay Khemka         "Platform Shutdown Initiated by Intel NM Policy",
735139aa4f0SVijay Khemka         "Unknown"};
736139aa4f0SVijay Khemka     uint8_t nmTypeIdx = (data[0] & 0xf);
737139aa4f0SVijay Khemka     uint8_t domIdx = (data[1] & 0xf);
738139aa4f0SVijay Khemka     uint8_t errIdx = ((data[1] >> 4) & 0xf);
739139aa4f0SVijay Khemka 
740139aa4f0SVijay Khemka     if (nmTypeIdx == 2)
741139aa4f0SVijay Khemka     {
742139aa4f0SVijay Khemka         errLog = "SensorIntelNM";
743139aa4f0SVijay Khemka     }
744139aa4f0SVijay Khemka     else
745139aa4f0SVijay Khemka     {
746139aa4f0SVijay Khemka         errLog = "Unknown";
747139aa4f0SVijay Khemka     }
748139aa4f0SVijay Khemka 
749139aa4f0SVijay Khemka     errLog += ", Domain:" + nmDomName[domIdx] +
750139aa4f0SVijay Khemka               ", ErrType:" + nmErrType[errIdx] + ", Err:0x" +
751139aa4f0SVijay Khemka               byteToStr(data[2]);
752139aa4f0SVijay Khemka }
753139aa4f0SVijay Khemka 
754139aa4f0SVijay Khemka static void logNmCap(uint8_t* data, std::string& errLog)
755139aa4f0SVijay Khemka {
756139aa4f0SVijay Khemka 
757139aa4f0SVijay Khemka     const std::vector<std::string> nmCapStsStr = {"Not Available", "Available"};
758139aa4f0SVijay Khemka     if (data[0] & 0x7) // BIT1=policy, BIT2=monitoring, BIT3=pwr
759139aa4f0SVijay Khemka                        // limit and the others are reserved
760139aa4f0SVijay Khemka     {
761139aa4f0SVijay Khemka         errLog = "PolicyInterface:" + nmCapStsStr[BIT(data[0], 0)] +
762139aa4f0SVijay Khemka                  ",Monitoring:" + nmCapStsStr[BIT(data[0], 1)] +
763139aa4f0SVijay Khemka                  ",PowerLimit:" + nmCapStsStr[BIT(data[0], 2)];
764139aa4f0SVijay Khemka     }
765139aa4f0SVijay Khemka     else
766139aa4f0SVijay Khemka     {
767139aa4f0SVijay Khemka         errLog = "Unknown";
768139aa4f0SVijay Khemka     }
769139aa4f0SVijay Khemka }
770139aa4f0SVijay Khemka 
771139aa4f0SVijay Khemka static void logNmThreshold(uint8_t* data, std::string& errLog)
772139aa4f0SVijay Khemka {
773139aa4f0SVijay Khemka     uint8_t thresNum = (data[0] & 0x3);
774139aa4f0SVijay Khemka     uint8_t domIdx = (data[1] & 0xf);
775139aa4f0SVijay Khemka     uint8_t polId = data[2];
776139aa4f0SVijay Khemka     uint8_t polEvtIdx = BIT(data[0], 3);
777139aa4f0SVijay Khemka     const std::vector<std::string> polEvtStr = {
778139aa4f0SVijay Khemka         "Threshold Exceeded", "Policy Correction Time Exceeded"};
779139aa4f0SVijay Khemka 
780139aa4f0SVijay Khemka     errLog = "Threshold Number:" + std::to_string(thresNum) + "-" +
781139aa4f0SVijay Khemka              polEvtStr[polEvtIdx] + ", Domain:" + nmDomName[domIdx] +
782139aa4f0SVijay Khemka              ", PolicyID:0x" + byteToStr(polId);
783139aa4f0SVijay Khemka }
784139aa4f0SVijay Khemka 
785139aa4f0SVijay Khemka static void logPwrThreshold(uint8_t* data, std::string& errLog)
786139aa4f0SVijay Khemka {
787139aa4f0SVijay Khemka     if (data[0] == 0x00)
788139aa4f0SVijay Khemka     {
789139aa4f0SVijay Khemka         errLog = "Limit Not Exceeded";
790139aa4f0SVijay Khemka     }
791139aa4f0SVijay Khemka     else if (data[0] == 0x01)
792139aa4f0SVijay Khemka     {
793139aa4f0SVijay Khemka         errLog = "Limit Exceeded";
794139aa4f0SVijay Khemka     }
795139aa4f0SVijay Khemka     else
796139aa4f0SVijay Khemka     {
797139aa4f0SVijay Khemka         errLog = "Unknown";
798139aa4f0SVijay Khemka     }
799139aa4f0SVijay Khemka }
800139aa4f0SVijay Khemka 
801139aa4f0SVijay Khemka static void logMSMI(uint8_t* data, std::string& errLog)
802139aa4f0SVijay Khemka {
803139aa4f0SVijay Khemka 
804139aa4f0SVijay Khemka     if (data[0] == 0x0)
805139aa4f0SVijay Khemka     {
806139aa4f0SVijay Khemka         errLog = "IERR/MSMI";
807139aa4f0SVijay Khemka     }
808139aa4f0SVijay Khemka     else if (data[0] == 0x0B)
809139aa4f0SVijay Khemka     {
810139aa4f0SVijay Khemka         errLog = "MCERR/MSMI";
811139aa4f0SVijay Khemka     }
812139aa4f0SVijay Khemka     else
813139aa4f0SVijay Khemka     {
814139aa4f0SVijay Khemka         errLog = "Unknown";
815139aa4f0SVijay Khemka     }
816139aa4f0SVijay Khemka }
817139aa4f0SVijay Khemka 
818139aa4f0SVijay Khemka static void logHprWarn(uint8_t* data, std::string& errLog)
819139aa4f0SVijay Khemka {
820139aa4f0SVijay Khemka     if (data[2] == 0x01)
821139aa4f0SVijay Khemka     {
822139aa4f0SVijay Khemka         if (data[1] == 0xFF)
823139aa4f0SVijay Khemka         {
824139aa4f0SVijay Khemka             errLog = "Infinite Time";
825139aa4f0SVijay Khemka         }
826139aa4f0SVijay Khemka         else
827139aa4f0SVijay Khemka         {
828139aa4f0SVijay Khemka             errLog = std::to_string(data[1]) + " minutes";
829139aa4f0SVijay Khemka         }
830139aa4f0SVijay Khemka     }
831139aa4f0SVijay Khemka     else
832139aa4f0SVijay Khemka     {
833139aa4f0SVijay Khemka         errLog = "Unknown";
834139aa4f0SVijay Khemka     }
835139aa4f0SVijay Khemka }
836139aa4f0SVijay Khemka 
837139aa4f0SVijay Khemka static const boost::container::flat_map<
838139aa4f0SVijay Khemka     uint8_t,
839139aa4f0SVijay Khemka     std::pair<std::string, std::function<void(uint8_t*, std::string&)>>>
840139aa4f0SVijay Khemka     sensorNameTable = {{0xE9, {"SYSTEM_EVENT", logSysEvent}},
841139aa4f0SVijay Khemka                        {0x7D, {"THERM_THRESH_EVT", logThermalEvent}},
842139aa4f0SVijay Khemka                        {0xAA, {"BUTTON", logDefault}},
843139aa4f0SVijay Khemka                        {0xAB, {"POWER_STATE", logDefault}},
844139aa4f0SVijay Khemka                        {0xEA, {"CRITICAL_IRQ", logCritIrq}},
845139aa4f0SVijay Khemka                        {0x2B, {"POST_ERROR", logPostErr}},
846139aa4f0SVijay Khemka                        {0x40, {"MACHINE_CHK_ERR", logMchChkErr}},
847139aa4f0SVijay Khemka                        {0x41, {"PCIE_ERR", logPcieErr}},
848139aa4f0SVijay Khemka                        {0x43, {"IIO_ERR", logIioErr}},
849139aa4f0SVijay Khemka                        {0X63, {"MEMORY_ECC_ERR", logDefault}},
850139aa4f0SVijay Khemka                        {0X87, {"MEMORY_ERR_LOG_DIS", logDefault}},
851139aa4f0SVijay Khemka                        {0X51, {"PROCHOT_EXT", logDefault}},
852139aa4f0SVijay Khemka                        {0X56, {"PWR_ERR", logPwrErr}},
853139aa4f0SVijay Khemka                        {0xE6, {"CATERR_A", logCatErr}},
854139aa4f0SVijay Khemka                        {0xEB, {"CATERR_B", logCatErr}},
855139aa4f0SVijay Khemka                        {0xB3, {"CPU_DIMM_HOT", logDimmHot}},
856139aa4f0SVijay Khemka                        {0x90, {"SOFTWARE_NMI", logSwNMI}},
857139aa4f0SVijay Khemka                        {0x1C, {"CPU0_THERM_STATUS", logCPUThermalSts}},
858139aa4f0SVijay Khemka                        {0x1D, {"CPU1_THERM_STATUS", logCPUThermalSts}},
859139aa4f0SVijay Khemka                        {0x16, {"ME_POWER_STATE", logMEPwrState}},
860139aa4f0SVijay Khemka                        {0x17, {"SPS_FW_HEALTH", logSPSFwHealth}},
861139aa4f0SVijay Khemka                        {0x18, {"NM_EXCEPTION_A", logNmExcA}},
862139aa4f0SVijay Khemka                        {0x08, {"PCH_THERM_THRESHOLD", logPCHThermal}},
863139aa4f0SVijay Khemka                        {0x19, {"NM_HEALTH", logNmHealth}},
864139aa4f0SVijay Khemka                        {0x1A, {"NM_CAPABILITIES", logNmCap}},
865139aa4f0SVijay Khemka                        {0x1B, {"NM_THRESHOLD", logNmThreshold}},
866139aa4f0SVijay Khemka                        {0x3B, {"PWR_THRESH_EVT", logPwrThreshold}},
867139aa4f0SVijay Khemka                        {0xE7, {"MSMI", logMSMI}},
868139aa4f0SVijay Khemka                        {0xC5, {"HPR_WARNING", logHprWarn}}};
869139aa4f0SVijay Khemka 
870139aa4f0SVijay Khemka static void parseSelHelper(StdSELEntry* data, std::string& errStr)
871139aa4f0SVijay Khemka {
872139aa4f0SVijay Khemka 
873139aa4f0SVijay Khemka     /* Check if sensor type is OS_BOOT (0x1f) */
874139aa4f0SVijay Khemka     if (data->sensorType == 0x1F)
875139aa4f0SVijay Khemka     {
876139aa4f0SVijay Khemka         /* OS_BOOT used by OS */
877139aa4f0SVijay Khemka         switch (data->eventData1 & 0xF)
878139aa4f0SVijay Khemka         {
879139aa4f0SVijay Khemka             case 0x07:
880139aa4f0SVijay Khemka                 errStr = "Base OS/Hypervisor Installation started";
881139aa4f0SVijay Khemka                 break;
882139aa4f0SVijay Khemka             case 0x08:
883139aa4f0SVijay Khemka                 errStr = "Base OS/Hypervisor Installation completed";
884139aa4f0SVijay Khemka                 break;
885139aa4f0SVijay Khemka             case 0x09:
886139aa4f0SVijay Khemka                 errStr = "Base OS/Hypervisor Installation aborted";
887139aa4f0SVijay Khemka                 break;
888139aa4f0SVijay Khemka             case 0x0A:
889139aa4f0SVijay Khemka                 errStr = "Base OS/Hypervisor Installation failed";
890139aa4f0SVijay Khemka                 break;
891139aa4f0SVijay Khemka             default:
892139aa4f0SVijay Khemka                 errStr = "Unknown";
893139aa4f0SVijay Khemka         }
894139aa4f0SVijay Khemka         return;
895139aa4f0SVijay Khemka     }
896139aa4f0SVijay Khemka 
897139aa4f0SVijay Khemka     auto findSensorName = sensorNameTable.find(data->sensorNum);
898139aa4f0SVijay Khemka     if (findSensorName == sensorNameTable.end())
899139aa4f0SVijay Khemka     {
900139aa4f0SVijay Khemka         errStr = "Unknown";
901139aa4f0SVijay Khemka         return;
902139aa4f0SVijay Khemka     }
903139aa4f0SVijay Khemka     else
904139aa4f0SVijay Khemka     {
905139aa4f0SVijay Khemka         switch (data->sensorNum)
906139aa4f0SVijay Khemka         {
907139aa4f0SVijay Khemka             /* logMemErr function needs data from sensor type */
908139aa4f0SVijay Khemka             case memoryEccError:
909139aa4f0SVijay Khemka             case memoryErrLogDIS:
910139aa4f0SVijay Khemka                 findSensorName->second.second(&(data->sensorType), errStr);
911139aa4f0SVijay Khemka                 break;
912139aa4f0SVijay Khemka             /* Other sensor function needs only event data for parsing */
913139aa4f0SVijay Khemka             default:
914139aa4f0SVijay Khemka                 findSensorName->second.second(&(data->eventData1), errStr);
915139aa4f0SVijay Khemka         }
916139aa4f0SVijay Khemka     }
917139aa4f0SVijay Khemka 
918139aa4f0SVijay Khemka     if (((data->eventData3 & 0x80) >> 7) == 0)
919139aa4f0SVijay Khemka     {
920139aa4f0SVijay Khemka         errStr += " Assertion";
921139aa4f0SVijay Khemka     }
922139aa4f0SVijay Khemka     else
923139aa4f0SVijay Khemka     {
924139aa4f0SVijay Khemka         errStr += " Deassertion";
925139aa4f0SVijay Khemka     }
926139aa4f0SVijay Khemka }
927139aa4f0SVijay Khemka 
928f36f345fSVijay Khemka static void parseStdSel(StdSELEntry* data, std::string& errStr)
929f36f345fSVijay Khemka {
930f36f345fSVijay Khemka     std::stringstream tmpStream;
931f36f345fSVijay Khemka     tmpStream << std::hex << std::uppercase;
932f36f345fSVijay Khemka 
933f36f345fSVijay Khemka     /* TODO: add pal_add_cri_sel */
934f36f345fSVijay Khemka     switch (data->sensorNum)
935f36f345fSVijay Khemka     {
936f36f345fSVijay Khemka         case memoryEccError:
937f36f345fSVijay Khemka             switch (data->eventData1 & 0x0F)
938f36f345fSVijay Khemka             {
939f36f345fSVijay Khemka                 case 0x00:
940f36f345fSVijay Khemka                     errStr = "Correctable";
941f36f345fSVijay Khemka                     tmpStream << "DIMM" << std::setw(2) << std::setfill('0')
942f36f345fSVijay Khemka                               << data->eventData3 << " ECC err";
943f36f345fSVijay Khemka                     break;
944f36f345fSVijay Khemka                 case 0x01:
945f36f345fSVijay Khemka                     errStr = "Uncorrectable";
946f36f345fSVijay Khemka                     tmpStream << "DIMM" << std::setw(2) << std::setfill('0')
947f36f345fSVijay Khemka                               << data->eventData3 << " UECC err";
948f36f345fSVijay Khemka                     break;
949f36f345fSVijay Khemka                 case 0x02:
950f36f345fSVijay Khemka                     errStr = "Parity";
951f36f345fSVijay Khemka                     break;
952f36f345fSVijay Khemka                 case 0x05:
953f36f345fSVijay Khemka                     errStr = "Correctable ECC error Logging Limit Reached";
954f36f345fSVijay Khemka                     break;
955f36f345fSVijay Khemka                 default:
956f36f345fSVijay Khemka                     errStr = "Unknown";
957f36f345fSVijay Khemka             }
958f36f345fSVijay Khemka             break;
959f36f345fSVijay Khemka         case memoryErrLogDIS:
960f36f345fSVijay Khemka             if ((data->eventData1 & 0x0F) == 0)
961f36f345fSVijay Khemka             {
962f36f345fSVijay Khemka                 errStr = "Correctable Memory Error Logging Disabled";
963f36f345fSVijay Khemka             }
964f36f345fSVijay Khemka             else
965f36f345fSVijay Khemka             {
966f36f345fSVijay Khemka                 errStr = "Unknown";
967f36f345fSVijay Khemka             }
968f36f345fSVijay Khemka             break;
969f36f345fSVijay Khemka         default:
970139aa4f0SVijay Khemka             parseSelHelper(data, errStr);
971f36f345fSVijay Khemka             return;
972f36f345fSVijay Khemka     }
973f36f345fSVijay Khemka 
974f36f345fSVijay Khemka     errStr += " (DIMM " + std::to_string(data->eventData3) + ")";
975f36f345fSVijay Khemka     errStr += " Logical Rank " + std::to_string(data->eventData2 & 0x03);
976f36f345fSVijay Khemka 
977f36f345fSVijay Khemka     switch ((data->eventData2 & 0x0C) >> 2)
978f36f345fSVijay Khemka     {
979f36f345fSVijay Khemka         case 0x00:
980f36f345fSVijay Khemka             // Ignore when " All info available"
981f36f345fSVijay Khemka             break;
982f36f345fSVijay Khemka         case 0x01:
983f36f345fSVijay Khemka             errStr += " DIMM info not valid";
984f36f345fSVijay Khemka             break;
985f36f345fSVijay Khemka         case 0x02:
986f36f345fSVijay Khemka             errStr += " CHN info not valid";
987f36f345fSVijay Khemka             break;
988f36f345fSVijay Khemka         case 0x03:
989f36f345fSVijay Khemka             errStr += " CPU info not valid";
990f36f345fSVijay Khemka             break;
991f36f345fSVijay Khemka         default:
992f36f345fSVijay Khemka             errStr += " Unknown";
993f36f345fSVijay Khemka     }
994f36f345fSVijay Khemka 
995f36f345fSVijay Khemka     if (((data->eventType & 0x80) >> 7) == 0)
996f36f345fSVijay Khemka     {
997f36f345fSVijay Khemka         errStr += " Assertion";
998f36f345fSVijay Khemka     }
999f36f345fSVijay Khemka     else
1000f36f345fSVijay Khemka     {
1001f36f345fSVijay Khemka         errStr += " Deassertion";
1002f36f345fSVijay Khemka     }
1003f36f345fSVijay Khemka 
1004f36f345fSVijay Khemka     return;
1005f36f345fSVijay Khemka }
1006f36f345fSVijay Khemka 
1007f36f345fSVijay Khemka static void parseOemSel(TsOemSELEntry* data, std::string& errStr)
1008f36f345fSVijay Khemka {
1009f36f345fSVijay Khemka     std::stringstream tmpStream;
1010f36f345fSVijay Khemka     tmpStream << std::hex << std::uppercase << std::setfill('0');
1011f36f345fSVijay Khemka 
1012f36f345fSVijay Khemka     switch (data->recordType)
1013f36f345fSVijay Khemka     {
1014f36f345fSVijay Khemka         case 0xC0:
1015f36f345fSVijay Khemka             tmpStream << "VID:0x" << std::setw(2) << (int)data->oemData[1]
1016f36f345fSVijay Khemka                       << std::setw(2) << (int)data->oemData[0] << " DID:0x"
1017f36f345fSVijay Khemka                       << std::setw(2) << (int)data->oemData[3] << std::setw(2)
1018f36f345fSVijay Khemka                       << (int)data->oemData[2] << " Slot:0x" << std::setw(2)
1019f36f345fSVijay Khemka                       << (int)data->oemData[4] << " Error ID:0x" << std::setw(2)
1020f36f345fSVijay Khemka                       << (int)data->oemData[5];
1021f36f345fSVijay Khemka             break;
1022f36f345fSVijay Khemka         case 0xC2:
1023f36f345fSVijay Khemka             tmpStream << "Extra info:0x" << std::setw(2)
1024f36f345fSVijay Khemka                       << (int)data->oemData[1] << " MSCOD:0x" << std::setw(2)
1025f36f345fSVijay Khemka                       << (int)data->oemData[3] << std::setw(2)
1026f36f345fSVijay Khemka                       << (int)data->oemData[2] << " MCACOD:0x" << std::setw(2)
1027f36f345fSVijay Khemka                       << (int)data->oemData[5] << std::setw(2)
1028f36f345fSVijay Khemka                       << (int)data->oemData[4];
1029f36f345fSVijay Khemka             break;
1030f36f345fSVijay Khemka         case 0xC3:
1031f36f345fSVijay Khemka             int bank = (data->oemData[1] & 0xf0) >> 4;
1032f36f345fSVijay Khemka             int col = ((data->oemData[1] & 0x0f) << 8) | data->oemData[2];
1033f36f345fSVijay Khemka 
1034f36f345fSVijay Khemka             tmpStream << "Fail Device:0x" << std::setw(2)
1035f36f345fSVijay Khemka                       << (int)data->oemData[0] << " Bank:0x" << std::setw(2)
1036f36f345fSVijay Khemka                       << bank << " Column:0x" << std::setw(2) << col
1037f36f345fSVijay Khemka                       << " Failed Row:0x" << std::setw(2)
1038f36f345fSVijay Khemka                       << (int)data->oemData[3] << std::setw(2)
1039f36f345fSVijay Khemka                       << (int)data->oemData[4] << std::setw(2)
1040f36f345fSVijay Khemka                       << (int)data->oemData[5];
1041f36f345fSVijay Khemka     }
1042f36f345fSVijay Khemka 
1043f36f345fSVijay Khemka     errStr = tmpStream.str();
1044f36f345fSVijay Khemka 
1045f36f345fSVijay Khemka     return;
1046f36f345fSVijay Khemka }
1047f36f345fSVijay Khemka 
104834a875f3SVijay Khemka static void parseOemUnifiedSel(NtsOemSELEntry* data, std::string& errStr)
104934a875f3SVijay Khemka {
105034a875f3SVijay Khemka     uint8_t* ptr = data->oemData;
105134a875f3SVijay Khemka     int genInfo = ptr[0];
105234a875f3SVijay Khemka     int errType = genInfo & 0x0f;
105334a875f3SVijay Khemka     std::vector<std::string> dimmEvent = {
105434a875f3SVijay Khemka         "Memory training failure", "Memory correctable error",
105534a875f3SVijay Khemka         "Memory uncorrectable error", "Reserved"};
105634a875f3SVijay Khemka 
105734a875f3SVijay Khemka     std::stringstream tmpStream;
105834a875f3SVijay Khemka     tmpStream << std::hex << std::uppercase << std::setfill('0');
105934a875f3SVijay Khemka 
106034a875f3SVijay Khemka     switch (errType)
106134a875f3SVijay Khemka     {
106234a875f3SVijay Khemka         case unifiedPcieErr:
106334a875f3SVijay Khemka             if (((genInfo & 0x10) >> 4) == 0) // x86
106434a875f3SVijay Khemka             {
106534a875f3SVijay Khemka                 tmpStream << "GeneralInfo: x86/PCIeErr(0x" << std::setw(2)
106634a875f3SVijay Khemka                           << genInfo << "),";
106734a875f3SVijay Khemka             }
106834a875f3SVijay Khemka 
106934a875f3SVijay Khemka             tmpStream << " Bus " << std::setw(2) << (int)(ptr[8]) << "/Dev "
107034a875f3SVijay Khemka                       << std::setw(2) << (int)(ptr[7] >> 3) << "/Fun "
107134a875f3SVijay Khemka                       << std::setw(2) << (int)(ptr[7] & 0x7)
107234a875f3SVijay Khemka                       << ", TotalErrID1Cnt: 0x" << std::setw(4)
107334a875f3SVijay Khemka                       << (int)((ptr[10] << 8) | ptr[9]) << ", ErrID2: 0x"
107434a875f3SVijay Khemka                       << std::setw(2) << (int)(ptr[11]) << ", ErrID1: 0x"
107534a875f3SVijay Khemka                       << std::setw(2) << (int)(ptr[12]);
107634a875f3SVijay Khemka 
107734a875f3SVijay Khemka             break;
107834a875f3SVijay Khemka         case unifiedMemErr:
107934a875f3SVijay Khemka             tmpStream << "GeneralInfo: MemErr(0x" << std::setw(2) << genInfo
108034a875f3SVijay Khemka                       << "), DIMM Slot Location: Sled " << std::setw(2)
108134a875f3SVijay Khemka                       << (int)((ptr[5] >> 4) & 0x03) << "/Socket "
108234a875f3SVijay Khemka                       << std::setw(2) << (int)(ptr[5] & 0x0f) << ", Channel "
108334a875f3SVijay Khemka                       << std::setw(2) << (int)(ptr[6] & 0x0f) << ", Slot "
108434a875f3SVijay Khemka                       << std::setw(2) << (int)(ptr[7] & 0x0f)
108534a875f3SVijay Khemka                       << ", DIMM Failure Event: " << dimmEvent[(ptr[9] & 0x03)]
108634a875f3SVijay Khemka                       << ", Major Code: 0x" << std::setw(2) << (int)(ptr[10])
108734a875f3SVijay Khemka                       << ", Minor Code: 0x" << std::setw(2) << (int)(ptr[11]);
108834a875f3SVijay Khemka 
108934a875f3SVijay Khemka             break;
109034a875f3SVijay Khemka         default:
109134a875f3SVijay Khemka             std::vector<uint8_t> oemData(ptr, ptr + 13);
109234a875f3SVijay Khemka             std::string oemDataStr;
109334a875f3SVijay Khemka             toHexStr(oemData, oemDataStr);
109434a875f3SVijay Khemka             tmpStream << "Undefined Error Type(0x" << std::setw(2) << errType
109534a875f3SVijay Khemka                       << "), Raw: " << oemDataStr;
109634a875f3SVijay Khemka     }
109734a875f3SVijay Khemka 
109834a875f3SVijay Khemka     errStr = tmpStream.str();
109934a875f3SVijay Khemka 
110034a875f3SVijay Khemka     return;
110134a875f3SVijay Khemka }
110234a875f3SVijay Khemka 
1103f36f345fSVijay Khemka static void parseSelData(std::vector<uint8_t>& reqData, std::string& msgLog)
1104f36f345fSVijay Khemka {
1105f36f345fSVijay Khemka 
1106f36f345fSVijay Khemka     /* Get record type */
1107f36f345fSVijay Khemka     int recType = reqData[2];
1108f36f345fSVijay Khemka     std::string errType, errLog;
1109f36f345fSVijay Khemka 
1110f36f345fSVijay Khemka     uint8_t* ptr = NULL;
1111f36f345fSVijay Khemka 
1112f36f345fSVijay Khemka     std::stringstream recTypeStream;
1113f36f345fSVijay Khemka     recTypeStream << std::hex << std::uppercase << std::setfill('0')
1114f36f345fSVijay Khemka                   << std::setw(2) << recType;
1115f36f345fSVijay Khemka 
1116f36f345fSVijay Khemka     msgLog = "SEL Entry: FRU: 1, Record: ";
1117f36f345fSVijay Khemka 
1118f36f345fSVijay Khemka     if (recType == stdErrType)
1119f36f345fSVijay Khemka     {
1120f36f345fSVijay Khemka         StdSELEntry* data = reinterpret_cast<StdSELEntry*>(&reqData[0]);
1121f36f345fSVijay Khemka         std::string sensorName;
1122f36f345fSVijay Khemka 
1123f36f345fSVijay Khemka         errType = stdErr;
1124f36f345fSVijay Khemka         if (data->sensorType == 0x1F)
1125f36f345fSVijay Khemka         {
1126f36f345fSVijay Khemka             sensorName = "OS";
1127f36f345fSVijay Khemka         }
1128f36f345fSVijay Khemka         else
1129f36f345fSVijay Khemka         {
1130f36f345fSVijay Khemka             auto findSensorName = sensorNameTable.find(data->sensorNum);
1131f36f345fSVijay Khemka             if (findSensorName == sensorNameTable.end())
1132f36f345fSVijay Khemka             {
1133f36f345fSVijay Khemka                 sensorName = "Unknown";
1134f36f345fSVijay Khemka             }
1135f36f345fSVijay Khemka             else
1136f36f345fSVijay Khemka             {
1137139aa4f0SVijay Khemka                 sensorName = findSensorName->second.first;
1138f36f345fSVijay Khemka             }
1139f36f345fSVijay Khemka         }
1140f36f345fSVijay Khemka 
1141f36f345fSVijay Khemka         std::tm* ts = localtime((time_t*)(&(data->timeStamp)));
1142f36f345fSVijay Khemka         std::string timeStr = std::asctime(ts);
1143f36f345fSVijay Khemka 
1144f36f345fSVijay Khemka         parseStdSel(data, errLog);
1145f36f345fSVijay Khemka         ptr = &(data->eventData1);
1146f36f345fSVijay Khemka         std::vector<uint8_t> evtData(ptr, ptr + 3);
1147f36f345fSVijay Khemka         std::string eventData;
1148f36f345fSVijay Khemka         toHexStr(evtData, eventData);
1149f36f345fSVijay Khemka 
1150f36f345fSVijay Khemka         std::stringstream senNumStream;
1151f36f345fSVijay Khemka         senNumStream << std::hex << std::uppercase << std::setfill('0')
1152f36f345fSVijay Khemka                      << std::setw(2) << (int)(data->sensorNum);
1153f36f345fSVijay Khemka 
1154f36f345fSVijay Khemka         msgLog += errType + " (0x" + recTypeStream.str() +
1155f36f345fSVijay Khemka                   "), Time: " + timeStr + ", Sensor: " + sensorName + " (0x" +
1156f36f345fSVijay Khemka                   senNumStream.str() + "), Event Data: (" + eventData + ") " +
1157f36f345fSVijay Khemka                   errLog;
1158f36f345fSVijay Khemka     }
1159f36f345fSVijay Khemka     else if ((recType >= oemTSErrTypeMin) && (recType <= oemTSErrTypeMax))
1160f36f345fSVijay Khemka     {
1161f36f345fSVijay Khemka         /* timestamped OEM SEL records */
1162f36f345fSVijay Khemka         TsOemSELEntry* data = reinterpret_cast<TsOemSELEntry*>(&reqData[0]);
1163f36f345fSVijay Khemka         ptr = data->mfrId;
1164f36f345fSVijay Khemka         std::vector<uint8_t> mfrIdData(ptr, ptr + 3);
1165f36f345fSVijay Khemka         std::string mfrIdStr;
1166f36f345fSVijay Khemka         toHexStr(mfrIdData, mfrIdStr);
1167f36f345fSVijay Khemka 
1168f36f345fSVijay Khemka         ptr = data->oemData;
1169f36f345fSVijay Khemka         std::vector<uint8_t> oemData(ptr, ptr + 6);
1170f36f345fSVijay Khemka         std::string oemDataStr;
1171f36f345fSVijay Khemka         toHexStr(oemData, oemDataStr);
1172f36f345fSVijay Khemka 
1173f36f345fSVijay Khemka         std::tm* ts = localtime((time_t*)(&(data->timeStamp)));
1174f36f345fSVijay Khemka         std::string timeStr = std::asctime(ts);
1175f36f345fSVijay Khemka 
1176f36f345fSVijay Khemka         errType = oemTSErr;
1177f36f345fSVijay Khemka         parseOemSel(data, errLog);
1178f36f345fSVijay Khemka 
1179f36f345fSVijay Khemka         msgLog += errType + " (0x" + recTypeStream.str() +
1180f36f345fSVijay Khemka                   "), Time: " + timeStr + ", MFG ID: " + mfrIdStr +
1181f36f345fSVijay Khemka                   ", OEM Data: (" + oemDataStr + ") " + errLog;
1182f36f345fSVijay Khemka     }
118334a875f3SVijay Khemka     else if (recType == fbUniErrType)
118434a875f3SVijay Khemka     {
118534a875f3SVijay Khemka         NtsOemSELEntry* data = reinterpret_cast<NtsOemSELEntry*>(&reqData[0]);
118634a875f3SVijay Khemka         errType = fbUniSELErr;
118734a875f3SVijay Khemka         parseOemUnifiedSel(data, errLog);
118834a875f3SVijay Khemka         msgLog += errType + " (0x" + recTypeStream.str() + "), " + errLog;
118934a875f3SVijay Khemka     }
1190f36f345fSVijay Khemka     else if ((recType >= oemNTSErrTypeMin) && (recType <= oemNTSErrTypeMax))
1191f36f345fSVijay Khemka     {
1192f36f345fSVijay Khemka         /* Non timestamped OEM SEL records */
1193f36f345fSVijay Khemka         NtsOemSELEntry* data = reinterpret_cast<NtsOemSELEntry*>(&reqData[0]);
1194f36f345fSVijay Khemka         errType = oemNTSErr;
1195f36f345fSVijay Khemka 
1196f36f345fSVijay Khemka         ptr = data->oemData;
1197f36f345fSVijay Khemka         std::vector<uint8_t> oemData(ptr, ptr + 13);
1198f36f345fSVijay Khemka         std::string oemDataStr;
1199f36f345fSVijay Khemka         toHexStr(oemData, oemDataStr);
1200f36f345fSVijay Khemka 
1201f36f345fSVijay Khemka         parseOemSel((TsOemSELEntry*)data, errLog);
1202f36f345fSVijay Khemka         msgLog += errType + " (0x" + recTypeStream.str() + "), OEM Data: (" +
1203f36f345fSVijay Khemka                   oemDataStr + ") " + errLog;
1204f36f345fSVijay Khemka     }
1205f36f345fSVijay Khemka     else
1206f36f345fSVijay Khemka     {
1207f36f345fSVijay Khemka         errType = unknownErr;
1208f36f345fSVijay Khemka         toHexStr(reqData, errLog);
1209f36f345fSVijay Khemka         msgLog +=
1210f36f345fSVijay Khemka             errType + " (0x" + recTypeStream.str() + ") RawData: " + errLog;
1211f36f345fSVijay Khemka     }
1212f36f345fSVijay Khemka }
1213f36f345fSVijay Khemka 
121411b9c3b1SVijay Khemka } // namespace fb_oem::ipmi::sel
121511b9c3b1SVijay Khemka 
121611b9c3b1SVijay Khemka namespace ipmi
121711b9c3b1SVijay Khemka {
121811b9c3b1SVijay Khemka 
121911b9c3b1SVijay Khemka namespace storage
122011b9c3b1SVijay Khemka {
122111b9c3b1SVijay Khemka 
122211b9c3b1SVijay Khemka static void registerSELFunctions() __attribute__((constructor));
122311b9c3b1SVijay Khemka static fb_oem::ipmi::sel::SELData selObj __attribute__((init_priority(101)));
122411b9c3b1SVijay Khemka 
122511b9c3b1SVijay Khemka ipmi::RspType<uint8_t,  // SEL version
122611b9c3b1SVijay Khemka               uint16_t, // SEL entry count
122711b9c3b1SVijay Khemka               uint16_t, // free space
122811b9c3b1SVijay Khemka               uint32_t, // last add timestamp
122911b9c3b1SVijay Khemka               uint32_t, // last erase timestamp
123011b9c3b1SVijay Khemka               uint8_t>  // operation support
123111b9c3b1SVijay Khemka     ipmiStorageGetSELInfo()
123211b9c3b1SVijay Khemka {
123311b9c3b1SVijay Khemka 
123411b9c3b1SVijay Khemka     fb_oem::ipmi::sel::GetSELInfoData info;
123511b9c3b1SVijay Khemka 
123611b9c3b1SVijay Khemka     selObj.getInfo(info);
123711b9c3b1SVijay Khemka     return ipmi::responseSuccess(info.selVersion, info.entries, info.freeSpace,
123811b9c3b1SVijay Khemka                                  info.addTimeStamp, info.eraseTimeStamp,
123911b9c3b1SVijay Khemka                                  info.operationSupport);
124011b9c3b1SVijay Khemka }
124111b9c3b1SVijay Khemka 
124211b9c3b1SVijay Khemka ipmi::RspType<uint16_t, std::vector<uint8_t>>
124311b9c3b1SVijay Khemka     ipmiStorageGetSELEntry(std::vector<uint8_t> data)
124411b9c3b1SVijay Khemka {
124511b9c3b1SVijay Khemka 
124611b9c3b1SVijay Khemka     if (data.size() != sizeof(fb_oem::ipmi::sel::GetSELEntryRequest))
124711b9c3b1SVijay Khemka     {
124811b9c3b1SVijay Khemka         return ipmi::responseReqDataLenInvalid();
124911b9c3b1SVijay Khemka     }
125011b9c3b1SVijay Khemka 
125111b9c3b1SVijay Khemka     fb_oem::ipmi::sel::GetSELEntryRequest* reqData =
125211b9c3b1SVijay Khemka         reinterpret_cast<fb_oem::ipmi::sel::GetSELEntryRequest*>(&data[0]);
125311b9c3b1SVijay Khemka 
125411b9c3b1SVijay Khemka     if (reqData->reservID != 0)
125511b9c3b1SVijay Khemka     {
125611b9c3b1SVijay Khemka         if (!checkSELReservation(reqData->reservID))
125711b9c3b1SVijay Khemka         {
125811b9c3b1SVijay Khemka             return ipmi::responseInvalidReservationId();
125911b9c3b1SVijay Khemka         }
126011b9c3b1SVijay Khemka     }
126111b9c3b1SVijay Khemka 
126211b9c3b1SVijay Khemka     uint16_t selCnt = selObj.getCount();
126311b9c3b1SVijay Khemka     if (selCnt == 0)
126411b9c3b1SVijay Khemka     {
126511b9c3b1SVijay Khemka         return ipmi::responseSensorInvalid();
126611b9c3b1SVijay Khemka     }
126711b9c3b1SVijay Khemka 
126811b9c3b1SVijay Khemka     /* If it is asked for first entry */
126911b9c3b1SVijay Khemka     if (reqData->recordID == fb_oem::ipmi::sel::firstEntry)
127011b9c3b1SVijay Khemka     {
127111b9c3b1SVijay Khemka         /* First Entry (0x0000) as per Spec */
127211b9c3b1SVijay Khemka         reqData->recordID = 1;
127311b9c3b1SVijay Khemka     }
127411b9c3b1SVijay Khemka     else if (reqData->recordID == fb_oem::ipmi::sel::lastEntry)
127511b9c3b1SVijay Khemka     {
127611b9c3b1SVijay Khemka         /* Last entry (0xFFFF) as per Spec */
127711b9c3b1SVijay Khemka         reqData->recordID = selCnt;
127811b9c3b1SVijay Khemka     }
127911b9c3b1SVijay Khemka 
128011b9c3b1SVijay Khemka     std::string ipmiRaw;
128111b9c3b1SVijay Khemka 
128211b9c3b1SVijay Khemka     if (selObj.getEntry(reqData->recordID, ipmiRaw) < 0)
128311b9c3b1SVijay Khemka     {
128411b9c3b1SVijay Khemka         return ipmi::responseSensorInvalid();
128511b9c3b1SVijay Khemka     }
128611b9c3b1SVijay Khemka 
128711b9c3b1SVijay Khemka     std::vector<uint8_t> recDataBytes;
128811b9c3b1SVijay Khemka     if (fromHexStr(ipmiRaw, recDataBytes) < 0)
128911b9c3b1SVijay Khemka     {
129011b9c3b1SVijay Khemka         return ipmi::responseUnspecifiedError();
129111b9c3b1SVijay Khemka     }
129211b9c3b1SVijay Khemka 
129311b9c3b1SVijay Khemka     /* Identify the next SEL record ID. If recordID is same as
129411b9c3b1SVijay Khemka      * total SeL count then next id should be last entry else
129511b9c3b1SVijay Khemka      * it should be incremented by 1 to current RecordID
129611b9c3b1SVijay Khemka      */
129711b9c3b1SVijay Khemka     uint16_t nextRecord;
129811b9c3b1SVijay Khemka     if (reqData->recordID == selCnt)
129911b9c3b1SVijay Khemka     {
130011b9c3b1SVijay Khemka         nextRecord = fb_oem::ipmi::sel::lastEntry;
130111b9c3b1SVijay Khemka     }
130211b9c3b1SVijay Khemka     else
130311b9c3b1SVijay Khemka     {
130411b9c3b1SVijay Khemka         nextRecord = reqData->recordID + 1;
130511b9c3b1SVijay Khemka     }
130611b9c3b1SVijay Khemka 
130711b9c3b1SVijay Khemka     if (reqData->readLen == fb_oem::ipmi::sel::entireRecord)
130811b9c3b1SVijay Khemka     {
130911b9c3b1SVijay Khemka         return ipmi::responseSuccess(nextRecord, recDataBytes);
131011b9c3b1SVijay Khemka     }
131111b9c3b1SVijay Khemka     else
131211b9c3b1SVijay Khemka     {
131311b9c3b1SVijay Khemka         if (reqData->offset >= fb_oem::ipmi::sel::selRecordSize ||
131411b9c3b1SVijay Khemka             reqData->readLen > fb_oem::ipmi::sel::selRecordSize)
131511b9c3b1SVijay Khemka         {
131611b9c3b1SVijay Khemka             return ipmi::responseUnspecifiedError();
131711b9c3b1SVijay Khemka         }
131811b9c3b1SVijay Khemka         std::vector<uint8_t> recPartData;
131911b9c3b1SVijay Khemka 
132011b9c3b1SVijay Khemka         auto diff = fb_oem::ipmi::sel::selRecordSize - reqData->offset;
132111b9c3b1SVijay Khemka         auto readLength = std::min(diff, static_cast<int>(reqData->readLen));
132211b9c3b1SVijay Khemka 
132311b9c3b1SVijay Khemka         for (int i = 0; i < readLength; i++)
132411b9c3b1SVijay Khemka         {
132511b9c3b1SVijay Khemka             recPartData.push_back(recDataBytes[i + reqData->offset]);
132611b9c3b1SVijay Khemka         }
132711b9c3b1SVijay Khemka         return ipmi::responseSuccess(nextRecord, recPartData);
132811b9c3b1SVijay Khemka     }
132911b9c3b1SVijay Khemka }
133011b9c3b1SVijay Khemka 
133111b9c3b1SVijay Khemka ipmi::RspType<uint16_t> ipmiStorageAddSELEntry(std::vector<uint8_t> data)
133211b9c3b1SVijay Khemka {
133311b9c3b1SVijay Khemka     /* Per the IPMI spec, need to cancel any reservation when a
133411b9c3b1SVijay Khemka      * SEL entry is added
133511b9c3b1SVijay Khemka      */
133611b9c3b1SVijay Khemka     cancelSELReservation();
133711b9c3b1SVijay Khemka 
133811b9c3b1SVijay Khemka     if (data.size() != fb_oem::ipmi::sel::selRecordSize)
133911b9c3b1SVijay Khemka     {
134011b9c3b1SVijay Khemka         return ipmi::responseReqDataLenInvalid();
134111b9c3b1SVijay Khemka     }
134211b9c3b1SVijay Khemka 
134311b9c3b1SVijay Khemka     std::string ipmiRaw, logErr;
134411b9c3b1SVijay Khemka     toHexStr(data, ipmiRaw);
134511b9c3b1SVijay Khemka 
1346f36f345fSVijay Khemka     /* Parse sel data and get an error log to be filed */
1347f36f345fSVijay Khemka     fb_oem::ipmi::sel::parseSelData(data, logErr);
1348f36f345fSVijay Khemka 
134915a7ae81SVijay Khemka     static const std::string openBMCMessageRegistryVersion("0.1");
135015a7ae81SVijay Khemka     std::string messageID =
135115a7ae81SVijay Khemka         "OpenBMC." + openBMCMessageRegistryVersion + ".SELEntryAdded";
135215a7ae81SVijay Khemka 
135311b9c3b1SVijay Khemka     /* Log the Raw SEL message to the journal */
135411b9c3b1SVijay Khemka     std::string journalMsg = "SEL Entry Added: " + ipmiRaw;
1355f36f345fSVijay Khemka 
135615a7ae81SVijay Khemka     phosphor::logging::log<phosphor::logging::level::INFO>(
135715a7ae81SVijay Khemka         journalMsg.c_str(),
135815a7ae81SVijay Khemka         phosphor::logging::entry("IPMISEL_MESSAGE_ID=%s", messageID.c_str()),
135915a7ae81SVijay Khemka         phosphor::logging::entry("IPMISEL_MESSAGE_ARGS=%s", logErr.c_str()));
136011b9c3b1SVijay Khemka 
136111b9c3b1SVijay Khemka     int responseID = selObj.addEntry(ipmiRaw.c_str());
136211b9c3b1SVijay Khemka     if (responseID < 0)
136311b9c3b1SVijay Khemka     {
136411b9c3b1SVijay Khemka         return ipmi::responseUnspecifiedError();
136511b9c3b1SVijay Khemka     }
136611b9c3b1SVijay Khemka     return ipmi::responseSuccess((uint16_t)responseID);
136711b9c3b1SVijay Khemka }
136811b9c3b1SVijay Khemka 
1369c1921c63SVijay Khemka ipmi::RspType<uint8_t> ipmiStorageClearSEL(uint16_t reservationID,
1370c1921c63SVijay Khemka                                            const std::array<uint8_t, 3>& clr,
1371c1921c63SVijay Khemka                                            uint8_t eraseOperation)
1372c1921c63SVijay Khemka {
1373c1921c63SVijay Khemka     if (!checkSELReservation(reservationID))
1374c1921c63SVijay Khemka     {
1375c1921c63SVijay Khemka         return ipmi::responseInvalidReservationId();
1376c1921c63SVijay Khemka     }
1377c1921c63SVijay Khemka 
1378c1921c63SVijay Khemka     static constexpr std::array<uint8_t, 3> clrExpected = {'C', 'L', 'R'};
1379c1921c63SVijay Khemka     if (clr != clrExpected)
1380c1921c63SVijay Khemka     {
1381c1921c63SVijay Khemka         return ipmi::responseInvalidFieldRequest();
1382c1921c63SVijay Khemka     }
1383c1921c63SVijay Khemka 
1384c1921c63SVijay Khemka     /* If there is no sel then return erase complete */
1385c1921c63SVijay Khemka     if (selObj.getCount() == 0)
1386c1921c63SVijay Khemka     {
1387c1921c63SVijay Khemka         return ipmi::responseSuccess(fb_oem::ipmi::sel::eraseComplete);
1388c1921c63SVijay Khemka     }
1389c1921c63SVijay Khemka 
1390c1921c63SVijay Khemka     /* Erasure status cannot be fetched, so always return erasure
1391c1921c63SVijay Khemka      * status as `erase completed`.
1392c1921c63SVijay Khemka      */
1393c1921c63SVijay Khemka     if (eraseOperation == fb_oem::ipmi::sel::getEraseStatus)
1394c1921c63SVijay Khemka     {
1395c1921c63SVijay Khemka         return ipmi::responseSuccess(fb_oem::ipmi::sel::eraseComplete);
1396c1921c63SVijay Khemka     }
1397c1921c63SVijay Khemka 
1398c1921c63SVijay Khemka     /* Check that initiate erase is correct */
1399c1921c63SVijay Khemka     if (eraseOperation != fb_oem::ipmi::sel::initiateErase)
1400c1921c63SVijay Khemka     {
1401c1921c63SVijay Khemka         return ipmi::responseInvalidFieldRequest();
1402c1921c63SVijay Khemka     }
1403c1921c63SVijay Khemka 
1404c1921c63SVijay Khemka     /* Per the IPMI spec, need to cancel any reservation when the
1405c1921c63SVijay Khemka      * SEL is cleared
1406c1921c63SVijay Khemka      */
1407c1921c63SVijay Khemka     cancelSELReservation();
1408c1921c63SVijay Khemka 
1409c1921c63SVijay Khemka     /* Clear the complete Sel Json object */
1410c1921c63SVijay Khemka     if (selObj.clear() < 0)
1411c1921c63SVijay Khemka     {
1412c1921c63SVijay Khemka         return ipmi::responseUnspecifiedError();
1413c1921c63SVijay Khemka     }
1414c1921c63SVijay Khemka 
1415c1921c63SVijay Khemka     return ipmi::responseSuccess(fb_oem::ipmi::sel::eraseComplete);
1416c1921c63SVijay Khemka }
1417c1921c63SVijay Khemka 
1418c1921c63SVijay Khemka ipmi::RspType<uint32_t> ipmiStorageGetSELTime()
1419c1921c63SVijay Khemka {
1420c1921c63SVijay Khemka     struct timespec selTime = {};
1421c1921c63SVijay Khemka 
1422c1921c63SVijay Khemka     if (clock_gettime(CLOCK_REALTIME, &selTime) < 0)
1423c1921c63SVijay Khemka     {
1424c1921c63SVijay Khemka         return ipmi::responseUnspecifiedError();
1425c1921c63SVijay Khemka     }
1426c1921c63SVijay Khemka 
1427c1921c63SVijay Khemka     return ipmi::responseSuccess(selTime.tv_sec);
1428c1921c63SVijay Khemka }
1429c1921c63SVijay Khemka 
1430c1921c63SVijay Khemka ipmi::RspType<> ipmiStorageSetSELTime(uint32_t selTime)
1431c1921c63SVijay Khemka {
1432c1921c63SVijay Khemka     // Set SEL Time is not supported
1433c1921c63SVijay Khemka     return ipmi::responseInvalidCommand();
1434c1921c63SVijay Khemka }
1435c1921c63SVijay Khemka 
1436c1921c63SVijay Khemka ipmi::RspType<uint16_t> ipmiStorageGetSELTimeUtcOffset()
1437c1921c63SVijay Khemka {
1438c1921c63SVijay Khemka     /* TODO: For now, the SEL time stamp is based on UTC time,
1439c1921c63SVijay Khemka      * so return 0x0000 as offset. Might need to change once
1440c1921c63SVijay Khemka      * supporting zones in SEL time stamps
1441c1921c63SVijay Khemka      */
1442c1921c63SVijay Khemka 
1443c1921c63SVijay Khemka     uint16_t utcOffset = 0x0000;
1444c1921c63SVijay Khemka     return ipmi::responseSuccess(utcOffset);
1445c1921c63SVijay Khemka }
1446c1921c63SVijay Khemka 
144711b9c3b1SVijay Khemka void registerSELFunctions()
144811b9c3b1SVijay Khemka {
144911b9c3b1SVijay Khemka     // <Get SEL Info>
145011b9c3b1SVijay Khemka     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
145111b9c3b1SVijay Khemka                           ipmi::storage::cmdGetSelInfo, ipmi::Privilege::User,
145211b9c3b1SVijay Khemka                           ipmiStorageGetSELInfo);
145311b9c3b1SVijay Khemka 
145411b9c3b1SVijay Khemka     // <Get SEL Entry>
145511b9c3b1SVijay Khemka     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
145611b9c3b1SVijay Khemka                           ipmi::storage::cmdGetSelEntry, ipmi::Privilege::User,
145711b9c3b1SVijay Khemka                           ipmiStorageGetSELEntry);
145811b9c3b1SVijay Khemka 
145911b9c3b1SVijay Khemka     // <Add SEL Entry>
146011b9c3b1SVijay Khemka     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
146111b9c3b1SVijay Khemka                           ipmi::storage::cmdAddSelEntry,
146211b9c3b1SVijay Khemka                           ipmi::Privilege::Operator, ipmiStorageAddSELEntry);
146311b9c3b1SVijay Khemka 
1464c1921c63SVijay Khemka     // <Clear SEL>
1465c1921c63SVijay Khemka     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
1466c1921c63SVijay Khemka                           ipmi::storage::cmdClearSel, ipmi::Privilege::Operator,
1467c1921c63SVijay Khemka                           ipmiStorageClearSEL);
1468c1921c63SVijay Khemka 
1469c1921c63SVijay Khemka     // <Get SEL Time>
1470c1921c63SVijay Khemka     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
1471c1921c63SVijay Khemka                           ipmi::storage::cmdGetSelTime, ipmi::Privilege::User,
1472c1921c63SVijay Khemka                           ipmiStorageGetSELTime);
1473c1921c63SVijay Khemka 
1474c1921c63SVijay Khemka     // <Set SEL Time>
1475c1921c63SVijay Khemka     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
1476c1921c63SVijay Khemka                           ipmi::storage::cmdSetSelTime,
1477c1921c63SVijay Khemka                           ipmi::Privilege::Operator, ipmiStorageSetSELTime);
1478c1921c63SVijay Khemka 
1479c1921c63SVijay Khemka     // <Get SEL Time UTC Offset>
1480c1921c63SVijay Khemka     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
1481c1921c63SVijay Khemka                           ipmi::storage::cmdGetSelTimeUtcOffset,
1482c1921c63SVijay Khemka                           ipmi::Privilege::User,
1483c1921c63SVijay Khemka                           ipmiStorageGetSELTimeUtcOffset);
1484c1921c63SVijay Khemka 
148511b9c3b1SVijay Khemka     return;
148611b9c3b1SVijay Khemka }
148711b9c3b1SVijay Khemka 
148811b9c3b1SVijay Khemka } // namespace storage
148911b9c3b1SVijay Khemka } // namespace ipmi
1490