blob: b95938201917320031e4cd6503654fa4ffad5656 [file] [log] [blame]
Vijay Khemka11b9c3b2019-08-21 15:21:42 -07001/*
2 * Copyright (c) 2018 Intel Corporation.
3 * Copyright (c) 2018-present Facebook.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
Vijay Khemka11b9c3b2019-08-21 15:21:42 -070018#include <boost/algorithm/string/join.hpp>
Patrick Williams020ff3e2022-09-20 12:09:32 -050019#include <boost/container/flat_map.hpp>
Vijay Khemka63c99be2020-05-27 19:14:35 -070020#include <ipmid/api.hpp>
Vijay Khemka11b9c3b2019-08-21 15:21:42 -070021#include <nlohmann/json.hpp>
Vijay Khemka11b9c3b2019-08-21 15:21:42 -070022#include <phosphor-logging/log.hpp>
23#include <sdbusplus/message/types.hpp>
24#include <sdbusplus/timer.hpp>
25#include <storagecommands.hpp>
26
Vijay Khemka63c99be2020-05-27 19:14:35 -070027#include <fstream>
28#include <iostream>
29#include <sstream>
30
cchoux74519032024-02-04 20:35:29 +080031enum class MemErrType
32{
33 memTrainErr = 0,
34 memPmicErr = 7
35};
36
37enum class PostEvtType
38{
39 pxeBootFail = 0,
40 httpBootFail = 6,
41 getCertFail = 7,
42 amdAblFail = 10
43};
44
45enum class PcieEvtType
46{
47 dpc = 0
48};
49
50enum class MemEvtType
51{
52 ppr = 0,
53 adddc = 5,
54 noDimm = 7
55};
56
Vijay Khemka11b9c3b2019-08-21 15:21:42 -070057//----------------------------------------------------------------------
58// Platform specific functions for storing app data
59//----------------------------------------------------------------------
60
Vijay Khemka139aa4f2019-08-16 09:57:41 -070061static std::string byteToStr(uint8_t byte)
62{
63 std::stringstream ss;
64
65 ss << std::hex << std::uppercase << std::setfill('0');
66 ss << std::setw(2) << (int)byte;
67
68 return ss.str();
69}
70
Vijay Khemka63c99be2020-05-27 19:14:35 -070071static void toHexStr(std::vector<uint8_t>& bytes, std::string& hexStr)
Vijay Khemka11b9c3b2019-08-21 15:21:42 -070072{
73 std::stringstream stream;
74 stream << std::hex << std::uppercase << std::setfill('0');
75 for (const uint8_t byte : bytes)
76 {
77 stream << std::setw(2) << static_cast<int>(byte);
78 }
79 hexStr = stream.str();
80}
81
Vijay Khemka63c99be2020-05-27 19:14:35 -070082static int fromHexStr(const std::string hexStr, std::vector<uint8_t>& data)
Vijay Khemka11b9c3b2019-08-21 15:21:42 -070083{
84 for (unsigned int i = 0; i < hexStr.size(); i += 2)
85 {
86 try
87 {
88 data.push_back(static_cast<uint8_t>(
89 std::stoul(hexStr.substr(i, 2), nullptr, 16)));
90 }
Patrick Williams35d12542021-10-06 11:21:13 -050091 catch (const std::invalid_argument& e)
Vijay Khemka11b9c3b2019-08-21 15:21:42 -070092 {
93 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
94 return -1;
95 }
Patrick Williams35d12542021-10-06 11:21:13 -050096 catch (const std::out_of_range& e)
Vijay Khemka11b9c3b2019-08-21 15:21:42 -070097 {
98 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
99 return -1;
100 }
101 }
102 return 0;
103}
104
105namespace fb_oem::ipmi::sel
106{
107
108class SELData
109{
110 private:
111 nlohmann::json selDataObj;
112
113 void flush()
114 {
115 std::ofstream file(SEL_JSON_DATA_FILE);
116 file << selDataObj;
117 file.close();
118 }
119
120 void init()
121 {
122 selDataObj[KEY_SEL_VER] = 0x51;
123 selDataObj[KEY_SEL_COUNT] = 0;
124 selDataObj[KEY_ADD_TIME] = 0xFFFFFFFF;
125 selDataObj[KEY_ERASE_TIME] = 0xFFFFFFFF;
126 selDataObj[KEY_OPER_SUPP] = 0x02;
127 /* Spec indicates that more than 64kB is free */
128 selDataObj[KEY_FREE_SPACE] = 0xFFFF;
129 }
130
131 public:
132 SELData()
133 {
134 /* Get App data stored in json file */
135 std::ifstream file(SEL_JSON_DATA_FILE);
136 if (file)
137 {
138 file >> selDataObj;
139 file.close();
140 }
141
142 /* Initialize SelData object if no entries. */
143 if (selDataObj.find(KEY_SEL_COUNT) == selDataObj.end())
144 {
145 init();
146 }
147 }
148
149 int clear()
150 {
151 /* Clear the complete Sel Json object */
152 selDataObj.clear();
153 /* Reinitialize it with basic data */
154 init();
155 /* Save the erase time */
156 struct timespec selTime = {};
157 if (clock_gettime(CLOCK_REALTIME, &selTime) < 0)
158 {
159 return -1;
160 }
161 selDataObj[KEY_ERASE_TIME] = selTime.tv_sec;
162 flush();
163 return 0;
164 }
165
166 uint32_t getCount()
167 {
168 return selDataObj[KEY_SEL_COUNT];
169 }
170
Vijay Khemka63c99be2020-05-27 19:14:35 -0700171 void getInfo(GetSELInfoData& info)
Vijay Khemka11b9c3b2019-08-21 15:21:42 -0700172 {
173 info.selVersion = selDataObj[KEY_SEL_VER];
174 info.entries = selDataObj[KEY_SEL_COUNT];
175 info.freeSpace = selDataObj[KEY_FREE_SPACE];
176 info.addTimeStamp = selDataObj[KEY_ADD_TIME];
177 info.eraseTimeStamp = selDataObj[KEY_ERASE_TIME];
178 info.operationSupport = selDataObj[KEY_OPER_SUPP];
179 }
180
Vijay Khemka63c99be2020-05-27 19:14:35 -0700181 int getEntry(uint32_t index, std::string& rawStr)
Vijay Khemka11b9c3b2019-08-21 15:21:42 -0700182 {
183 std::stringstream ss;
184 ss << std::hex;
185 ss << std::setw(2) << std::setfill('0') << index;
186
187 /* Check or the requested SEL Entry, if record is available */
188 if (selDataObj.find(ss.str()) == selDataObj.end())
189 {
190 return -1;
191 }
192
193 rawStr = selDataObj[ss.str()][KEY_SEL_ENTRY_RAW];
194 return 0;
195 }
196
197 int addEntry(std::string keyStr)
198 {
199 struct timespec selTime = {};
200
201 if (clock_gettime(CLOCK_REALTIME, &selTime) < 0)
202 {
203 return -1;
204 }
205
206 selDataObj[KEY_ADD_TIME] = selTime.tv_sec;
207
208 int selCount = selDataObj[KEY_SEL_COUNT];
209 selDataObj[KEY_SEL_COUNT] = ++selCount;
210
211 std::stringstream ss;
212 ss << std::hex;
213 ss << std::setw(2) << std::setfill('0') << selCount;
214
215 selDataObj[ss.str()][KEY_SEL_ENTRY_RAW] = keyStr;
216 flush();
217 return selCount;
218 }
219};
220
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700221/*
Manojkiran Eda519530b2024-06-17 11:46:15 +0530222 * A Function to parse common SEL message, a helper function
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700223 * for parseStdSel.
224 *
Manojkiran Eda519530b2024-06-17 11:46:15 +0530225 * Note that this function __CANNOT__ be overridden.
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700226 * To add board specific routine, please override parseStdSel.
227 */
228
229/*Used by decoding ME event*/
230std::vector<std::string> nmDomName = {
231 "Entire Platform", "CPU Subsystem",
232 "Memory Subsystem", "HW Protection",
233 "High Power I/O subsystem", "Unknown"};
234
235/* Default log message for unknown type */
Willy Tue39f9392022-06-15 13:24:20 -0700236static void logDefault(uint8_t*, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700237{
238 errLog = "Unknown";
239}
240
Vijay Khemka63c99be2020-05-27 19:14:35 -0700241static void logSysEvent(uint8_t* data, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700242{
243 if (data[0] == 0xE5)
244 {
245 errLog = "Cause of Time change - ";
246 switch (data[2])
247 {
248 case 0x00:
249 errLog += "NTP";
250 break;
251 case 0x01:
252 errLog += "Host RTL";
253 break;
254 case 0x02:
255 errLog += "Set SEL time cmd";
256 break;
257 case 0x03:
258 errLog += "Set SEL time UTC offset cmd";
259 break;
260 default:
261 errLog += "Unknown";
262 }
263
264 if (data[1] == 0x00)
265 errLog += " - First Time";
266 else if (data[1] == 0x80)
267 errLog += " - Second Time";
268 }
269 else
270 {
271 errLog = "Unknown";
272 }
273}
274
Vijay Khemka63c99be2020-05-27 19:14:35 -0700275static void logThermalEvent(uint8_t* data, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700276{
277 if (data[0] == 0x1)
278 {
279 errLog = "Limit Exceeded";
280 }
281 else
282 {
283 errLog = "Unknown";
284 }
285}
286
Vijay Khemka63c99be2020-05-27 19:14:35 -0700287static void logCritIrq(uint8_t* data, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700288{
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700289 if (data[0] == 0x0)
290 {
291 errLog = "NMI / Diagnostic Interrupt";
292 }
293 else if (data[0] == 0x03)
294 {
295 errLog = "Software NMI";
296 }
297 else
298 {
299 errLog = "Unknown";
300 }
301
302 /* TODO: Call add_cri_sel for CRITICAL_IRQ */
303}
304
Vijay Khemka63c99be2020-05-27 19:14:35 -0700305static void logPostErr(uint8_t* data, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700306{
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700307 if ((data[0] & 0x0F) == 0x0)
308 {
309 errLog = "System Firmware Error";
310 }
311 else
312 {
313 errLog = "Unknown";
314 }
315
316 if (((data[0] >> 6) & 0x03) == 0x3)
317 {
318 // TODO: Need to implement IPMI spec based Post Code
319 errLog += ", IPMI Post Code";
320 }
321 else if (((data[0] >> 6) & 0x03) == 0x2)
322 {
Patrick Williams2405ae92023-05-10 07:50:09 -0500323 errLog += ", OEM Post Code 0x" + byteToStr(data[2]) +
324 byteToStr(data[1]);
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700325
326 switch ((data[2] << 8) | data[1])
327 {
328 case 0xA105:
329 errLog += ", BMC Failed (No Response)";
330 break;
331 case 0xA106:
332 errLog += ", BMC Failed (Self Test Fail)";
333 break;
334 case 0xA10A:
335 errLog += ", System Firmware Corruption Detected";
336 break;
337 case 0xA10B:
338 errLog += ", TPM Self-Test FAIL Detected";
339 }
340 }
341}
342
Vijay Khemka63c99be2020-05-27 19:14:35 -0700343static void logMchChkErr(uint8_t* data, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700344{
345 /* TODO: Call add_cri_sel for CRITICAL_IRQ */
Daniel Hsud17c3562024-10-17 11:10:31 +0800346 switch (data[0] & 0x0F)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700347 {
Daniel Hsud17c3562024-10-17 11:10:31 +0800348 case 0x0B:
349 switch ((data[1] >> 5) & 0x03)
350 {
351 case 0x00:
352 errLog = "Uncorrected Recoverable Error";
353 break;
354 case 0x01:
355 errLog = "Uncorrected Thread Fatal Error";
356 break;
357 case 0x02:
358 errLog = "Uncorrected System Fatal Error";
359 break;
360 default:
361 errLog = "Unknown";
362 }
363 break;
364 case 0x0C:
365 switch ((data[1] >> 5) & 0x03)
366 {
367 case 0x00:
368 errLog = "Correctable Error";
369 break;
370 case 0x01:
371 errLog = "Deferred Error";
372 break;
373 default:
374 errLog = "Unknown";
375 }
376 break;
377 default:
378 errLog = "Unknown";
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700379 }
380
381 errLog += ", Machine Check bank Number " + std::to_string(data[1]) +
382 ", CPU " + std::to_string(data[2] >> 5) + ", Core " +
383 std::to_string(data[2] & 0x1F);
384}
385
Vijay Khemka63c99be2020-05-27 19:14:35 -0700386static void logPcieErr(uint8_t* data, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700387{
388 std::stringstream tmp1, tmp2;
389 tmp1 << std::hex << std::uppercase << std::setfill('0');
390 tmp2 << std::hex << std::uppercase << std::setfill('0');
391 tmp1 << " (Bus " << std::setw(2) << (int)(data[2]) << " / Dev "
392 << std::setw(2) << (int)(data[1] >> 3) << " / Fun " << std::setw(2)
393 << (int)(data[1] & 0x7) << ")";
394
395 switch (data[0] & 0xF)
396 {
397 case 0x4:
398 errLog = "PCI PERR" + tmp1.str();
399 break;
400 case 0x5:
401 errLog = "PCI SERR" + tmp1.str();
402 break;
403 case 0x7:
404 errLog = "Correctable" + tmp1.str();
405 break;
406 case 0x8:
407 errLog = "Uncorrectable" + tmp1.str();
408 break;
409 case 0xA:
410 errLog = "Bus Fatal" + tmp1.str();
411 break;
Vijay Khemkad1194022020-05-27 18:58:33 -0700412 case 0xD:
413 {
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700414 uint32_t venId = (uint32_t)data[1] << 8 | (uint32_t)data[2];
415 tmp2 << "Vendor ID: 0x" << std::setw(4) << venId;
416 errLog = tmp2.str();
417 }
418 break;
Vijay Khemkad1194022020-05-27 18:58:33 -0700419 case 0xE:
420 {
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700421 uint32_t devId = (uint32_t)data[1] << 8 | (uint32_t)data[2];
422 tmp2 << "Device ID: 0x" << std::setw(4) << devId;
423 errLog = tmp2.str();
424 }
425 break;
426 case 0xF:
427 tmp2 << "Error ID from downstream: 0x" << std::setw(2)
428 << (int)(data[1]) << std::setw(2) << (int)(data[2]);
429 errLog = tmp2.str();
430 break;
431 default:
432 errLog = "Unknown";
433 }
434}
435
Vijay Khemka63c99be2020-05-27 19:14:35 -0700436static void logIioErr(uint8_t* data, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700437{
438 std::vector<std::string> tmpStr = {
439 "IRP0", "IRP1", " IIO-Core", "VT-d", "Intel Quick Data",
440 "Misc", " DMA", "ITC", "OTC", "CI"};
441
442 if ((data[0] & 0xF) == 0)
443 {
444 errLog += "CPU " + std::to_string(data[2] >> 5) + ", Error ID 0x" +
445 byteToStr(data[1]) + " - ";
446
447 if ((data[2] & 0xF) <= 0x9)
448 {
449 errLog += tmpStr[(data[2] & 0xF)];
450 }
451 else
452 {
453 errLog += "Reserved";
454 }
455 }
456 else
457 {
458 errLog = "Unknown";
459 }
460}
461
Willy Tue39f9392022-06-15 13:24:20 -0700462[[maybe_unused]] static void logMemErr(uint8_t* dataPtr, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700463{
464 uint8_t snrType = dataPtr[0];
465 uint8_t snrNum = dataPtr[1];
Vijay Khemka63c99be2020-05-27 19:14:35 -0700466 uint8_t* data = &(dataPtr[3]);
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700467
468 /* TODO: add pal_add_cri_sel */
469
470 if (snrNum == memoryEccError)
471 {
472 /* SEL from MEMORY_ECC_ERR Sensor */
473 switch (data[0] & 0x0F)
474 {
475 case 0x0:
476 if (snrType == 0x0C)
477 {
478 errLog = "Correctable";
479 }
480 else if (snrType == 0x10)
481 {
482 errLog = "Correctable ECC error Logging Disabled";
483 }
484 break;
485 case 0x1:
486 errLog = "Uncorrectable";
487 break;
488 case 0x5:
489 errLog = "Correctable ECC error Logging Limit Disabled";
490 break;
491 default:
492 errLog = "Unknown";
493 }
494 }
495 else if (snrNum == memoryErrLogDIS)
496 {
497 // SEL from MEMORY_ERR_LOG_DIS Sensor
498 if ((data[0] & 0x0F) == 0x0)
499 {
500 errLog = "Correctable Memory Error Logging Disabled";
501 }
502 else
503 {
504 errLog = "Unknown";
505 }
506 }
507 else
508 {
509 errLog = "Unknown";
510 return;
511 }
512
513 /* Common routine for both MEM_ECC_ERR and MEMORY_ERR_LOG_DIS */
514
515 errLog += " (DIMM " + byteToStr(data[2]) + ") Logical Rank " +
516 std::to_string(data[1] & 0x03);
517
518 /* DIMM number (data[2]):
519 * Bit[7:5]: Socket number (Range: 0-7)
520 * Bit[4:3]: Channel number (Range: 0-3)
521 * Bit[2:0]: DIMM number (Range: 0-7)
522 */
523
524 /* TODO: Verify these bits */
525 std::string cpuStr = "CPU# " + std::to_string((data[2] & 0xE0) >> 5);
526 std::string chStr = "CHN# " + std::to_string((data[2] & 0x18) >> 3);
Manikandan Elumalaic056dc02020-12-11 06:20:32 +0530527 std::string dimmStr = "DIMM#" + std::to_string(data[2] & 0x7);
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700528
529 switch ((data[1] & 0xC) >> 2)
530 {
Vijay Khemkad1194022020-05-27 18:58:33 -0700531 case 0x0:
532 {
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700533 /* All Info Valid */
Willy Tue39f9392022-06-15 13:24:20 -0700534 [[maybe_unused]] uint8_t chnNum = (data[2] & 0x1C) >> 2;
535 [[maybe_unused]] uint8_t dimmNum = data[2] & 0x3;
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700536
537 /* TODO: If critical SEL logging is available, do it */
538 if (snrType == 0x0C)
539 {
540 if ((data[0] & 0x0F) == 0x0)
541 {
542 /* TODO: add_cri_sel */
543 /* "DIMM"+ 'A'+ chnNum + dimmNum + " ECC err,FRU:1"
544 */
545 }
546 else if ((data[0] & 0x0F) == 0x1)
547 {
548 /* TODO: add_cri_sel */
549 /* "DIMM"+ 'A'+ chnNum + dimmNum + " UECC err,FRU:1"
550 */
551 }
552 }
553 /* Continue to parse the error into a string. All Info Valid
554 */
555 errLog += " (" + cpuStr + ", " + chStr + ", " + dimmStr + ")";
556 }
557
558 break;
559 case 0x1:
560
561 /* DIMM info not valid */
562 errLog += " (" + cpuStr + ", " + chStr + ")";
563 break;
564 case 0x2:
565
566 /* CHN info not valid */
567 errLog += " (" + cpuStr + ", " + dimmStr + ")";
568 break;
569 case 0x3:
570
571 /* CPU info not valid */
572 errLog += " (" + chStr + ", " + dimmStr + ")";
573 break;
574 }
575}
576
Vijay Khemka63c99be2020-05-27 19:14:35 -0700577static void logPwrErr(uint8_t* data, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700578{
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700579 if (data[0] == 0x1)
580 {
581 errLog = "SYS_PWROK failure";
Manojkiran Eda519530b2024-06-17 11:46:15 +0530582 /* Also try logging to Critical log file, if available */
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700583 /* "SYS_PWROK failure,FRU:1" */
584 }
585 else if (data[0] == 0x2)
586 {
587 errLog = "PCH_PWROK failure";
Manojkiran Eda519530b2024-06-17 11:46:15 +0530588 /* Also try logging to Critical log file, if available */
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700589 /* "PCH_PWROK failure,FRU:1" */
590 }
591 else
592 {
593 errLog = "Unknown";
594 }
595}
596
Vijay Khemka63c99be2020-05-27 19:14:35 -0700597static void logCatErr(uint8_t* data, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700598{
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700599 if (data[0] == 0x0)
600 {
601 errLog = "IERR/CATERR";
Manojkiran Eda519530b2024-06-17 11:46:15 +0530602 /* Also try logging to Critical log file, if available */
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700603 /* "IERR,FRU:1 */
604 }
605 else if (data[0] == 0xB)
606 {
607 errLog = "MCERR/CATERR";
Manojkiran Eda519530b2024-06-17 11:46:15 +0530608 /* Also try logging to Critical log file, if available */
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700609 /* "MCERR,FRU:1 */
610 }
611 else
612 {
613 errLog = "Unknown";
614 }
615}
616
Vijay Khemka63c99be2020-05-27 19:14:35 -0700617static void logDimmHot(uint8_t* data, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700618{
619 if ((data[0] << 16 | data[1] << 8 | data[2]) == 0x01FFFF)
620 {
621 errLog = "SOC MEMHOT";
622 }
623 else
624 {
625 errLog = "Unknown";
Manojkiran Eda519530b2024-06-17 11:46:15 +0530626 /* Also try logging to Critical log file, if available */
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700627 /* ""CPU_DIMM_HOT %s,FRU:1" */
628 }
629}
630
Vijay Khemka63c99be2020-05-27 19:14:35 -0700631static void logSwNMI(uint8_t* data, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700632{
633 if ((data[0] << 16 | data[1] << 8 | data[2]) == 0x03FFFF)
634 {
635 errLog = "Software NMI";
636 }
637 else
638 {
639 errLog = "Unknown SW NMI";
640 }
641}
642
Vijay Khemka63c99be2020-05-27 19:14:35 -0700643static void logCPUThermalSts(uint8_t* data, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700644{
645 switch (data[0])
646 {
647 case 0x0:
648 errLog = "CPU Critical Temperature";
649 break;
650 case 0x1:
651 errLog = "PROCHOT#";
652 break;
653 case 0x2:
654 errLog = "TCC Activation";
655 break;
656 default:
657 errLog = "Unknown";
658 }
659}
660
Vijay Khemka63c99be2020-05-27 19:14:35 -0700661static void logMEPwrState(uint8_t* data, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700662{
663 switch (data[0])
664 {
665 case 0:
666 errLog = "RUNNING";
667 break;
668 case 2:
669 errLog = "POWER_OFF";
670 break;
671 default:
672 errLog = "Unknown[" + std::to_string(data[0]) + "]";
673 break;
674 }
675}
676
Vijay Khemka63c99be2020-05-27 19:14:35 -0700677static void logSPSFwHealth(uint8_t* data, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700678{
679 if ((data[0] & 0x0F) == 0x00)
680 {
681 const std::vector<std::string> tmpStr = {
682 "Recovery GPIO forced",
683 "Image execution failed",
684 "Flash erase error",
685 "Flash state information",
686 "Internal error",
687 "BMC did not respond",
688 "Direct Flash update",
689 "Manufacturing error",
690 "Automatic Restore to Factory Presets",
691 "Firmware Exception",
692 "Flash Wear-Out Protection Warning",
693 "Unknown",
694 "Unknown",
695 "DMI interface error",
696 "MCTP interface error",
697 "Auto-configuration finished",
698 "Unsupported Segment Defined Feature",
699 "Unknown",
700 "CPU Debug Capability Disabled",
701 "UMA operation error"};
702
703 if (data[1] < 0x14)
704 {
705 errLog = tmpStr[data[1]];
706 }
707 else
708 {
709 errLog = "Unknown";
710 }
711 }
712 else if ((data[0] & 0x0F) == 0x01)
713 {
714 errLog = "SMBus link failure";
715 }
716 else
717 {
718 errLog = "Unknown";
719 }
720}
721
Vijay Khemka63c99be2020-05-27 19:14:35 -0700722static void logNmExcA(uint8_t* data, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700723{
724 /*NM4.0 #550710, Revision 1.95, and turn to p.155*/
725 if (data[0] == 0xA8)
726 {
727 errLog = "Policy Correction Time Exceeded";
728 }
729 else
730 {
731 errLog = "Unknown";
732 }
733}
734
Vijay Khemka63c99be2020-05-27 19:14:35 -0700735static void logPCHThermal(uint8_t* data, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700736{
Patrick Williams010dee02024-08-16 15:19:44 -0400737 const std::vector<std::string> thresEvtName = {
738 "Lower Non-critical",
739 "Unknown",
740 "Lower Critical",
741 "Unknown",
742 "Lower Non-recoverable",
743 "Unknown",
744 "Unknown",
745 "Upper Non-critical",
746 "Unknown",
747 "Upper Critical",
748 "Unknown",
749 "Upper Non-recoverable"};
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700750
751 if ((data[0] & 0x0f) < 12)
752 {
753 errLog = thresEvtName[(data[0] & 0x0f)];
754 }
755 else
756 {
757 errLog = "Unknown";
758 }
759
760 errLog += ", curr_val: " + std::to_string(data[1]) +
761 " C, thresh_val: " + std::to_string(data[2]) + " C";
762}
763
Vijay Khemka63c99be2020-05-27 19:14:35 -0700764static void logNmHealth(uint8_t* data, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700765{
766 std::vector<std::string> nmErrType = {
767 "Unknown",
768 "Unknown",
769 "Unknown",
770 "Unknown",
771 "Unknown",
772 "Unknown",
773 "Unknown",
774 "Extended Telemetry Device Reading Failure",
775 "Outlet Temperature Reading Failure",
776 "Volumetric Airflow Reading Failure",
777 "Policy Misconfiguration",
778 "Power Sensor Reading Failure",
779 "Inlet Temperature Reading Failure",
780 "Host Communication Error",
781 "Real-time Clock Synchronization Failure",
782 "Platform Shutdown Initiated by Intel NM Policy",
783 "Unknown"};
784 uint8_t nmTypeIdx = (data[0] & 0xf);
785 uint8_t domIdx = (data[1] & 0xf);
786 uint8_t errIdx = ((data[1] >> 4) & 0xf);
787
788 if (nmTypeIdx == 2)
789 {
790 errLog = "SensorIntelNM";
791 }
792 else
793 {
794 errLog = "Unknown";
795 }
796
Patrick Williams010dee02024-08-16 15:19:44 -0400797 errLog += ", Domain:" + nmDomName[domIdx] + ", ErrType:" +
798 nmErrType[errIdx] + ", Err:0x" + byteToStr(data[2]);
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700799}
800
Vijay Khemka63c99be2020-05-27 19:14:35 -0700801static void logNmCap(uint8_t* data, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700802{
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700803 const std::vector<std::string> nmCapStsStr = {"Not Available", "Available"};
804 if (data[0] & 0x7) // BIT1=policy, BIT2=monitoring, BIT3=pwr
805 // limit and the others are reserved
806 {
807 errLog = "PolicyInterface:" + nmCapStsStr[BIT(data[0], 0)] +
808 ",Monitoring:" + nmCapStsStr[BIT(data[0], 1)] +
809 ",PowerLimit:" + nmCapStsStr[BIT(data[0], 2)];
810 }
811 else
812 {
813 errLog = "Unknown";
814 }
815}
816
Vijay Khemka63c99be2020-05-27 19:14:35 -0700817static void logNmThreshold(uint8_t* data, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700818{
819 uint8_t thresNum = (data[0] & 0x3);
820 uint8_t domIdx = (data[1] & 0xf);
821 uint8_t polId = data[2];
822 uint8_t polEvtIdx = BIT(data[0], 3);
823 const std::vector<std::string> polEvtStr = {
824 "Threshold Exceeded", "Policy Correction Time Exceeded"};
825
826 errLog = "Threshold Number:" + std::to_string(thresNum) + "-" +
827 polEvtStr[polEvtIdx] + ", Domain:" + nmDomName[domIdx] +
828 ", PolicyID:0x" + byteToStr(polId);
829}
830
Vijay Khemka63c99be2020-05-27 19:14:35 -0700831static void logPwrThreshold(uint8_t* data, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700832{
833 if (data[0] == 0x00)
834 {
835 errLog = "Limit Not Exceeded";
836 }
837 else if (data[0] == 0x01)
838 {
839 errLog = "Limit Exceeded";
840 }
841 else
842 {
843 errLog = "Unknown";
844 }
845}
846
Vijay Khemka63c99be2020-05-27 19:14:35 -0700847static void logMSMI(uint8_t* data, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700848{
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700849 if (data[0] == 0x0)
850 {
851 errLog = "IERR/MSMI";
852 }
853 else if (data[0] == 0x0B)
854 {
855 errLog = "MCERR/MSMI";
856 }
857 else
858 {
859 errLog = "Unknown";
860 }
861}
862
Vijay Khemka63c99be2020-05-27 19:14:35 -0700863static void logHprWarn(uint8_t* data, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700864{
865 if (data[2] == 0x01)
866 {
867 if (data[1] == 0xFF)
868 {
869 errLog = "Infinite Time";
870 }
871 else
872 {
873 errLog = std::to_string(data[1]) + " minutes";
874 }
875 }
876 else
877 {
878 errLog = "Unknown";
879 }
880}
881
882static const boost::container::flat_map<
883 uint8_t,
Vijay Khemka63c99be2020-05-27 19:14:35 -0700884 std::pair<std::string, std::function<void(uint8_t*, std::string&)>>>
Patrick Williams010dee02024-08-16 15:19:44 -0400885 sensorNameTable = {
886 {0xE9, {"SYSTEM_EVENT", logSysEvent}},
887 {0x7D, {"THERM_THRESH_EVT", logThermalEvent}},
888 {0xAA, {"BUTTON", logDefault}},
889 {0xAB, {"POWER_STATE", logDefault}},
890 {0xEA, {"CRITICAL_IRQ", logCritIrq}},
891 {0x2B, {"POST_ERROR", logPostErr}},
892 {0x40, {"MACHINE_CHK_ERR", logMchChkErr}},
893 {0x41, {"PCIE_ERR", logPcieErr}},
894 {0x43, {"IIO_ERR", logIioErr}},
895 {0X63, {"MEMORY_ECC_ERR", logDefault}},
896 {0X87, {"MEMORY_ERR_LOG_DIS", logDefault}},
897 {0X51, {"PROCHOT_EXT", logDefault}},
898 {0X56, {"PWR_ERR", logPwrErr}},
899 {0xE6, {"CATERR_A", logCatErr}},
900 {0xEB, {"CATERR_B", logCatErr}},
901 {0xB3, {"CPU_DIMM_HOT", logDimmHot}},
902 {0x90, {"SOFTWARE_NMI", logSwNMI}},
903 {0x1C, {"CPU0_THERM_STATUS", logCPUThermalSts}},
904 {0x1D, {"CPU1_THERM_STATUS", logCPUThermalSts}},
905 {0x16, {"ME_POWER_STATE", logMEPwrState}},
906 {0x17, {"SPS_FW_HEALTH", logSPSFwHealth}},
907 {0x18, {"NM_EXCEPTION_A", logNmExcA}},
908 {0x08, {"PCH_THERM_THRESHOLD", logPCHThermal}},
909 {0x19, {"NM_HEALTH", logNmHealth}},
910 {0x1A, {"NM_CAPABILITIES", logNmCap}},
911 {0x1B, {"NM_THRESHOLD", logNmThreshold}},
912 {0x3B, {"PWR_THRESH_EVT", logPwrThreshold}},
913 {0xE7, {"MSMI", logMSMI}},
914 {0xC5, {"HPR_WARNING", logHprWarn}}};
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700915
Vijay Khemka63c99be2020-05-27 19:14:35 -0700916static void parseSelHelper(StdSELEntry* data, std::string& errStr)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700917{
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700918 /* Check if sensor type is OS_BOOT (0x1f) */
919 if (data->sensorType == 0x1F)
920 {
921 /* OS_BOOT used by OS */
922 switch (data->eventData1 & 0xF)
923 {
924 case 0x07:
925 errStr = "Base OS/Hypervisor Installation started";
926 break;
927 case 0x08:
928 errStr = "Base OS/Hypervisor Installation completed";
929 break;
930 case 0x09:
931 errStr = "Base OS/Hypervisor Installation aborted";
932 break;
933 case 0x0A:
934 errStr = "Base OS/Hypervisor Installation failed";
935 break;
936 default:
937 errStr = "Unknown";
938 }
939 return;
940 }
941
942 auto findSensorName = sensorNameTable.find(data->sensorNum);
943 if (findSensorName == sensorNameTable.end())
944 {
945 errStr = "Unknown";
946 return;
947 }
948 else
949 {
950 switch (data->sensorNum)
951 {
952 /* logMemErr function needs data from sensor type */
953 case memoryEccError:
954 case memoryErrLogDIS:
955 findSensorName->second.second(&(data->sensorType), errStr);
956 break;
957 /* Other sensor function needs only event data for parsing */
958 default:
959 findSensorName->second.second(&(data->eventData1), errStr);
960 }
961 }
962
963 if (((data->eventData3 & 0x80) >> 7) == 0)
964 {
965 errStr += " Assertion";
966 }
967 else
968 {
969 errStr += " Deassertion";
970 }
971}
972
Manikandan Elumalaic056dc02020-12-11 06:20:32 +0530973static void parseDimmPhyloc(StdSELEntry* data, std::string& errStr)
974{
975 // Log when " All info available"
976 uint8_t chNum = (data->eventData3 & 0x18) >> 3;
977 uint8_t dimmNum = data->eventData3 & 0x7;
978 uint8_t rankNum = data->eventData2 & 0x03;
979 uint8_t nodeNum = (data->eventData3 & 0xE0) >> 5;
980
981 if (chNum == 3 && dimmNum == 0)
982 {
983 errStr += " Node: " + std::to_string(nodeNum) + "," +
984 " Card: " + std::to_string(chNum) + "," +
985 " Module: " + std::to_string(dimmNum) + "," +
986 " Rank Number: " + std::to_string(rankNum) + "," +
987 " Location: DIMM A0";
988 }
989 else if (chNum == 2 && dimmNum == 0)
990 {
991 errStr += " Node: " + std::to_string(nodeNum) + "," +
992 " Card: " + std::to_string(chNum) + "," +
993 " Module: " + std::to_string(dimmNum) + "," +
994 " Rank Number: " + std::to_string(rankNum) + "," +
995 " Location: DIMM B0";
996 }
997 else if (chNum == 4 && dimmNum == 0)
998 {
999 errStr += " Node: " + std::to_string(nodeNum) + "," +
1000 " Card: " + std::to_string(chNum) + "," +
1001 " Module: " + std::to_string(dimmNum) + "," +
1002 " Rank Number: " + std::to_string(rankNum) + "," +
1003 " Location: DIMM C0 ";
1004 }
1005 else if (chNum == 5 && dimmNum == 0)
1006 {
1007 errStr += " Node: " + std::to_string(nodeNum) + "," +
1008 " Card: " + std::to_string(chNum) + "," +
1009 " Module: " + std::to_string(dimmNum) + "," +
1010 " Rank Number: " + std::to_string(rankNum) + "," +
1011 " Location: DIMM D0";
1012 }
1013 else
1014 {
1015 errStr += " Node: " + std::to_string(nodeNum) + "," +
1016 " Card: " + std::to_string(chNum) + "," +
1017 " Module: " + std::to_string(dimmNum) + "," +
1018 " Rank Number: " + std::to_string(rankNum) + "," +
Manojkiran Eda519530b2024-06-17 11:46:15 +05301019 " Location: DIMM Unknown";
Manikandan Elumalaic056dc02020-12-11 06:20:32 +05301020 }
1021}
1022
Vijay Khemka63c99be2020-05-27 19:14:35 -07001023static void parseStdSel(StdSELEntry* data, std::string& errStr)
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001024{
1025 std::stringstream tmpStream;
1026 tmpStream << std::hex << std::uppercase;
1027
1028 /* TODO: add pal_add_cri_sel */
1029 switch (data->sensorNum)
1030 {
1031 case memoryEccError:
1032 switch (data->eventData1 & 0x0F)
1033 {
1034 case 0x00:
1035 errStr = "Correctable";
1036 tmpStream << "DIMM" << std::setw(2) << std::setfill('0')
1037 << data->eventData3 << " ECC err";
Manikandan Elumalaic056dc02020-12-11 06:20:32 +05301038 parseDimmPhyloc(data, errStr);
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001039 break;
1040 case 0x01:
1041 errStr = "Uncorrectable";
1042 tmpStream << "DIMM" << std::setw(2) << std::setfill('0')
1043 << data->eventData3 << " UECC err";
Manikandan Elumalaic056dc02020-12-11 06:20:32 +05301044 parseDimmPhyloc(data, errStr);
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001045 break;
1046 case 0x02:
1047 errStr = "Parity";
1048 break;
1049 case 0x05:
1050 errStr = "Correctable ECC error Logging Limit Reached";
1051 break;
1052 default:
1053 errStr = "Unknown";
1054 }
1055 break;
1056 case memoryErrLogDIS:
1057 if ((data->eventData1 & 0x0F) == 0)
1058 {
1059 errStr = "Correctable Memory Error Logging Disabled";
1060 }
1061 else
1062 {
1063 errStr = "Unknown";
1064 }
1065 break;
1066 default:
Vijay Khemka139aa4f2019-08-16 09:57:41 -07001067 parseSelHelper(data, errStr);
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001068 return;
1069 }
1070
1071 errStr += " (DIMM " + std::to_string(data->eventData3) + ")";
1072 errStr += " Logical Rank " + std::to_string(data->eventData2 & 0x03);
1073
1074 switch ((data->eventData2 & 0x0C) >> 2)
1075 {
1076 case 0x00:
1077 // Ignore when " All info available"
1078 break;
1079 case 0x01:
1080 errStr += " DIMM info not valid";
1081 break;
1082 case 0x02:
1083 errStr += " CHN info not valid";
1084 break;
1085 case 0x03:
1086 errStr += " CPU info not valid";
1087 break;
1088 default:
1089 errStr += " Unknown";
1090 }
1091
1092 if (((data->eventType & 0x80) >> 7) == 0)
1093 {
1094 errStr += " Assertion";
1095 }
1096 else
1097 {
1098 errStr += " Deassertion";
1099 }
1100
1101 return;
1102}
1103
Vijay Khemka63c99be2020-05-27 19:14:35 -07001104static void parseOemSel(TsOemSELEntry* data, std::string& errStr)
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001105{
1106 std::stringstream tmpStream;
1107 tmpStream << std::hex << std::uppercase << std::setfill('0');
1108
1109 switch (data->recordType)
1110 {
1111 case 0xC0:
1112 tmpStream << "VID:0x" << std::setw(2) << (int)data->oemData[1]
1113 << std::setw(2) << (int)data->oemData[0] << " DID:0x"
1114 << std::setw(2) << (int)data->oemData[3] << std::setw(2)
1115 << (int)data->oemData[2] << " Slot:0x" << std::setw(2)
1116 << (int)data->oemData[4] << " Error ID:0x" << std::setw(2)
1117 << (int)data->oemData[5];
1118 break;
1119 case 0xC2:
1120 tmpStream << "Extra info:0x" << std::setw(2)
1121 << (int)data->oemData[1] << " MSCOD:0x" << std::setw(2)
1122 << (int)data->oemData[3] << std::setw(2)
1123 << (int)data->oemData[2] << " MCACOD:0x" << std::setw(2)
1124 << (int)data->oemData[5] << std::setw(2)
1125 << (int)data->oemData[4];
1126 break;
1127 case 0xC3:
1128 int bank = (data->oemData[1] & 0xf0) >> 4;
1129 int col = ((data->oemData[1] & 0x0f) << 8) | data->oemData[2];
1130
1131 tmpStream << "Fail Device:0x" << std::setw(2)
1132 << (int)data->oemData[0] << " Bank:0x" << std::setw(2)
1133 << bank << " Column:0x" << std::setw(2) << col
1134 << " Failed Row:0x" << std::setw(2)
1135 << (int)data->oemData[3] << std::setw(2)
1136 << (int)data->oemData[4] << std::setw(2)
1137 << (int)data->oemData[5];
1138 }
1139
1140 errStr = tmpStream.str();
1141
1142 return;
1143}
1144
cchoux74519032024-02-04 20:35:29 +08001145static std::string dimmLocationStr(uint8_t socket, uint8_t channel,
1146 uint8_t slot)
1147{
1148 uint8_t sled = (socket >> 4) & 0x3;
1149
1150 socket &= 0xf;
1151 if (channel == 0xFF && slot == 0xFF)
1152 {
1153 return std::format(
1154 "DIMM Slot Location: Sled {:02}/Socket {:02}, Channel unknown"
1155 ", Slot unknown, DIMM unknown",
1156 sled, socket);
1157 }
1158 else
1159 {
1160 channel &= 0xf;
1161 slot &= 0xf;
1162 const char label[] = {'A', 'C', 'B', 'D'};
1163 uint8_t idx = socket * 2 + slot;
1164 return std::format("DIMM Slot Location: Sled {:02}/Socket {:02}"
1165 ", Channel {:02}, Slot {:02} DIMM {}",
1166 sled, socket, channel, slot,
1167 (idx < sizeof(label))
1168 ? label[idx] + std::to_string(channel)
1169 : "NA");
1170 }
1171}
1172
Vijay Khemka63c99be2020-05-27 19:14:35 -07001173static void parseOemUnifiedSel(NtsOemSELEntry* data, std::string& errStr)
Vijay Khemka34a875f2019-08-09 15:08:15 -07001174{
Vijay Khemka63c99be2020-05-27 19:14:35 -07001175 uint8_t* ptr = data->oemData;
cchoux74519032024-02-04 20:35:29 +08001176 uint8_t eventType = ptr[5] & 0xf;
Vijay Khemka34a875f2019-08-09 15:08:15 -07001177 int genInfo = ptr[0];
1178 int errType = genInfo & 0x0f;
cchoux74519032024-02-04 20:35:29 +08001179 std::vector<std::string> dimmErr = {
1180 "Memory training failure",
1181 "Memory correctable error",
1182 "Memory uncorrectable error",
1183 "Memory correctable error (Patrol scrub)",
1184 "Memory uncorrectable error (Patrol scrub)",
1185 "Memory Parity Error (PCC=0)",
1186 "Memory Parity Error (PCC=1)",
1187 "Memory PMIC Error",
1188 "CXL Memory training error",
1189 "Reserved"};
1190 std::vector<std::string> postEvent = {
1191 "System PXE boot fail",
1192 "CMOS/NVRAM configuration cleared",
1193 "TPM Self-Test Fail",
1194 "Boot Drive failure",
1195 "Data Drive failure",
1196 "Received invalid boot order request from BMC",
1197 "System HTTP boot fail",
1198 "BIOS fails to get the certificate from BMC",
1199 "Password cleared by jumper",
1200 "DXE FV check failure",
1201 "AMD ABL failure",
1202 "Reserved"};
1203 std::vector<std::string> certErr = {
1204 "No certificate at BMC", "IPMI transaction fail",
1205 "Certificate data corrupted", "Reserved"};
Patrick Williams010dee02024-08-16 15:19:44 -04001206 std::vector<std::string> pcieEvent = {
1207 "PCIe DPC Event",
1208 "PCIe LER Event",
1209 "PCIe Link Retraining and Recovery",
1210 "PCIe Link CRC Error Check and Retry",
1211 "PCIe Corrupt Data Containment",
1212 "PCIe Express ECRC",
1213 "Reserved"};
cchoux74519032024-02-04 20:35:29 +08001214 std::vector<std::string> memEvent = {
1215 "Memory PPR event",
1216 "Memory Correctable Error logging limit reached",
1217 "Memory disable/map-out for FRB",
1218 "Memory SDDC",
1219 "Memory Address range/Partial mirroring",
1220 "Memory ADDDC",
1221 "Memory SMBus hang recovery",
1222 "No DIMM in System",
1223 "Reserved"};
1224 std::vector<std::string> memPprTime = {"Boot time", "Autonomous",
1225 "Run time", "Reserved"};
1226 std::vector<std::string> memPpr = {"PPR success", "PPR fail", "PPR request",
1227 "Reserved"};
Patrick Williams010dee02024-08-16 15:19:44 -04001228 std::vector<std::string> memAdddc = {
1229 "Bank VLS", "r-Bank VLS + re-buddy", "r-Bank VLS + Rank VLS",
1230 "r-Rank VLS + re-buddy", "Reserved"};
cchoux74519032024-02-04 20:35:29 +08001231 std::vector<std::string> pprEvent = {"PPR disable", "Soft PPR", "Hard PPR",
1232 "Reserved"};
Vijay Khemka34a875f2019-08-09 15:08:15 -07001233
1234 std::stringstream tmpStream;
Vijay Khemka34a875f2019-08-09 15:08:15 -07001235
1236 switch (errType)
1237 {
1238 case unifiedPcieErr:
cchoux74519032024-02-04 20:35:29 +08001239 tmpStream << std::format(
1240 "GeneralInfo: x86/PCIeErr(0x{:02X})"
1241 ", Bus {:02X}/Dev {:02X}/Fun {:02X}, TotalErrID1Cnt: 0x{:04X}"
1242 ", ErrID2: 0x{:02X}, ErrID1: 0x{:02X}",
1243 genInfo, ptr[8], ptr[7] >> 3, ptr[7] & 0x7,
1244 (ptr[10] << 8) | ptr[9], ptr[11], ptr[12]);
Vijay Khemka34a875f2019-08-09 15:08:15 -07001245 break;
1246 case unifiedMemErr:
cchoux74519032024-02-04 20:35:29 +08001247 eventType = ptr[9] & 0xf;
1248 tmpStream << std::format(
1249 "GeneralInfo: MemErr(0x{:02X}), {}, DIMM Failure Event: {}",
1250 genInfo, dimmLocationStr(ptr[5], ptr[6], ptr[7]),
1251 dimmErr[std::min(eventType,
1252 static_cast<uint8_t>(dimmErr.size() - 1))]);
Vijay Khemka34a875f2019-08-09 15:08:15 -07001253
cchoux74519032024-02-04 20:35:29 +08001254 if (static_cast<MemErrType>(eventType) == MemErrType::memTrainErr ||
1255 static_cast<MemErrType>(eventType) == MemErrType::memPmicErr)
1256 {
1257 bool amd = ptr[9] & 0x80;
1258 tmpStream << std::format(
1259 ", Major Code: 0x{:02X}, Minor Code: 0x{:0{}X}", ptr[10],
1260 amd ? (ptr[12] << 8 | ptr[11]) : ptr[11], amd ? 4 : 2);
1261 }
1262 break;
1263 case unifiedIioErr:
1264 tmpStream << std::format(
1265 "GeneralInfo: IIOErr(0x{:02X})"
1266 ", IIO Port Location: Sled {:02}/Socket {:02}, Stack 0x{:02X}"
1267 ", Error Type: 0x{:02X}, Error Severity: 0x{:02X}"
1268 ", Error ID: 0x{:02X}",
1269 genInfo, (ptr[5] >> 4) & 0x3, ptr[5] & 0xf, ptr[6], ptr[10],
1270 ptr[11] & 0xf, ptr[12]);
1271 break;
1272 case unifiedPostEvt:
1273 tmpStream << std::format(
1274 "GeneralInfo: POST(0x{:02X}), POST Failure Event: {}", genInfo,
1275 postEvent[std::min(
1276 eventType, static_cast<uint8_t>(postEvent.size() - 1))]);
1277
1278 switch (static_cast<PostEvtType>(eventType))
1279 {
1280 case PostEvtType::pxeBootFail:
1281 case PostEvtType::httpBootFail:
1282 {
1283 uint8_t failType = ptr[10] & 0xf;
1284 tmpStream
1285 << std::format(", Fail Type: {}, Error Code: 0x{:02X}",
1286 (failType == 4 || failType == 6)
1287 ? std::format("IPv{} fail", failType)
1288 : std::format("0x{:02X}", ptr[10]),
1289 ptr[11]);
1290 break;
1291 }
1292 case PostEvtType::getCertFail:
1293 tmpStream << std::format(
1294 ", Failure Detail: {}",
1295 certErr[std::min(
1296 ptr[9], static_cast<uint8_t>(certErr.size() - 1))]);
1297 break;
1298 case PostEvtType::amdAblFail:
1299 tmpStream << std::format(", ABL Error Code: 0x{:04X}",
1300 (ptr[12] << 8) | ptr[11]);
1301 break;
1302 }
1303 break;
1304 case unifiedPcieEvt:
1305 tmpStream << std::format(
1306 "GeneralInfo: PCIeEvent(0x{:02X}), PCIe Failure Event: {}",
1307 genInfo,
1308 pcieEvent[std::min(
1309 eventType, static_cast<uint8_t>(pcieEvent.size() - 1))]);
1310
1311 if (static_cast<PcieEvtType>(eventType) == PcieEvtType::dpc)
1312 {
1313 tmpStream << std::format(
1314 ", Status: 0x{:04X}, Source ID: 0x{:04X}",
1315 (ptr[8] << 8) | ptr[7], (ptr[10] << 8) | ptr[9]);
1316 }
1317 break;
1318 case unifiedMemEvt:
1319 eventType = ptr[9] & 0xf;
Patrick Williams010dee02024-08-16 15:19:44 -04001320 tmpStream
1321 << std::format("GeneralInfo: MemEvent(0x{:02X})", genInfo)
1322 << (static_cast<MemEvtType>(eventType) != MemEvtType::noDimm
1323 ? std::format(", {}",
1324 dimmLocationStr(ptr[5], ptr[6], ptr[7]))
1325 : "")
1326 << ", DIMM Failure Event: ";
cchoux74519032024-02-04 20:35:29 +08001327
1328 switch (static_cast<MemEvtType>(eventType))
1329 {
1330 case MemEvtType::ppr:
1331 tmpStream << std::format("{} {}",
1332 memPprTime[(ptr[10] >> 2) & 0x3],
1333 memPpr[ptr[10] & 0x3]);
1334 break;
1335 case MemEvtType::adddc:
1336 tmpStream << std::format(
1337 "{} {}",
1338 memEvent[std::min(eventType, static_cast<uint8_t>(
1339 memEvent.size() - 1))],
1340 memAdddc[std::min(
1341 static_cast<uint8_t>(ptr[11] & 0xf),
1342 static_cast<uint8_t>(memAdddc.size() - 1))]);
1343 break;
1344 default:
1345 tmpStream << std::format(
1346 "{}", memEvent[std::min(
1347 eventType,
1348 static_cast<uint8_t>(memEvent.size() - 1))]);
1349 break;
1350 }
1351 break;
1352 case unifiedBootGuard:
1353 tmpStream << std::format(
1354 "GeneralInfo: Boot Guard ACM Failure Events(0x{:02X})"
1355 ", Error Class: 0x{:02X}, Error Code: 0x{:02X}",
1356 genInfo, ptr[9], ptr[10]);
1357 break;
1358 case unifiedPprEvt:
1359 tmpStream << std::format(
1360 "GeneralInfo: PPREvent(0x{:02X}), {}"
1361 ", DIMM Info: {:02X}{:02X}{:02X}{:02X}{:02X}{:02X}{:02X}",
1362 genInfo,
1363 pprEvent[std::min(eventType,
1364 static_cast<uint8_t>(pprEvent.size() - 1))],
1365 ptr[6], ptr[7], ptr[8], ptr[9], ptr[10], ptr[11], ptr[12]);
Vijay Khemka34a875f2019-08-09 15:08:15 -07001366 break;
1367 default:
1368 std::vector<uint8_t> oemData(ptr, ptr + 13);
1369 std::string oemDataStr;
1370 toHexStr(oemData, oemDataStr);
cchoux74519032024-02-04 20:35:29 +08001371 tmpStream << std::format("Undefined Error Type(0x{:02X}), Raw: {}",
1372 errType, oemDataStr);
Vijay Khemka34a875f2019-08-09 15:08:15 -07001373 }
1374
1375 errStr = tmpStream.str();
1376
1377 return;
1378}
1379
Manikandan Elumalaic056dc02020-12-11 06:20:32 +05301380static void parseSelData(uint8_t fruId, std::vector<uint8_t>& reqData,
1381 std::string& msgLog)
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001382{
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001383 /* Get record type */
1384 int recType = reqData[2];
1385 std::string errType, errLog;
1386
Vijay Khemka63c99be2020-05-27 19:14:35 -07001387 uint8_t* ptr = NULL;
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001388
1389 std::stringstream recTypeStream;
1390 recTypeStream << std::hex << std::uppercase << std::setfill('0')
1391 << std::setw(2) << recType;
1392
Manikandan Elumalaic056dc02020-12-11 06:20:32 +05301393 msgLog = "SEL Entry: FRU: " + std::to_string(fruId) + ", Record: ";
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001394
1395 if (recType == stdErrType)
1396 {
Vijay Khemka63c99be2020-05-27 19:14:35 -07001397 StdSELEntry* data = reinterpret_cast<StdSELEntry*>(&reqData[0]);
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001398 std::string sensorName;
1399
1400 errType = stdErr;
1401 if (data->sensorType == 0x1F)
1402 {
1403 sensorName = "OS";
1404 }
1405 else
1406 {
1407 auto findSensorName = sensorNameTable.find(data->sensorNum);
1408 if (findSensorName == sensorNameTable.end())
1409 {
1410 sensorName = "Unknown";
1411 }
1412 else
1413 {
Vijay Khemka139aa4f2019-08-16 09:57:41 -07001414 sensorName = findSensorName->second.first;
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001415 }
1416 }
1417
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001418 parseStdSel(data, errLog);
1419 ptr = &(data->eventData1);
1420 std::vector<uint8_t> evtData(ptr, ptr + 3);
1421 std::string eventData;
1422 toHexStr(evtData, eventData);
1423
1424 std::stringstream senNumStream;
1425 senNumStream << std::hex << std::uppercase << std::setfill('0')
1426 << std::setw(2) << (int)(data->sensorNum);
1427
1428 msgLog += errType + " (0x" + recTypeStream.str() +
Peter Yin0d053ef2024-10-11 23:39:58 +08001429 "), Sensor: " + sensorName + " (0x" + senNumStream.str() +
1430 "), Event Data: (" + eventData + ") " + errLog;
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001431 }
1432 else if ((recType >= oemTSErrTypeMin) && (recType <= oemTSErrTypeMax))
1433 {
1434 /* timestamped OEM SEL records */
Vijay Khemka63c99be2020-05-27 19:14:35 -07001435 TsOemSELEntry* data = reinterpret_cast<TsOemSELEntry*>(&reqData[0]);
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001436 ptr = data->mfrId;
1437 std::vector<uint8_t> mfrIdData(ptr, ptr + 3);
1438 std::string mfrIdStr;
1439 toHexStr(mfrIdData, mfrIdStr);
1440
1441 ptr = data->oemData;
1442 std::vector<uint8_t> oemData(ptr, ptr + 6);
1443 std::string oemDataStr;
1444 toHexStr(oemData, oemDataStr);
1445
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001446 errType = oemTSErr;
1447 parseOemSel(data, errLog);
1448
Peter Yin0d053ef2024-10-11 23:39:58 +08001449 msgLog += errType + " (0x" + recTypeStream.str() + "), MFG ID: " +
1450 mfrIdStr + ", OEM Data: (" + oemDataStr + ") " + errLog;
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001451 }
Vijay Khemka34a875f2019-08-09 15:08:15 -07001452 else if (recType == fbUniErrType)
1453 {
Vijay Khemka63c99be2020-05-27 19:14:35 -07001454 NtsOemSELEntry* data = reinterpret_cast<NtsOemSELEntry*>(&reqData[0]);
Vijay Khemka34a875f2019-08-09 15:08:15 -07001455 errType = fbUniSELErr;
1456 parseOemUnifiedSel(data, errLog);
1457 msgLog += errType + " (0x" + recTypeStream.str() + "), " + errLog;
1458 }
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001459 else if ((recType >= oemNTSErrTypeMin) && (recType <= oemNTSErrTypeMax))
1460 {
1461 /* Non timestamped OEM SEL records */
Vijay Khemka63c99be2020-05-27 19:14:35 -07001462 NtsOemSELEntry* data = reinterpret_cast<NtsOemSELEntry*>(&reqData[0]);
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001463 errType = oemNTSErr;
1464
1465 ptr = data->oemData;
1466 std::vector<uint8_t> oemData(ptr, ptr + 13);
1467 std::string oemDataStr;
1468 toHexStr(oemData, oemDataStr);
1469
Vijay Khemka63c99be2020-05-27 19:14:35 -07001470 parseOemSel((TsOemSELEntry*)data, errLog);
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001471 msgLog += errType + " (0x" + recTypeStream.str() + "), OEM Data: (" +
1472 oemDataStr + ") " + errLog;
1473 }
1474 else
1475 {
1476 errType = unknownErr;
1477 toHexStr(reqData, errLog);
Patrick Williams2405ae92023-05-10 07:50:09 -05001478 msgLog += errType + " (0x" + recTypeStream.str() +
1479 ") RawData: " + errLog;
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001480 }
1481}
1482
Vijay Khemka11b9c3b2019-08-21 15:21:42 -07001483} // namespace fb_oem::ipmi::sel
1484
1485namespace ipmi
1486{
1487
1488namespace storage
1489{
1490
1491static void registerSELFunctions() __attribute__((constructor));
1492static fb_oem::ipmi::sel::SELData selObj __attribute__((init_priority(101)));
1493
1494ipmi::RspType<uint8_t, // SEL version
1495 uint16_t, // SEL entry count
1496 uint16_t, // free space
1497 uint32_t, // last add timestamp
1498 uint32_t, // last erase timestamp
1499 uint8_t> // operation support
1500 ipmiStorageGetSELInfo()
1501{
Vijay Khemka11b9c3b2019-08-21 15:21:42 -07001502 fb_oem::ipmi::sel::GetSELInfoData info;
1503
1504 selObj.getInfo(info);
1505 return ipmi::responseSuccess(info.selVersion, info.entries, info.freeSpace,
1506 info.addTimeStamp, info.eraseTimeStamp,
1507 info.operationSupport);
1508}
1509
1510ipmi::RspType<uint16_t, std::vector<uint8_t>>
1511 ipmiStorageGetSELEntry(std::vector<uint8_t> data)
1512{
Vijay Khemka11b9c3b2019-08-21 15:21:42 -07001513 if (data.size() != sizeof(fb_oem::ipmi::sel::GetSELEntryRequest))
1514 {
1515 return ipmi::responseReqDataLenInvalid();
1516 }
1517
Vijay Khemka63c99be2020-05-27 19:14:35 -07001518 fb_oem::ipmi::sel::GetSELEntryRequest* reqData =
1519 reinterpret_cast<fb_oem::ipmi::sel::GetSELEntryRequest*>(&data[0]);
Vijay Khemka11b9c3b2019-08-21 15:21:42 -07001520
1521 if (reqData->reservID != 0)
1522 {
1523 if (!checkSELReservation(reqData->reservID))
1524 {
1525 return ipmi::responseInvalidReservationId();
1526 }
1527 }
1528
1529 uint16_t selCnt = selObj.getCount();
1530 if (selCnt == 0)
1531 {
1532 return ipmi::responseSensorInvalid();
1533 }
1534
1535 /* If it is asked for first entry */
1536 if (reqData->recordID == fb_oem::ipmi::sel::firstEntry)
1537 {
1538 /* First Entry (0x0000) as per Spec */
1539 reqData->recordID = 1;
1540 }
1541 else if (reqData->recordID == fb_oem::ipmi::sel::lastEntry)
1542 {
1543 /* Last entry (0xFFFF) as per Spec */
1544 reqData->recordID = selCnt;
1545 }
1546
1547 std::string ipmiRaw;
1548
1549 if (selObj.getEntry(reqData->recordID, ipmiRaw) < 0)
1550 {
1551 return ipmi::responseSensorInvalid();
1552 }
1553
1554 std::vector<uint8_t> recDataBytes;
1555 if (fromHexStr(ipmiRaw, recDataBytes) < 0)
1556 {
1557 return ipmi::responseUnspecifiedError();
1558 }
1559
1560 /* Identify the next SEL record ID. If recordID is same as
1561 * total SeL count then next id should be last entry else
1562 * it should be incremented by 1 to current RecordID
1563 */
1564 uint16_t nextRecord;
1565 if (reqData->recordID == selCnt)
1566 {
1567 nextRecord = fb_oem::ipmi::sel::lastEntry;
1568 }
1569 else
1570 {
1571 nextRecord = reqData->recordID + 1;
1572 }
1573
1574 if (reqData->readLen == fb_oem::ipmi::sel::entireRecord)
1575 {
1576 return ipmi::responseSuccess(nextRecord, recDataBytes);
1577 }
1578 else
1579 {
1580 if (reqData->offset >= fb_oem::ipmi::sel::selRecordSize ||
1581 reqData->readLen > fb_oem::ipmi::sel::selRecordSize)
1582 {
1583 return ipmi::responseUnspecifiedError();
1584 }
1585 std::vector<uint8_t> recPartData;
1586
1587 auto diff = fb_oem::ipmi::sel::selRecordSize - reqData->offset;
1588 auto readLength = std::min(diff, static_cast<int>(reqData->readLen));
1589
1590 for (int i = 0; i < readLength; i++)
1591 {
1592 recPartData.push_back(recDataBytes[i + reqData->offset]);
1593 }
1594 return ipmi::responseSuccess(nextRecord, recPartData);
1595 }
1596}
1597
Patrick Williams010dee02024-08-16 15:19:44 -04001598ipmi::RspType<uint16_t>
1599 ipmiStorageAddSELEntry(ipmi::Context::ptr ctx, std::vector<uint8_t> data)
Vijay Khemka11b9c3b2019-08-21 15:21:42 -07001600{
1601 /* Per the IPMI spec, need to cancel any reservation when a
1602 * SEL entry is added
1603 */
1604 cancelSELReservation();
1605
1606 if (data.size() != fb_oem::ipmi::sel::selRecordSize)
1607 {
1608 return ipmi::responseReqDataLenInvalid();
1609 }
1610
1611 std::string ipmiRaw, logErr;
1612 toHexStr(data, ipmiRaw);
1613
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001614 /* Parse sel data and get an error log to be filed */
Manikandan Elumalaic056dc02020-12-11 06:20:32 +05301615 fb_oem::ipmi::sel::parseSelData((ctx->hostIdx + 1), data, logErr);
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001616
Vijay Khemka15a7ae82019-08-20 12:08:14 -07001617 static const std::string openBMCMessageRegistryVersion("0.1");
Patrick Williams010dee02024-08-16 15:19:44 -04001618 std::string messageID =
1619 "OpenBMC." + openBMCMessageRegistryVersion + ".SELEntryAdded";
Vijay Khemka15a7ae82019-08-20 12:08:14 -07001620
Vijay Khemka11b9c3b2019-08-21 15:21:42 -07001621 /* Log the Raw SEL message to the journal */
1622 std::string journalMsg = "SEL Entry Added: " + ipmiRaw;
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001623
Vijay Khemka15a7ae82019-08-20 12:08:14 -07001624 phosphor::logging::log<phosphor::logging::level::INFO>(
1625 journalMsg.c_str(),
1626 phosphor::logging::entry("IPMISEL_MESSAGE_ID=%s", messageID.c_str()),
1627 phosphor::logging::entry("IPMISEL_MESSAGE_ARGS=%s", logErr.c_str()));
Vijay Khemka11b9c3b2019-08-21 15:21:42 -07001628
BonnieLo-wiwynn21a79232023-03-09 16:42:48 +08001629 std::map<std::string, std::string> ad;
1630 std::string severity = "xyz.openbmc_project.Logging.Entry.Level.Critical";
1631 ad.emplace("IPMI_RAW", ipmiRaw);
1632
1633 auto bus = sdbusplus::bus::new_default();
1634 auto reqMsg = bus.new_method_call(
1635 "xyz.openbmc_project.Logging", "/xyz/openbmc_project/logging",
1636 "xyz.openbmc_project.Logging.Create", "Create");
1637 reqMsg.append(logErr, severity, ad);
1638
1639 try
1640 {
1641 bus.call(reqMsg);
1642 }
1643 catch (sdbusplus::exception_t& e)
1644 {
1645 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
1646 }
1647
Vijay Khemka11b9c3b2019-08-21 15:21:42 -07001648 int responseID = selObj.addEntry(ipmiRaw.c_str());
1649 if (responseID < 0)
1650 {
1651 return ipmi::responseUnspecifiedError();
1652 }
1653 return ipmi::responseSuccess((uint16_t)responseID);
1654}
1655
Vijay Khemkac1921c62019-08-09 13:11:31 -07001656ipmi::RspType<uint8_t> ipmiStorageClearSEL(uint16_t reservationID,
Vijay Khemka63c99be2020-05-27 19:14:35 -07001657 const std::array<uint8_t, 3>& clr,
Vijay Khemkac1921c62019-08-09 13:11:31 -07001658 uint8_t eraseOperation)
1659{
1660 if (!checkSELReservation(reservationID))
1661 {
1662 return ipmi::responseInvalidReservationId();
1663 }
1664
1665 static constexpr std::array<uint8_t, 3> clrExpected = {'C', 'L', 'R'};
1666 if (clr != clrExpected)
1667 {
1668 return ipmi::responseInvalidFieldRequest();
1669 }
1670
1671 /* If there is no sel then return erase complete */
1672 if (selObj.getCount() == 0)
1673 {
1674 return ipmi::responseSuccess(fb_oem::ipmi::sel::eraseComplete);
1675 }
1676
1677 /* Erasure status cannot be fetched, so always return erasure
1678 * status as `erase completed`.
1679 */
1680 if (eraseOperation == fb_oem::ipmi::sel::getEraseStatus)
1681 {
1682 return ipmi::responseSuccess(fb_oem::ipmi::sel::eraseComplete);
1683 }
1684
1685 /* Check that initiate erase is correct */
1686 if (eraseOperation != fb_oem::ipmi::sel::initiateErase)
1687 {
1688 return ipmi::responseInvalidFieldRequest();
1689 }
1690
1691 /* Per the IPMI spec, need to cancel any reservation when the
1692 * SEL is cleared
1693 */
1694 cancelSELReservation();
1695
1696 /* Clear the complete Sel Json object */
1697 if (selObj.clear() < 0)
1698 {
1699 return ipmi::responseUnspecifiedError();
1700 }
1701
1702 return ipmi::responseSuccess(fb_oem::ipmi::sel::eraseComplete);
1703}
1704
1705ipmi::RspType<uint32_t> ipmiStorageGetSELTime()
1706{
1707 struct timespec selTime = {};
1708
1709 if (clock_gettime(CLOCK_REALTIME, &selTime) < 0)
1710 {
1711 return ipmi::responseUnspecifiedError();
1712 }
1713
1714 return ipmi::responseSuccess(selTime.tv_sec);
1715}
1716
Willy Tue39f9392022-06-15 13:24:20 -07001717ipmi::RspType<> ipmiStorageSetSELTime(uint32_t)
Vijay Khemkac1921c62019-08-09 13:11:31 -07001718{
1719 // Set SEL Time is not supported
1720 return ipmi::responseInvalidCommand();
1721}
1722
1723ipmi::RspType<uint16_t> ipmiStorageGetSELTimeUtcOffset()
1724{
1725 /* TODO: For now, the SEL time stamp is based on UTC time,
1726 * so return 0x0000 as offset. Might need to change once
1727 * supporting zones in SEL time stamps
1728 */
1729
1730 uint16_t utcOffset = 0x0000;
1731 return ipmi::responseSuccess(utcOffset);
1732}
1733
Vijay Khemka11b9c3b2019-08-21 15:21:42 -07001734void registerSELFunctions()
1735{
1736 // <Get SEL Info>
1737 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
1738 ipmi::storage::cmdGetSelInfo, ipmi::Privilege::User,
1739 ipmiStorageGetSELInfo);
1740
1741 // <Get SEL Entry>
1742 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
1743 ipmi::storage::cmdGetSelEntry, ipmi::Privilege::User,
1744 ipmiStorageGetSELEntry);
1745
1746 // <Add SEL Entry>
1747 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
1748 ipmi::storage::cmdAddSelEntry,
1749 ipmi::Privilege::Operator, ipmiStorageAddSELEntry);
1750
Vijay Khemkac1921c62019-08-09 13:11:31 -07001751 // <Clear SEL>
1752 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
1753 ipmi::storage::cmdClearSel, ipmi::Privilege::Operator,
1754 ipmiStorageClearSEL);
1755
1756 // <Get SEL Time>
1757 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
1758 ipmi::storage::cmdGetSelTime, ipmi::Privilege::User,
1759 ipmiStorageGetSELTime);
1760
1761 // <Set SEL Time>
1762 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
1763 ipmi::storage::cmdSetSelTime,
1764 ipmi::Privilege::Operator, ipmiStorageSetSELTime);
1765
1766 // <Get SEL Time UTC Offset>
1767 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
1768 ipmi::storage::cmdGetSelTimeUtcOffset,
1769 ipmi::Privilege::User,
1770 ipmiStorageGetSELTimeUtcOffset);
1771
Vijay Khemka11b9c3b2019-08-21 15:21:42 -07001772 return;
1773}
1774
1775} // namespace storage
1776} // namespace ipmi