blob: 9fb3ced39dc8025ebd38efc0b2db199018f5ef8d [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>
Peter Yin7f97f752024-11-06 14:00:05 +080030#include <thread>
Vijay Khemka63c99be2020-05-27 19:14:35 -070031
cchoux74519032024-02-04 20:35:29 +080032enum class MemErrType
33{
34 memTrainErr = 0,
35 memPmicErr = 7
36};
37
38enum class PostEvtType
39{
40 pxeBootFail = 0,
41 httpBootFail = 6,
42 getCertFail = 7,
43 amdAblFail = 10
44};
45
46enum class PcieEvtType
47{
48 dpc = 0
49};
50
51enum class MemEvtType
52{
53 ppr = 0,
54 adddc = 5,
55 noDimm = 7
56};
57
Vijay Khemka11b9c3b2019-08-21 15:21:42 -070058//----------------------------------------------------------------------
59// Platform specific functions for storing app data
60//----------------------------------------------------------------------
61
Vijay Khemka139aa4f2019-08-16 09:57:41 -070062static std::string byteToStr(uint8_t byte)
63{
64 std::stringstream ss;
65
66 ss << std::hex << std::uppercase << std::setfill('0');
67 ss << std::setw(2) << (int)byte;
68
69 return ss.str();
70}
71
Vijay Khemka63c99be2020-05-27 19:14:35 -070072static void toHexStr(std::vector<uint8_t>& bytes, std::string& hexStr)
Vijay Khemka11b9c3b2019-08-21 15:21:42 -070073{
74 std::stringstream stream;
75 stream << std::hex << std::uppercase << std::setfill('0');
76 for (const uint8_t byte : bytes)
77 {
78 stream << std::setw(2) << static_cast<int>(byte);
79 }
80 hexStr = stream.str();
81}
82
Vijay Khemka63c99be2020-05-27 19:14:35 -070083static int fromHexStr(const std::string hexStr, std::vector<uint8_t>& data)
Vijay Khemka11b9c3b2019-08-21 15:21:42 -070084{
85 for (unsigned int i = 0; i < hexStr.size(); i += 2)
86 {
87 try
88 {
89 data.push_back(static_cast<uint8_t>(
90 std::stoul(hexStr.substr(i, 2), nullptr, 16)));
91 }
Patrick Williams35d12542021-10-06 11:21:13 -050092 catch (const std::invalid_argument& e)
Vijay Khemka11b9c3b2019-08-21 15:21:42 -070093 {
94 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
95 return -1;
96 }
Patrick Williams35d12542021-10-06 11:21:13 -050097 catch (const std::out_of_range& e)
Vijay Khemka11b9c3b2019-08-21 15:21:42 -070098 {
99 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
100 return -1;
101 }
102 }
103 return 0;
104}
105
106namespace fb_oem::ipmi::sel
107{
108
109class SELData
110{
111 private:
112 nlohmann::json selDataObj;
113
114 void flush()
115 {
116 std::ofstream file(SEL_JSON_DATA_FILE);
117 file << selDataObj;
118 file.close();
119 }
120
121 void init()
122 {
123 selDataObj[KEY_SEL_VER] = 0x51;
124 selDataObj[KEY_SEL_COUNT] = 0;
125 selDataObj[KEY_ADD_TIME] = 0xFFFFFFFF;
126 selDataObj[KEY_ERASE_TIME] = 0xFFFFFFFF;
127 selDataObj[KEY_OPER_SUPP] = 0x02;
128 /* Spec indicates that more than 64kB is free */
129 selDataObj[KEY_FREE_SPACE] = 0xFFFF;
130 }
131
Peter Yinac597172024-11-05 16:15:50 +0800132 void writeEmptyJson()
133 {
134 selDataObj = nlohmann::json::object(); // Create an empty JSON object
135 std::ofstream outFile(SEL_JSON_DATA_FILE);
136 if (outFile)
137 {
138 // Write empty JSON object to the file
139 outFile << selDataObj.dump(4);
140 outFile.close();
141 }
142 else
143 {
144 lg2::info("Failed to create SEL JSON file with empty JSON.");
145 }
146 }
147
Vijay Khemka11b9c3b2019-08-21 15:21:42 -0700148 public:
149 SELData()
150 {
151 /* Get App data stored in json file */
152 std::ifstream file(SEL_JSON_DATA_FILE);
153 if (file)
154 {
Peter Yinac597172024-11-05 16:15:50 +0800155 try
156 {
157 file >> selDataObj;
158 }
159 catch (const nlohmann::json::parse_error& e)
160 {
161 lg2::error("Error parsing SEL JSON file: {ERROR}", "ERROR", e);
162 writeEmptyJson();
163 init(); // Initialize to default values
164 }
Vijay Khemka11b9c3b2019-08-21 15:21:42 -0700165 file.close();
166 }
Peter Yinac597172024-11-05 16:15:50 +0800167 else
168 {
169 lg2::info("Failed to open SEL JSON file.");
170 writeEmptyJson();
171 init();
172 }
Vijay Khemka11b9c3b2019-08-21 15:21:42 -0700173
174 /* Initialize SelData object if no entries. */
175 if (selDataObj.find(KEY_SEL_COUNT) == selDataObj.end())
176 {
177 init();
178 }
179 }
180
181 int clear()
182 {
183 /* Clear the complete Sel Json object */
184 selDataObj.clear();
185 /* Reinitialize it with basic data */
186 init();
187 /* Save the erase time */
188 struct timespec selTime = {};
189 if (clock_gettime(CLOCK_REALTIME, &selTime) < 0)
190 {
191 return -1;
192 }
193 selDataObj[KEY_ERASE_TIME] = selTime.tv_sec;
194 flush();
195 return 0;
196 }
197
198 uint32_t getCount()
199 {
200 return selDataObj[KEY_SEL_COUNT];
201 }
202
Vijay Khemka63c99be2020-05-27 19:14:35 -0700203 void getInfo(GetSELInfoData& info)
Vijay Khemka11b9c3b2019-08-21 15:21:42 -0700204 {
205 info.selVersion = selDataObj[KEY_SEL_VER];
206 info.entries = selDataObj[KEY_SEL_COUNT];
207 info.freeSpace = selDataObj[KEY_FREE_SPACE];
208 info.addTimeStamp = selDataObj[KEY_ADD_TIME];
209 info.eraseTimeStamp = selDataObj[KEY_ERASE_TIME];
210 info.operationSupport = selDataObj[KEY_OPER_SUPP];
211 }
212
Vijay Khemka63c99be2020-05-27 19:14:35 -0700213 int getEntry(uint32_t index, std::string& rawStr)
Vijay Khemka11b9c3b2019-08-21 15:21:42 -0700214 {
215 std::stringstream ss;
216 ss << std::hex;
217 ss << std::setw(2) << std::setfill('0') << index;
218
219 /* Check or the requested SEL Entry, if record is available */
220 if (selDataObj.find(ss.str()) == selDataObj.end())
221 {
222 return -1;
223 }
224
225 rawStr = selDataObj[ss.str()][KEY_SEL_ENTRY_RAW];
226 return 0;
227 }
228
229 int addEntry(std::string keyStr)
230 {
231 struct timespec selTime = {};
232
233 if (clock_gettime(CLOCK_REALTIME, &selTime) < 0)
234 {
235 return -1;
236 }
237
238 selDataObj[KEY_ADD_TIME] = selTime.tv_sec;
239
240 int selCount = selDataObj[KEY_SEL_COUNT];
241 selDataObj[KEY_SEL_COUNT] = ++selCount;
242
243 std::stringstream ss;
244 ss << std::hex;
245 ss << std::setw(2) << std::setfill('0') << selCount;
246
247 selDataObj[ss.str()][KEY_SEL_ENTRY_RAW] = keyStr;
248 flush();
249 return selCount;
250 }
251};
252
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700253/*
Manojkiran Eda519530b2024-06-17 11:46:15 +0530254 * A Function to parse common SEL message, a helper function
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700255 * for parseStdSel.
256 *
Manojkiran Eda519530b2024-06-17 11:46:15 +0530257 * Note that this function __CANNOT__ be overridden.
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700258 * To add board specific routine, please override parseStdSel.
259 */
260
261/*Used by decoding ME event*/
262std::vector<std::string> nmDomName = {
263 "Entire Platform", "CPU Subsystem",
264 "Memory Subsystem", "HW Protection",
265 "High Power I/O subsystem", "Unknown"};
266
267/* Default log message for unknown type */
Willy Tue39f9392022-06-15 13:24:20 -0700268static void logDefault(uint8_t*, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700269{
270 errLog = "Unknown";
271}
272
Vijay Khemka63c99be2020-05-27 19:14:35 -0700273static void logSysEvent(uint8_t* data, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700274{
275 if (data[0] == 0xE5)
276 {
277 errLog = "Cause of Time change - ";
278 switch (data[2])
279 {
280 case 0x00:
281 errLog += "NTP";
282 break;
283 case 0x01:
284 errLog += "Host RTL";
285 break;
286 case 0x02:
287 errLog += "Set SEL time cmd";
288 break;
289 case 0x03:
290 errLog += "Set SEL time UTC offset cmd";
291 break;
292 default:
293 errLog += "Unknown";
294 }
295
296 if (data[1] == 0x00)
297 errLog += " - First Time";
298 else if (data[1] == 0x80)
299 errLog += " - Second Time";
300 }
301 else
302 {
303 errLog = "Unknown";
304 }
305}
306
Vijay Khemka63c99be2020-05-27 19:14:35 -0700307static void logThermalEvent(uint8_t* data, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700308{
309 if (data[0] == 0x1)
310 {
311 errLog = "Limit Exceeded";
312 }
313 else
314 {
315 errLog = "Unknown";
316 }
317}
318
Vijay Khemka63c99be2020-05-27 19:14:35 -0700319static void logCritIrq(uint8_t* data, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700320{
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700321 if (data[0] == 0x0)
322 {
323 errLog = "NMI / Diagnostic Interrupt";
324 }
325 else if (data[0] == 0x03)
326 {
327 errLog = "Software NMI";
328 }
329 else
330 {
331 errLog = "Unknown";
332 }
333
334 /* TODO: Call add_cri_sel for CRITICAL_IRQ */
335}
336
Vijay Khemka63c99be2020-05-27 19:14:35 -0700337static void logPostErr(uint8_t* data, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700338{
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700339 if ((data[0] & 0x0F) == 0x0)
340 {
341 errLog = "System Firmware Error";
342 }
343 else
344 {
345 errLog = "Unknown";
346 }
347
348 if (((data[0] >> 6) & 0x03) == 0x3)
349 {
350 // TODO: Need to implement IPMI spec based Post Code
351 errLog += ", IPMI Post Code";
352 }
353 else if (((data[0] >> 6) & 0x03) == 0x2)
354 {
Patrick Williams2405ae92023-05-10 07:50:09 -0500355 errLog += ", OEM Post Code 0x" + byteToStr(data[2]) +
356 byteToStr(data[1]);
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700357
358 switch ((data[2] << 8) | data[1])
359 {
360 case 0xA105:
361 errLog += ", BMC Failed (No Response)";
362 break;
363 case 0xA106:
364 errLog += ", BMC Failed (Self Test Fail)";
365 break;
366 case 0xA10A:
367 errLog += ", System Firmware Corruption Detected";
368 break;
369 case 0xA10B:
370 errLog += ", TPM Self-Test FAIL Detected";
371 }
372 }
373}
374
Vijay Khemka63c99be2020-05-27 19:14:35 -0700375static void logMchChkErr(uint8_t* data, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700376{
377 /* TODO: Call add_cri_sel for CRITICAL_IRQ */
Daniel Hsud17c3562024-10-17 11:10:31 +0800378 switch (data[0] & 0x0F)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700379 {
Daniel Hsud17c3562024-10-17 11:10:31 +0800380 case 0x0B:
381 switch ((data[1] >> 5) & 0x03)
382 {
383 case 0x00:
384 errLog = "Uncorrected Recoverable Error";
385 break;
386 case 0x01:
387 errLog = "Uncorrected Thread Fatal Error";
388 break;
389 case 0x02:
390 errLog = "Uncorrected System Fatal Error";
391 break;
392 default:
393 errLog = "Unknown";
394 }
395 break;
396 case 0x0C:
397 switch ((data[1] >> 5) & 0x03)
398 {
399 case 0x00:
400 errLog = "Correctable Error";
401 break;
402 case 0x01:
403 errLog = "Deferred Error";
404 break;
405 default:
406 errLog = "Unknown";
407 }
408 break;
409 default:
410 errLog = "Unknown";
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700411 }
412
413 errLog += ", Machine Check bank Number " + std::to_string(data[1]) +
414 ", CPU " + std::to_string(data[2] >> 5) + ", Core " +
415 std::to_string(data[2] & 0x1F);
416}
417
Vijay Khemka63c99be2020-05-27 19:14:35 -0700418static void logPcieErr(uint8_t* data, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700419{
420 std::stringstream tmp1, tmp2;
421 tmp1 << std::hex << std::uppercase << std::setfill('0');
422 tmp2 << std::hex << std::uppercase << std::setfill('0');
423 tmp1 << " (Bus " << std::setw(2) << (int)(data[2]) << " / Dev "
424 << std::setw(2) << (int)(data[1] >> 3) << " / Fun " << std::setw(2)
425 << (int)(data[1] & 0x7) << ")";
426
427 switch (data[0] & 0xF)
428 {
429 case 0x4:
430 errLog = "PCI PERR" + tmp1.str();
431 break;
432 case 0x5:
433 errLog = "PCI SERR" + tmp1.str();
434 break;
435 case 0x7:
436 errLog = "Correctable" + tmp1.str();
437 break;
438 case 0x8:
439 errLog = "Uncorrectable" + tmp1.str();
440 break;
441 case 0xA:
442 errLog = "Bus Fatal" + tmp1.str();
443 break;
Vijay Khemkad1194022020-05-27 18:58:33 -0700444 case 0xD:
445 {
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700446 uint32_t venId = (uint32_t)data[1] << 8 | (uint32_t)data[2];
447 tmp2 << "Vendor ID: 0x" << std::setw(4) << venId;
448 errLog = tmp2.str();
449 }
450 break;
Vijay Khemkad1194022020-05-27 18:58:33 -0700451 case 0xE:
452 {
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700453 uint32_t devId = (uint32_t)data[1] << 8 | (uint32_t)data[2];
454 tmp2 << "Device ID: 0x" << std::setw(4) << devId;
455 errLog = tmp2.str();
456 }
457 break;
458 case 0xF:
459 tmp2 << "Error ID from downstream: 0x" << std::setw(2)
460 << (int)(data[1]) << std::setw(2) << (int)(data[2]);
461 errLog = tmp2.str();
462 break;
463 default:
464 errLog = "Unknown";
465 }
466}
467
Vijay Khemka63c99be2020-05-27 19:14:35 -0700468static void logIioErr(uint8_t* data, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700469{
470 std::vector<std::string> tmpStr = {
471 "IRP0", "IRP1", " IIO-Core", "VT-d", "Intel Quick Data",
472 "Misc", " DMA", "ITC", "OTC", "CI"};
473
474 if ((data[0] & 0xF) == 0)
475 {
476 errLog += "CPU " + std::to_string(data[2] >> 5) + ", Error ID 0x" +
477 byteToStr(data[1]) + " - ";
478
479 if ((data[2] & 0xF) <= 0x9)
480 {
481 errLog += tmpStr[(data[2] & 0xF)];
482 }
483 else
484 {
485 errLog += "Reserved";
486 }
487 }
488 else
489 {
490 errLog = "Unknown";
491 }
492}
493
Willy Tue39f9392022-06-15 13:24:20 -0700494[[maybe_unused]] static void logMemErr(uint8_t* dataPtr, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700495{
496 uint8_t snrType = dataPtr[0];
497 uint8_t snrNum = dataPtr[1];
Vijay Khemka63c99be2020-05-27 19:14:35 -0700498 uint8_t* data = &(dataPtr[3]);
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700499
500 /* TODO: add pal_add_cri_sel */
501
502 if (snrNum == memoryEccError)
503 {
504 /* SEL from MEMORY_ECC_ERR Sensor */
505 switch (data[0] & 0x0F)
506 {
507 case 0x0:
508 if (snrType == 0x0C)
509 {
510 errLog = "Correctable";
511 }
512 else if (snrType == 0x10)
513 {
514 errLog = "Correctable ECC error Logging Disabled";
515 }
516 break;
517 case 0x1:
518 errLog = "Uncorrectable";
519 break;
520 case 0x5:
521 errLog = "Correctable ECC error Logging Limit Disabled";
522 break;
523 default:
524 errLog = "Unknown";
525 }
526 }
527 else if (snrNum == memoryErrLogDIS)
528 {
529 // SEL from MEMORY_ERR_LOG_DIS Sensor
530 if ((data[0] & 0x0F) == 0x0)
531 {
532 errLog = "Correctable Memory Error Logging Disabled";
533 }
534 else
535 {
536 errLog = "Unknown";
537 }
538 }
539 else
540 {
541 errLog = "Unknown";
542 return;
543 }
544
545 /* Common routine for both MEM_ECC_ERR and MEMORY_ERR_LOG_DIS */
546
547 errLog += " (DIMM " + byteToStr(data[2]) + ") Logical Rank " +
548 std::to_string(data[1] & 0x03);
549
550 /* DIMM number (data[2]):
551 * Bit[7:5]: Socket number (Range: 0-7)
552 * Bit[4:3]: Channel number (Range: 0-3)
553 * Bit[2:0]: DIMM number (Range: 0-7)
554 */
555
556 /* TODO: Verify these bits */
557 std::string cpuStr = "CPU# " + std::to_string((data[2] & 0xE0) >> 5);
558 std::string chStr = "CHN# " + std::to_string((data[2] & 0x18) >> 3);
Manikandan Elumalaic056dc02020-12-11 06:20:32 +0530559 std::string dimmStr = "DIMM#" + std::to_string(data[2] & 0x7);
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700560
561 switch ((data[1] & 0xC) >> 2)
562 {
Vijay Khemkad1194022020-05-27 18:58:33 -0700563 case 0x0:
564 {
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700565 /* All Info Valid */
Willy Tue39f9392022-06-15 13:24:20 -0700566 [[maybe_unused]] uint8_t chnNum = (data[2] & 0x1C) >> 2;
567 [[maybe_unused]] uint8_t dimmNum = data[2] & 0x3;
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700568
569 /* TODO: If critical SEL logging is available, do it */
570 if (snrType == 0x0C)
571 {
572 if ((data[0] & 0x0F) == 0x0)
573 {
574 /* TODO: add_cri_sel */
575 /* "DIMM"+ 'A'+ chnNum + dimmNum + " ECC err,FRU:1"
576 */
577 }
578 else if ((data[0] & 0x0F) == 0x1)
579 {
580 /* TODO: add_cri_sel */
581 /* "DIMM"+ 'A'+ chnNum + dimmNum + " UECC err,FRU:1"
582 */
583 }
584 }
585 /* Continue to parse the error into a string. All Info Valid
586 */
587 errLog += " (" + cpuStr + ", " + chStr + ", " + dimmStr + ")";
588 }
589
590 break;
591 case 0x1:
592
593 /* DIMM info not valid */
594 errLog += " (" + cpuStr + ", " + chStr + ")";
595 break;
596 case 0x2:
597
598 /* CHN info not valid */
599 errLog += " (" + cpuStr + ", " + dimmStr + ")";
600 break;
601 case 0x3:
602
603 /* CPU info not valid */
604 errLog += " (" + chStr + ", " + dimmStr + ")";
605 break;
606 }
607}
608
Vijay Khemka63c99be2020-05-27 19:14:35 -0700609static void logPwrErr(uint8_t* data, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700610{
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700611 if (data[0] == 0x1)
612 {
613 errLog = "SYS_PWROK failure";
Manojkiran Eda519530b2024-06-17 11:46:15 +0530614 /* Also try logging to Critical log file, if available */
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700615 /* "SYS_PWROK failure,FRU:1" */
616 }
617 else if (data[0] == 0x2)
618 {
619 errLog = "PCH_PWROK failure";
Manojkiran Eda519530b2024-06-17 11:46:15 +0530620 /* Also try logging to Critical log file, if available */
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700621 /* "PCH_PWROK failure,FRU:1" */
622 }
623 else
624 {
625 errLog = "Unknown";
626 }
627}
628
Vijay Khemka63c99be2020-05-27 19:14:35 -0700629static void logCatErr(uint8_t* data, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700630{
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700631 if (data[0] == 0x0)
632 {
633 errLog = "IERR/CATERR";
Manojkiran Eda519530b2024-06-17 11:46:15 +0530634 /* Also try logging to Critical log file, if available */
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700635 /* "IERR,FRU:1 */
636 }
637 else if (data[0] == 0xB)
638 {
639 errLog = "MCERR/CATERR";
Manojkiran Eda519530b2024-06-17 11:46:15 +0530640 /* Also try logging to Critical log file, if available */
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700641 /* "MCERR,FRU:1 */
642 }
643 else
644 {
645 errLog = "Unknown";
646 }
647}
648
Vijay Khemka63c99be2020-05-27 19:14:35 -0700649static void logDimmHot(uint8_t* data, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700650{
651 if ((data[0] << 16 | data[1] << 8 | data[2]) == 0x01FFFF)
652 {
653 errLog = "SOC MEMHOT";
654 }
655 else
656 {
657 errLog = "Unknown";
Manojkiran Eda519530b2024-06-17 11:46:15 +0530658 /* Also try logging to Critical log file, if available */
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700659 /* ""CPU_DIMM_HOT %s,FRU:1" */
660 }
661}
662
Vijay Khemka63c99be2020-05-27 19:14:35 -0700663static void logSwNMI(uint8_t* data, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700664{
665 if ((data[0] << 16 | data[1] << 8 | data[2]) == 0x03FFFF)
666 {
667 errLog = "Software NMI";
668 }
669 else
670 {
671 errLog = "Unknown SW NMI";
672 }
673}
674
Vijay Khemka63c99be2020-05-27 19:14:35 -0700675static void logCPUThermalSts(uint8_t* data, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700676{
677 switch (data[0])
678 {
679 case 0x0:
680 errLog = "CPU Critical Temperature";
681 break;
682 case 0x1:
683 errLog = "PROCHOT#";
684 break;
685 case 0x2:
686 errLog = "TCC Activation";
687 break;
688 default:
689 errLog = "Unknown";
690 }
691}
692
Vijay Khemka63c99be2020-05-27 19:14:35 -0700693static void logMEPwrState(uint8_t* data, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700694{
695 switch (data[0])
696 {
697 case 0:
698 errLog = "RUNNING";
699 break;
700 case 2:
701 errLog = "POWER_OFF";
702 break;
703 default:
704 errLog = "Unknown[" + std::to_string(data[0]) + "]";
705 break;
706 }
707}
708
Vijay Khemka63c99be2020-05-27 19:14:35 -0700709static void logSPSFwHealth(uint8_t* data, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700710{
711 if ((data[0] & 0x0F) == 0x00)
712 {
713 const std::vector<std::string> tmpStr = {
714 "Recovery GPIO forced",
715 "Image execution failed",
716 "Flash erase error",
717 "Flash state information",
718 "Internal error",
719 "BMC did not respond",
720 "Direct Flash update",
721 "Manufacturing error",
722 "Automatic Restore to Factory Presets",
723 "Firmware Exception",
724 "Flash Wear-Out Protection Warning",
725 "Unknown",
726 "Unknown",
727 "DMI interface error",
728 "MCTP interface error",
729 "Auto-configuration finished",
730 "Unsupported Segment Defined Feature",
731 "Unknown",
732 "CPU Debug Capability Disabled",
733 "UMA operation error"};
734
735 if (data[1] < 0x14)
736 {
737 errLog = tmpStr[data[1]];
738 }
739 else
740 {
741 errLog = "Unknown";
742 }
743 }
744 else if ((data[0] & 0x0F) == 0x01)
745 {
746 errLog = "SMBus link failure";
747 }
748 else
749 {
750 errLog = "Unknown";
751 }
752}
753
Vijay Khemka63c99be2020-05-27 19:14:35 -0700754static void logNmExcA(uint8_t* data, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700755{
756 /*NM4.0 #550710, Revision 1.95, and turn to p.155*/
757 if (data[0] == 0xA8)
758 {
759 errLog = "Policy Correction Time Exceeded";
760 }
761 else
762 {
763 errLog = "Unknown";
764 }
765}
766
Vijay Khemka63c99be2020-05-27 19:14:35 -0700767static void logPCHThermal(uint8_t* data, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700768{
Patrick Williams010dee02024-08-16 15:19:44 -0400769 const std::vector<std::string> thresEvtName = {
770 "Lower Non-critical",
771 "Unknown",
772 "Lower Critical",
773 "Unknown",
774 "Lower Non-recoverable",
775 "Unknown",
776 "Unknown",
777 "Upper Non-critical",
778 "Unknown",
779 "Upper Critical",
780 "Unknown",
781 "Upper Non-recoverable"};
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700782
783 if ((data[0] & 0x0f) < 12)
784 {
785 errLog = thresEvtName[(data[0] & 0x0f)];
786 }
787 else
788 {
789 errLog = "Unknown";
790 }
791
792 errLog += ", curr_val: " + std::to_string(data[1]) +
793 " C, thresh_val: " + std::to_string(data[2]) + " C";
794}
795
Vijay Khemka63c99be2020-05-27 19:14:35 -0700796static void logNmHealth(uint8_t* data, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700797{
798 std::vector<std::string> nmErrType = {
799 "Unknown",
800 "Unknown",
801 "Unknown",
802 "Unknown",
803 "Unknown",
804 "Unknown",
805 "Unknown",
806 "Extended Telemetry Device Reading Failure",
807 "Outlet Temperature Reading Failure",
808 "Volumetric Airflow Reading Failure",
809 "Policy Misconfiguration",
810 "Power Sensor Reading Failure",
811 "Inlet Temperature Reading Failure",
812 "Host Communication Error",
813 "Real-time Clock Synchronization Failure",
814 "Platform Shutdown Initiated by Intel NM Policy",
815 "Unknown"};
816 uint8_t nmTypeIdx = (data[0] & 0xf);
817 uint8_t domIdx = (data[1] & 0xf);
818 uint8_t errIdx = ((data[1] >> 4) & 0xf);
819
820 if (nmTypeIdx == 2)
821 {
822 errLog = "SensorIntelNM";
823 }
824 else
825 {
826 errLog = "Unknown";
827 }
828
Patrick Williams010dee02024-08-16 15:19:44 -0400829 errLog += ", Domain:" + nmDomName[domIdx] + ", ErrType:" +
830 nmErrType[errIdx] + ", Err:0x" + byteToStr(data[2]);
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700831}
832
Vijay Khemka63c99be2020-05-27 19:14:35 -0700833static void logNmCap(uint8_t* data, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700834{
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700835 const std::vector<std::string> nmCapStsStr = {"Not Available", "Available"};
836 if (data[0] & 0x7) // BIT1=policy, BIT2=monitoring, BIT3=pwr
837 // limit and the others are reserved
838 {
839 errLog = "PolicyInterface:" + nmCapStsStr[BIT(data[0], 0)] +
840 ",Monitoring:" + nmCapStsStr[BIT(data[0], 1)] +
841 ",PowerLimit:" + nmCapStsStr[BIT(data[0], 2)];
842 }
843 else
844 {
845 errLog = "Unknown";
846 }
847}
848
Vijay Khemka63c99be2020-05-27 19:14:35 -0700849static void logNmThreshold(uint8_t* data, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700850{
851 uint8_t thresNum = (data[0] & 0x3);
852 uint8_t domIdx = (data[1] & 0xf);
853 uint8_t polId = data[2];
854 uint8_t polEvtIdx = BIT(data[0], 3);
855 const std::vector<std::string> polEvtStr = {
856 "Threshold Exceeded", "Policy Correction Time Exceeded"};
857
858 errLog = "Threshold Number:" + std::to_string(thresNum) + "-" +
859 polEvtStr[polEvtIdx] + ", Domain:" + nmDomName[domIdx] +
860 ", PolicyID:0x" + byteToStr(polId);
861}
862
Vijay Khemka63c99be2020-05-27 19:14:35 -0700863static void logPwrThreshold(uint8_t* data, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700864{
865 if (data[0] == 0x00)
866 {
867 errLog = "Limit Not Exceeded";
868 }
869 else if (data[0] == 0x01)
870 {
871 errLog = "Limit Exceeded";
872 }
873 else
874 {
875 errLog = "Unknown";
876 }
877}
878
Vijay Khemka63c99be2020-05-27 19:14:35 -0700879static void logMSMI(uint8_t* data, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700880{
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700881 if (data[0] == 0x0)
882 {
883 errLog = "IERR/MSMI";
884 }
885 else if (data[0] == 0x0B)
886 {
887 errLog = "MCERR/MSMI";
888 }
889 else
890 {
891 errLog = "Unknown";
892 }
893}
894
Vijay Khemka63c99be2020-05-27 19:14:35 -0700895static void logHprWarn(uint8_t* data, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700896{
897 if (data[2] == 0x01)
898 {
899 if (data[1] == 0xFF)
900 {
901 errLog = "Infinite Time";
902 }
903 else
904 {
905 errLog = std::to_string(data[1]) + " minutes";
906 }
907 }
908 else
909 {
910 errLog = "Unknown";
911 }
912}
913
914static const boost::container::flat_map<
915 uint8_t,
Vijay Khemka63c99be2020-05-27 19:14:35 -0700916 std::pair<std::string, std::function<void(uint8_t*, std::string&)>>>
Patrick Williams010dee02024-08-16 15:19:44 -0400917 sensorNameTable = {
918 {0xE9, {"SYSTEM_EVENT", logSysEvent}},
919 {0x7D, {"THERM_THRESH_EVT", logThermalEvent}},
920 {0xAA, {"BUTTON", logDefault}},
921 {0xAB, {"POWER_STATE", logDefault}},
922 {0xEA, {"CRITICAL_IRQ", logCritIrq}},
923 {0x2B, {"POST_ERROR", logPostErr}},
924 {0x40, {"MACHINE_CHK_ERR", logMchChkErr}},
925 {0x41, {"PCIE_ERR", logPcieErr}},
926 {0x43, {"IIO_ERR", logIioErr}},
927 {0X63, {"MEMORY_ECC_ERR", logDefault}},
928 {0X87, {"MEMORY_ERR_LOG_DIS", logDefault}},
929 {0X51, {"PROCHOT_EXT", logDefault}},
930 {0X56, {"PWR_ERR", logPwrErr}},
931 {0xE6, {"CATERR_A", logCatErr}},
932 {0xEB, {"CATERR_B", logCatErr}},
933 {0xB3, {"CPU_DIMM_HOT", logDimmHot}},
934 {0x90, {"SOFTWARE_NMI", logSwNMI}},
935 {0x1C, {"CPU0_THERM_STATUS", logCPUThermalSts}},
936 {0x1D, {"CPU1_THERM_STATUS", logCPUThermalSts}},
937 {0x16, {"ME_POWER_STATE", logMEPwrState}},
938 {0x17, {"SPS_FW_HEALTH", logSPSFwHealth}},
939 {0x18, {"NM_EXCEPTION_A", logNmExcA}},
940 {0x08, {"PCH_THERM_THRESHOLD", logPCHThermal}},
941 {0x19, {"NM_HEALTH", logNmHealth}},
942 {0x1A, {"NM_CAPABILITIES", logNmCap}},
943 {0x1B, {"NM_THRESHOLD", logNmThreshold}},
944 {0x3B, {"PWR_THRESH_EVT", logPwrThreshold}},
945 {0xE7, {"MSMI", logMSMI}},
946 {0xC5, {"HPR_WARNING", logHprWarn}}};
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700947
Vijay Khemka63c99be2020-05-27 19:14:35 -0700948static void parseSelHelper(StdSELEntry* data, std::string& errStr)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700949{
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700950 /* Check if sensor type is OS_BOOT (0x1f) */
951 if (data->sensorType == 0x1F)
952 {
953 /* OS_BOOT used by OS */
954 switch (data->eventData1 & 0xF)
955 {
956 case 0x07:
957 errStr = "Base OS/Hypervisor Installation started";
958 break;
959 case 0x08:
960 errStr = "Base OS/Hypervisor Installation completed";
961 break;
962 case 0x09:
963 errStr = "Base OS/Hypervisor Installation aborted";
964 break;
965 case 0x0A:
966 errStr = "Base OS/Hypervisor Installation failed";
967 break;
968 default:
969 errStr = "Unknown";
970 }
971 return;
972 }
973
974 auto findSensorName = sensorNameTable.find(data->sensorNum);
975 if (findSensorName == sensorNameTable.end())
976 {
977 errStr = "Unknown";
978 return;
979 }
980 else
981 {
982 switch (data->sensorNum)
983 {
984 /* logMemErr function needs data from sensor type */
985 case memoryEccError:
986 case memoryErrLogDIS:
987 findSensorName->second.second(&(data->sensorType), errStr);
988 break;
989 /* Other sensor function needs only event data for parsing */
990 default:
991 findSensorName->second.second(&(data->eventData1), errStr);
992 }
993 }
994
995 if (((data->eventData3 & 0x80) >> 7) == 0)
996 {
997 errStr += " Assertion";
998 }
999 else
1000 {
1001 errStr += " Deassertion";
1002 }
1003}
1004
Manikandan Elumalaic056dc02020-12-11 06:20:32 +05301005static void parseDimmPhyloc(StdSELEntry* data, std::string& errStr)
1006{
1007 // Log when " All info available"
1008 uint8_t chNum = (data->eventData3 & 0x18) >> 3;
1009 uint8_t dimmNum = data->eventData3 & 0x7;
1010 uint8_t rankNum = data->eventData2 & 0x03;
1011 uint8_t nodeNum = (data->eventData3 & 0xE0) >> 5;
1012
1013 if (chNum == 3 && dimmNum == 0)
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) + "," +
1019 " Location: DIMM A0";
1020 }
1021 else if (chNum == 2 && dimmNum == 0)
1022 {
1023 errStr += " Node: " + std::to_string(nodeNum) + "," +
1024 " Card: " + std::to_string(chNum) + "," +
1025 " Module: " + std::to_string(dimmNum) + "," +
1026 " Rank Number: " + std::to_string(rankNum) + "," +
1027 " Location: DIMM B0";
1028 }
1029 else if (chNum == 4 && dimmNum == 0)
1030 {
1031 errStr += " Node: " + std::to_string(nodeNum) + "," +
1032 " Card: " + std::to_string(chNum) + "," +
1033 " Module: " + std::to_string(dimmNum) + "," +
1034 " Rank Number: " + std::to_string(rankNum) + "," +
1035 " Location: DIMM C0 ";
1036 }
1037 else if (chNum == 5 && dimmNum == 0)
1038 {
1039 errStr += " Node: " + std::to_string(nodeNum) + "," +
1040 " Card: " + std::to_string(chNum) + "," +
1041 " Module: " + std::to_string(dimmNum) + "," +
1042 " Rank Number: " + std::to_string(rankNum) + "," +
1043 " Location: DIMM D0";
1044 }
1045 else
1046 {
1047 errStr += " Node: " + std::to_string(nodeNum) + "," +
1048 " Card: " + std::to_string(chNum) + "," +
1049 " Module: " + std::to_string(dimmNum) + "," +
1050 " Rank Number: " + std::to_string(rankNum) + "," +
Manojkiran Eda519530b2024-06-17 11:46:15 +05301051 " Location: DIMM Unknown";
Manikandan Elumalaic056dc02020-12-11 06:20:32 +05301052 }
1053}
1054
Vijay Khemka63c99be2020-05-27 19:14:35 -07001055static void parseStdSel(StdSELEntry* data, std::string& errStr)
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001056{
1057 std::stringstream tmpStream;
1058 tmpStream << std::hex << std::uppercase;
1059
1060 /* TODO: add pal_add_cri_sel */
1061 switch (data->sensorNum)
1062 {
1063 case memoryEccError:
1064 switch (data->eventData1 & 0x0F)
1065 {
1066 case 0x00:
1067 errStr = "Correctable";
1068 tmpStream << "DIMM" << std::setw(2) << std::setfill('0')
1069 << data->eventData3 << " ECC err";
Manikandan Elumalaic056dc02020-12-11 06:20:32 +05301070 parseDimmPhyloc(data, errStr);
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001071 break;
1072 case 0x01:
1073 errStr = "Uncorrectable";
1074 tmpStream << "DIMM" << std::setw(2) << std::setfill('0')
1075 << data->eventData3 << " UECC err";
Manikandan Elumalaic056dc02020-12-11 06:20:32 +05301076 parseDimmPhyloc(data, errStr);
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001077 break;
1078 case 0x02:
1079 errStr = "Parity";
1080 break;
1081 case 0x05:
1082 errStr = "Correctable ECC error Logging Limit Reached";
1083 break;
1084 default:
1085 errStr = "Unknown";
1086 }
1087 break;
1088 case memoryErrLogDIS:
1089 if ((data->eventData1 & 0x0F) == 0)
1090 {
1091 errStr = "Correctable Memory Error Logging Disabled";
1092 }
1093 else
1094 {
1095 errStr = "Unknown";
1096 }
1097 break;
1098 default:
Vijay Khemka139aa4f2019-08-16 09:57:41 -07001099 parseSelHelper(data, errStr);
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001100 return;
1101 }
1102
1103 errStr += " (DIMM " + std::to_string(data->eventData3) + ")";
1104 errStr += " Logical Rank " + std::to_string(data->eventData2 & 0x03);
1105
1106 switch ((data->eventData2 & 0x0C) >> 2)
1107 {
1108 case 0x00:
1109 // Ignore when " All info available"
1110 break;
1111 case 0x01:
1112 errStr += " DIMM info not valid";
1113 break;
1114 case 0x02:
1115 errStr += " CHN info not valid";
1116 break;
1117 case 0x03:
1118 errStr += " CPU info not valid";
1119 break;
1120 default:
1121 errStr += " Unknown";
1122 }
1123
1124 if (((data->eventType & 0x80) >> 7) == 0)
1125 {
1126 errStr += " Assertion";
1127 }
1128 else
1129 {
1130 errStr += " Deassertion";
1131 }
1132
1133 return;
1134}
1135
Vijay Khemka63c99be2020-05-27 19:14:35 -07001136static void parseOemSel(TsOemSELEntry* data, std::string& errStr)
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001137{
1138 std::stringstream tmpStream;
1139 tmpStream << std::hex << std::uppercase << std::setfill('0');
1140
1141 switch (data->recordType)
1142 {
1143 case 0xC0:
1144 tmpStream << "VID:0x" << std::setw(2) << (int)data->oemData[1]
1145 << std::setw(2) << (int)data->oemData[0] << " DID:0x"
1146 << std::setw(2) << (int)data->oemData[3] << std::setw(2)
1147 << (int)data->oemData[2] << " Slot:0x" << std::setw(2)
1148 << (int)data->oemData[4] << " Error ID:0x" << std::setw(2)
1149 << (int)data->oemData[5];
1150 break;
1151 case 0xC2:
1152 tmpStream << "Extra info:0x" << std::setw(2)
1153 << (int)data->oemData[1] << " MSCOD:0x" << std::setw(2)
1154 << (int)data->oemData[3] << std::setw(2)
1155 << (int)data->oemData[2] << " MCACOD:0x" << std::setw(2)
1156 << (int)data->oemData[5] << std::setw(2)
1157 << (int)data->oemData[4];
1158 break;
1159 case 0xC3:
1160 int bank = (data->oemData[1] & 0xf0) >> 4;
1161 int col = ((data->oemData[1] & 0x0f) << 8) | data->oemData[2];
1162
1163 tmpStream << "Fail Device:0x" << std::setw(2)
1164 << (int)data->oemData[0] << " Bank:0x" << std::setw(2)
1165 << bank << " Column:0x" << std::setw(2) << col
1166 << " Failed Row:0x" << std::setw(2)
1167 << (int)data->oemData[3] << std::setw(2)
1168 << (int)data->oemData[4] << std::setw(2)
1169 << (int)data->oemData[5];
1170 }
1171
1172 errStr = tmpStream.str();
1173
1174 return;
1175}
1176
cchoux74519032024-02-04 20:35:29 +08001177static std::string dimmLocationStr(uint8_t socket, uint8_t channel,
1178 uint8_t slot)
1179{
1180 uint8_t sled = (socket >> 4) & 0x3;
1181
1182 socket &= 0xf;
1183 if (channel == 0xFF && slot == 0xFF)
1184 {
1185 return std::format(
1186 "DIMM Slot Location: Sled {:02}/Socket {:02}, Channel unknown"
1187 ", Slot unknown, DIMM unknown",
1188 sled, socket);
1189 }
1190 else
1191 {
1192 channel &= 0xf;
1193 slot &= 0xf;
1194 const char label[] = {'A', 'C', 'B', 'D'};
1195 uint8_t idx = socket * 2 + slot;
1196 return std::format("DIMM Slot Location: Sled {:02}/Socket {:02}"
1197 ", Channel {:02}, Slot {:02} DIMM {}",
1198 sled, socket, channel, slot,
1199 (idx < sizeof(label))
1200 ? label[idx] + std::to_string(channel)
1201 : "NA");
1202 }
1203}
1204
Vijay Khemka63c99be2020-05-27 19:14:35 -07001205static void parseOemUnifiedSel(NtsOemSELEntry* data, std::string& errStr)
Vijay Khemka34a875f2019-08-09 15:08:15 -07001206{
Vijay Khemka63c99be2020-05-27 19:14:35 -07001207 uint8_t* ptr = data->oemData;
cchoux74519032024-02-04 20:35:29 +08001208 uint8_t eventType = ptr[5] & 0xf;
Vijay Khemka34a875f2019-08-09 15:08:15 -07001209 int genInfo = ptr[0];
1210 int errType = genInfo & 0x0f;
cchoux74519032024-02-04 20:35:29 +08001211 std::vector<std::string> dimmErr = {
1212 "Memory training failure",
1213 "Memory correctable error",
1214 "Memory uncorrectable error",
1215 "Memory correctable error (Patrol scrub)",
1216 "Memory uncorrectable error (Patrol scrub)",
1217 "Memory Parity Error (PCC=0)",
1218 "Memory Parity Error (PCC=1)",
1219 "Memory PMIC Error",
1220 "CXL Memory training error",
1221 "Reserved"};
1222 std::vector<std::string> postEvent = {
1223 "System PXE boot fail",
1224 "CMOS/NVRAM configuration cleared",
1225 "TPM Self-Test Fail",
1226 "Boot Drive failure",
1227 "Data Drive failure",
1228 "Received invalid boot order request from BMC",
1229 "System HTTP boot fail",
1230 "BIOS fails to get the certificate from BMC",
1231 "Password cleared by jumper",
1232 "DXE FV check failure",
1233 "AMD ABL failure",
1234 "Reserved"};
1235 std::vector<std::string> certErr = {
1236 "No certificate at BMC", "IPMI transaction fail",
1237 "Certificate data corrupted", "Reserved"};
Patrick Williams010dee02024-08-16 15:19:44 -04001238 std::vector<std::string> pcieEvent = {
1239 "PCIe DPC Event",
1240 "PCIe LER Event",
1241 "PCIe Link Retraining and Recovery",
1242 "PCIe Link CRC Error Check and Retry",
1243 "PCIe Corrupt Data Containment",
1244 "PCIe Express ECRC",
1245 "Reserved"};
cchoux74519032024-02-04 20:35:29 +08001246 std::vector<std::string> memEvent = {
1247 "Memory PPR event",
1248 "Memory Correctable Error logging limit reached",
1249 "Memory disable/map-out for FRB",
1250 "Memory SDDC",
1251 "Memory Address range/Partial mirroring",
1252 "Memory ADDDC",
1253 "Memory SMBus hang recovery",
1254 "No DIMM in System",
1255 "Reserved"};
1256 std::vector<std::string> memPprTime = {"Boot time", "Autonomous",
1257 "Run time", "Reserved"};
1258 std::vector<std::string> memPpr = {"PPR success", "PPR fail", "PPR request",
1259 "Reserved"};
Patrick Williams010dee02024-08-16 15:19:44 -04001260 std::vector<std::string> memAdddc = {
1261 "Bank VLS", "r-Bank VLS + re-buddy", "r-Bank VLS + Rank VLS",
1262 "r-Rank VLS + re-buddy", "Reserved"};
cchoux74519032024-02-04 20:35:29 +08001263 std::vector<std::string> pprEvent = {"PPR disable", "Soft PPR", "Hard PPR",
1264 "Reserved"};
Vijay Khemka34a875f2019-08-09 15:08:15 -07001265
1266 std::stringstream tmpStream;
Vijay Khemka34a875f2019-08-09 15:08:15 -07001267
1268 switch (errType)
1269 {
1270 case unifiedPcieErr:
cchoux74519032024-02-04 20:35:29 +08001271 tmpStream << std::format(
1272 "GeneralInfo: x86/PCIeErr(0x{:02X})"
1273 ", Bus {:02X}/Dev {:02X}/Fun {:02X}, TotalErrID1Cnt: 0x{:04X}"
1274 ", ErrID2: 0x{:02X}, ErrID1: 0x{:02X}",
1275 genInfo, ptr[8], ptr[7] >> 3, ptr[7] & 0x7,
1276 (ptr[10] << 8) | ptr[9], ptr[11], ptr[12]);
Vijay Khemka34a875f2019-08-09 15:08:15 -07001277 break;
1278 case unifiedMemErr:
cchoux74519032024-02-04 20:35:29 +08001279 eventType = ptr[9] & 0xf;
1280 tmpStream << std::format(
1281 "GeneralInfo: MemErr(0x{:02X}), {}, DIMM Failure Event: {}",
1282 genInfo, dimmLocationStr(ptr[5], ptr[6], ptr[7]),
1283 dimmErr[std::min(eventType,
1284 static_cast<uint8_t>(dimmErr.size() - 1))]);
Vijay Khemka34a875f2019-08-09 15:08:15 -07001285
cchoux74519032024-02-04 20:35:29 +08001286 if (static_cast<MemErrType>(eventType) == MemErrType::memTrainErr ||
1287 static_cast<MemErrType>(eventType) == MemErrType::memPmicErr)
1288 {
1289 bool amd = ptr[9] & 0x80;
1290 tmpStream << std::format(
1291 ", Major Code: 0x{:02X}, Minor Code: 0x{:0{}X}", ptr[10],
1292 amd ? (ptr[12] << 8 | ptr[11]) : ptr[11], amd ? 4 : 2);
1293 }
1294 break;
1295 case unifiedIioErr:
1296 tmpStream << std::format(
1297 "GeneralInfo: IIOErr(0x{:02X})"
1298 ", IIO Port Location: Sled {:02}/Socket {:02}, Stack 0x{:02X}"
1299 ", Error Type: 0x{:02X}, Error Severity: 0x{:02X}"
1300 ", Error ID: 0x{:02X}",
1301 genInfo, (ptr[5] >> 4) & 0x3, ptr[5] & 0xf, ptr[6], ptr[10],
1302 ptr[11] & 0xf, ptr[12]);
1303 break;
1304 case unifiedPostEvt:
1305 tmpStream << std::format(
1306 "GeneralInfo: POST(0x{:02X}), POST Failure Event: {}", genInfo,
1307 postEvent[std::min(
1308 eventType, static_cast<uint8_t>(postEvent.size() - 1))]);
1309
1310 switch (static_cast<PostEvtType>(eventType))
1311 {
1312 case PostEvtType::pxeBootFail:
1313 case PostEvtType::httpBootFail:
1314 {
1315 uint8_t failType = ptr[10] & 0xf;
1316 tmpStream
1317 << std::format(", Fail Type: {}, Error Code: 0x{:02X}",
1318 (failType == 4 || failType == 6)
1319 ? std::format("IPv{} fail", failType)
1320 : std::format("0x{:02X}", ptr[10]),
1321 ptr[11]);
1322 break;
1323 }
1324 case PostEvtType::getCertFail:
1325 tmpStream << std::format(
1326 ", Failure Detail: {}",
1327 certErr[std::min(
1328 ptr[9], static_cast<uint8_t>(certErr.size() - 1))]);
1329 break;
1330 case PostEvtType::amdAblFail:
1331 tmpStream << std::format(", ABL Error Code: 0x{:04X}",
1332 (ptr[12] << 8) | ptr[11]);
1333 break;
1334 }
1335 break;
1336 case unifiedPcieEvt:
1337 tmpStream << std::format(
1338 "GeneralInfo: PCIeEvent(0x{:02X}), PCIe Failure Event: {}",
1339 genInfo,
1340 pcieEvent[std::min(
1341 eventType, static_cast<uint8_t>(pcieEvent.size() - 1))]);
1342
1343 if (static_cast<PcieEvtType>(eventType) == PcieEvtType::dpc)
1344 {
1345 tmpStream << std::format(
1346 ", Status: 0x{:04X}, Source ID: 0x{:04X}",
1347 (ptr[8] << 8) | ptr[7], (ptr[10] << 8) | ptr[9]);
1348 }
1349 break;
1350 case unifiedMemEvt:
1351 eventType = ptr[9] & 0xf;
Patrick Williams010dee02024-08-16 15:19:44 -04001352 tmpStream
1353 << std::format("GeneralInfo: MemEvent(0x{:02X})", genInfo)
1354 << (static_cast<MemEvtType>(eventType) != MemEvtType::noDimm
1355 ? std::format(", {}",
1356 dimmLocationStr(ptr[5], ptr[6], ptr[7]))
1357 : "")
1358 << ", DIMM Failure Event: ";
cchoux74519032024-02-04 20:35:29 +08001359
1360 switch (static_cast<MemEvtType>(eventType))
1361 {
1362 case MemEvtType::ppr:
1363 tmpStream << std::format("{} {}",
1364 memPprTime[(ptr[10] >> 2) & 0x3],
1365 memPpr[ptr[10] & 0x3]);
1366 break;
1367 case MemEvtType::adddc:
1368 tmpStream << std::format(
1369 "{} {}",
1370 memEvent[std::min(eventType, static_cast<uint8_t>(
1371 memEvent.size() - 1))],
1372 memAdddc[std::min(
1373 static_cast<uint8_t>(ptr[11] & 0xf),
1374 static_cast<uint8_t>(memAdddc.size() - 1))]);
1375 break;
1376 default:
1377 tmpStream << std::format(
1378 "{}", memEvent[std::min(
1379 eventType,
1380 static_cast<uint8_t>(memEvent.size() - 1))]);
1381 break;
1382 }
1383 break;
1384 case unifiedBootGuard:
1385 tmpStream << std::format(
1386 "GeneralInfo: Boot Guard ACM Failure Events(0x{:02X})"
1387 ", Error Class: 0x{:02X}, Error Code: 0x{:02X}",
1388 genInfo, ptr[9], ptr[10]);
1389 break;
1390 case unifiedPprEvt:
1391 tmpStream << std::format(
1392 "GeneralInfo: PPREvent(0x{:02X}), {}"
1393 ", DIMM Info: {:02X}{:02X}{:02X}{:02X}{:02X}{:02X}{:02X}",
1394 genInfo,
1395 pprEvent[std::min(eventType,
1396 static_cast<uint8_t>(pprEvent.size() - 1))],
1397 ptr[6], ptr[7], ptr[8], ptr[9], ptr[10], ptr[11], ptr[12]);
Vijay Khemka34a875f2019-08-09 15:08:15 -07001398 break;
1399 default:
1400 std::vector<uint8_t> oemData(ptr, ptr + 13);
1401 std::string oemDataStr;
1402 toHexStr(oemData, oemDataStr);
cchoux74519032024-02-04 20:35:29 +08001403 tmpStream << std::format("Undefined Error Type(0x{:02X}), Raw: {}",
1404 errType, oemDataStr);
Vijay Khemka34a875f2019-08-09 15:08:15 -07001405 }
1406
1407 errStr = tmpStream.str();
1408
1409 return;
1410}
1411
Manikandan Elumalaic056dc02020-12-11 06:20:32 +05301412static void parseSelData(uint8_t fruId, std::vector<uint8_t>& reqData,
1413 std::string& msgLog)
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001414{
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001415 /* Get record type */
1416 int recType = reqData[2];
1417 std::string errType, errLog;
1418
Vijay Khemka63c99be2020-05-27 19:14:35 -07001419 uint8_t* ptr = NULL;
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001420
1421 std::stringstream recTypeStream;
1422 recTypeStream << std::hex << std::uppercase << std::setfill('0')
1423 << std::setw(2) << recType;
1424
Manikandan Elumalaic056dc02020-12-11 06:20:32 +05301425 msgLog = "SEL Entry: FRU: " + std::to_string(fruId) + ", Record: ";
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001426
1427 if (recType == stdErrType)
1428 {
Vijay Khemka63c99be2020-05-27 19:14:35 -07001429 StdSELEntry* data = reinterpret_cast<StdSELEntry*>(&reqData[0]);
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001430 std::string sensorName;
1431
1432 errType = stdErr;
1433 if (data->sensorType == 0x1F)
1434 {
1435 sensorName = "OS";
1436 }
1437 else
1438 {
1439 auto findSensorName = sensorNameTable.find(data->sensorNum);
1440 if (findSensorName == sensorNameTable.end())
1441 {
1442 sensorName = "Unknown";
1443 }
1444 else
1445 {
Vijay Khemka139aa4f2019-08-16 09:57:41 -07001446 sensorName = findSensorName->second.first;
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001447 }
1448 }
1449
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001450 parseStdSel(data, errLog);
1451 ptr = &(data->eventData1);
1452 std::vector<uint8_t> evtData(ptr, ptr + 3);
1453 std::string eventData;
1454 toHexStr(evtData, eventData);
1455
1456 std::stringstream senNumStream;
1457 senNumStream << std::hex << std::uppercase << std::setfill('0')
1458 << std::setw(2) << (int)(data->sensorNum);
1459
1460 msgLog += errType + " (0x" + recTypeStream.str() +
Peter Yin0d053ef2024-10-11 23:39:58 +08001461 "), Sensor: " + sensorName + " (0x" + senNumStream.str() +
1462 "), Event Data: (" + eventData + ") " + errLog;
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001463 }
1464 else if ((recType >= oemTSErrTypeMin) && (recType <= oemTSErrTypeMax))
1465 {
1466 /* timestamped OEM SEL records */
Vijay Khemka63c99be2020-05-27 19:14:35 -07001467 TsOemSELEntry* data = reinterpret_cast<TsOemSELEntry*>(&reqData[0]);
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001468 ptr = data->mfrId;
1469 std::vector<uint8_t> mfrIdData(ptr, ptr + 3);
1470 std::string mfrIdStr;
1471 toHexStr(mfrIdData, mfrIdStr);
1472
1473 ptr = data->oemData;
1474 std::vector<uint8_t> oemData(ptr, ptr + 6);
1475 std::string oemDataStr;
1476 toHexStr(oemData, oemDataStr);
1477
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001478 errType = oemTSErr;
1479 parseOemSel(data, errLog);
1480
Peter Yin0d053ef2024-10-11 23:39:58 +08001481 msgLog += errType + " (0x" + recTypeStream.str() + "), MFG ID: " +
1482 mfrIdStr + ", OEM Data: (" + oemDataStr + ") " + errLog;
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001483 }
Vijay Khemka34a875f2019-08-09 15:08:15 -07001484 else if (recType == fbUniErrType)
1485 {
Vijay Khemka63c99be2020-05-27 19:14:35 -07001486 NtsOemSELEntry* data = reinterpret_cast<NtsOemSELEntry*>(&reqData[0]);
Vijay Khemka34a875f2019-08-09 15:08:15 -07001487 errType = fbUniSELErr;
1488 parseOemUnifiedSel(data, errLog);
1489 msgLog += errType + " (0x" + recTypeStream.str() + "), " + errLog;
1490 }
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001491 else if ((recType >= oemNTSErrTypeMin) && (recType <= oemNTSErrTypeMax))
1492 {
1493 /* Non timestamped OEM SEL records */
Vijay Khemka63c99be2020-05-27 19:14:35 -07001494 NtsOemSELEntry* data = reinterpret_cast<NtsOemSELEntry*>(&reqData[0]);
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001495 errType = oemNTSErr;
1496
1497 ptr = data->oemData;
1498 std::vector<uint8_t> oemData(ptr, ptr + 13);
1499 std::string oemDataStr;
1500 toHexStr(oemData, oemDataStr);
1501
Vijay Khemka63c99be2020-05-27 19:14:35 -07001502 parseOemSel((TsOemSELEntry*)data, errLog);
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001503 msgLog += errType + " (0x" + recTypeStream.str() + "), OEM Data: (" +
1504 oemDataStr + ") " + errLog;
1505 }
1506 else
1507 {
1508 errType = unknownErr;
1509 toHexStr(reqData, errLog);
Patrick Williams2405ae92023-05-10 07:50:09 -05001510 msgLog += errType + " (0x" + recTypeStream.str() +
1511 ") RawData: " + errLog;
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001512 }
1513}
1514
Vijay Khemka11b9c3b2019-08-21 15:21:42 -07001515} // namespace fb_oem::ipmi::sel
1516
1517namespace ipmi
1518{
1519
1520namespace storage
1521{
1522
1523static void registerSELFunctions() __attribute__((constructor));
1524static fb_oem::ipmi::sel::SELData selObj __attribute__((init_priority(101)));
1525
1526ipmi::RspType<uint8_t, // SEL version
1527 uint16_t, // SEL entry count
1528 uint16_t, // free space
1529 uint32_t, // last add timestamp
1530 uint32_t, // last erase timestamp
1531 uint8_t> // operation support
1532 ipmiStorageGetSELInfo()
1533{
Vijay Khemka11b9c3b2019-08-21 15:21:42 -07001534 fb_oem::ipmi::sel::GetSELInfoData info;
1535
1536 selObj.getInfo(info);
1537 return ipmi::responseSuccess(info.selVersion, info.entries, info.freeSpace,
1538 info.addTimeStamp, info.eraseTimeStamp,
1539 info.operationSupport);
1540}
1541
1542ipmi::RspType<uint16_t, std::vector<uint8_t>>
1543 ipmiStorageGetSELEntry(std::vector<uint8_t> data)
1544{
Vijay Khemka11b9c3b2019-08-21 15:21:42 -07001545 if (data.size() != sizeof(fb_oem::ipmi::sel::GetSELEntryRequest))
1546 {
1547 return ipmi::responseReqDataLenInvalid();
1548 }
1549
Vijay Khemka63c99be2020-05-27 19:14:35 -07001550 fb_oem::ipmi::sel::GetSELEntryRequest* reqData =
1551 reinterpret_cast<fb_oem::ipmi::sel::GetSELEntryRequest*>(&data[0]);
Vijay Khemka11b9c3b2019-08-21 15:21:42 -07001552
1553 if (reqData->reservID != 0)
1554 {
1555 if (!checkSELReservation(reqData->reservID))
1556 {
1557 return ipmi::responseInvalidReservationId();
1558 }
1559 }
1560
1561 uint16_t selCnt = selObj.getCount();
1562 if (selCnt == 0)
1563 {
1564 return ipmi::responseSensorInvalid();
1565 }
1566
1567 /* If it is asked for first entry */
1568 if (reqData->recordID == fb_oem::ipmi::sel::firstEntry)
1569 {
1570 /* First Entry (0x0000) as per Spec */
1571 reqData->recordID = 1;
1572 }
1573 else if (reqData->recordID == fb_oem::ipmi::sel::lastEntry)
1574 {
1575 /* Last entry (0xFFFF) as per Spec */
1576 reqData->recordID = selCnt;
1577 }
1578
1579 std::string ipmiRaw;
1580
1581 if (selObj.getEntry(reqData->recordID, ipmiRaw) < 0)
1582 {
1583 return ipmi::responseSensorInvalid();
1584 }
1585
1586 std::vector<uint8_t> recDataBytes;
1587 if (fromHexStr(ipmiRaw, recDataBytes) < 0)
1588 {
1589 return ipmi::responseUnspecifiedError();
1590 }
1591
1592 /* Identify the next SEL record ID. If recordID is same as
1593 * total SeL count then next id should be last entry else
1594 * it should be incremented by 1 to current RecordID
1595 */
1596 uint16_t nextRecord;
1597 if (reqData->recordID == selCnt)
1598 {
1599 nextRecord = fb_oem::ipmi::sel::lastEntry;
1600 }
1601 else
1602 {
1603 nextRecord = reqData->recordID + 1;
1604 }
1605
1606 if (reqData->readLen == fb_oem::ipmi::sel::entireRecord)
1607 {
1608 return ipmi::responseSuccess(nextRecord, recDataBytes);
1609 }
1610 else
1611 {
1612 if (reqData->offset >= fb_oem::ipmi::sel::selRecordSize ||
1613 reqData->readLen > fb_oem::ipmi::sel::selRecordSize)
1614 {
1615 return ipmi::responseUnspecifiedError();
1616 }
1617 std::vector<uint8_t> recPartData;
1618
1619 auto diff = fb_oem::ipmi::sel::selRecordSize - reqData->offset;
1620 auto readLength = std::min(diff, static_cast<int>(reqData->readLen));
1621
1622 for (int i = 0; i < readLength; i++)
1623 {
1624 recPartData.push_back(recDataBytes[i + reqData->offset]);
1625 }
1626 return ipmi::responseSuccess(nextRecord, recPartData);
1627 }
1628}
1629
Peter Yin7f97f752024-11-06 14:00:05 +08001630// Retry function to log the SEL entry message and make D-Bus call
1631bool logWithRetry(
1632 const std::string& journalMsg, const std::string& messageID,
1633 const std::string& logErr, const std::string& severity,
1634 const std::map<std::string, std::string>& ad, int maxRetries = 10,
1635 std::chrono::milliseconds waitTimeMs = std::chrono::milliseconds(100))
1636{
1637 // Attempt to log the SEL entry message
1638 lg2::info(
1639 "SEL Entry Added: {IPMI_RAW}, IPMISEL_MESSAGE_ID={MESSAGE_ID}, IPMISEL_MESSAGE_ARGS={LOG_ERR}",
1640 "IPMI_RAW", journalMsg, "MESSAGE_ID", messageID, "LOG_ERR", logErr);
1641
1642 int attempts = 0;
1643 while (attempts < maxRetries)
1644 {
1645 // Create D-Bus call
1646 auto bus = sdbusplus::bus::new_default();
1647 auto reqMsg = bus.new_method_call(
1648 "xyz.openbmc_project.Logging", "/xyz/openbmc_project/logging",
1649 "xyz.openbmc_project.Logging.Create", "Create");
1650 reqMsg.append(logErr, severity, ad);
1651
1652 try
1653 {
1654 // Attempt to make the D-Bus call
1655 bus.call(reqMsg);
1656 return true; // D-Bus call successful, exit the loop
1657 }
1658 catch (sdbusplus::exception_t& e)
1659 {
1660 lg2::error("D-Bus call failed: {ERROR}", "ERROR", e);
1661 }
1662
1663 // Wait before retrying
1664 std::this_thread::sleep_for(std::chrono::milliseconds(waitTimeMs));
1665 attempts++;
1666 }
1667
1668 return false; // Failed after max retries
1669}
1670
1671// Main function to add SEL entry
Patrick Williams010dee02024-08-16 15:19:44 -04001672ipmi::RspType<uint16_t>
1673 ipmiStorageAddSELEntry(ipmi::Context::ptr ctx, std::vector<uint8_t> data)
Vijay Khemka11b9c3b2019-08-21 15:21:42 -07001674{
1675 /* Per the IPMI spec, need to cancel any reservation when a
1676 * SEL entry is added
1677 */
1678 cancelSELReservation();
1679
1680 if (data.size() != fb_oem::ipmi::sel::selRecordSize)
1681 {
1682 return ipmi::responseReqDataLenInvalid();
1683 }
1684
1685 std::string ipmiRaw, logErr;
1686 toHexStr(data, ipmiRaw);
1687
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001688 /* Parse sel data and get an error log to be filed */
Manikandan Elumalaic056dc02020-12-11 06:20:32 +05301689 fb_oem::ipmi::sel::parseSelData((ctx->hostIdx + 1), data, logErr);
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001690
Vijay Khemka15a7ae82019-08-20 12:08:14 -07001691 static const std::string openBMCMessageRegistryVersion("0.1");
Patrick Williams010dee02024-08-16 15:19:44 -04001692 std::string messageID =
1693 "OpenBMC." + openBMCMessageRegistryVersion + ".SELEntryAdded";
Vijay Khemka15a7ae82019-08-20 12:08:14 -07001694
Vijay Khemka11b9c3b2019-08-21 15:21:42 -07001695 /* Log the Raw SEL message to the journal */
1696 std::string journalMsg = "SEL Entry Added: " + ipmiRaw;
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001697
BonnieLo-wiwynn21a79232023-03-09 16:42:48 +08001698 std::map<std::string, std::string> ad;
1699 std::string severity = "xyz.openbmc_project.Logging.Entry.Level.Critical";
1700 ad.emplace("IPMI_RAW", ipmiRaw);
1701
Peter Yin7f97f752024-11-06 14:00:05 +08001702 // Launch the logging thread
1703 std::thread([=]() {
1704 bool success =
1705 logWithRetry(journalMsg, messageID, logErr, severity, ad);
1706 if (!success)
1707 {
1708 lg2::error("Failed to log SEL entry added event after retries.");
1709 }
1710 }).detach();
BonnieLo-wiwynn21a79232023-03-09 16:42:48 +08001711
Vijay Khemka11b9c3b2019-08-21 15:21:42 -07001712 int responseID = selObj.addEntry(ipmiRaw.c_str());
1713 if (responseID < 0)
1714 {
1715 return ipmi::responseUnspecifiedError();
1716 }
Peter Yin7f97f752024-11-06 14:00:05 +08001717 return ipmi::responseSuccess(static_cast<uint16_t>(responseID));
Vijay Khemka11b9c3b2019-08-21 15:21:42 -07001718}
1719
Vijay Khemkac1921c62019-08-09 13:11:31 -07001720ipmi::RspType<uint8_t> ipmiStorageClearSEL(uint16_t reservationID,
Vijay Khemka63c99be2020-05-27 19:14:35 -07001721 const std::array<uint8_t, 3>& clr,
Vijay Khemkac1921c62019-08-09 13:11:31 -07001722 uint8_t eraseOperation)
1723{
1724 if (!checkSELReservation(reservationID))
1725 {
1726 return ipmi::responseInvalidReservationId();
1727 }
1728
1729 static constexpr std::array<uint8_t, 3> clrExpected = {'C', 'L', 'R'};
1730 if (clr != clrExpected)
1731 {
1732 return ipmi::responseInvalidFieldRequest();
1733 }
1734
1735 /* If there is no sel then return erase complete */
1736 if (selObj.getCount() == 0)
1737 {
1738 return ipmi::responseSuccess(fb_oem::ipmi::sel::eraseComplete);
1739 }
1740
1741 /* Erasure status cannot be fetched, so always return erasure
1742 * status as `erase completed`.
1743 */
1744 if (eraseOperation == fb_oem::ipmi::sel::getEraseStatus)
1745 {
1746 return ipmi::responseSuccess(fb_oem::ipmi::sel::eraseComplete);
1747 }
1748
1749 /* Check that initiate erase is correct */
1750 if (eraseOperation != fb_oem::ipmi::sel::initiateErase)
1751 {
1752 return ipmi::responseInvalidFieldRequest();
1753 }
1754
1755 /* Per the IPMI spec, need to cancel any reservation when the
1756 * SEL is cleared
1757 */
1758 cancelSELReservation();
1759
1760 /* Clear the complete Sel Json object */
1761 if (selObj.clear() < 0)
1762 {
1763 return ipmi::responseUnspecifiedError();
1764 }
1765
1766 return ipmi::responseSuccess(fb_oem::ipmi::sel::eraseComplete);
1767}
1768
1769ipmi::RspType<uint32_t> ipmiStorageGetSELTime()
1770{
1771 struct timespec selTime = {};
1772
1773 if (clock_gettime(CLOCK_REALTIME, &selTime) < 0)
1774 {
1775 return ipmi::responseUnspecifiedError();
1776 }
1777
1778 return ipmi::responseSuccess(selTime.tv_sec);
1779}
1780
Willy Tue39f9392022-06-15 13:24:20 -07001781ipmi::RspType<> ipmiStorageSetSELTime(uint32_t)
Vijay Khemkac1921c62019-08-09 13:11:31 -07001782{
1783 // Set SEL Time is not supported
1784 return ipmi::responseInvalidCommand();
1785}
1786
1787ipmi::RspType<uint16_t> ipmiStorageGetSELTimeUtcOffset()
1788{
1789 /* TODO: For now, the SEL time stamp is based on UTC time,
1790 * so return 0x0000 as offset. Might need to change once
1791 * supporting zones in SEL time stamps
1792 */
1793
1794 uint16_t utcOffset = 0x0000;
1795 return ipmi::responseSuccess(utcOffset);
1796}
1797
Vijay Khemka11b9c3b2019-08-21 15:21:42 -07001798void registerSELFunctions()
1799{
1800 // <Get SEL Info>
1801 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
1802 ipmi::storage::cmdGetSelInfo, ipmi::Privilege::User,
1803 ipmiStorageGetSELInfo);
1804
1805 // <Get SEL Entry>
1806 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
1807 ipmi::storage::cmdGetSelEntry, ipmi::Privilege::User,
1808 ipmiStorageGetSELEntry);
1809
1810 // <Add SEL Entry>
1811 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
1812 ipmi::storage::cmdAddSelEntry,
1813 ipmi::Privilege::Operator, ipmiStorageAddSELEntry);
1814
Vijay Khemkac1921c62019-08-09 13:11:31 -07001815 // <Clear SEL>
1816 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
1817 ipmi::storage::cmdClearSel, ipmi::Privilege::Operator,
1818 ipmiStorageClearSEL);
1819
1820 // <Get SEL Time>
1821 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
1822 ipmi::storage::cmdGetSelTime, ipmi::Privilege::User,
1823 ipmiStorageGetSELTime);
1824
1825 // <Set SEL Time>
1826 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
1827 ipmi::storage::cmdSetSelTime,
1828 ipmi::Privilege::Operator, ipmiStorageSetSELTime);
1829
1830 // <Get SEL Time UTC Offset>
1831 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
1832 ipmi::storage::cmdGetSelTimeUtcOffset,
1833 ipmi::Privilege::User,
1834 ipmiStorageGetSELTimeUtcOffset);
1835
Vijay Khemka11b9c3b2019-08-21 15:21:42 -07001836 return;
1837}
1838
1839} // namespace storage
1840} // namespace ipmi