xref: /openbmc/fb-ipmi-oem/src/selcommands.cpp (revision 21a79235d372dcbd8282f09dfc819c24bd080183)
111b9c3b1SVijay Khemka /*
211b9c3b1SVijay Khemka  * Copyright (c)  2018 Intel Corporation.
311b9c3b1SVijay Khemka  * Copyright (c)  2018-present Facebook.
411b9c3b1SVijay Khemka  *
511b9c3b1SVijay Khemka  * Licensed under the Apache License, Version 2.0 (the "License");
611b9c3b1SVijay Khemka  * you may not use this file except in compliance with the License.
711b9c3b1SVijay Khemka  * You may obtain a copy of the License at
811b9c3b1SVijay Khemka  *
911b9c3b1SVijay Khemka  *      http://www.apache.org/licenses/LICENSE-2.0
1011b9c3b1SVijay Khemka  *
1111b9c3b1SVijay Khemka  * Unless required by applicable law or agreed to in writing, software
1211b9c3b1SVijay Khemka  * distributed under the License is distributed on an "AS IS" BASIS,
1311b9c3b1SVijay Khemka  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1411b9c3b1SVijay Khemka  * See the License for the specific language governing permissions and
1511b9c3b1SVijay Khemka  * limitations under the License.
1611b9c3b1SVijay Khemka  */
1711b9c3b1SVijay Khemka 
1811b9c3b1SVijay Khemka #include <boost/algorithm/string/join.hpp>
19020ff3e4SPatrick Williams #include <boost/container/flat_map.hpp>
2063c99be4SVijay Khemka #include <ipmid/api.hpp>
2111b9c3b1SVijay Khemka #include <nlohmann/json.hpp>
2211b9c3b1SVijay Khemka #include <phosphor-logging/log.hpp>
2311b9c3b1SVijay Khemka #include <sdbusplus/message/types.hpp>
2411b9c3b1SVijay Khemka #include <sdbusplus/timer.hpp>
2511b9c3b1SVijay Khemka #include <storagecommands.hpp>
2611b9c3b1SVijay Khemka 
2763c99be4SVijay Khemka #include <fstream>
2863c99be4SVijay Khemka #include <iostream>
2963c99be4SVijay Khemka #include <sstream>
3063c99be4SVijay Khemka 
3111b9c3b1SVijay Khemka //----------------------------------------------------------------------
3211b9c3b1SVijay Khemka // Platform specific functions for storing app data
3311b9c3b1SVijay Khemka //----------------------------------------------------------------------
3411b9c3b1SVijay Khemka 
35139aa4f0SVijay Khemka static std::string byteToStr(uint8_t byte)
36139aa4f0SVijay Khemka {
37139aa4f0SVijay Khemka     std::stringstream ss;
38139aa4f0SVijay Khemka 
39139aa4f0SVijay Khemka     ss << std::hex << std::uppercase << std::setfill('0');
40139aa4f0SVijay Khemka     ss << std::setw(2) << (int)byte;
41139aa4f0SVijay Khemka 
42139aa4f0SVijay Khemka     return ss.str();
43139aa4f0SVijay Khemka }
44139aa4f0SVijay Khemka 
4511b9c3b1SVijay Khemka static void toHexStr(std::vector<uint8_t>& bytes, std::string& hexStr)
4611b9c3b1SVijay Khemka {
4711b9c3b1SVijay Khemka     std::stringstream stream;
4811b9c3b1SVijay Khemka     stream << std::hex << std::uppercase << std::setfill('0');
4911b9c3b1SVijay Khemka     for (const uint8_t byte : bytes)
5011b9c3b1SVijay Khemka     {
5111b9c3b1SVijay Khemka         stream << std::setw(2) << static_cast<int>(byte);
5211b9c3b1SVijay Khemka     }
5311b9c3b1SVijay Khemka     hexStr = stream.str();
5411b9c3b1SVijay Khemka }
5511b9c3b1SVijay Khemka 
5611b9c3b1SVijay Khemka static int fromHexStr(const std::string hexStr, std::vector<uint8_t>& data)
5711b9c3b1SVijay Khemka {
5811b9c3b1SVijay Khemka     for (unsigned int i = 0; i < hexStr.size(); i += 2)
5911b9c3b1SVijay Khemka     {
6011b9c3b1SVijay Khemka         try
6111b9c3b1SVijay Khemka         {
6211b9c3b1SVijay Khemka             data.push_back(static_cast<uint8_t>(
6311b9c3b1SVijay Khemka                 std::stoul(hexStr.substr(i, 2), nullptr, 16)));
6411b9c3b1SVijay Khemka         }
6535d12546SPatrick Williams         catch (const std::invalid_argument& e)
6611b9c3b1SVijay Khemka         {
6711b9c3b1SVijay Khemka             phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
6811b9c3b1SVijay Khemka             return -1;
6911b9c3b1SVijay Khemka         }
7035d12546SPatrick Williams         catch (const std::out_of_range& e)
7111b9c3b1SVijay Khemka         {
7211b9c3b1SVijay Khemka             phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
7311b9c3b1SVijay Khemka             return -1;
7411b9c3b1SVijay Khemka         }
7511b9c3b1SVijay Khemka     }
7611b9c3b1SVijay Khemka     return 0;
7711b9c3b1SVijay Khemka }
7811b9c3b1SVijay Khemka 
7911b9c3b1SVijay Khemka namespace fb_oem::ipmi::sel
8011b9c3b1SVijay Khemka {
8111b9c3b1SVijay Khemka 
8211b9c3b1SVijay Khemka class SELData
8311b9c3b1SVijay Khemka {
8411b9c3b1SVijay Khemka   private:
8511b9c3b1SVijay Khemka     nlohmann::json selDataObj;
8611b9c3b1SVijay Khemka 
8711b9c3b1SVijay Khemka     void flush()
8811b9c3b1SVijay Khemka     {
8911b9c3b1SVijay Khemka         std::ofstream file(SEL_JSON_DATA_FILE);
9011b9c3b1SVijay Khemka         file << selDataObj;
9111b9c3b1SVijay Khemka         file.close();
9211b9c3b1SVijay Khemka     }
9311b9c3b1SVijay Khemka 
9411b9c3b1SVijay Khemka     void init()
9511b9c3b1SVijay Khemka     {
9611b9c3b1SVijay Khemka         selDataObj[KEY_SEL_VER] = 0x51;
9711b9c3b1SVijay Khemka         selDataObj[KEY_SEL_COUNT] = 0;
9811b9c3b1SVijay Khemka         selDataObj[KEY_ADD_TIME] = 0xFFFFFFFF;
9911b9c3b1SVijay Khemka         selDataObj[KEY_ERASE_TIME] = 0xFFFFFFFF;
10011b9c3b1SVijay Khemka         selDataObj[KEY_OPER_SUPP] = 0x02;
10111b9c3b1SVijay Khemka         /* Spec indicates that more than 64kB is free */
10211b9c3b1SVijay Khemka         selDataObj[KEY_FREE_SPACE] = 0xFFFF;
10311b9c3b1SVijay Khemka     }
10411b9c3b1SVijay Khemka 
10511b9c3b1SVijay Khemka   public:
10611b9c3b1SVijay Khemka     SELData()
10711b9c3b1SVijay Khemka     {
10811b9c3b1SVijay Khemka         /* Get App data stored in json file */
10911b9c3b1SVijay Khemka         std::ifstream file(SEL_JSON_DATA_FILE);
11011b9c3b1SVijay Khemka         if (file)
11111b9c3b1SVijay Khemka         {
11211b9c3b1SVijay Khemka             file >> selDataObj;
11311b9c3b1SVijay Khemka             file.close();
11411b9c3b1SVijay Khemka         }
11511b9c3b1SVijay Khemka 
11611b9c3b1SVijay Khemka         /* Initialize SelData object if no entries. */
11711b9c3b1SVijay Khemka         if (selDataObj.find(KEY_SEL_COUNT) == selDataObj.end())
11811b9c3b1SVijay Khemka         {
11911b9c3b1SVijay Khemka             init();
12011b9c3b1SVijay Khemka         }
12111b9c3b1SVijay Khemka     }
12211b9c3b1SVijay Khemka 
12311b9c3b1SVijay Khemka     int clear()
12411b9c3b1SVijay Khemka     {
12511b9c3b1SVijay Khemka         /* Clear the complete Sel Json object */
12611b9c3b1SVijay Khemka         selDataObj.clear();
12711b9c3b1SVijay Khemka         /* Reinitialize it with basic data */
12811b9c3b1SVijay Khemka         init();
12911b9c3b1SVijay Khemka         /* Save the erase time */
13011b9c3b1SVijay Khemka         struct timespec selTime = {};
13111b9c3b1SVijay Khemka         if (clock_gettime(CLOCK_REALTIME, &selTime) < 0)
13211b9c3b1SVijay Khemka         {
13311b9c3b1SVijay Khemka             return -1;
13411b9c3b1SVijay Khemka         }
13511b9c3b1SVijay Khemka         selDataObj[KEY_ERASE_TIME] = selTime.tv_sec;
13611b9c3b1SVijay Khemka         flush();
13711b9c3b1SVijay Khemka         return 0;
13811b9c3b1SVijay Khemka     }
13911b9c3b1SVijay Khemka 
14011b9c3b1SVijay Khemka     uint32_t getCount()
14111b9c3b1SVijay Khemka     {
14211b9c3b1SVijay Khemka         return selDataObj[KEY_SEL_COUNT];
14311b9c3b1SVijay Khemka     }
14411b9c3b1SVijay Khemka 
14511b9c3b1SVijay Khemka     void getInfo(GetSELInfoData& info)
14611b9c3b1SVijay Khemka     {
14711b9c3b1SVijay Khemka         info.selVersion = selDataObj[KEY_SEL_VER];
14811b9c3b1SVijay Khemka         info.entries = selDataObj[KEY_SEL_COUNT];
14911b9c3b1SVijay Khemka         info.freeSpace = selDataObj[KEY_FREE_SPACE];
15011b9c3b1SVijay Khemka         info.addTimeStamp = selDataObj[KEY_ADD_TIME];
15111b9c3b1SVijay Khemka         info.eraseTimeStamp = selDataObj[KEY_ERASE_TIME];
15211b9c3b1SVijay Khemka         info.operationSupport = selDataObj[KEY_OPER_SUPP];
15311b9c3b1SVijay Khemka     }
15411b9c3b1SVijay Khemka 
15511b9c3b1SVijay Khemka     int getEntry(uint32_t index, std::string& rawStr)
15611b9c3b1SVijay Khemka     {
15711b9c3b1SVijay Khemka         std::stringstream ss;
15811b9c3b1SVijay Khemka         ss << std::hex;
15911b9c3b1SVijay Khemka         ss << std::setw(2) << std::setfill('0') << index;
16011b9c3b1SVijay Khemka 
16111b9c3b1SVijay Khemka         /* Check or the requested SEL Entry, if record is available */
16211b9c3b1SVijay Khemka         if (selDataObj.find(ss.str()) == selDataObj.end())
16311b9c3b1SVijay Khemka         {
16411b9c3b1SVijay Khemka             return -1;
16511b9c3b1SVijay Khemka         }
16611b9c3b1SVijay Khemka 
16711b9c3b1SVijay Khemka         rawStr = selDataObj[ss.str()][KEY_SEL_ENTRY_RAW];
16811b9c3b1SVijay Khemka         return 0;
16911b9c3b1SVijay Khemka     }
17011b9c3b1SVijay Khemka 
17111b9c3b1SVijay Khemka     int addEntry(std::string keyStr)
17211b9c3b1SVijay Khemka     {
17311b9c3b1SVijay Khemka         struct timespec selTime = {};
17411b9c3b1SVijay Khemka 
17511b9c3b1SVijay Khemka         if (clock_gettime(CLOCK_REALTIME, &selTime) < 0)
17611b9c3b1SVijay Khemka         {
17711b9c3b1SVijay Khemka             return -1;
17811b9c3b1SVijay Khemka         }
17911b9c3b1SVijay Khemka 
18011b9c3b1SVijay Khemka         selDataObj[KEY_ADD_TIME] = selTime.tv_sec;
18111b9c3b1SVijay Khemka 
18211b9c3b1SVijay Khemka         int selCount = selDataObj[KEY_SEL_COUNT];
18311b9c3b1SVijay Khemka         selDataObj[KEY_SEL_COUNT] = ++selCount;
18411b9c3b1SVijay Khemka 
18511b9c3b1SVijay Khemka         std::stringstream ss;
18611b9c3b1SVijay Khemka         ss << std::hex;
18711b9c3b1SVijay Khemka         ss << std::setw(2) << std::setfill('0') << selCount;
18811b9c3b1SVijay Khemka 
18911b9c3b1SVijay Khemka         selDataObj[ss.str()][KEY_SEL_ENTRY_RAW] = keyStr;
19011b9c3b1SVijay Khemka         flush();
19111b9c3b1SVijay Khemka         return selCount;
19211b9c3b1SVijay Khemka     }
19311b9c3b1SVijay Khemka };
19411b9c3b1SVijay Khemka 
195139aa4f0SVijay Khemka /*
196139aa4f0SVijay Khemka  * A Function to parse common SEL message, a helper funciton
197139aa4f0SVijay Khemka  * for parseStdSel.
198139aa4f0SVijay Khemka  *
199139aa4f0SVijay Khemka  * Note that this function __CANNOT__ be overriden.
200139aa4f0SVijay Khemka  * To add board specific routine, please override parseStdSel.
201139aa4f0SVijay Khemka  */
202139aa4f0SVijay Khemka 
203139aa4f0SVijay Khemka /*Used by decoding ME event*/
204139aa4f0SVijay Khemka std::vector<std::string> nmDomName = {
205139aa4f0SVijay Khemka     "Entire Platform",          "CPU Subsystem",
206139aa4f0SVijay Khemka     "Memory Subsystem",         "HW Protection",
207139aa4f0SVijay Khemka     "High Power I/O subsystem", "Unknown"};
208139aa4f0SVijay Khemka 
209139aa4f0SVijay Khemka /* Default log message for unknown type */
210e39f9393SWilly Tu static void logDefault(uint8_t*, std::string& errLog)
211139aa4f0SVijay Khemka {
212139aa4f0SVijay Khemka     errLog = "Unknown";
213139aa4f0SVijay Khemka }
214139aa4f0SVijay Khemka 
215139aa4f0SVijay Khemka static void logSysEvent(uint8_t* data, std::string& errLog)
216139aa4f0SVijay Khemka {
217139aa4f0SVijay Khemka     if (data[0] == 0xE5)
218139aa4f0SVijay Khemka     {
219139aa4f0SVijay Khemka         errLog = "Cause of Time change - ";
220139aa4f0SVijay Khemka         switch (data[2])
221139aa4f0SVijay Khemka         {
222139aa4f0SVijay Khemka             case 0x00:
223139aa4f0SVijay Khemka                 errLog += "NTP";
224139aa4f0SVijay Khemka                 break;
225139aa4f0SVijay Khemka             case 0x01:
226139aa4f0SVijay Khemka                 errLog += "Host RTL";
227139aa4f0SVijay Khemka                 break;
228139aa4f0SVijay Khemka             case 0x02:
229139aa4f0SVijay Khemka                 errLog += "Set SEL time cmd";
230139aa4f0SVijay Khemka                 break;
231139aa4f0SVijay Khemka             case 0x03:
232139aa4f0SVijay Khemka                 errLog += "Set SEL time UTC offset cmd";
233139aa4f0SVijay Khemka                 break;
234139aa4f0SVijay Khemka             default:
235139aa4f0SVijay Khemka                 errLog += "Unknown";
236139aa4f0SVijay Khemka         }
237139aa4f0SVijay Khemka 
238139aa4f0SVijay Khemka         if (data[1] == 0x00)
239139aa4f0SVijay Khemka             errLog += " - First Time";
240139aa4f0SVijay Khemka         else if (data[1] == 0x80)
241139aa4f0SVijay Khemka             errLog += " - Second Time";
242139aa4f0SVijay Khemka     }
243139aa4f0SVijay Khemka     else
244139aa4f0SVijay Khemka     {
245139aa4f0SVijay Khemka         errLog = "Unknown";
246139aa4f0SVijay Khemka     }
247139aa4f0SVijay Khemka }
248139aa4f0SVijay Khemka 
249139aa4f0SVijay Khemka static void logThermalEvent(uint8_t* data, std::string& errLog)
250139aa4f0SVijay Khemka {
251139aa4f0SVijay Khemka     if (data[0] == 0x1)
252139aa4f0SVijay Khemka     {
253139aa4f0SVijay Khemka         errLog = "Limit Exceeded";
254139aa4f0SVijay Khemka     }
255139aa4f0SVijay Khemka     else
256139aa4f0SVijay Khemka     {
257139aa4f0SVijay Khemka         errLog = "Unknown";
258139aa4f0SVijay Khemka     }
259139aa4f0SVijay Khemka }
260139aa4f0SVijay Khemka 
261139aa4f0SVijay Khemka static void logCritIrq(uint8_t* data, std::string& errLog)
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     if ((data[0] & 0x0F) == 0x0)
282139aa4f0SVijay Khemka     {
283139aa4f0SVijay Khemka         errLog = "System Firmware Error";
284139aa4f0SVijay Khemka     }
285139aa4f0SVijay Khemka     else
286139aa4f0SVijay Khemka     {
287139aa4f0SVijay Khemka         errLog = "Unknown";
288139aa4f0SVijay Khemka     }
289139aa4f0SVijay Khemka 
290139aa4f0SVijay Khemka     if (((data[0] >> 6) & 0x03) == 0x3)
291139aa4f0SVijay Khemka     {
292139aa4f0SVijay Khemka         // TODO: Need to implement IPMI spec based Post Code
293139aa4f0SVijay Khemka         errLog += ", IPMI Post Code";
294139aa4f0SVijay Khemka     }
295139aa4f0SVijay Khemka     else if (((data[0] >> 6) & 0x03) == 0x2)
296139aa4f0SVijay Khemka     {
2972405ae98SPatrick Williams         errLog += ", OEM Post Code 0x" + byteToStr(data[2]) +
2982405ae98SPatrick Williams                   byteToStr(data[1]);
299139aa4f0SVijay Khemka 
300139aa4f0SVijay Khemka         switch ((data[2] << 8) | data[1])
301139aa4f0SVijay Khemka         {
302139aa4f0SVijay Khemka             case 0xA105:
303139aa4f0SVijay Khemka                 errLog += ", BMC Failed (No Response)";
304139aa4f0SVijay Khemka                 break;
305139aa4f0SVijay Khemka             case 0xA106:
306139aa4f0SVijay Khemka                 errLog += ", BMC Failed (Self Test Fail)";
307139aa4f0SVijay Khemka                 break;
308139aa4f0SVijay Khemka             case 0xA10A:
309139aa4f0SVijay Khemka                 errLog += ", System Firmware Corruption Detected";
310139aa4f0SVijay Khemka                 break;
311139aa4f0SVijay Khemka             case 0xA10B:
312139aa4f0SVijay Khemka                 errLog += ", TPM Self-Test FAIL Detected";
313139aa4f0SVijay Khemka         }
314139aa4f0SVijay Khemka     }
315139aa4f0SVijay Khemka }
316139aa4f0SVijay Khemka 
317139aa4f0SVijay Khemka static void logMchChkErr(uint8_t* data, std::string& errLog)
318139aa4f0SVijay Khemka {
319139aa4f0SVijay Khemka     /* TODO: Call add_cri_sel for CRITICAL_IRQ */
320139aa4f0SVijay Khemka     if ((data[0] & 0x0F) == 0x0B)
321139aa4f0SVijay Khemka     {
322139aa4f0SVijay Khemka         errLog = "Uncorrectable";
323139aa4f0SVijay Khemka     }
324139aa4f0SVijay Khemka     else if ((data[0] & 0x0F) == 0x0C)
325139aa4f0SVijay Khemka     {
326139aa4f0SVijay Khemka         errLog = "Correctable";
327139aa4f0SVijay Khemka     }
328139aa4f0SVijay Khemka     else
329139aa4f0SVijay Khemka     {
330139aa4f0SVijay Khemka         errLog = "Unknown";
331139aa4f0SVijay Khemka     }
332139aa4f0SVijay Khemka 
333139aa4f0SVijay Khemka     errLog += ", Machine Check bank Number " + std::to_string(data[1]) +
334139aa4f0SVijay Khemka               ", CPU " + std::to_string(data[2] >> 5) + ", Core " +
335139aa4f0SVijay Khemka               std::to_string(data[2] & 0x1F);
336139aa4f0SVijay Khemka }
337139aa4f0SVijay Khemka 
338139aa4f0SVijay Khemka static void logPcieErr(uint8_t* data, std::string& errLog)
339139aa4f0SVijay Khemka {
340139aa4f0SVijay Khemka     std::stringstream tmp1, tmp2;
341139aa4f0SVijay Khemka     tmp1 << std::hex << std::uppercase << std::setfill('0');
342139aa4f0SVijay Khemka     tmp2 << std::hex << std::uppercase << std::setfill('0');
343139aa4f0SVijay Khemka     tmp1 << " (Bus " << std::setw(2) << (int)(data[2]) << " / Dev "
344139aa4f0SVijay Khemka          << std::setw(2) << (int)(data[1] >> 3) << " / Fun " << std::setw(2)
345139aa4f0SVijay Khemka          << (int)(data[1] & 0x7) << ")";
346139aa4f0SVijay Khemka 
347139aa4f0SVijay Khemka     switch (data[0] & 0xF)
348139aa4f0SVijay Khemka     {
349139aa4f0SVijay Khemka         case 0x4:
350139aa4f0SVijay Khemka             errLog = "PCI PERR" + tmp1.str();
351139aa4f0SVijay Khemka             break;
352139aa4f0SVijay Khemka         case 0x5:
353139aa4f0SVijay Khemka             errLog = "PCI SERR" + tmp1.str();
354139aa4f0SVijay Khemka             break;
355139aa4f0SVijay Khemka         case 0x7:
356139aa4f0SVijay Khemka             errLog = "Correctable" + tmp1.str();
357139aa4f0SVijay Khemka             break;
358139aa4f0SVijay Khemka         case 0x8:
359139aa4f0SVijay Khemka             errLog = "Uncorrectable" + tmp1.str();
360139aa4f0SVijay Khemka             break;
361139aa4f0SVijay Khemka         case 0xA:
362139aa4f0SVijay Khemka             errLog = "Bus Fatal" + tmp1.str();
363139aa4f0SVijay Khemka             break;
364d1194024SVijay Khemka         case 0xD:
365d1194024SVijay Khemka         {
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;
371d1194024SVijay Khemka         case 0xE:
372d1194024SVijay Khemka         {
373139aa4f0SVijay Khemka             uint32_t devId = (uint32_t)data[1] << 8 | (uint32_t)data[2];
374139aa4f0SVijay Khemka             tmp2 << "Device ID: 0x" << std::setw(4) << devId;
375139aa4f0SVijay Khemka             errLog = tmp2.str();
376139aa4f0SVijay Khemka         }
377139aa4f0SVijay Khemka         break;
378139aa4f0SVijay Khemka         case 0xF:
379139aa4f0SVijay Khemka             tmp2 << "Error ID from downstream: 0x" << std::setw(2)
380139aa4f0SVijay Khemka                  << (int)(data[1]) << std::setw(2) << (int)(data[2]);
381139aa4f0SVijay Khemka             errLog = tmp2.str();
382139aa4f0SVijay Khemka             break;
383139aa4f0SVijay Khemka         default:
384139aa4f0SVijay Khemka             errLog = "Unknown";
385139aa4f0SVijay Khemka     }
386139aa4f0SVijay Khemka }
387139aa4f0SVijay Khemka 
388139aa4f0SVijay Khemka static void logIioErr(uint8_t* data, std::string& errLog)
389139aa4f0SVijay Khemka {
390139aa4f0SVijay Khemka     std::vector<std::string> tmpStr = {
391139aa4f0SVijay Khemka         "IRP0", "IRP1", " IIO-Core", "VT-d", "Intel Quick Data",
392139aa4f0SVijay Khemka         "Misc", " DMA", "ITC",       "OTC",  "CI"};
393139aa4f0SVijay Khemka 
394139aa4f0SVijay Khemka     if ((data[0] & 0xF) == 0)
395139aa4f0SVijay Khemka     {
396139aa4f0SVijay Khemka         errLog += "CPU " + std::to_string(data[2] >> 5) + ", Error ID 0x" +
397139aa4f0SVijay Khemka                   byteToStr(data[1]) + " - ";
398139aa4f0SVijay Khemka 
399139aa4f0SVijay Khemka         if ((data[2] & 0xF) <= 0x9)
400139aa4f0SVijay Khemka         {
401139aa4f0SVijay Khemka             errLog += tmpStr[(data[2] & 0xF)];
402139aa4f0SVijay Khemka         }
403139aa4f0SVijay Khemka         else
404139aa4f0SVijay Khemka         {
405139aa4f0SVijay Khemka             errLog += "Reserved";
406139aa4f0SVijay Khemka         }
407139aa4f0SVijay Khemka     }
408139aa4f0SVijay Khemka     else
409139aa4f0SVijay Khemka     {
410139aa4f0SVijay Khemka         errLog = "Unknown";
411139aa4f0SVijay Khemka     }
412139aa4f0SVijay Khemka }
413139aa4f0SVijay Khemka 
414e39f9393SWilly Tu [[maybe_unused]] static void logMemErr(uint8_t* dataPtr, std::string& errLog)
415139aa4f0SVijay Khemka {
416139aa4f0SVijay Khemka     uint8_t snrType = dataPtr[0];
417139aa4f0SVijay Khemka     uint8_t snrNum = dataPtr[1];
418139aa4f0SVijay Khemka     uint8_t* data = &(dataPtr[3]);
419139aa4f0SVijay Khemka 
420139aa4f0SVijay Khemka     /* TODO: add pal_add_cri_sel */
421139aa4f0SVijay Khemka 
422139aa4f0SVijay Khemka     if (snrNum == memoryEccError)
423139aa4f0SVijay Khemka     {
424139aa4f0SVijay Khemka         /* SEL from MEMORY_ECC_ERR Sensor */
425139aa4f0SVijay Khemka         switch (data[0] & 0x0F)
426139aa4f0SVijay Khemka         {
427139aa4f0SVijay Khemka             case 0x0:
428139aa4f0SVijay Khemka                 if (snrType == 0x0C)
429139aa4f0SVijay Khemka                 {
430139aa4f0SVijay Khemka                     errLog = "Correctable";
431139aa4f0SVijay Khemka                 }
432139aa4f0SVijay Khemka                 else if (snrType == 0x10)
433139aa4f0SVijay Khemka                 {
434139aa4f0SVijay Khemka                     errLog = "Correctable ECC error Logging Disabled";
435139aa4f0SVijay Khemka                 }
436139aa4f0SVijay Khemka                 break;
437139aa4f0SVijay Khemka             case 0x1:
438139aa4f0SVijay Khemka                 errLog = "Uncorrectable";
439139aa4f0SVijay Khemka                 break;
440139aa4f0SVijay Khemka             case 0x5:
441139aa4f0SVijay Khemka                 errLog = "Correctable ECC error Logging Limit Disabled";
442139aa4f0SVijay Khemka                 break;
443139aa4f0SVijay Khemka             default:
444139aa4f0SVijay Khemka                 errLog = "Unknown";
445139aa4f0SVijay Khemka         }
446139aa4f0SVijay Khemka     }
447139aa4f0SVijay Khemka     else if (snrNum == memoryErrLogDIS)
448139aa4f0SVijay Khemka     {
449139aa4f0SVijay Khemka         // SEL from MEMORY_ERR_LOG_DIS Sensor
450139aa4f0SVijay Khemka         if ((data[0] & 0x0F) == 0x0)
451139aa4f0SVijay Khemka         {
452139aa4f0SVijay Khemka             errLog = "Correctable Memory Error Logging Disabled";
453139aa4f0SVijay Khemka         }
454139aa4f0SVijay Khemka         else
455139aa4f0SVijay Khemka         {
456139aa4f0SVijay Khemka             errLog = "Unknown";
457139aa4f0SVijay Khemka         }
458139aa4f0SVijay Khemka     }
459139aa4f0SVijay Khemka     else
460139aa4f0SVijay Khemka     {
461139aa4f0SVijay Khemka         errLog = "Unknown";
462139aa4f0SVijay Khemka         return;
463139aa4f0SVijay Khemka     }
464139aa4f0SVijay Khemka 
465139aa4f0SVijay Khemka     /* Common routine for both MEM_ECC_ERR and MEMORY_ERR_LOG_DIS */
466139aa4f0SVijay Khemka 
467139aa4f0SVijay Khemka     errLog += " (DIMM " + byteToStr(data[2]) + ") Logical Rank " +
468139aa4f0SVijay Khemka               std::to_string(data[1] & 0x03);
469139aa4f0SVijay Khemka 
470139aa4f0SVijay Khemka     /* DIMM number (data[2]):
471139aa4f0SVijay Khemka      * Bit[7:5]: Socket number  (Range: 0-7)
472139aa4f0SVijay Khemka      * Bit[4:3]: Channel number (Range: 0-3)
473139aa4f0SVijay Khemka      * Bit[2:0]: DIMM number    (Range: 0-7)
474139aa4f0SVijay Khemka      */
475139aa4f0SVijay Khemka 
476139aa4f0SVijay Khemka     /* TODO: Verify these bits */
477139aa4f0SVijay Khemka     std::string cpuStr = "CPU# " + std::to_string((data[2] & 0xE0) >> 5);
478139aa4f0SVijay Khemka     std::string chStr = "CHN# " + std::to_string((data[2] & 0x18) >> 3);
479139aa4f0SVijay Khemka     std::string dimmStr = "DIMM#" + std::to_string(data[2] & 0x7);
480139aa4f0SVijay Khemka 
481139aa4f0SVijay Khemka     switch ((data[1] & 0xC) >> 2)
482139aa4f0SVijay Khemka     {
483d1194024SVijay Khemka         case 0x0:
484d1194024SVijay Khemka         {
485139aa4f0SVijay Khemka             /* All Info Valid */
486e39f9393SWilly Tu             [[maybe_unused]] uint8_t chnNum = (data[2] & 0x1C) >> 2;
487e39f9393SWilly Tu             [[maybe_unused]] uint8_t dimmNum = data[2] & 0x3;
488139aa4f0SVijay Khemka 
489139aa4f0SVijay Khemka             /* TODO: If critical SEL logging is available, do it */
490139aa4f0SVijay Khemka             if (snrType == 0x0C)
491139aa4f0SVijay Khemka             {
492139aa4f0SVijay Khemka                 if ((data[0] & 0x0F) == 0x0)
493139aa4f0SVijay Khemka                 {
494139aa4f0SVijay Khemka                     /* TODO: add_cri_sel */
495139aa4f0SVijay Khemka                     /* "DIMM"+ 'A'+ chnNum + dimmNum + " ECC err,FRU:1"
496139aa4f0SVijay Khemka                      */
497139aa4f0SVijay Khemka                 }
498139aa4f0SVijay Khemka                 else if ((data[0] & 0x0F) == 0x1)
499139aa4f0SVijay Khemka                 {
500139aa4f0SVijay Khemka                     /* TODO: add_cri_sel */
501139aa4f0SVijay Khemka                     /* "DIMM"+ 'A'+ chnNum + dimmNum + " UECC err,FRU:1"
502139aa4f0SVijay Khemka                      */
503139aa4f0SVijay Khemka                 }
504139aa4f0SVijay Khemka             }
505139aa4f0SVijay Khemka             /* Continue to parse the error into a string. All Info Valid
506139aa4f0SVijay Khemka              */
507139aa4f0SVijay Khemka             errLog += " (" + cpuStr + ", " + chStr + ", " + dimmStr + ")";
508139aa4f0SVijay Khemka         }
509139aa4f0SVijay Khemka 
510139aa4f0SVijay Khemka         break;
511139aa4f0SVijay Khemka         case 0x1:
512139aa4f0SVijay Khemka 
513139aa4f0SVijay Khemka             /* DIMM info not valid */
514139aa4f0SVijay Khemka             errLog += " (" + cpuStr + ", " + chStr + ")";
515139aa4f0SVijay Khemka             break;
516139aa4f0SVijay Khemka         case 0x2:
517139aa4f0SVijay Khemka 
518139aa4f0SVijay Khemka             /* CHN info not valid */
519139aa4f0SVijay Khemka             errLog += " (" + cpuStr + ", " + dimmStr + ")";
520139aa4f0SVijay Khemka             break;
521139aa4f0SVijay Khemka         case 0x3:
522139aa4f0SVijay Khemka 
523139aa4f0SVijay Khemka             /* CPU info not valid */
524139aa4f0SVijay Khemka             errLog += " (" + chStr + ", " + dimmStr + ")";
525139aa4f0SVijay Khemka             break;
526139aa4f0SVijay Khemka     }
527139aa4f0SVijay Khemka }
528139aa4f0SVijay Khemka 
529139aa4f0SVijay Khemka static void logPwrErr(uint8_t* data, std::string& errLog)
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     if (data[0] == 0x0)
552139aa4f0SVijay Khemka     {
553139aa4f0SVijay Khemka         errLog = "IERR/CATERR";
554139aa4f0SVijay Khemka         /* Also try logging to Critial log file, if available */
555139aa4f0SVijay Khemka         /* "IERR,FRU:1 */
556139aa4f0SVijay Khemka     }
557139aa4f0SVijay Khemka     else if (data[0] == 0xB)
558139aa4f0SVijay Khemka     {
559139aa4f0SVijay Khemka         errLog = "MCERR/CATERR";
560139aa4f0SVijay Khemka         /* Also try logging to Critial log file, if available */
561139aa4f0SVijay Khemka         /* "MCERR,FRU:1 */
562139aa4f0SVijay Khemka     }
563139aa4f0SVijay Khemka     else
564139aa4f0SVijay Khemka     {
565139aa4f0SVijay Khemka         errLog = "Unknown";
566139aa4f0SVijay Khemka     }
567139aa4f0SVijay Khemka }
568139aa4f0SVijay Khemka 
569139aa4f0SVijay Khemka static void logDimmHot(uint8_t* data, std::string& errLog)
570139aa4f0SVijay Khemka {
571139aa4f0SVijay Khemka     if ((data[0] << 16 | data[1] << 8 | data[2]) == 0x01FFFF)
572139aa4f0SVijay Khemka     {
573139aa4f0SVijay Khemka         errLog = "SOC MEMHOT";
574139aa4f0SVijay Khemka     }
575139aa4f0SVijay Khemka     else
576139aa4f0SVijay Khemka     {
577139aa4f0SVijay Khemka         errLog = "Unknown";
578139aa4f0SVijay Khemka         /* Also try logging to Critial log file, if available */
579139aa4f0SVijay Khemka         /* ""CPU_DIMM_HOT %s,FRU:1" */
580139aa4f0SVijay Khemka     }
581139aa4f0SVijay Khemka }
582139aa4f0SVijay Khemka 
583139aa4f0SVijay Khemka static void logSwNMI(uint8_t* data, std::string& errLog)
584139aa4f0SVijay Khemka {
585139aa4f0SVijay Khemka     if ((data[0] << 16 | data[1] << 8 | data[2]) == 0x03FFFF)
586139aa4f0SVijay Khemka     {
587139aa4f0SVijay Khemka         errLog = "Software NMI";
588139aa4f0SVijay Khemka     }
589139aa4f0SVijay Khemka     else
590139aa4f0SVijay Khemka     {
591139aa4f0SVijay Khemka         errLog = "Unknown SW NMI";
592139aa4f0SVijay Khemka     }
593139aa4f0SVijay Khemka }
594139aa4f0SVijay Khemka 
595139aa4f0SVijay Khemka static void logCPUThermalSts(uint8_t* data, std::string& errLog)
596139aa4f0SVijay Khemka {
597139aa4f0SVijay Khemka     switch (data[0])
598139aa4f0SVijay Khemka     {
599139aa4f0SVijay Khemka         case 0x0:
600139aa4f0SVijay Khemka             errLog = "CPU Critical Temperature";
601139aa4f0SVijay Khemka             break;
602139aa4f0SVijay Khemka         case 0x1:
603139aa4f0SVijay Khemka             errLog = "PROCHOT#";
604139aa4f0SVijay Khemka             break;
605139aa4f0SVijay Khemka         case 0x2:
606139aa4f0SVijay Khemka             errLog = "TCC Activation";
607139aa4f0SVijay Khemka             break;
608139aa4f0SVijay Khemka         default:
609139aa4f0SVijay Khemka             errLog = "Unknown";
610139aa4f0SVijay Khemka     }
611139aa4f0SVijay Khemka }
612139aa4f0SVijay Khemka 
613139aa4f0SVijay Khemka static void logMEPwrState(uint8_t* data, std::string& errLog)
614139aa4f0SVijay Khemka {
615139aa4f0SVijay Khemka     switch (data[0])
616139aa4f0SVijay Khemka     {
617139aa4f0SVijay Khemka         case 0:
618139aa4f0SVijay Khemka             errLog = "RUNNING";
619139aa4f0SVijay Khemka             break;
620139aa4f0SVijay Khemka         case 2:
621139aa4f0SVijay Khemka             errLog = "POWER_OFF";
622139aa4f0SVijay Khemka             break;
623139aa4f0SVijay Khemka         default:
624139aa4f0SVijay Khemka             errLog = "Unknown[" + std::to_string(data[0]) + "]";
625139aa4f0SVijay Khemka             break;
626139aa4f0SVijay Khemka     }
627139aa4f0SVijay Khemka }
628139aa4f0SVijay Khemka 
629139aa4f0SVijay Khemka static void logSPSFwHealth(uint8_t* data, std::string& errLog)
630139aa4f0SVijay Khemka {
631139aa4f0SVijay Khemka     if ((data[0] & 0x0F) == 0x00)
632139aa4f0SVijay Khemka     {
633139aa4f0SVijay Khemka         const std::vector<std::string> tmpStr = {
634139aa4f0SVijay Khemka             "Recovery GPIO forced",
635139aa4f0SVijay Khemka             "Image execution failed",
636139aa4f0SVijay Khemka             "Flash erase error",
637139aa4f0SVijay Khemka             "Flash state information",
638139aa4f0SVijay Khemka             "Internal error",
639139aa4f0SVijay Khemka             "BMC did not respond",
640139aa4f0SVijay Khemka             "Direct Flash update",
641139aa4f0SVijay Khemka             "Manufacturing error",
642139aa4f0SVijay Khemka             "Automatic Restore to Factory Presets",
643139aa4f0SVijay Khemka             "Firmware Exception",
644139aa4f0SVijay Khemka             "Flash Wear-Out Protection Warning",
645139aa4f0SVijay Khemka             "Unknown",
646139aa4f0SVijay Khemka             "Unknown",
647139aa4f0SVijay Khemka             "DMI interface error",
648139aa4f0SVijay Khemka             "MCTP interface error",
649139aa4f0SVijay Khemka             "Auto-configuration finished",
650139aa4f0SVijay Khemka             "Unsupported Segment Defined Feature",
651139aa4f0SVijay Khemka             "Unknown",
652139aa4f0SVijay Khemka             "CPU Debug Capability Disabled",
653139aa4f0SVijay Khemka             "UMA operation error"};
654139aa4f0SVijay Khemka 
655139aa4f0SVijay Khemka         if (data[1] < 0x14)
656139aa4f0SVijay Khemka         {
657139aa4f0SVijay Khemka             errLog = tmpStr[data[1]];
658139aa4f0SVijay Khemka         }
659139aa4f0SVijay Khemka         else
660139aa4f0SVijay Khemka         {
661139aa4f0SVijay Khemka             errLog = "Unknown";
662139aa4f0SVijay Khemka         }
663139aa4f0SVijay Khemka     }
664139aa4f0SVijay Khemka     else if ((data[0] & 0x0F) == 0x01)
665139aa4f0SVijay Khemka     {
666139aa4f0SVijay Khemka         errLog = "SMBus link failure";
667139aa4f0SVijay Khemka     }
668139aa4f0SVijay Khemka     else
669139aa4f0SVijay Khemka     {
670139aa4f0SVijay Khemka         errLog = "Unknown";
671139aa4f0SVijay Khemka     }
672139aa4f0SVijay Khemka }
673139aa4f0SVijay Khemka 
674139aa4f0SVijay Khemka static void logNmExcA(uint8_t* data, std::string& errLog)
675139aa4f0SVijay Khemka {
676139aa4f0SVijay Khemka     /*NM4.0 #550710, Revision 1.95, and turn to p.155*/
677139aa4f0SVijay Khemka     if (data[0] == 0xA8)
678139aa4f0SVijay Khemka     {
679139aa4f0SVijay Khemka         errLog = "Policy Correction Time Exceeded";
680139aa4f0SVijay Khemka     }
681139aa4f0SVijay Khemka     else
682139aa4f0SVijay Khemka     {
683139aa4f0SVijay Khemka         errLog = "Unknown";
684139aa4f0SVijay Khemka     }
685139aa4f0SVijay Khemka }
686139aa4f0SVijay Khemka 
687139aa4f0SVijay Khemka static void logPCHThermal(uint8_t* data, std::string& errLog)
688139aa4f0SVijay Khemka {
689139aa4f0SVijay Khemka     const std::vector<std::string> thresEvtName = {"Lower Non-critical",
690139aa4f0SVijay Khemka                                                    "Unknown",
691139aa4f0SVijay Khemka                                                    "Lower Critical",
692139aa4f0SVijay Khemka                                                    "Unknown",
693139aa4f0SVijay Khemka                                                    "Lower Non-recoverable",
694139aa4f0SVijay Khemka                                                    "Unknown",
695139aa4f0SVijay Khemka                                                    "Unknown",
696139aa4f0SVijay Khemka                                                    "Upper Non-critical",
697139aa4f0SVijay Khemka                                                    "Unknown",
698139aa4f0SVijay Khemka                                                    "Upper Critical",
699139aa4f0SVijay Khemka                                                    "Unknown",
700139aa4f0SVijay Khemka                                                    "Upper Non-recoverable"};
701139aa4f0SVijay Khemka 
702139aa4f0SVijay Khemka     if ((data[0] & 0x0f) < 12)
703139aa4f0SVijay Khemka     {
704139aa4f0SVijay Khemka         errLog = thresEvtName[(data[0] & 0x0f)];
705139aa4f0SVijay Khemka     }
706139aa4f0SVijay Khemka     else
707139aa4f0SVijay Khemka     {
708139aa4f0SVijay Khemka         errLog = "Unknown";
709139aa4f0SVijay Khemka     }
710139aa4f0SVijay Khemka 
711139aa4f0SVijay Khemka     errLog += ", curr_val: " + std::to_string(data[1]) +
712139aa4f0SVijay Khemka               " C, thresh_val: " + std::to_string(data[2]) + " C";
713139aa4f0SVijay Khemka }
714139aa4f0SVijay Khemka 
715139aa4f0SVijay Khemka static void logNmHealth(uint8_t* data, std::string& errLog)
716139aa4f0SVijay Khemka {
717139aa4f0SVijay Khemka     std::vector<std::string> nmErrType = {
718139aa4f0SVijay Khemka         "Unknown",
719139aa4f0SVijay Khemka         "Unknown",
720139aa4f0SVijay Khemka         "Unknown",
721139aa4f0SVijay Khemka         "Unknown",
722139aa4f0SVijay Khemka         "Unknown",
723139aa4f0SVijay Khemka         "Unknown",
724139aa4f0SVijay Khemka         "Unknown",
725139aa4f0SVijay Khemka         "Extended Telemetry Device Reading Failure",
726139aa4f0SVijay Khemka         "Outlet Temperature Reading Failure",
727139aa4f0SVijay Khemka         "Volumetric Airflow Reading Failure",
728139aa4f0SVijay Khemka         "Policy Misconfiguration",
729139aa4f0SVijay Khemka         "Power Sensor Reading Failure",
730139aa4f0SVijay Khemka         "Inlet Temperature Reading Failure",
731139aa4f0SVijay Khemka         "Host Communication Error",
732139aa4f0SVijay Khemka         "Real-time Clock Synchronization Failure",
733139aa4f0SVijay Khemka         "Platform Shutdown Initiated by Intel NM Policy",
734139aa4f0SVijay Khemka         "Unknown"};
735139aa4f0SVijay Khemka     uint8_t nmTypeIdx = (data[0] & 0xf);
736139aa4f0SVijay Khemka     uint8_t domIdx = (data[1] & 0xf);
737139aa4f0SVijay Khemka     uint8_t errIdx = ((data[1] >> 4) & 0xf);
738139aa4f0SVijay Khemka 
739139aa4f0SVijay Khemka     if (nmTypeIdx == 2)
740139aa4f0SVijay Khemka     {
741139aa4f0SVijay Khemka         errLog = "SensorIntelNM";
742139aa4f0SVijay Khemka     }
743139aa4f0SVijay Khemka     else
744139aa4f0SVijay Khemka     {
745139aa4f0SVijay Khemka         errLog = "Unknown";
746139aa4f0SVijay Khemka     }
747139aa4f0SVijay Khemka 
748139aa4f0SVijay Khemka     errLog += ", Domain:" + nmDomName[domIdx] +
749139aa4f0SVijay Khemka               ", ErrType:" + nmErrType[errIdx] + ", Err:0x" +
750139aa4f0SVijay Khemka               byteToStr(data[2]);
751139aa4f0SVijay Khemka }
752139aa4f0SVijay Khemka 
753139aa4f0SVijay Khemka static void logNmCap(uint8_t* data, std::string& errLog)
754139aa4f0SVijay Khemka {
755139aa4f0SVijay Khemka     const std::vector<std::string> nmCapStsStr = {"Not Available", "Available"};
756139aa4f0SVijay Khemka     if (data[0] & 0x7) // BIT1=policy, BIT2=monitoring, BIT3=pwr
757139aa4f0SVijay Khemka                        // limit and the others are reserved
758139aa4f0SVijay Khemka     {
759139aa4f0SVijay Khemka         errLog = "PolicyInterface:" + nmCapStsStr[BIT(data[0], 0)] +
760139aa4f0SVijay Khemka                  ",Monitoring:" + nmCapStsStr[BIT(data[0], 1)] +
761139aa4f0SVijay Khemka                  ",PowerLimit:" + nmCapStsStr[BIT(data[0], 2)];
762139aa4f0SVijay Khemka     }
763139aa4f0SVijay Khemka     else
764139aa4f0SVijay Khemka     {
765139aa4f0SVijay Khemka         errLog = "Unknown";
766139aa4f0SVijay Khemka     }
767139aa4f0SVijay Khemka }
768139aa4f0SVijay Khemka 
769139aa4f0SVijay Khemka static void logNmThreshold(uint8_t* data, std::string& errLog)
770139aa4f0SVijay Khemka {
771139aa4f0SVijay Khemka     uint8_t thresNum = (data[0] & 0x3);
772139aa4f0SVijay Khemka     uint8_t domIdx = (data[1] & 0xf);
773139aa4f0SVijay Khemka     uint8_t polId = data[2];
774139aa4f0SVijay Khemka     uint8_t polEvtIdx = BIT(data[0], 3);
775139aa4f0SVijay Khemka     const std::vector<std::string> polEvtStr = {
776139aa4f0SVijay Khemka         "Threshold Exceeded", "Policy Correction Time Exceeded"};
777139aa4f0SVijay Khemka 
778139aa4f0SVijay Khemka     errLog = "Threshold Number:" + std::to_string(thresNum) + "-" +
779139aa4f0SVijay Khemka              polEvtStr[polEvtIdx] + ", Domain:" + nmDomName[domIdx] +
780139aa4f0SVijay Khemka              ", PolicyID:0x" + byteToStr(polId);
781139aa4f0SVijay Khemka }
782139aa4f0SVijay Khemka 
783139aa4f0SVijay Khemka static void logPwrThreshold(uint8_t* data, std::string& errLog)
784139aa4f0SVijay Khemka {
785139aa4f0SVijay Khemka     if (data[0] == 0x00)
786139aa4f0SVijay Khemka     {
787139aa4f0SVijay Khemka         errLog = "Limit Not Exceeded";
788139aa4f0SVijay Khemka     }
789139aa4f0SVijay Khemka     else if (data[0] == 0x01)
790139aa4f0SVijay Khemka     {
791139aa4f0SVijay Khemka         errLog = "Limit Exceeded";
792139aa4f0SVijay Khemka     }
793139aa4f0SVijay Khemka     else
794139aa4f0SVijay Khemka     {
795139aa4f0SVijay Khemka         errLog = "Unknown";
796139aa4f0SVijay Khemka     }
797139aa4f0SVijay Khemka }
798139aa4f0SVijay Khemka 
799139aa4f0SVijay Khemka static void logMSMI(uint8_t* data, std::string& errLog)
800139aa4f0SVijay Khemka {
801139aa4f0SVijay Khemka     if (data[0] == 0x0)
802139aa4f0SVijay Khemka     {
803139aa4f0SVijay Khemka         errLog = "IERR/MSMI";
804139aa4f0SVijay Khemka     }
805139aa4f0SVijay Khemka     else if (data[0] == 0x0B)
806139aa4f0SVijay Khemka     {
807139aa4f0SVijay Khemka         errLog = "MCERR/MSMI";
808139aa4f0SVijay Khemka     }
809139aa4f0SVijay Khemka     else
810139aa4f0SVijay Khemka     {
811139aa4f0SVijay Khemka         errLog = "Unknown";
812139aa4f0SVijay Khemka     }
813139aa4f0SVijay Khemka }
814139aa4f0SVijay Khemka 
815139aa4f0SVijay Khemka static void logHprWarn(uint8_t* data, std::string& errLog)
816139aa4f0SVijay Khemka {
817139aa4f0SVijay Khemka     if (data[2] == 0x01)
818139aa4f0SVijay Khemka     {
819139aa4f0SVijay Khemka         if (data[1] == 0xFF)
820139aa4f0SVijay Khemka         {
821139aa4f0SVijay Khemka             errLog = "Infinite Time";
822139aa4f0SVijay Khemka         }
823139aa4f0SVijay Khemka         else
824139aa4f0SVijay Khemka         {
825139aa4f0SVijay Khemka             errLog = std::to_string(data[1]) + " minutes";
826139aa4f0SVijay Khemka         }
827139aa4f0SVijay Khemka     }
828139aa4f0SVijay Khemka     else
829139aa4f0SVijay Khemka     {
830139aa4f0SVijay Khemka         errLog = "Unknown";
831139aa4f0SVijay Khemka     }
832139aa4f0SVijay Khemka }
833139aa4f0SVijay Khemka 
834139aa4f0SVijay Khemka static const boost::container::flat_map<
835139aa4f0SVijay Khemka     uint8_t,
836139aa4f0SVijay Khemka     std::pair<std::string, std::function<void(uint8_t*, std::string&)>>>
837139aa4f0SVijay Khemka     sensorNameTable = {{0xE9, {"SYSTEM_EVENT", logSysEvent}},
838139aa4f0SVijay Khemka                        {0x7D, {"THERM_THRESH_EVT", logThermalEvent}},
839139aa4f0SVijay Khemka                        {0xAA, {"BUTTON", logDefault}},
840139aa4f0SVijay Khemka                        {0xAB, {"POWER_STATE", logDefault}},
841139aa4f0SVijay Khemka                        {0xEA, {"CRITICAL_IRQ", logCritIrq}},
842139aa4f0SVijay Khemka                        {0x2B, {"POST_ERROR", logPostErr}},
843139aa4f0SVijay Khemka                        {0x40, {"MACHINE_CHK_ERR", logMchChkErr}},
844139aa4f0SVijay Khemka                        {0x41, {"PCIE_ERR", logPcieErr}},
845139aa4f0SVijay Khemka                        {0x43, {"IIO_ERR", logIioErr}},
846139aa4f0SVijay Khemka                        {0X63, {"MEMORY_ECC_ERR", logDefault}},
847139aa4f0SVijay Khemka                        {0X87, {"MEMORY_ERR_LOG_DIS", logDefault}},
848139aa4f0SVijay Khemka                        {0X51, {"PROCHOT_EXT", logDefault}},
849139aa4f0SVijay Khemka                        {0X56, {"PWR_ERR", logPwrErr}},
850139aa4f0SVijay Khemka                        {0xE6, {"CATERR_A", logCatErr}},
851139aa4f0SVijay Khemka                        {0xEB, {"CATERR_B", logCatErr}},
852139aa4f0SVijay Khemka                        {0xB3, {"CPU_DIMM_HOT", logDimmHot}},
853139aa4f0SVijay Khemka                        {0x90, {"SOFTWARE_NMI", logSwNMI}},
854139aa4f0SVijay Khemka                        {0x1C, {"CPU0_THERM_STATUS", logCPUThermalSts}},
855139aa4f0SVijay Khemka                        {0x1D, {"CPU1_THERM_STATUS", logCPUThermalSts}},
856139aa4f0SVijay Khemka                        {0x16, {"ME_POWER_STATE", logMEPwrState}},
857139aa4f0SVijay Khemka                        {0x17, {"SPS_FW_HEALTH", logSPSFwHealth}},
858139aa4f0SVijay Khemka                        {0x18, {"NM_EXCEPTION_A", logNmExcA}},
859139aa4f0SVijay Khemka                        {0x08, {"PCH_THERM_THRESHOLD", logPCHThermal}},
860139aa4f0SVijay Khemka                        {0x19, {"NM_HEALTH", logNmHealth}},
861139aa4f0SVijay Khemka                        {0x1A, {"NM_CAPABILITIES", logNmCap}},
862139aa4f0SVijay Khemka                        {0x1B, {"NM_THRESHOLD", logNmThreshold}},
863139aa4f0SVijay Khemka                        {0x3B, {"PWR_THRESH_EVT", logPwrThreshold}},
864139aa4f0SVijay Khemka                        {0xE7, {"MSMI", logMSMI}},
865139aa4f0SVijay Khemka                        {0xC5, {"HPR_WARNING", logHprWarn}}};
866139aa4f0SVijay Khemka 
867139aa4f0SVijay Khemka static void parseSelHelper(StdSELEntry* data, std::string& errStr)
868139aa4f0SVijay Khemka {
869139aa4f0SVijay Khemka     /* Check if sensor type is OS_BOOT (0x1f) */
870139aa4f0SVijay Khemka     if (data->sensorType == 0x1F)
871139aa4f0SVijay Khemka     {
872139aa4f0SVijay Khemka         /* OS_BOOT used by OS */
873139aa4f0SVijay Khemka         switch (data->eventData1 & 0xF)
874139aa4f0SVijay Khemka         {
875139aa4f0SVijay Khemka             case 0x07:
876139aa4f0SVijay Khemka                 errStr = "Base OS/Hypervisor Installation started";
877139aa4f0SVijay Khemka                 break;
878139aa4f0SVijay Khemka             case 0x08:
879139aa4f0SVijay Khemka                 errStr = "Base OS/Hypervisor Installation completed";
880139aa4f0SVijay Khemka                 break;
881139aa4f0SVijay Khemka             case 0x09:
882139aa4f0SVijay Khemka                 errStr = "Base OS/Hypervisor Installation aborted";
883139aa4f0SVijay Khemka                 break;
884139aa4f0SVijay Khemka             case 0x0A:
885139aa4f0SVijay Khemka                 errStr = "Base OS/Hypervisor Installation failed";
886139aa4f0SVijay Khemka                 break;
887139aa4f0SVijay Khemka             default:
888139aa4f0SVijay Khemka                 errStr = "Unknown";
889139aa4f0SVijay Khemka         }
890139aa4f0SVijay Khemka         return;
891139aa4f0SVijay Khemka     }
892139aa4f0SVijay Khemka 
893139aa4f0SVijay Khemka     auto findSensorName = sensorNameTable.find(data->sensorNum);
894139aa4f0SVijay Khemka     if (findSensorName == sensorNameTable.end())
895139aa4f0SVijay Khemka     {
896139aa4f0SVijay Khemka         errStr = "Unknown";
897139aa4f0SVijay Khemka         return;
898139aa4f0SVijay Khemka     }
899139aa4f0SVijay Khemka     else
900139aa4f0SVijay Khemka     {
901139aa4f0SVijay Khemka         switch (data->sensorNum)
902139aa4f0SVijay Khemka         {
903139aa4f0SVijay Khemka             /* logMemErr function needs data from sensor type */
904139aa4f0SVijay Khemka             case memoryEccError:
905139aa4f0SVijay Khemka             case memoryErrLogDIS:
906139aa4f0SVijay Khemka                 findSensorName->second.second(&(data->sensorType), errStr);
907139aa4f0SVijay Khemka                 break;
908139aa4f0SVijay Khemka             /* Other sensor function needs only event data for parsing */
909139aa4f0SVijay Khemka             default:
910139aa4f0SVijay Khemka                 findSensorName->second.second(&(data->eventData1), errStr);
911139aa4f0SVijay Khemka         }
912139aa4f0SVijay Khemka     }
913139aa4f0SVijay Khemka 
914139aa4f0SVijay Khemka     if (((data->eventData3 & 0x80) >> 7) == 0)
915139aa4f0SVijay Khemka     {
916139aa4f0SVijay Khemka         errStr += " Assertion";
917139aa4f0SVijay Khemka     }
918139aa4f0SVijay Khemka     else
919139aa4f0SVijay Khemka     {
920139aa4f0SVijay Khemka         errStr += " Deassertion";
921139aa4f0SVijay Khemka     }
922139aa4f0SVijay Khemka }
923139aa4f0SVijay Khemka 
924c056dc00SManikandan Elumalai static void parseDimmPhyloc(StdSELEntry* data, std::string& errStr)
925c056dc00SManikandan Elumalai {
926c056dc00SManikandan Elumalai     // Log when " All info available"
927c056dc00SManikandan Elumalai     uint8_t chNum = (data->eventData3 & 0x18) >> 3;
928c056dc00SManikandan Elumalai     uint8_t dimmNum = data->eventData3 & 0x7;
929c056dc00SManikandan Elumalai     uint8_t rankNum = data->eventData2 & 0x03;
930c056dc00SManikandan Elumalai     uint8_t nodeNum = (data->eventData3 & 0xE0) >> 5;
931c056dc00SManikandan Elumalai 
932c056dc00SManikandan Elumalai     if (chNum == 3 && dimmNum == 0)
933c056dc00SManikandan Elumalai     {
934c056dc00SManikandan Elumalai         errStr += " Node: " + std::to_string(nodeNum) + "," +
935c056dc00SManikandan Elumalai                   " Card: " + std::to_string(chNum) + "," +
936c056dc00SManikandan Elumalai                   " Module: " + std::to_string(dimmNum) + "," +
937c056dc00SManikandan Elumalai                   " Rank Number: " + std::to_string(rankNum) + "," +
938c056dc00SManikandan Elumalai                   "  Location: DIMM A0";
939c056dc00SManikandan Elumalai     }
940c056dc00SManikandan Elumalai     else if (chNum == 2 && dimmNum == 0)
941c056dc00SManikandan Elumalai     {
942c056dc00SManikandan Elumalai         errStr += " Node: " + std::to_string(nodeNum) + "," +
943c056dc00SManikandan Elumalai                   " Card: " + std::to_string(chNum) + "," +
944c056dc00SManikandan Elumalai                   " Module: " + std::to_string(dimmNum) + "," +
945c056dc00SManikandan Elumalai                   " Rank Number: " + std::to_string(rankNum) + "," +
946c056dc00SManikandan Elumalai                   " Location: DIMM B0";
947c056dc00SManikandan Elumalai     }
948c056dc00SManikandan Elumalai     else if (chNum == 4 && dimmNum == 0)
949c056dc00SManikandan Elumalai     {
950c056dc00SManikandan Elumalai         errStr += " Node: " + std::to_string(nodeNum) + "," +
951c056dc00SManikandan Elumalai                   " Card: " + std::to_string(chNum) + "," +
952c056dc00SManikandan Elumalai                   " Module: " + std::to_string(dimmNum) + "," +
953c056dc00SManikandan Elumalai                   " Rank Number: " + std::to_string(rankNum) + "," +
954c056dc00SManikandan Elumalai                   " Location: DIMM C0 ";
955c056dc00SManikandan Elumalai     }
956c056dc00SManikandan Elumalai     else if (chNum == 5 && dimmNum == 0)
957c056dc00SManikandan Elumalai     {
958c056dc00SManikandan Elumalai         errStr += " Node: " + std::to_string(nodeNum) + "," +
959c056dc00SManikandan Elumalai                   " Card: " + std::to_string(chNum) + "," +
960c056dc00SManikandan Elumalai                   " Module: " + std::to_string(dimmNum) + "," +
961c056dc00SManikandan Elumalai                   " Rank Number: " + std::to_string(rankNum) + "," +
962c056dc00SManikandan Elumalai                   " Location: DIMM D0";
963c056dc00SManikandan Elumalai     }
964c056dc00SManikandan Elumalai     else
965c056dc00SManikandan Elumalai     {
966c056dc00SManikandan Elumalai         errStr += " Node: " + std::to_string(nodeNum) + "," +
967c056dc00SManikandan Elumalai                   " Card: " + std::to_string(chNum) + "," +
968c056dc00SManikandan Elumalai                   " Module: " + std::to_string(dimmNum) + "," +
969c056dc00SManikandan Elumalai                   " Rank Number: " + std::to_string(rankNum) + "," +
970c056dc00SManikandan Elumalai                   " Location: DIMM Unknow";
971c056dc00SManikandan Elumalai     }
972c056dc00SManikandan Elumalai }
973c056dc00SManikandan Elumalai 
974f36f345fSVijay Khemka static void parseStdSel(StdSELEntry* data, std::string& errStr)
975f36f345fSVijay Khemka {
976f36f345fSVijay Khemka     std::stringstream tmpStream;
977f36f345fSVijay Khemka     tmpStream << std::hex << std::uppercase;
978f36f345fSVijay Khemka 
979f36f345fSVijay Khemka     /* TODO: add pal_add_cri_sel */
980f36f345fSVijay Khemka     switch (data->sensorNum)
981f36f345fSVijay Khemka     {
982f36f345fSVijay Khemka         case memoryEccError:
983f36f345fSVijay Khemka             switch (data->eventData1 & 0x0F)
984f36f345fSVijay Khemka             {
985f36f345fSVijay Khemka                 case 0x00:
986f36f345fSVijay Khemka                     errStr = "Correctable";
987f36f345fSVijay Khemka                     tmpStream << "DIMM" << std::setw(2) << std::setfill('0')
988f36f345fSVijay Khemka                               << data->eventData3 << " ECC err";
989c056dc00SManikandan Elumalai                     parseDimmPhyloc(data, errStr);
990f36f345fSVijay Khemka                     break;
991f36f345fSVijay Khemka                 case 0x01:
992f36f345fSVijay Khemka                     errStr = "Uncorrectable";
993f36f345fSVijay Khemka                     tmpStream << "DIMM" << std::setw(2) << std::setfill('0')
994f36f345fSVijay Khemka                               << data->eventData3 << " UECC err";
995c056dc00SManikandan Elumalai                     parseDimmPhyloc(data, errStr);
996f36f345fSVijay Khemka                     break;
997f36f345fSVijay Khemka                 case 0x02:
998f36f345fSVijay Khemka                     errStr = "Parity";
999f36f345fSVijay Khemka                     break;
1000f36f345fSVijay Khemka                 case 0x05:
1001f36f345fSVijay Khemka                     errStr = "Correctable ECC error Logging Limit Reached";
1002f36f345fSVijay Khemka                     break;
1003f36f345fSVijay Khemka                 default:
1004f36f345fSVijay Khemka                     errStr = "Unknown";
1005f36f345fSVijay Khemka             }
1006f36f345fSVijay Khemka             break;
1007f36f345fSVijay Khemka         case memoryErrLogDIS:
1008f36f345fSVijay Khemka             if ((data->eventData1 & 0x0F) == 0)
1009f36f345fSVijay Khemka             {
1010f36f345fSVijay Khemka                 errStr = "Correctable Memory Error Logging Disabled";
1011f36f345fSVijay Khemka             }
1012f36f345fSVijay Khemka             else
1013f36f345fSVijay Khemka             {
1014f36f345fSVijay Khemka                 errStr = "Unknown";
1015f36f345fSVijay Khemka             }
1016f36f345fSVijay Khemka             break;
1017f36f345fSVijay Khemka         default:
1018139aa4f0SVijay Khemka             parseSelHelper(data, errStr);
1019f36f345fSVijay Khemka             return;
1020f36f345fSVijay Khemka     }
1021f36f345fSVijay Khemka 
1022f36f345fSVijay Khemka     errStr += " (DIMM " + std::to_string(data->eventData3) + ")";
1023f36f345fSVijay Khemka     errStr += " Logical Rank " + std::to_string(data->eventData2 & 0x03);
1024f36f345fSVijay Khemka 
1025f36f345fSVijay Khemka     switch ((data->eventData2 & 0x0C) >> 2)
1026f36f345fSVijay Khemka     {
1027f36f345fSVijay Khemka         case 0x00:
1028f36f345fSVijay Khemka             // Ignore when " All info available"
1029f36f345fSVijay Khemka             break;
1030f36f345fSVijay Khemka         case 0x01:
1031f36f345fSVijay Khemka             errStr += " DIMM info not valid";
1032f36f345fSVijay Khemka             break;
1033f36f345fSVijay Khemka         case 0x02:
1034f36f345fSVijay Khemka             errStr += " CHN info not valid";
1035f36f345fSVijay Khemka             break;
1036f36f345fSVijay Khemka         case 0x03:
1037f36f345fSVijay Khemka             errStr += " CPU info not valid";
1038f36f345fSVijay Khemka             break;
1039f36f345fSVijay Khemka         default:
1040f36f345fSVijay Khemka             errStr += " Unknown";
1041f36f345fSVijay Khemka     }
1042f36f345fSVijay Khemka 
1043f36f345fSVijay Khemka     if (((data->eventType & 0x80) >> 7) == 0)
1044f36f345fSVijay Khemka     {
1045f36f345fSVijay Khemka         errStr += " Assertion";
1046f36f345fSVijay Khemka     }
1047f36f345fSVijay Khemka     else
1048f36f345fSVijay Khemka     {
1049f36f345fSVijay Khemka         errStr += " Deassertion";
1050f36f345fSVijay Khemka     }
1051f36f345fSVijay Khemka 
1052f36f345fSVijay Khemka     return;
1053f36f345fSVijay Khemka }
1054f36f345fSVijay Khemka 
1055f36f345fSVijay Khemka static void parseOemSel(TsOemSELEntry* data, std::string& errStr)
1056f36f345fSVijay Khemka {
1057f36f345fSVijay Khemka     std::stringstream tmpStream;
1058f36f345fSVijay Khemka     tmpStream << std::hex << std::uppercase << std::setfill('0');
1059f36f345fSVijay Khemka 
1060f36f345fSVijay Khemka     switch (data->recordType)
1061f36f345fSVijay Khemka     {
1062f36f345fSVijay Khemka         case 0xC0:
1063f36f345fSVijay Khemka             tmpStream << "VID:0x" << std::setw(2) << (int)data->oemData[1]
1064f36f345fSVijay Khemka                       << std::setw(2) << (int)data->oemData[0] << " DID:0x"
1065f36f345fSVijay Khemka                       << std::setw(2) << (int)data->oemData[3] << std::setw(2)
1066f36f345fSVijay Khemka                       << (int)data->oemData[2] << " Slot:0x" << std::setw(2)
1067f36f345fSVijay Khemka                       << (int)data->oemData[4] << " Error ID:0x" << std::setw(2)
1068f36f345fSVijay Khemka                       << (int)data->oemData[5];
1069f36f345fSVijay Khemka             break;
1070f36f345fSVijay Khemka         case 0xC2:
1071f36f345fSVijay Khemka             tmpStream << "Extra info:0x" << std::setw(2)
1072f36f345fSVijay Khemka                       << (int)data->oemData[1] << " MSCOD:0x" << std::setw(2)
1073f36f345fSVijay Khemka                       << (int)data->oemData[3] << std::setw(2)
1074f36f345fSVijay Khemka                       << (int)data->oemData[2] << " MCACOD:0x" << std::setw(2)
1075f36f345fSVijay Khemka                       << (int)data->oemData[5] << std::setw(2)
1076f36f345fSVijay Khemka                       << (int)data->oemData[4];
1077f36f345fSVijay Khemka             break;
1078f36f345fSVijay Khemka         case 0xC3:
1079f36f345fSVijay Khemka             int bank = (data->oemData[1] & 0xf0) >> 4;
1080f36f345fSVijay Khemka             int col = ((data->oemData[1] & 0x0f) << 8) | data->oemData[2];
1081f36f345fSVijay Khemka 
1082f36f345fSVijay Khemka             tmpStream << "Fail Device:0x" << std::setw(2)
1083f36f345fSVijay Khemka                       << (int)data->oemData[0] << " Bank:0x" << std::setw(2)
1084f36f345fSVijay Khemka                       << bank << " Column:0x" << std::setw(2) << col
1085f36f345fSVijay Khemka                       << " Failed Row:0x" << std::setw(2)
1086f36f345fSVijay Khemka                       << (int)data->oemData[3] << std::setw(2)
1087f36f345fSVijay Khemka                       << (int)data->oemData[4] << std::setw(2)
1088f36f345fSVijay Khemka                       << (int)data->oemData[5];
1089f36f345fSVijay Khemka     }
1090f36f345fSVijay Khemka 
1091f36f345fSVijay Khemka     errStr = tmpStream.str();
1092f36f345fSVijay Khemka 
1093f36f345fSVijay Khemka     return;
1094f36f345fSVijay Khemka }
1095f36f345fSVijay Khemka 
109634a875f3SVijay Khemka static void parseOemUnifiedSel(NtsOemSELEntry* data, std::string& errStr)
109734a875f3SVijay Khemka {
109834a875f3SVijay Khemka     uint8_t* ptr = data->oemData;
109934a875f3SVijay Khemka     int genInfo = ptr[0];
110034a875f3SVijay Khemka     int errType = genInfo & 0x0f;
110134a875f3SVijay Khemka     std::vector<std::string> dimmEvent = {
110234a875f3SVijay Khemka         "Memory training failure", "Memory correctable error",
110334a875f3SVijay Khemka         "Memory uncorrectable error", "Reserved"};
110434a875f3SVijay Khemka 
110534a875f3SVijay Khemka     std::stringstream tmpStream;
110634a875f3SVijay Khemka     tmpStream << std::hex << std::uppercase << std::setfill('0');
110734a875f3SVijay Khemka 
110834a875f3SVijay Khemka     switch (errType)
110934a875f3SVijay Khemka     {
111034a875f3SVijay Khemka         case unifiedPcieErr:
111134a875f3SVijay Khemka             if (((genInfo & 0x10) >> 4) == 0) // x86
111234a875f3SVijay Khemka             {
111334a875f3SVijay Khemka                 tmpStream << "GeneralInfo: x86/PCIeErr(0x" << std::setw(2)
111434a875f3SVijay Khemka                           << genInfo << "),";
111534a875f3SVijay Khemka             }
111634a875f3SVijay Khemka 
111734a875f3SVijay Khemka             tmpStream << " Bus " << std::setw(2) << (int)(ptr[8]) << "/Dev "
111834a875f3SVijay Khemka                       << std::setw(2) << (int)(ptr[7] >> 3) << "/Fun "
111934a875f3SVijay Khemka                       << std::setw(2) << (int)(ptr[7] & 0x7)
112034a875f3SVijay Khemka                       << ", TotalErrID1Cnt: 0x" << std::setw(4)
112134a875f3SVijay Khemka                       << (int)((ptr[10] << 8) | ptr[9]) << ", ErrID2: 0x"
112234a875f3SVijay Khemka                       << std::setw(2) << (int)(ptr[11]) << ", ErrID1: 0x"
112334a875f3SVijay Khemka                       << std::setw(2) << (int)(ptr[12]);
112434a875f3SVijay Khemka 
112534a875f3SVijay Khemka             break;
112634a875f3SVijay Khemka         case unifiedMemErr:
112734a875f3SVijay Khemka             tmpStream << "GeneralInfo: MemErr(0x" << std::setw(2) << genInfo
112834a875f3SVijay Khemka                       << "), DIMM Slot Location: Sled " << std::setw(2)
112934a875f3SVijay Khemka                       << (int)((ptr[5] >> 4) & 0x03) << "/Socket "
113034a875f3SVijay Khemka                       << std::setw(2) << (int)(ptr[5] & 0x0f) << ", Channel "
113134a875f3SVijay Khemka                       << std::setw(2) << (int)(ptr[6] & 0x0f) << ", Slot "
113234a875f3SVijay Khemka                       << std::setw(2) << (int)(ptr[7] & 0x0f)
113334a875f3SVijay Khemka                       << ", DIMM Failure Event: " << dimmEvent[(ptr[9] & 0x03)]
113434a875f3SVijay Khemka                       << ", Major Code: 0x" << std::setw(2) << (int)(ptr[10])
113534a875f3SVijay Khemka                       << ", Minor Code: 0x" << std::setw(2) << (int)(ptr[11]);
113634a875f3SVijay Khemka 
113734a875f3SVijay Khemka             break;
113834a875f3SVijay Khemka         default:
113934a875f3SVijay Khemka             std::vector<uint8_t> oemData(ptr, ptr + 13);
114034a875f3SVijay Khemka             std::string oemDataStr;
114134a875f3SVijay Khemka             toHexStr(oemData, oemDataStr);
114234a875f3SVijay Khemka             tmpStream << "Undefined Error Type(0x" << std::setw(2) << errType
114334a875f3SVijay Khemka                       << "), Raw: " << oemDataStr;
114434a875f3SVijay Khemka     }
114534a875f3SVijay Khemka 
114634a875f3SVijay Khemka     errStr = tmpStream.str();
114734a875f3SVijay Khemka 
114834a875f3SVijay Khemka     return;
114934a875f3SVijay Khemka }
115034a875f3SVijay Khemka 
1151c056dc00SManikandan Elumalai static void parseSelData(uint8_t fruId, std::vector<uint8_t>& reqData,
1152c056dc00SManikandan Elumalai                          std::string& msgLog)
1153f36f345fSVijay Khemka {
1154f36f345fSVijay Khemka     /* Get record type */
1155f36f345fSVijay Khemka     int recType = reqData[2];
1156f36f345fSVijay Khemka     std::string errType, errLog;
1157f36f345fSVijay Khemka 
1158f36f345fSVijay Khemka     uint8_t* ptr = NULL;
1159f36f345fSVijay Khemka 
1160f36f345fSVijay Khemka     std::stringstream recTypeStream;
1161f36f345fSVijay Khemka     recTypeStream << std::hex << std::uppercase << std::setfill('0')
1162f36f345fSVijay Khemka                   << std::setw(2) << recType;
1163f36f345fSVijay Khemka 
1164c056dc00SManikandan Elumalai     msgLog = "SEL Entry: FRU: " + std::to_string(fruId) + ", Record: ";
1165f36f345fSVijay Khemka 
1166f36f345fSVijay Khemka     if (recType == stdErrType)
1167f36f345fSVijay Khemka     {
1168f36f345fSVijay Khemka         StdSELEntry* data = reinterpret_cast<StdSELEntry*>(&reqData[0]);
1169f36f345fSVijay Khemka         std::string sensorName;
1170f36f345fSVijay Khemka 
1171f36f345fSVijay Khemka         errType = stdErr;
1172f36f345fSVijay Khemka         if (data->sensorType == 0x1F)
1173f36f345fSVijay Khemka         {
1174f36f345fSVijay Khemka             sensorName = "OS";
1175f36f345fSVijay Khemka         }
1176f36f345fSVijay Khemka         else
1177f36f345fSVijay Khemka         {
1178f36f345fSVijay Khemka             auto findSensorName = sensorNameTable.find(data->sensorNum);
1179f36f345fSVijay Khemka             if (findSensorName == sensorNameTable.end())
1180f36f345fSVijay Khemka             {
1181f36f345fSVijay Khemka                 sensorName = "Unknown";
1182f36f345fSVijay Khemka             }
1183f36f345fSVijay Khemka             else
1184f36f345fSVijay Khemka             {
1185139aa4f0SVijay Khemka                 sensorName = findSensorName->second.first;
1186f36f345fSVijay Khemka             }
1187f36f345fSVijay Khemka         }
1188f36f345fSVijay Khemka 
1189e39f9393SWilly Tu         uint32_t timeStamp = data->timeStamp;
1190e39f9393SWilly Tu         std::tm* ts = localtime(reinterpret_cast<time_t*>(&timeStamp));
1191f36f345fSVijay Khemka         std::string timeStr = std::asctime(ts);
1192f36f345fSVijay Khemka 
1193f36f345fSVijay Khemka         parseStdSel(data, errLog);
1194f36f345fSVijay Khemka         ptr = &(data->eventData1);
1195f36f345fSVijay Khemka         std::vector<uint8_t> evtData(ptr, ptr + 3);
1196f36f345fSVijay Khemka         std::string eventData;
1197f36f345fSVijay Khemka         toHexStr(evtData, eventData);
1198f36f345fSVijay Khemka 
1199f36f345fSVijay Khemka         std::stringstream senNumStream;
1200f36f345fSVijay Khemka         senNumStream << std::hex << std::uppercase << std::setfill('0')
1201f36f345fSVijay Khemka                      << std::setw(2) << (int)(data->sensorNum);
1202f36f345fSVijay Khemka 
1203f36f345fSVijay Khemka         msgLog += errType + " (0x" + recTypeStream.str() +
1204f36f345fSVijay Khemka                   "), Time: " + timeStr + ", Sensor: " + sensorName + " (0x" +
1205f36f345fSVijay Khemka                   senNumStream.str() + "), Event Data: (" + eventData + ") " +
1206f36f345fSVijay Khemka                   errLog;
1207f36f345fSVijay Khemka     }
1208f36f345fSVijay Khemka     else if ((recType >= oemTSErrTypeMin) && (recType <= oemTSErrTypeMax))
1209f36f345fSVijay Khemka     {
1210f36f345fSVijay Khemka         /* timestamped OEM SEL records */
1211f36f345fSVijay Khemka         TsOemSELEntry* data = reinterpret_cast<TsOemSELEntry*>(&reqData[0]);
1212f36f345fSVijay Khemka         ptr = data->mfrId;
1213f36f345fSVijay Khemka         std::vector<uint8_t> mfrIdData(ptr, ptr + 3);
1214f36f345fSVijay Khemka         std::string mfrIdStr;
1215f36f345fSVijay Khemka         toHexStr(mfrIdData, mfrIdStr);
1216f36f345fSVijay Khemka 
1217f36f345fSVijay Khemka         ptr = data->oemData;
1218f36f345fSVijay Khemka         std::vector<uint8_t> oemData(ptr, ptr + 6);
1219f36f345fSVijay Khemka         std::string oemDataStr;
1220f36f345fSVijay Khemka         toHexStr(oemData, oemDataStr);
1221f36f345fSVijay Khemka 
1222e39f9393SWilly Tu         uint32_t timeStamp = data->timeStamp;
1223e39f9393SWilly Tu         std::tm* ts = localtime(reinterpret_cast<time_t*>(&timeStamp));
1224f36f345fSVijay Khemka         std::string timeStr = std::asctime(ts);
1225f36f345fSVijay Khemka 
1226f36f345fSVijay Khemka         errType = oemTSErr;
1227f36f345fSVijay Khemka         parseOemSel(data, errLog);
1228f36f345fSVijay Khemka 
1229f36f345fSVijay Khemka         msgLog += errType + " (0x" + recTypeStream.str() +
1230f36f345fSVijay Khemka                   "), Time: " + timeStr + ", MFG ID: " + mfrIdStr +
1231f36f345fSVijay Khemka                   ", OEM Data: (" + oemDataStr + ") " + errLog;
1232f36f345fSVijay Khemka     }
123334a875f3SVijay Khemka     else if (recType == fbUniErrType)
123434a875f3SVijay Khemka     {
123534a875f3SVijay Khemka         NtsOemSELEntry* data = reinterpret_cast<NtsOemSELEntry*>(&reqData[0]);
123634a875f3SVijay Khemka         errType = fbUniSELErr;
123734a875f3SVijay Khemka         parseOemUnifiedSel(data, errLog);
123834a875f3SVijay Khemka         msgLog += errType + " (0x" + recTypeStream.str() + "), " + errLog;
123934a875f3SVijay Khemka     }
1240f36f345fSVijay Khemka     else if ((recType >= oemNTSErrTypeMin) && (recType <= oemNTSErrTypeMax))
1241f36f345fSVijay Khemka     {
1242f36f345fSVijay Khemka         /* Non timestamped OEM SEL records */
1243f36f345fSVijay Khemka         NtsOemSELEntry* data = reinterpret_cast<NtsOemSELEntry*>(&reqData[0]);
1244f36f345fSVijay Khemka         errType = oemNTSErr;
1245f36f345fSVijay Khemka 
1246f36f345fSVijay Khemka         ptr = data->oemData;
1247f36f345fSVijay Khemka         std::vector<uint8_t> oemData(ptr, ptr + 13);
1248f36f345fSVijay Khemka         std::string oemDataStr;
1249f36f345fSVijay Khemka         toHexStr(oemData, oemDataStr);
1250f36f345fSVijay Khemka 
1251f36f345fSVijay Khemka         parseOemSel((TsOemSELEntry*)data, errLog);
1252f36f345fSVijay Khemka         msgLog += errType + " (0x" + recTypeStream.str() + "), OEM Data: (" +
1253f36f345fSVijay Khemka                   oemDataStr + ") " + errLog;
1254f36f345fSVijay Khemka     }
1255f36f345fSVijay Khemka     else
1256f36f345fSVijay Khemka     {
1257f36f345fSVijay Khemka         errType = unknownErr;
1258f36f345fSVijay Khemka         toHexStr(reqData, errLog);
12592405ae98SPatrick Williams         msgLog += errType + " (0x" + recTypeStream.str() +
12602405ae98SPatrick Williams                   ") RawData: " + errLog;
1261f36f345fSVijay Khemka     }
1262f36f345fSVijay Khemka }
1263f36f345fSVijay Khemka 
126411b9c3b1SVijay Khemka } // namespace fb_oem::ipmi::sel
126511b9c3b1SVijay Khemka 
126611b9c3b1SVijay Khemka namespace ipmi
126711b9c3b1SVijay Khemka {
126811b9c3b1SVijay Khemka 
126911b9c3b1SVijay Khemka namespace storage
127011b9c3b1SVijay Khemka {
127111b9c3b1SVijay Khemka 
127211b9c3b1SVijay Khemka static void registerSELFunctions() __attribute__((constructor));
127311b9c3b1SVijay Khemka static fb_oem::ipmi::sel::SELData selObj __attribute__((init_priority(101)));
127411b9c3b1SVijay Khemka 
127511b9c3b1SVijay Khemka ipmi::RspType<uint8_t,  // SEL version
127611b9c3b1SVijay Khemka               uint16_t, // SEL entry count
127711b9c3b1SVijay Khemka               uint16_t, // free space
127811b9c3b1SVijay Khemka               uint32_t, // last add timestamp
127911b9c3b1SVijay Khemka               uint32_t, // last erase timestamp
128011b9c3b1SVijay Khemka               uint8_t>  // operation support
128111b9c3b1SVijay Khemka     ipmiStorageGetSELInfo()
128211b9c3b1SVijay Khemka {
128311b9c3b1SVijay Khemka     fb_oem::ipmi::sel::GetSELInfoData info;
128411b9c3b1SVijay Khemka 
128511b9c3b1SVijay Khemka     selObj.getInfo(info);
128611b9c3b1SVijay Khemka     return ipmi::responseSuccess(info.selVersion, info.entries, info.freeSpace,
128711b9c3b1SVijay Khemka                                  info.addTimeStamp, info.eraseTimeStamp,
128811b9c3b1SVijay Khemka                                  info.operationSupport);
128911b9c3b1SVijay Khemka }
129011b9c3b1SVijay Khemka 
129111b9c3b1SVijay Khemka ipmi::RspType<uint16_t, std::vector<uint8_t>>
129211b9c3b1SVijay Khemka     ipmiStorageGetSELEntry(std::vector<uint8_t> data)
129311b9c3b1SVijay Khemka {
129411b9c3b1SVijay Khemka     if (data.size() != sizeof(fb_oem::ipmi::sel::GetSELEntryRequest))
129511b9c3b1SVijay Khemka     {
129611b9c3b1SVijay Khemka         return ipmi::responseReqDataLenInvalid();
129711b9c3b1SVijay Khemka     }
129811b9c3b1SVijay Khemka 
129911b9c3b1SVijay Khemka     fb_oem::ipmi::sel::GetSELEntryRequest* reqData =
130011b9c3b1SVijay Khemka         reinterpret_cast<fb_oem::ipmi::sel::GetSELEntryRequest*>(&data[0]);
130111b9c3b1SVijay Khemka 
130211b9c3b1SVijay Khemka     if (reqData->reservID != 0)
130311b9c3b1SVijay Khemka     {
130411b9c3b1SVijay Khemka         if (!checkSELReservation(reqData->reservID))
130511b9c3b1SVijay Khemka         {
130611b9c3b1SVijay Khemka             return ipmi::responseInvalidReservationId();
130711b9c3b1SVijay Khemka         }
130811b9c3b1SVijay Khemka     }
130911b9c3b1SVijay Khemka 
131011b9c3b1SVijay Khemka     uint16_t selCnt = selObj.getCount();
131111b9c3b1SVijay Khemka     if (selCnt == 0)
131211b9c3b1SVijay Khemka     {
131311b9c3b1SVijay Khemka         return ipmi::responseSensorInvalid();
131411b9c3b1SVijay Khemka     }
131511b9c3b1SVijay Khemka 
131611b9c3b1SVijay Khemka     /* If it is asked for first entry */
131711b9c3b1SVijay Khemka     if (reqData->recordID == fb_oem::ipmi::sel::firstEntry)
131811b9c3b1SVijay Khemka     {
131911b9c3b1SVijay Khemka         /* First Entry (0x0000) as per Spec */
132011b9c3b1SVijay Khemka         reqData->recordID = 1;
132111b9c3b1SVijay Khemka     }
132211b9c3b1SVijay Khemka     else if (reqData->recordID == fb_oem::ipmi::sel::lastEntry)
132311b9c3b1SVijay Khemka     {
132411b9c3b1SVijay Khemka         /* Last entry (0xFFFF) as per Spec */
132511b9c3b1SVijay Khemka         reqData->recordID = selCnt;
132611b9c3b1SVijay Khemka     }
132711b9c3b1SVijay Khemka 
132811b9c3b1SVijay Khemka     std::string ipmiRaw;
132911b9c3b1SVijay Khemka 
133011b9c3b1SVijay Khemka     if (selObj.getEntry(reqData->recordID, ipmiRaw) < 0)
133111b9c3b1SVijay Khemka     {
133211b9c3b1SVijay Khemka         return ipmi::responseSensorInvalid();
133311b9c3b1SVijay Khemka     }
133411b9c3b1SVijay Khemka 
133511b9c3b1SVijay Khemka     std::vector<uint8_t> recDataBytes;
133611b9c3b1SVijay Khemka     if (fromHexStr(ipmiRaw, recDataBytes) < 0)
133711b9c3b1SVijay Khemka     {
133811b9c3b1SVijay Khemka         return ipmi::responseUnspecifiedError();
133911b9c3b1SVijay Khemka     }
134011b9c3b1SVijay Khemka 
134111b9c3b1SVijay Khemka     /* Identify the next SEL record ID. If recordID is same as
134211b9c3b1SVijay Khemka      * total SeL count then next id should be last entry else
134311b9c3b1SVijay Khemka      * it should be incremented by 1 to current RecordID
134411b9c3b1SVijay Khemka      */
134511b9c3b1SVijay Khemka     uint16_t nextRecord;
134611b9c3b1SVijay Khemka     if (reqData->recordID == selCnt)
134711b9c3b1SVijay Khemka     {
134811b9c3b1SVijay Khemka         nextRecord = fb_oem::ipmi::sel::lastEntry;
134911b9c3b1SVijay Khemka     }
135011b9c3b1SVijay Khemka     else
135111b9c3b1SVijay Khemka     {
135211b9c3b1SVijay Khemka         nextRecord = reqData->recordID + 1;
135311b9c3b1SVijay Khemka     }
135411b9c3b1SVijay Khemka 
135511b9c3b1SVijay Khemka     if (reqData->readLen == fb_oem::ipmi::sel::entireRecord)
135611b9c3b1SVijay Khemka     {
135711b9c3b1SVijay Khemka         return ipmi::responseSuccess(nextRecord, recDataBytes);
135811b9c3b1SVijay Khemka     }
135911b9c3b1SVijay Khemka     else
136011b9c3b1SVijay Khemka     {
136111b9c3b1SVijay Khemka         if (reqData->offset >= fb_oem::ipmi::sel::selRecordSize ||
136211b9c3b1SVijay Khemka             reqData->readLen > fb_oem::ipmi::sel::selRecordSize)
136311b9c3b1SVijay Khemka         {
136411b9c3b1SVijay Khemka             return ipmi::responseUnspecifiedError();
136511b9c3b1SVijay Khemka         }
136611b9c3b1SVijay Khemka         std::vector<uint8_t> recPartData;
136711b9c3b1SVijay Khemka 
136811b9c3b1SVijay Khemka         auto diff = fb_oem::ipmi::sel::selRecordSize - reqData->offset;
136911b9c3b1SVijay Khemka         auto readLength = std::min(diff, static_cast<int>(reqData->readLen));
137011b9c3b1SVijay Khemka 
137111b9c3b1SVijay Khemka         for (int i = 0; i < readLength; i++)
137211b9c3b1SVijay Khemka         {
137311b9c3b1SVijay Khemka             recPartData.push_back(recDataBytes[i + reqData->offset]);
137411b9c3b1SVijay Khemka         }
137511b9c3b1SVijay Khemka         return ipmi::responseSuccess(nextRecord, recPartData);
137611b9c3b1SVijay Khemka     }
137711b9c3b1SVijay Khemka }
137811b9c3b1SVijay Khemka 
1379c056dc00SManikandan Elumalai ipmi::RspType<uint16_t> ipmiStorageAddSELEntry(ipmi::Context::ptr ctx,
1380c056dc00SManikandan Elumalai                                                std::vector<uint8_t> data)
138111b9c3b1SVijay Khemka {
138211b9c3b1SVijay Khemka     /* Per the IPMI spec, need to cancel any reservation when a
138311b9c3b1SVijay Khemka      * SEL entry is added
138411b9c3b1SVijay Khemka      */
138511b9c3b1SVijay Khemka     cancelSELReservation();
138611b9c3b1SVijay Khemka 
138711b9c3b1SVijay Khemka     if (data.size() != fb_oem::ipmi::sel::selRecordSize)
138811b9c3b1SVijay Khemka     {
138911b9c3b1SVijay Khemka         return ipmi::responseReqDataLenInvalid();
139011b9c3b1SVijay Khemka     }
139111b9c3b1SVijay Khemka 
139211b9c3b1SVijay Khemka     std::string ipmiRaw, logErr;
139311b9c3b1SVijay Khemka     toHexStr(data, ipmiRaw);
139411b9c3b1SVijay Khemka 
1395f36f345fSVijay Khemka     /* Parse sel data and get an error log to be filed */
1396c056dc00SManikandan Elumalai     fb_oem::ipmi::sel::parseSelData((ctx->hostIdx + 1), data, logErr);
1397f36f345fSVijay Khemka 
139815a7ae81SVijay Khemka     static const std::string openBMCMessageRegistryVersion("0.1");
13992405ae98SPatrick Williams     std::string messageID = "OpenBMC." + openBMCMessageRegistryVersion +
14002405ae98SPatrick Williams                             ".SELEntryAdded";
140115a7ae81SVijay Khemka 
140211b9c3b1SVijay Khemka     /* Log the Raw SEL message to the journal */
140311b9c3b1SVijay Khemka     std::string journalMsg = "SEL Entry Added: " + ipmiRaw;
1404f36f345fSVijay Khemka 
140515a7ae81SVijay Khemka     phosphor::logging::log<phosphor::logging::level::INFO>(
140615a7ae81SVijay Khemka         journalMsg.c_str(),
140715a7ae81SVijay Khemka         phosphor::logging::entry("IPMISEL_MESSAGE_ID=%s", messageID.c_str()),
140815a7ae81SVijay Khemka         phosphor::logging::entry("IPMISEL_MESSAGE_ARGS=%s", logErr.c_str()));
140911b9c3b1SVijay Khemka 
1410*21a79235SBonnieLo-wiwynn     std::map<std::string, std::string> ad;
1411*21a79235SBonnieLo-wiwynn     std::string severity = "xyz.openbmc_project.Logging.Entry.Level.Critical";
1412*21a79235SBonnieLo-wiwynn     ad.emplace("IPMI_RAW", ipmiRaw);
1413*21a79235SBonnieLo-wiwynn 
1414*21a79235SBonnieLo-wiwynn     auto bus = sdbusplus::bus::new_default();
1415*21a79235SBonnieLo-wiwynn     auto reqMsg = bus.new_method_call(
1416*21a79235SBonnieLo-wiwynn         "xyz.openbmc_project.Logging", "/xyz/openbmc_project/logging",
1417*21a79235SBonnieLo-wiwynn         "xyz.openbmc_project.Logging.Create", "Create");
1418*21a79235SBonnieLo-wiwynn     reqMsg.append(logErr, severity, ad);
1419*21a79235SBonnieLo-wiwynn 
1420*21a79235SBonnieLo-wiwynn     try
1421*21a79235SBonnieLo-wiwynn     {
1422*21a79235SBonnieLo-wiwynn         bus.call(reqMsg);
1423*21a79235SBonnieLo-wiwynn     }
1424*21a79235SBonnieLo-wiwynn     catch (sdbusplus::exception_t& e)
1425*21a79235SBonnieLo-wiwynn     {
1426*21a79235SBonnieLo-wiwynn         phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
1427*21a79235SBonnieLo-wiwynn     }
1428*21a79235SBonnieLo-wiwynn 
142911b9c3b1SVijay Khemka     int responseID = selObj.addEntry(ipmiRaw.c_str());
143011b9c3b1SVijay Khemka     if (responseID < 0)
143111b9c3b1SVijay Khemka     {
143211b9c3b1SVijay Khemka         return ipmi::responseUnspecifiedError();
143311b9c3b1SVijay Khemka     }
143411b9c3b1SVijay Khemka     return ipmi::responseSuccess((uint16_t)responseID);
143511b9c3b1SVijay Khemka }
143611b9c3b1SVijay Khemka 
1437c1921c63SVijay Khemka ipmi::RspType<uint8_t> ipmiStorageClearSEL(uint16_t reservationID,
1438c1921c63SVijay Khemka                                            const std::array<uint8_t, 3>& clr,
1439c1921c63SVijay Khemka                                            uint8_t eraseOperation)
1440c1921c63SVijay Khemka {
1441c1921c63SVijay Khemka     if (!checkSELReservation(reservationID))
1442c1921c63SVijay Khemka     {
1443c1921c63SVijay Khemka         return ipmi::responseInvalidReservationId();
1444c1921c63SVijay Khemka     }
1445c1921c63SVijay Khemka 
1446c1921c63SVijay Khemka     static constexpr std::array<uint8_t, 3> clrExpected = {'C', 'L', 'R'};
1447c1921c63SVijay Khemka     if (clr != clrExpected)
1448c1921c63SVijay Khemka     {
1449c1921c63SVijay Khemka         return ipmi::responseInvalidFieldRequest();
1450c1921c63SVijay Khemka     }
1451c1921c63SVijay Khemka 
1452c1921c63SVijay Khemka     /* If there is no sel then return erase complete */
1453c1921c63SVijay Khemka     if (selObj.getCount() == 0)
1454c1921c63SVijay Khemka     {
1455c1921c63SVijay Khemka         return ipmi::responseSuccess(fb_oem::ipmi::sel::eraseComplete);
1456c1921c63SVijay Khemka     }
1457c1921c63SVijay Khemka 
1458c1921c63SVijay Khemka     /* Erasure status cannot be fetched, so always return erasure
1459c1921c63SVijay Khemka      * status as `erase completed`.
1460c1921c63SVijay Khemka      */
1461c1921c63SVijay Khemka     if (eraseOperation == fb_oem::ipmi::sel::getEraseStatus)
1462c1921c63SVijay Khemka     {
1463c1921c63SVijay Khemka         return ipmi::responseSuccess(fb_oem::ipmi::sel::eraseComplete);
1464c1921c63SVijay Khemka     }
1465c1921c63SVijay Khemka 
1466c1921c63SVijay Khemka     /* Check that initiate erase is correct */
1467c1921c63SVijay Khemka     if (eraseOperation != fb_oem::ipmi::sel::initiateErase)
1468c1921c63SVijay Khemka     {
1469c1921c63SVijay Khemka         return ipmi::responseInvalidFieldRequest();
1470c1921c63SVijay Khemka     }
1471c1921c63SVijay Khemka 
1472c1921c63SVijay Khemka     /* Per the IPMI spec, need to cancel any reservation when the
1473c1921c63SVijay Khemka      * SEL is cleared
1474c1921c63SVijay Khemka      */
1475c1921c63SVijay Khemka     cancelSELReservation();
1476c1921c63SVijay Khemka 
1477c1921c63SVijay Khemka     /* Clear the complete Sel Json object */
1478c1921c63SVijay Khemka     if (selObj.clear() < 0)
1479c1921c63SVijay Khemka     {
1480c1921c63SVijay Khemka         return ipmi::responseUnspecifiedError();
1481c1921c63SVijay Khemka     }
1482c1921c63SVijay Khemka 
1483c1921c63SVijay Khemka     return ipmi::responseSuccess(fb_oem::ipmi::sel::eraseComplete);
1484c1921c63SVijay Khemka }
1485c1921c63SVijay Khemka 
1486c1921c63SVijay Khemka ipmi::RspType<uint32_t> ipmiStorageGetSELTime()
1487c1921c63SVijay Khemka {
1488c1921c63SVijay Khemka     struct timespec selTime = {};
1489c1921c63SVijay Khemka 
1490c1921c63SVijay Khemka     if (clock_gettime(CLOCK_REALTIME, &selTime) < 0)
1491c1921c63SVijay Khemka     {
1492c1921c63SVijay Khemka         return ipmi::responseUnspecifiedError();
1493c1921c63SVijay Khemka     }
1494c1921c63SVijay Khemka 
1495c1921c63SVijay Khemka     return ipmi::responseSuccess(selTime.tv_sec);
1496c1921c63SVijay Khemka }
1497c1921c63SVijay Khemka 
1498e39f9393SWilly Tu ipmi::RspType<> ipmiStorageSetSELTime(uint32_t)
1499c1921c63SVijay Khemka {
1500c1921c63SVijay Khemka     // Set SEL Time is not supported
1501c1921c63SVijay Khemka     return ipmi::responseInvalidCommand();
1502c1921c63SVijay Khemka }
1503c1921c63SVijay Khemka 
1504c1921c63SVijay Khemka ipmi::RspType<uint16_t> ipmiStorageGetSELTimeUtcOffset()
1505c1921c63SVijay Khemka {
1506c1921c63SVijay Khemka     /* TODO: For now, the SEL time stamp is based on UTC time,
1507c1921c63SVijay Khemka      * so return 0x0000 as offset. Might need to change once
1508c1921c63SVijay Khemka      * supporting zones in SEL time stamps
1509c1921c63SVijay Khemka      */
1510c1921c63SVijay Khemka 
1511c1921c63SVijay Khemka     uint16_t utcOffset = 0x0000;
1512c1921c63SVijay Khemka     return ipmi::responseSuccess(utcOffset);
1513c1921c63SVijay Khemka }
1514c1921c63SVijay Khemka 
151511b9c3b1SVijay Khemka void registerSELFunctions()
151611b9c3b1SVijay Khemka {
151711b9c3b1SVijay Khemka     // <Get SEL Info>
151811b9c3b1SVijay Khemka     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
151911b9c3b1SVijay Khemka                           ipmi::storage::cmdGetSelInfo, ipmi::Privilege::User,
152011b9c3b1SVijay Khemka                           ipmiStorageGetSELInfo);
152111b9c3b1SVijay Khemka 
152211b9c3b1SVijay Khemka     // <Get SEL Entry>
152311b9c3b1SVijay Khemka     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
152411b9c3b1SVijay Khemka                           ipmi::storage::cmdGetSelEntry, ipmi::Privilege::User,
152511b9c3b1SVijay Khemka                           ipmiStorageGetSELEntry);
152611b9c3b1SVijay Khemka 
152711b9c3b1SVijay Khemka     // <Add SEL Entry>
152811b9c3b1SVijay Khemka     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
152911b9c3b1SVijay Khemka                           ipmi::storage::cmdAddSelEntry,
153011b9c3b1SVijay Khemka                           ipmi::Privilege::Operator, ipmiStorageAddSELEntry);
153111b9c3b1SVijay Khemka 
1532c1921c63SVijay Khemka     // <Clear SEL>
1533c1921c63SVijay Khemka     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
1534c1921c63SVijay Khemka                           ipmi::storage::cmdClearSel, ipmi::Privilege::Operator,
1535c1921c63SVijay Khemka                           ipmiStorageClearSEL);
1536c1921c63SVijay Khemka 
1537c1921c63SVijay Khemka     // <Get SEL Time>
1538c1921c63SVijay Khemka     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
1539c1921c63SVijay Khemka                           ipmi::storage::cmdGetSelTime, ipmi::Privilege::User,
1540c1921c63SVijay Khemka                           ipmiStorageGetSELTime);
1541c1921c63SVijay Khemka 
1542c1921c63SVijay Khemka     // <Set SEL Time>
1543c1921c63SVijay Khemka     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
1544c1921c63SVijay Khemka                           ipmi::storage::cmdSetSelTime,
1545c1921c63SVijay Khemka                           ipmi::Privilege::Operator, ipmiStorageSetSELTime);
1546c1921c63SVijay Khemka 
1547c1921c63SVijay Khemka     // <Get SEL Time UTC Offset>
1548c1921c63SVijay Khemka     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
1549c1921c63SVijay Khemka                           ipmi::storage::cmdGetSelTimeUtcOffset,
1550c1921c63SVijay Khemka                           ipmi::Privilege::User,
1551c1921c63SVijay Khemka                           ipmiStorageGetSELTimeUtcOffset);
1552c1921c63SVijay Khemka 
155311b9c3b1SVijay Khemka     return;
155411b9c3b1SVijay Khemka }
155511b9c3b1SVijay Khemka 
155611b9c3b1SVijay Khemka } // namespace storage
155711b9c3b1SVijay Khemka } // namespace ipmi
1558