blob: 70691534be7ba0af44d311da9fefe9d622c386a4 [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
Peter Yinac597172024-11-05 16:15:50 +0800131 void writeEmptyJson()
132 {
133 selDataObj = nlohmann::json::object(); // Create an empty JSON object
134 std::ofstream outFile(SEL_JSON_DATA_FILE);
135 if (outFile)
136 {
137 // Write empty JSON object to the file
138 outFile << selDataObj.dump(4);
139 outFile.close();
140 }
141 else
142 {
143 lg2::info("Failed to create SEL JSON file with empty JSON.");
144 }
145 }
146
Vijay Khemka11b9c3b2019-08-21 15:21:42 -0700147 public:
148 SELData()
149 {
150 /* Get App data stored in json file */
151 std::ifstream file(SEL_JSON_DATA_FILE);
152 if (file)
153 {
Peter Yinac597172024-11-05 16:15:50 +0800154 try
155 {
156 file >> selDataObj;
157 }
158 catch (const nlohmann::json::parse_error& e)
159 {
160 lg2::error("Error parsing SEL JSON file: {ERROR}", "ERROR", e);
161 writeEmptyJson();
162 init(); // Initialize to default values
163 }
Vijay Khemka11b9c3b2019-08-21 15:21:42 -0700164 file.close();
165 }
Peter Yinac597172024-11-05 16:15:50 +0800166 else
167 {
168 lg2::info("Failed to open SEL JSON file.");
169 writeEmptyJson();
170 init();
171 }
Vijay Khemka11b9c3b2019-08-21 15:21:42 -0700172
173 /* Initialize SelData object if no entries. */
174 if (selDataObj.find(KEY_SEL_COUNT) == selDataObj.end())
175 {
176 init();
177 }
178 }
179
180 int clear()
181 {
182 /* Clear the complete Sel Json object */
183 selDataObj.clear();
184 /* Reinitialize it with basic data */
185 init();
186 /* Save the erase time */
187 struct timespec selTime = {};
188 if (clock_gettime(CLOCK_REALTIME, &selTime) < 0)
189 {
190 return -1;
191 }
192 selDataObj[KEY_ERASE_TIME] = selTime.tv_sec;
193 flush();
194 return 0;
195 }
196
197 uint32_t getCount()
198 {
199 return selDataObj[KEY_SEL_COUNT];
200 }
201
Vijay Khemka63c99be2020-05-27 19:14:35 -0700202 void getInfo(GetSELInfoData& info)
Vijay Khemka11b9c3b2019-08-21 15:21:42 -0700203 {
204 info.selVersion = selDataObj[KEY_SEL_VER];
205 info.entries = selDataObj[KEY_SEL_COUNT];
206 info.freeSpace = selDataObj[KEY_FREE_SPACE];
207 info.addTimeStamp = selDataObj[KEY_ADD_TIME];
208 info.eraseTimeStamp = selDataObj[KEY_ERASE_TIME];
209 info.operationSupport = selDataObj[KEY_OPER_SUPP];
210 }
211
Vijay Khemka63c99be2020-05-27 19:14:35 -0700212 int getEntry(uint32_t index, std::string& rawStr)
Vijay Khemka11b9c3b2019-08-21 15:21:42 -0700213 {
214 std::stringstream ss;
215 ss << std::hex;
216 ss << std::setw(2) << std::setfill('0') << index;
217
218 /* Check or the requested SEL Entry, if record is available */
219 if (selDataObj.find(ss.str()) == selDataObj.end())
220 {
221 return -1;
222 }
223
224 rawStr = selDataObj[ss.str()][KEY_SEL_ENTRY_RAW];
225 return 0;
226 }
227
228 int addEntry(std::string keyStr)
229 {
230 struct timespec selTime = {};
231
232 if (clock_gettime(CLOCK_REALTIME, &selTime) < 0)
233 {
234 return -1;
235 }
236
237 selDataObj[KEY_ADD_TIME] = selTime.tv_sec;
238
239 int selCount = selDataObj[KEY_SEL_COUNT];
240 selDataObj[KEY_SEL_COUNT] = ++selCount;
241
242 std::stringstream ss;
243 ss << std::hex;
244 ss << std::setw(2) << std::setfill('0') << selCount;
245
246 selDataObj[ss.str()][KEY_SEL_ENTRY_RAW] = keyStr;
247 flush();
248 return selCount;
249 }
250};
251
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700252/*
Manojkiran Eda519530b2024-06-17 11:46:15 +0530253 * A Function to parse common SEL message, a helper function
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700254 * for parseStdSel.
255 *
Manojkiran Eda519530b2024-06-17 11:46:15 +0530256 * Note that this function __CANNOT__ be overridden.
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700257 * To add board specific routine, please override parseStdSel.
258 */
259
260/*Used by decoding ME event*/
261std::vector<std::string> nmDomName = {
262 "Entire Platform", "CPU Subsystem",
263 "Memory Subsystem", "HW Protection",
264 "High Power I/O subsystem", "Unknown"};
265
266/* Default log message for unknown type */
Willy Tue39f9392022-06-15 13:24:20 -0700267static void logDefault(uint8_t*, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700268{
269 errLog = "Unknown";
270}
271
Vijay Khemka63c99be2020-05-27 19:14:35 -0700272static void logSysEvent(uint8_t* data, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700273{
274 if (data[0] == 0xE5)
275 {
276 errLog = "Cause of Time change - ";
277 switch (data[2])
278 {
279 case 0x00:
280 errLog += "NTP";
281 break;
282 case 0x01:
283 errLog += "Host RTL";
284 break;
285 case 0x02:
286 errLog += "Set SEL time cmd";
287 break;
288 case 0x03:
289 errLog += "Set SEL time UTC offset cmd";
290 break;
291 default:
292 errLog += "Unknown";
293 }
294
295 if (data[1] == 0x00)
296 errLog += " - First Time";
297 else if (data[1] == 0x80)
298 errLog += " - Second Time";
299 }
300 else
301 {
302 errLog = "Unknown";
303 }
304}
305
Vijay Khemka63c99be2020-05-27 19:14:35 -0700306static void logThermalEvent(uint8_t* data, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700307{
308 if (data[0] == 0x1)
309 {
310 errLog = "Limit Exceeded";
311 }
312 else
313 {
314 errLog = "Unknown";
315 }
316}
317
Vijay Khemka63c99be2020-05-27 19:14:35 -0700318static void logCritIrq(uint8_t* data, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700319{
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700320 if (data[0] == 0x0)
321 {
322 errLog = "NMI / Diagnostic Interrupt";
323 }
324 else if (data[0] == 0x03)
325 {
326 errLog = "Software NMI";
327 }
328 else
329 {
330 errLog = "Unknown";
331 }
332
333 /* TODO: Call add_cri_sel for CRITICAL_IRQ */
334}
335
Vijay Khemka63c99be2020-05-27 19:14:35 -0700336static void logPostErr(uint8_t* data, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700337{
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700338 if ((data[0] & 0x0F) == 0x0)
339 {
340 errLog = "System Firmware Error";
341 }
342 else
343 {
344 errLog = "Unknown";
345 }
346
347 if (((data[0] >> 6) & 0x03) == 0x3)
348 {
349 // TODO: Need to implement IPMI spec based Post Code
350 errLog += ", IPMI Post Code";
351 }
352 else if (((data[0] >> 6) & 0x03) == 0x2)
353 {
Patrick Williams2405ae92023-05-10 07:50:09 -0500354 errLog += ", OEM Post Code 0x" + byteToStr(data[2]) +
355 byteToStr(data[1]);
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700356
357 switch ((data[2] << 8) | data[1])
358 {
359 case 0xA105:
360 errLog += ", BMC Failed (No Response)";
361 break;
362 case 0xA106:
363 errLog += ", BMC Failed (Self Test Fail)";
364 break;
365 case 0xA10A:
366 errLog += ", System Firmware Corruption Detected";
367 break;
368 case 0xA10B:
369 errLog += ", TPM Self-Test FAIL Detected";
370 }
371 }
372}
373
Vijay Khemka63c99be2020-05-27 19:14:35 -0700374static void logMchChkErr(uint8_t* data, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700375{
376 /* TODO: Call add_cri_sel for CRITICAL_IRQ */
Daniel Hsud17c3562024-10-17 11:10:31 +0800377 switch (data[0] & 0x0F)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700378 {
Daniel Hsud17c3562024-10-17 11:10:31 +0800379 case 0x0B:
380 switch ((data[1] >> 5) & 0x03)
381 {
382 case 0x00:
383 errLog = "Uncorrected Recoverable Error";
384 break;
385 case 0x01:
386 errLog = "Uncorrected Thread Fatal Error";
387 break;
388 case 0x02:
389 errLog = "Uncorrected System Fatal Error";
390 break;
391 default:
392 errLog = "Unknown";
393 }
394 break;
395 case 0x0C:
396 switch ((data[1] >> 5) & 0x03)
397 {
398 case 0x00:
399 errLog = "Correctable Error";
400 break;
401 case 0x01:
402 errLog = "Deferred Error";
403 break;
404 default:
405 errLog = "Unknown";
406 }
407 break;
408 default:
409 errLog = "Unknown";
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700410 }
411
412 errLog += ", Machine Check bank Number " + std::to_string(data[1]) +
413 ", CPU " + std::to_string(data[2] >> 5) + ", Core " +
414 std::to_string(data[2] & 0x1F);
415}
416
Vijay Khemka63c99be2020-05-27 19:14:35 -0700417static void logPcieErr(uint8_t* data, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700418{
419 std::stringstream tmp1, tmp2;
420 tmp1 << std::hex << std::uppercase << std::setfill('0');
421 tmp2 << std::hex << std::uppercase << std::setfill('0');
422 tmp1 << " (Bus " << std::setw(2) << (int)(data[2]) << " / Dev "
423 << std::setw(2) << (int)(data[1] >> 3) << " / Fun " << std::setw(2)
424 << (int)(data[1] & 0x7) << ")";
425
426 switch (data[0] & 0xF)
427 {
428 case 0x4:
429 errLog = "PCI PERR" + tmp1.str();
430 break;
431 case 0x5:
432 errLog = "PCI SERR" + tmp1.str();
433 break;
434 case 0x7:
435 errLog = "Correctable" + tmp1.str();
436 break;
437 case 0x8:
438 errLog = "Uncorrectable" + tmp1.str();
439 break;
440 case 0xA:
441 errLog = "Bus Fatal" + tmp1.str();
442 break;
Vijay Khemkad1194022020-05-27 18:58:33 -0700443 case 0xD:
444 {
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700445 uint32_t venId = (uint32_t)data[1] << 8 | (uint32_t)data[2];
446 tmp2 << "Vendor ID: 0x" << std::setw(4) << venId;
447 errLog = tmp2.str();
448 }
449 break;
Vijay Khemkad1194022020-05-27 18:58:33 -0700450 case 0xE:
451 {
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700452 uint32_t devId = (uint32_t)data[1] << 8 | (uint32_t)data[2];
453 tmp2 << "Device ID: 0x" << std::setw(4) << devId;
454 errLog = tmp2.str();
455 }
456 break;
457 case 0xF:
458 tmp2 << "Error ID from downstream: 0x" << std::setw(2)
459 << (int)(data[1]) << std::setw(2) << (int)(data[2]);
460 errLog = tmp2.str();
461 break;
462 default:
463 errLog = "Unknown";
464 }
465}
466
Vijay Khemka63c99be2020-05-27 19:14:35 -0700467static void logIioErr(uint8_t* data, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700468{
469 std::vector<std::string> tmpStr = {
470 "IRP0", "IRP1", " IIO-Core", "VT-d", "Intel Quick Data",
471 "Misc", " DMA", "ITC", "OTC", "CI"};
472
473 if ((data[0] & 0xF) == 0)
474 {
475 errLog += "CPU " + std::to_string(data[2] >> 5) + ", Error ID 0x" +
476 byteToStr(data[1]) + " - ";
477
478 if ((data[2] & 0xF) <= 0x9)
479 {
480 errLog += tmpStr[(data[2] & 0xF)];
481 }
482 else
483 {
484 errLog += "Reserved";
485 }
486 }
487 else
488 {
489 errLog = "Unknown";
490 }
491}
492
Willy Tue39f9392022-06-15 13:24:20 -0700493[[maybe_unused]] static void logMemErr(uint8_t* dataPtr, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700494{
495 uint8_t snrType = dataPtr[0];
496 uint8_t snrNum = dataPtr[1];
Vijay Khemka63c99be2020-05-27 19:14:35 -0700497 uint8_t* data = &(dataPtr[3]);
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700498
499 /* TODO: add pal_add_cri_sel */
500
501 if (snrNum == memoryEccError)
502 {
503 /* SEL from MEMORY_ECC_ERR Sensor */
504 switch (data[0] & 0x0F)
505 {
506 case 0x0:
507 if (snrType == 0x0C)
508 {
509 errLog = "Correctable";
510 }
511 else if (snrType == 0x10)
512 {
513 errLog = "Correctable ECC error Logging Disabled";
514 }
515 break;
516 case 0x1:
517 errLog = "Uncorrectable";
518 break;
519 case 0x5:
520 errLog = "Correctable ECC error Logging Limit Disabled";
521 break;
522 default:
523 errLog = "Unknown";
524 }
525 }
526 else if (snrNum == memoryErrLogDIS)
527 {
528 // SEL from MEMORY_ERR_LOG_DIS Sensor
529 if ((data[0] & 0x0F) == 0x0)
530 {
531 errLog = "Correctable Memory Error Logging Disabled";
532 }
533 else
534 {
535 errLog = "Unknown";
536 }
537 }
538 else
539 {
540 errLog = "Unknown";
541 return;
542 }
543
544 /* Common routine for both MEM_ECC_ERR and MEMORY_ERR_LOG_DIS */
545
546 errLog += " (DIMM " + byteToStr(data[2]) + ") Logical Rank " +
547 std::to_string(data[1] & 0x03);
548
549 /* DIMM number (data[2]):
550 * Bit[7:5]: Socket number (Range: 0-7)
551 * Bit[4:3]: Channel number (Range: 0-3)
552 * Bit[2:0]: DIMM number (Range: 0-7)
553 */
554
555 /* TODO: Verify these bits */
556 std::string cpuStr = "CPU# " + std::to_string((data[2] & 0xE0) >> 5);
557 std::string chStr = "CHN# " + std::to_string((data[2] & 0x18) >> 3);
Manikandan Elumalaic056dc02020-12-11 06:20:32 +0530558 std::string dimmStr = "DIMM#" + std::to_string(data[2] & 0x7);
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700559
560 switch ((data[1] & 0xC) >> 2)
561 {
Vijay Khemkad1194022020-05-27 18:58:33 -0700562 case 0x0:
563 {
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700564 /* All Info Valid */
Willy Tue39f9392022-06-15 13:24:20 -0700565 [[maybe_unused]] uint8_t chnNum = (data[2] & 0x1C) >> 2;
566 [[maybe_unused]] uint8_t dimmNum = data[2] & 0x3;
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700567
568 /* TODO: If critical SEL logging is available, do it */
569 if (snrType == 0x0C)
570 {
571 if ((data[0] & 0x0F) == 0x0)
572 {
573 /* TODO: add_cri_sel */
574 /* "DIMM"+ 'A'+ chnNum + dimmNum + " ECC err,FRU:1"
575 */
576 }
577 else if ((data[0] & 0x0F) == 0x1)
578 {
579 /* TODO: add_cri_sel */
580 /* "DIMM"+ 'A'+ chnNum + dimmNum + " UECC err,FRU:1"
581 */
582 }
583 }
584 /* Continue to parse the error into a string. All Info Valid
585 */
586 errLog += " (" + cpuStr + ", " + chStr + ", " + dimmStr + ")";
587 }
588
589 break;
590 case 0x1:
591
592 /* DIMM info not valid */
593 errLog += " (" + cpuStr + ", " + chStr + ")";
594 break;
595 case 0x2:
596
597 /* CHN info not valid */
598 errLog += " (" + cpuStr + ", " + dimmStr + ")";
599 break;
600 case 0x3:
601
602 /* CPU info not valid */
603 errLog += " (" + chStr + ", " + dimmStr + ")";
604 break;
605 }
606}
607
Vijay Khemka63c99be2020-05-27 19:14:35 -0700608static void logPwrErr(uint8_t* data, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700609{
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700610 if (data[0] == 0x1)
611 {
612 errLog = "SYS_PWROK failure";
Manojkiran Eda519530b2024-06-17 11:46:15 +0530613 /* Also try logging to Critical log file, if available */
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700614 /* "SYS_PWROK failure,FRU:1" */
615 }
616 else if (data[0] == 0x2)
617 {
618 errLog = "PCH_PWROK failure";
Manojkiran Eda519530b2024-06-17 11:46:15 +0530619 /* Also try logging to Critical log file, if available */
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700620 /* "PCH_PWROK failure,FRU:1" */
621 }
622 else
623 {
624 errLog = "Unknown";
625 }
626}
627
Vijay Khemka63c99be2020-05-27 19:14:35 -0700628static void logCatErr(uint8_t* data, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700629{
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700630 if (data[0] == 0x0)
631 {
632 errLog = "IERR/CATERR";
Manojkiran Eda519530b2024-06-17 11:46:15 +0530633 /* Also try logging to Critical log file, if available */
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700634 /* "IERR,FRU:1 */
635 }
636 else if (data[0] == 0xB)
637 {
638 errLog = "MCERR/CATERR";
Manojkiran Eda519530b2024-06-17 11:46:15 +0530639 /* Also try logging to Critical log file, if available */
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700640 /* "MCERR,FRU:1 */
641 }
642 else
643 {
644 errLog = "Unknown";
645 }
646}
647
Vijay Khemka63c99be2020-05-27 19:14:35 -0700648static void logDimmHot(uint8_t* data, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700649{
650 if ((data[0] << 16 | data[1] << 8 | data[2]) == 0x01FFFF)
651 {
652 errLog = "SOC MEMHOT";
653 }
654 else
655 {
656 errLog = "Unknown";
Manojkiran Eda519530b2024-06-17 11:46:15 +0530657 /* Also try logging to Critical log file, if available */
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700658 /* ""CPU_DIMM_HOT %s,FRU:1" */
659 }
660}
661
Vijay Khemka63c99be2020-05-27 19:14:35 -0700662static void logSwNMI(uint8_t* data, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700663{
664 if ((data[0] << 16 | data[1] << 8 | data[2]) == 0x03FFFF)
665 {
666 errLog = "Software NMI";
667 }
668 else
669 {
670 errLog = "Unknown SW NMI";
671 }
672}
673
Vijay Khemka63c99be2020-05-27 19:14:35 -0700674static void logCPUThermalSts(uint8_t* data, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700675{
676 switch (data[0])
677 {
678 case 0x0:
679 errLog = "CPU Critical Temperature";
680 break;
681 case 0x1:
682 errLog = "PROCHOT#";
683 break;
684 case 0x2:
685 errLog = "TCC Activation";
686 break;
687 default:
688 errLog = "Unknown";
689 }
690}
691
Vijay Khemka63c99be2020-05-27 19:14:35 -0700692static void logMEPwrState(uint8_t* data, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700693{
694 switch (data[0])
695 {
696 case 0:
697 errLog = "RUNNING";
698 break;
699 case 2:
700 errLog = "POWER_OFF";
701 break;
702 default:
703 errLog = "Unknown[" + std::to_string(data[0]) + "]";
704 break;
705 }
706}
707
Vijay Khemka63c99be2020-05-27 19:14:35 -0700708static void logSPSFwHealth(uint8_t* data, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700709{
710 if ((data[0] & 0x0F) == 0x00)
711 {
712 const std::vector<std::string> tmpStr = {
713 "Recovery GPIO forced",
714 "Image execution failed",
715 "Flash erase error",
716 "Flash state information",
717 "Internal error",
718 "BMC did not respond",
719 "Direct Flash update",
720 "Manufacturing error",
721 "Automatic Restore to Factory Presets",
722 "Firmware Exception",
723 "Flash Wear-Out Protection Warning",
724 "Unknown",
725 "Unknown",
726 "DMI interface error",
727 "MCTP interface error",
728 "Auto-configuration finished",
729 "Unsupported Segment Defined Feature",
730 "Unknown",
731 "CPU Debug Capability Disabled",
732 "UMA operation error"};
733
734 if (data[1] < 0x14)
735 {
736 errLog = tmpStr[data[1]];
737 }
738 else
739 {
740 errLog = "Unknown";
741 }
742 }
743 else if ((data[0] & 0x0F) == 0x01)
744 {
745 errLog = "SMBus link failure";
746 }
747 else
748 {
749 errLog = "Unknown";
750 }
751}
752
Vijay Khemka63c99be2020-05-27 19:14:35 -0700753static void logNmExcA(uint8_t* data, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700754{
755 /*NM4.0 #550710, Revision 1.95, and turn to p.155*/
756 if (data[0] == 0xA8)
757 {
758 errLog = "Policy Correction Time Exceeded";
759 }
760 else
761 {
762 errLog = "Unknown";
763 }
764}
765
Vijay Khemka63c99be2020-05-27 19:14:35 -0700766static void logPCHThermal(uint8_t* data, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700767{
Patrick Williams010dee02024-08-16 15:19:44 -0400768 const std::vector<std::string> thresEvtName = {
769 "Lower Non-critical",
770 "Unknown",
771 "Lower Critical",
772 "Unknown",
773 "Lower Non-recoverable",
774 "Unknown",
775 "Unknown",
776 "Upper Non-critical",
777 "Unknown",
778 "Upper Critical",
779 "Unknown",
780 "Upper Non-recoverable"};
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700781
782 if ((data[0] & 0x0f) < 12)
783 {
784 errLog = thresEvtName[(data[0] & 0x0f)];
785 }
786 else
787 {
788 errLog = "Unknown";
789 }
790
791 errLog += ", curr_val: " + std::to_string(data[1]) +
792 " C, thresh_val: " + std::to_string(data[2]) + " C";
793}
794
Vijay Khemka63c99be2020-05-27 19:14:35 -0700795static void logNmHealth(uint8_t* data, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700796{
797 std::vector<std::string> nmErrType = {
798 "Unknown",
799 "Unknown",
800 "Unknown",
801 "Unknown",
802 "Unknown",
803 "Unknown",
804 "Unknown",
805 "Extended Telemetry Device Reading Failure",
806 "Outlet Temperature Reading Failure",
807 "Volumetric Airflow Reading Failure",
808 "Policy Misconfiguration",
809 "Power Sensor Reading Failure",
810 "Inlet Temperature Reading Failure",
811 "Host Communication Error",
812 "Real-time Clock Synchronization Failure",
813 "Platform Shutdown Initiated by Intel NM Policy",
814 "Unknown"};
815 uint8_t nmTypeIdx = (data[0] & 0xf);
816 uint8_t domIdx = (data[1] & 0xf);
817 uint8_t errIdx = ((data[1] >> 4) & 0xf);
818
819 if (nmTypeIdx == 2)
820 {
821 errLog = "SensorIntelNM";
822 }
823 else
824 {
825 errLog = "Unknown";
826 }
827
Patrick Williams010dee02024-08-16 15:19:44 -0400828 errLog += ", Domain:" + nmDomName[domIdx] + ", ErrType:" +
829 nmErrType[errIdx] + ", Err:0x" + byteToStr(data[2]);
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700830}
831
Vijay Khemka63c99be2020-05-27 19:14:35 -0700832static void logNmCap(uint8_t* data, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700833{
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700834 const std::vector<std::string> nmCapStsStr = {"Not Available", "Available"};
835 if (data[0] & 0x7) // BIT1=policy, BIT2=monitoring, BIT3=pwr
836 // limit and the others are reserved
837 {
838 errLog = "PolicyInterface:" + nmCapStsStr[BIT(data[0], 0)] +
839 ",Monitoring:" + nmCapStsStr[BIT(data[0], 1)] +
840 ",PowerLimit:" + nmCapStsStr[BIT(data[0], 2)];
841 }
842 else
843 {
844 errLog = "Unknown";
845 }
846}
847
Vijay Khemka63c99be2020-05-27 19:14:35 -0700848static void logNmThreshold(uint8_t* data, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700849{
850 uint8_t thresNum = (data[0] & 0x3);
851 uint8_t domIdx = (data[1] & 0xf);
852 uint8_t polId = data[2];
853 uint8_t polEvtIdx = BIT(data[0], 3);
854 const std::vector<std::string> polEvtStr = {
855 "Threshold Exceeded", "Policy Correction Time Exceeded"};
856
857 errLog = "Threshold Number:" + std::to_string(thresNum) + "-" +
858 polEvtStr[polEvtIdx] + ", Domain:" + nmDomName[domIdx] +
859 ", PolicyID:0x" + byteToStr(polId);
860}
861
Vijay Khemka63c99be2020-05-27 19:14:35 -0700862static void logPwrThreshold(uint8_t* data, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700863{
864 if (data[0] == 0x00)
865 {
866 errLog = "Limit Not Exceeded";
867 }
868 else if (data[0] == 0x01)
869 {
870 errLog = "Limit Exceeded";
871 }
872 else
873 {
874 errLog = "Unknown";
875 }
876}
877
Vijay Khemka63c99be2020-05-27 19:14:35 -0700878static void logMSMI(uint8_t* data, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700879{
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700880 if (data[0] == 0x0)
881 {
882 errLog = "IERR/MSMI";
883 }
884 else if (data[0] == 0x0B)
885 {
886 errLog = "MCERR/MSMI";
887 }
888 else
889 {
890 errLog = "Unknown";
891 }
892}
893
Vijay Khemka63c99be2020-05-27 19:14:35 -0700894static void logHprWarn(uint8_t* data, std::string& errLog)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700895{
896 if (data[2] == 0x01)
897 {
898 if (data[1] == 0xFF)
899 {
900 errLog = "Infinite Time";
901 }
902 else
903 {
904 errLog = std::to_string(data[1]) + " minutes";
905 }
906 }
907 else
908 {
909 errLog = "Unknown";
910 }
911}
912
913static const boost::container::flat_map<
914 uint8_t,
Vijay Khemka63c99be2020-05-27 19:14:35 -0700915 std::pair<std::string, std::function<void(uint8_t*, std::string&)>>>
Patrick Williams010dee02024-08-16 15:19:44 -0400916 sensorNameTable = {
917 {0xE9, {"SYSTEM_EVENT", logSysEvent}},
918 {0x7D, {"THERM_THRESH_EVT", logThermalEvent}},
919 {0xAA, {"BUTTON", logDefault}},
920 {0xAB, {"POWER_STATE", logDefault}},
921 {0xEA, {"CRITICAL_IRQ", logCritIrq}},
922 {0x2B, {"POST_ERROR", logPostErr}},
923 {0x40, {"MACHINE_CHK_ERR", logMchChkErr}},
924 {0x41, {"PCIE_ERR", logPcieErr}},
925 {0x43, {"IIO_ERR", logIioErr}},
926 {0X63, {"MEMORY_ECC_ERR", logDefault}},
927 {0X87, {"MEMORY_ERR_LOG_DIS", logDefault}},
928 {0X51, {"PROCHOT_EXT", logDefault}},
929 {0X56, {"PWR_ERR", logPwrErr}},
930 {0xE6, {"CATERR_A", logCatErr}},
931 {0xEB, {"CATERR_B", logCatErr}},
932 {0xB3, {"CPU_DIMM_HOT", logDimmHot}},
933 {0x90, {"SOFTWARE_NMI", logSwNMI}},
934 {0x1C, {"CPU0_THERM_STATUS", logCPUThermalSts}},
935 {0x1D, {"CPU1_THERM_STATUS", logCPUThermalSts}},
936 {0x16, {"ME_POWER_STATE", logMEPwrState}},
937 {0x17, {"SPS_FW_HEALTH", logSPSFwHealth}},
938 {0x18, {"NM_EXCEPTION_A", logNmExcA}},
939 {0x08, {"PCH_THERM_THRESHOLD", logPCHThermal}},
940 {0x19, {"NM_HEALTH", logNmHealth}},
941 {0x1A, {"NM_CAPABILITIES", logNmCap}},
942 {0x1B, {"NM_THRESHOLD", logNmThreshold}},
943 {0x3B, {"PWR_THRESH_EVT", logPwrThreshold}},
944 {0xE7, {"MSMI", logMSMI}},
945 {0xC5, {"HPR_WARNING", logHprWarn}}};
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700946
Vijay Khemka63c99be2020-05-27 19:14:35 -0700947static void parseSelHelper(StdSELEntry* data, std::string& errStr)
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700948{
Vijay Khemka139aa4f2019-08-16 09:57:41 -0700949 /* Check if sensor type is OS_BOOT (0x1f) */
950 if (data->sensorType == 0x1F)
951 {
952 /* OS_BOOT used by OS */
953 switch (data->eventData1 & 0xF)
954 {
955 case 0x07:
956 errStr = "Base OS/Hypervisor Installation started";
957 break;
958 case 0x08:
959 errStr = "Base OS/Hypervisor Installation completed";
960 break;
961 case 0x09:
962 errStr = "Base OS/Hypervisor Installation aborted";
963 break;
964 case 0x0A:
965 errStr = "Base OS/Hypervisor Installation failed";
966 break;
967 default:
968 errStr = "Unknown";
969 }
970 return;
971 }
972
973 auto findSensorName = sensorNameTable.find(data->sensorNum);
974 if (findSensorName == sensorNameTable.end())
975 {
976 errStr = "Unknown";
977 return;
978 }
979 else
980 {
981 switch (data->sensorNum)
982 {
983 /* logMemErr function needs data from sensor type */
984 case memoryEccError:
985 case memoryErrLogDIS:
986 findSensorName->second.second(&(data->sensorType), errStr);
987 break;
988 /* Other sensor function needs only event data for parsing */
989 default:
990 findSensorName->second.second(&(data->eventData1), errStr);
991 }
992 }
993
994 if (((data->eventData3 & 0x80) >> 7) == 0)
995 {
996 errStr += " Assertion";
997 }
998 else
999 {
1000 errStr += " Deassertion";
1001 }
1002}
1003
Manikandan Elumalaic056dc02020-12-11 06:20:32 +05301004static void parseDimmPhyloc(StdSELEntry* data, std::string& errStr)
1005{
1006 // Log when " All info available"
1007 uint8_t chNum = (data->eventData3 & 0x18) >> 3;
1008 uint8_t dimmNum = data->eventData3 & 0x7;
1009 uint8_t rankNum = data->eventData2 & 0x03;
1010 uint8_t nodeNum = (data->eventData3 & 0xE0) >> 5;
1011
1012 if (chNum == 3 && dimmNum == 0)
1013 {
1014 errStr += " Node: " + std::to_string(nodeNum) + "," +
1015 " Card: " + std::to_string(chNum) + "," +
1016 " Module: " + std::to_string(dimmNum) + "," +
1017 " Rank Number: " + std::to_string(rankNum) + "," +
1018 " Location: DIMM A0";
1019 }
1020 else if (chNum == 2 && dimmNum == 0)
1021 {
1022 errStr += " Node: " + std::to_string(nodeNum) + "," +
1023 " Card: " + std::to_string(chNum) + "," +
1024 " Module: " + std::to_string(dimmNum) + "," +
1025 " Rank Number: " + std::to_string(rankNum) + "," +
1026 " Location: DIMM B0";
1027 }
1028 else if (chNum == 4 && dimmNum == 0)
1029 {
1030 errStr += " Node: " + std::to_string(nodeNum) + "," +
1031 " Card: " + std::to_string(chNum) + "," +
1032 " Module: " + std::to_string(dimmNum) + "," +
1033 " Rank Number: " + std::to_string(rankNum) + "," +
1034 " Location: DIMM C0 ";
1035 }
1036 else if (chNum == 5 && dimmNum == 0)
1037 {
1038 errStr += " Node: " + std::to_string(nodeNum) + "," +
1039 " Card: " + std::to_string(chNum) + "," +
1040 " Module: " + std::to_string(dimmNum) + "," +
1041 " Rank Number: " + std::to_string(rankNum) + "," +
1042 " Location: DIMM D0";
1043 }
1044 else
1045 {
1046 errStr += " Node: " + std::to_string(nodeNum) + "," +
1047 " Card: " + std::to_string(chNum) + "," +
1048 " Module: " + std::to_string(dimmNum) + "," +
1049 " Rank Number: " + std::to_string(rankNum) + "," +
Manojkiran Eda519530b2024-06-17 11:46:15 +05301050 " Location: DIMM Unknown";
Manikandan Elumalaic056dc02020-12-11 06:20:32 +05301051 }
1052}
1053
Vijay Khemka63c99be2020-05-27 19:14:35 -07001054static void parseStdSel(StdSELEntry* data, std::string& errStr)
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001055{
1056 std::stringstream tmpStream;
1057 tmpStream << std::hex << std::uppercase;
1058
1059 /* TODO: add pal_add_cri_sel */
1060 switch (data->sensorNum)
1061 {
1062 case memoryEccError:
1063 switch (data->eventData1 & 0x0F)
1064 {
1065 case 0x00:
1066 errStr = "Correctable";
1067 tmpStream << "DIMM" << std::setw(2) << std::setfill('0')
1068 << data->eventData3 << " ECC err";
Manikandan Elumalaic056dc02020-12-11 06:20:32 +05301069 parseDimmPhyloc(data, errStr);
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001070 break;
1071 case 0x01:
1072 errStr = "Uncorrectable";
1073 tmpStream << "DIMM" << std::setw(2) << std::setfill('0')
1074 << data->eventData3 << " UECC err";
Manikandan Elumalaic056dc02020-12-11 06:20:32 +05301075 parseDimmPhyloc(data, errStr);
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001076 break;
1077 case 0x02:
1078 errStr = "Parity";
1079 break;
1080 case 0x05:
1081 errStr = "Correctable ECC error Logging Limit Reached";
1082 break;
1083 default:
1084 errStr = "Unknown";
1085 }
1086 break;
1087 case memoryErrLogDIS:
1088 if ((data->eventData1 & 0x0F) == 0)
1089 {
1090 errStr = "Correctable Memory Error Logging Disabled";
1091 }
1092 else
1093 {
1094 errStr = "Unknown";
1095 }
1096 break;
1097 default:
Vijay Khemka139aa4f2019-08-16 09:57:41 -07001098 parseSelHelper(data, errStr);
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001099 return;
1100 }
1101
1102 errStr += " (DIMM " + std::to_string(data->eventData3) + ")";
1103 errStr += " Logical Rank " + std::to_string(data->eventData2 & 0x03);
1104
1105 switch ((data->eventData2 & 0x0C) >> 2)
1106 {
1107 case 0x00:
1108 // Ignore when " All info available"
1109 break;
1110 case 0x01:
1111 errStr += " DIMM info not valid";
1112 break;
1113 case 0x02:
1114 errStr += " CHN info not valid";
1115 break;
1116 case 0x03:
1117 errStr += " CPU info not valid";
1118 break;
1119 default:
1120 errStr += " Unknown";
1121 }
1122
1123 if (((data->eventType & 0x80) >> 7) == 0)
1124 {
1125 errStr += " Assertion";
1126 }
1127 else
1128 {
1129 errStr += " Deassertion";
1130 }
1131
1132 return;
1133}
1134
Vijay Khemka63c99be2020-05-27 19:14:35 -07001135static void parseOemSel(TsOemSELEntry* data, std::string& errStr)
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001136{
1137 std::stringstream tmpStream;
1138 tmpStream << std::hex << std::uppercase << std::setfill('0');
1139
1140 switch (data->recordType)
1141 {
1142 case 0xC0:
1143 tmpStream << "VID:0x" << std::setw(2) << (int)data->oemData[1]
1144 << std::setw(2) << (int)data->oemData[0] << " DID:0x"
1145 << std::setw(2) << (int)data->oemData[3] << std::setw(2)
1146 << (int)data->oemData[2] << " Slot:0x" << std::setw(2)
1147 << (int)data->oemData[4] << " Error ID:0x" << std::setw(2)
1148 << (int)data->oemData[5];
1149 break;
1150 case 0xC2:
1151 tmpStream << "Extra info:0x" << std::setw(2)
1152 << (int)data->oemData[1] << " MSCOD:0x" << std::setw(2)
1153 << (int)data->oemData[3] << std::setw(2)
1154 << (int)data->oemData[2] << " MCACOD:0x" << std::setw(2)
1155 << (int)data->oemData[5] << std::setw(2)
1156 << (int)data->oemData[4];
1157 break;
1158 case 0xC3:
1159 int bank = (data->oemData[1] & 0xf0) >> 4;
1160 int col = ((data->oemData[1] & 0x0f) << 8) | data->oemData[2];
1161
1162 tmpStream << "Fail Device:0x" << std::setw(2)
1163 << (int)data->oemData[0] << " Bank:0x" << std::setw(2)
1164 << bank << " Column:0x" << std::setw(2) << col
1165 << " Failed Row:0x" << std::setw(2)
1166 << (int)data->oemData[3] << std::setw(2)
1167 << (int)data->oemData[4] << std::setw(2)
1168 << (int)data->oemData[5];
1169 }
1170
1171 errStr = tmpStream.str();
1172
1173 return;
1174}
1175
cchoux74519032024-02-04 20:35:29 +08001176static std::string dimmLocationStr(uint8_t socket, uint8_t channel,
1177 uint8_t slot)
1178{
1179 uint8_t sled = (socket >> 4) & 0x3;
1180
1181 socket &= 0xf;
1182 if (channel == 0xFF && slot == 0xFF)
1183 {
1184 return std::format(
1185 "DIMM Slot Location: Sled {:02}/Socket {:02}, Channel unknown"
1186 ", Slot unknown, DIMM unknown",
1187 sled, socket);
1188 }
1189 else
1190 {
1191 channel &= 0xf;
1192 slot &= 0xf;
1193 const char label[] = {'A', 'C', 'B', 'D'};
1194 uint8_t idx = socket * 2 + slot;
1195 return std::format("DIMM Slot Location: Sled {:02}/Socket {:02}"
1196 ", Channel {:02}, Slot {:02} DIMM {}",
1197 sled, socket, channel, slot,
1198 (idx < sizeof(label))
1199 ? label[idx] + std::to_string(channel)
1200 : "NA");
1201 }
1202}
1203
Vijay Khemka63c99be2020-05-27 19:14:35 -07001204static void parseOemUnifiedSel(NtsOemSELEntry* data, std::string& errStr)
Vijay Khemka34a875f2019-08-09 15:08:15 -07001205{
Vijay Khemka63c99be2020-05-27 19:14:35 -07001206 uint8_t* ptr = data->oemData;
cchoux74519032024-02-04 20:35:29 +08001207 uint8_t eventType = ptr[5] & 0xf;
Vijay Khemka34a875f2019-08-09 15:08:15 -07001208 int genInfo = ptr[0];
1209 int errType = genInfo & 0x0f;
cchoux74519032024-02-04 20:35:29 +08001210 std::vector<std::string> dimmErr = {
1211 "Memory training failure",
1212 "Memory correctable error",
1213 "Memory uncorrectable error",
1214 "Memory correctable error (Patrol scrub)",
1215 "Memory uncorrectable error (Patrol scrub)",
1216 "Memory Parity Error (PCC=0)",
1217 "Memory Parity Error (PCC=1)",
1218 "Memory PMIC Error",
1219 "CXL Memory training error",
1220 "Reserved"};
1221 std::vector<std::string> postEvent = {
1222 "System PXE boot fail",
1223 "CMOS/NVRAM configuration cleared",
1224 "TPM Self-Test Fail",
1225 "Boot Drive failure",
1226 "Data Drive failure",
1227 "Received invalid boot order request from BMC",
1228 "System HTTP boot fail",
1229 "BIOS fails to get the certificate from BMC",
1230 "Password cleared by jumper",
1231 "DXE FV check failure",
1232 "AMD ABL failure",
1233 "Reserved"};
1234 std::vector<std::string> certErr = {
1235 "No certificate at BMC", "IPMI transaction fail",
1236 "Certificate data corrupted", "Reserved"};
Patrick Williams010dee02024-08-16 15:19:44 -04001237 std::vector<std::string> pcieEvent = {
1238 "PCIe DPC Event",
1239 "PCIe LER Event",
1240 "PCIe Link Retraining and Recovery",
1241 "PCIe Link CRC Error Check and Retry",
1242 "PCIe Corrupt Data Containment",
1243 "PCIe Express ECRC",
1244 "Reserved"};
cchoux74519032024-02-04 20:35:29 +08001245 std::vector<std::string> memEvent = {
1246 "Memory PPR event",
1247 "Memory Correctable Error logging limit reached",
1248 "Memory disable/map-out for FRB",
1249 "Memory SDDC",
1250 "Memory Address range/Partial mirroring",
1251 "Memory ADDDC",
1252 "Memory SMBus hang recovery",
1253 "No DIMM in System",
1254 "Reserved"};
1255 std::vector<std::string> memPprTime = {"Boot time", "Autonomous",
1256 "Run time", "Reserved"};
1257 std::vector<std::string> memPpr = {"PPR success", "PPR fail", "PPR request",
1258 "Reserved"};
Patrick Williams010dee02024-08-16 15:19:44 -04001259 std::vector<std::string> memAdddc = {
1260 "Bank VLS", "r-Bank VLS + re-buddy", "r-Bank VLS + Rank VLS",
1261 "r-Rank VLS + re-buddy", "Reserved"};
cchoux74519032024-02-04 20:35:29 +08001262 std::vector<std::string> pprEvent = {"PPR disable", "Soft PPR", "Hard PPR",
1263 "Reserved"};
Vijay Khemka34a875f2019-08-09 15:08:15 -07001264
1265 std::stringstream tmpStream;
Vijay Khemka34a875f2019-08-09 15:08:15 -07001266
1267 switch (errType)
1268 {
1269 case unifiedPcieErr:
cchoux74519032024-02-04 20:35:29 +08001270 tmpStream << std::format(
1271 "GeneralInfo: x86/PCIeErr(0x{:02X})"
1272 ", Bus {:02X}/Dev {:02X}/Fun {:02X}, TotalErrID1Cnt: 0x{:04X}"
1273 ", ErrID2: 0x{:02X}, ErrID1: 0x{:02X}",
1274 genInfo, ptr[8], ptr[7] >> 3, ptr[7] & 0x7,
1275 (ptr[10] << 8) | ptr[9], ptr[11], ptr[12]);
Vijay Khemka34a875f2019-08-09 15:08:15 -07001276 break;
1277 case unifiedMemErr:
cchoux74519032024-02-04 20:35:29 +08001278 eventType = ptr[9] & 0xf;
1279 tmpStream << std::format(
1280 "GeneralInfo: MemErr(0x{:02X}), {}, DIMM Failure Event: {}",
1281 genInfo, dimmLocationStr(ptr[5], ptr[6], ptr[7]),
1282 dimmErr[std::min(eventType,
1283 static_cast<uint8_t>(dimmErr.size() - 1))]);
Vijay Khemka34a875f2019-08-09 15:08:15 -07001284
cchoux74519032024-02-04 20:35:29 +08001285 if (static_cast<MemErrType>(eventType) == MemErrType::memTrainErr ||
1286 static_cast<MemErrType>(eventType) == MemErrType::memPmicErr)
1287 {
1288 bool amd = ptr[9] & 0x80;
1289 tmpStream << std::format(
1290 ", Major Code: 0x{:02X}, Minor Code: 0x{:0{}X}", ptr[10],
1291 amd ? (ptr[12] << 8 | ptr[11]) : ptr[11], amd ? 4 : 2);
1292 }
1293 break;
1294 case unifiedIioErr:
1295 tmpStream << std::format(
1296 "GeneralInfo: IIOErr(0x{:02X})"
1297 ", IIO Port Location: Sled {:02}/Socket {:02}, Stack 0x{:02X}"
1298 ", Error Type: 0x{:02X}, Error Severity: 0x{:02X}"
1299 ", Error ID: 0x{:02X}",
1300 genInfo, (ptr[5] >> 4) & 0x3, ptr[5] & 0xf, ptr[6], ptr[10],
1301 ptr[11] & 0xf, ptr[12]);
1302 break;
1303 case unifiedPostEvt:
1304 tmpStream << std::format(
1305 "GeneralInfo: POST(0x{:02X}), POST Failure Event: {}", genInfo,
1306 postEvent[std::min(
1307 eventType, static_cast<uint8_t>(postEvent.size() - 1))]);
1308
1309 switch (static_cast<PostEvtType>(eventType))
1310 {
1311 case PostEvtType::pxeBootFail:
1312 case PostEvtType::httpBootFail:
1313 {
1314 uint8_t failType = ptr[10] & 0xf;
1315 tmpStream
1316 << std::format(", Fail Type: {}, Error Code: 0x{:02X}",
1317 (failType == 4 || failType == 6)
1318 ? std::format("IPv{} fail", failType)
1319 : std::format("0x{:02X}", ptr[10]),
1320 ptr[11]);
1321 break;
1322 }
1323 case PostEvtType::getCertFail:
1324 tmpStream << std::format(
1325 ", Failure Detail: {}",
1326 certErr[std::min(
1327 ptr[9], static_cast<uint8_t>(certErr.size() - 1))]);
1328 break;
1329 case PostEvtType::amdAblFail:
1330 tmpStream << std::format(", ABL Error Code: 0x{:04X}",
1331 (ptr[12] << 8) | ptr[11]);
1332 break;
1333 }
1334 break;
1335 case unifiedPcieEvt:
1336 tmpStream << std::format(
1337 "GeneralInfo: PCIeEvent(0x{:02X}), PCIe Failure Event: {}",
1338 genInfo,
1339 pcieEvent[std::min(
1340 eventType, static_cast<uint8_t>(pcieEvent.size() - 1))]);
1341
1342 if (static_cast<PcieEvtType>(eventType) == PcieEvtType::dpc)
1343 {
1344 tmpStream << std::format(
1345 ", Status: 0x{:04X}, Source ID: 0x{:04X}",
1346 (ptr[8] << 8) | ptr[7], (ptr[10] << 8) | ptr[9]);
1347 }
1348 break;
1349 case unifiedMemEvt:
1350 eventType = ptr[9] & 0xf;
Patrick Williams010dee02024-08-16 15:19:44 -04001351 tmpStream
1352 << std::format("GeneralInfo: MemEvent(0x{:02X})", genInfo)
1353 << (static_cast<MemEvtType>(eventType) != MemEvtType::noDimm
1354 ? std::format(", {}",
1355 dimmLocationStr(ptr[5], ptr[6], ptr[7]))
1356 : "")
1357 << ", DIMM Failure Event: ";
cchoux74519032024-02-04 20:35:29 +08001358
1359 switch (static_cast<MemEvtType>(eventType))
1360 {
1361 case MemEvtType::ppr:
1362 tmpStream << std::format("{} {}",
1363 memPprTime[(ptr[10] >> 2) & 0x3],
1364 memPpr[ptr[10] & 0x3]);
1365 break;
1366 case MemEvtType::adddc:
1367 tmpStream << std::format(
1368 "{} {}",
1369 memEvent[std::min(eventType, static_cast<uint8_t>(
1370 memEvent.size() - 1))],
1371 memAdddc[std::min(
1372 static_cast<uint8_t>(ptr[11] & 0xf),
1373 static_cast<uint8_t>(memAdddc.size() - 1))]);
1374 break;
1375 default:
1376 tmpStream << std::format(
1377 "{}", memEvent[std::min(
1378 eventType,
1379 static_cast<uint8_t>(memEvent.size() - 1))]);
1380 break;
1381 }
1382 break;
1383 case unifiedBootGuard:
1384 tmpStream << std::format(
1385 "GeneralInfo: Boot Guard ACM Failure Events(0x{:02X})"
1386 ", Error Class: 0x{:02X}, Error Code: 0x{:02X}",
1387 genInfo, ptr[9], ptr[10]);
1388 break;
1389 case unifiedPprEvt:
1390 tmpStream << std::format(
1391 "GeneralInfo: PPREvent(0x{:02X}), {}"
1392 ", DIMM Info: {:02X}{:02X}{:02X}{:02X}{:02X}{:02X}{:02X}",
1393 genInfo,
1394 pprEvent[std::min(eventType,
1395 static_cast<uint8_t>(pprEvent.size() - 1))],
1396 ptr[6], ptr[7], ptr[8], ptr[9], ptr[10], ptr[11], ptr[12]);
Vijay Khemka34a875f2019-08-09 15:08:15 -07001397 break;
1398 default:
1399 std::vector<uint8_t> oemData(ptr, ptr + 13);
1400 std::string oemDataStr;
1401 toHexStr(oemData, oemDataStr);
cchoux74519032024-02-04 20:35:29 +08001402 tmpStream << std::format("Undefined Error Type(0x{:02X}), Raw: {}",
1403 errType, oemDataStr);
Vijay Khemka34a875f2019-08-09 15:08:15 -07001404 }
1405
1406 errStr = tmpStream.str();
1407
1408 return;
1409}
1410
Manikandan Elumalaic056dc02020-12-11 06:20:32 +05301411static void parseSelData(uint8_t fruId, std::vector<uint8_t>& reqData,
1412 std::string& msgLog)
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001413{
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001414 /* Get record type */
1415 int recType = reqData[2];
1416 std::string errType, errLog;
1417
Vijay Khemka63c99be2020-05-27 19:14:35 -07001418 uint8_t* ptr = NULL;
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001419
1420 std::stringstream recTypeStream;
1421 recTypeStream << std::hex << std::uppercase << std::setfill('0')
1422 << std::setw(2) << recType;
1423
Manikandan Elumalaic056dc02020-12-11 06:20:32 +05301424 msgLog = "SEL Entry: FRU: " + std::to_string(fruId) + ", Record: ";
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001425
1426 if (recType == stdErrType)
1427 {
Vijay Khemka63c99be2020-05-27 19:14:35 -07001428 StdSELEntry* data = reinterpret_cast<StdSELEntry*>(&reqData[0]);
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001429 std::string sensorName;
1430
1431 errType = stdErr;
1432 if (data->sensorType == 0x1F)
1433 {
1434 sensorName = "OS";
1435 }
1436 else
1437 {
1438 auto findSensorName = sensorNameTable.find(data->sensorNum);
1439 if (findSensorName == sensorNameTable.end())
1440 {
1441 sensorName = "Unknown";
1442 }
1443 else
1444 {
Vijay Khemka139aa4f2019-08-16 09:57:41 -07001445 sensorName = findSensorName->second.first;
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001446 }
1447 }
1448
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001449 parseStdSel(data, errLog);
1450 ptr = &(data->eventData1);
1451 std::vector<uint8_t> evtData(ptr, ptr + 3);
1452 std::string eventData;
1453 toHexStr(evtData, eventData);
1454
1455 std::stringstream senNumStream;
1456 senNumStream << std::hex << std::uppercase << std::setfill('0')
1457 << std::setw(2) << (int)(data->sensorNum);
1458
1459 msgLog += errType + " (0x" + recTypeStream.str() +
Peter Yin0d053ef2024-10-11 23:39:58 +08001460 "), Sensor: " + sensorName + " (0x" + senNumStream.str() +
1461 "), Event Data: (" + eventData + ") " + errLog;
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001462 }
1463 else if ((recType >= oemTSErrTypeMin) && (recType <= oemTSErrTypeMax))
1464 {
1465 /* timestamped OEM SEL records */
Vijay Khemka63c99be2020-05-27 19:14:35 -07001466 TsOemSELEntry* data = reinterpret_cast<TsOemSELEntry*>(&reqData[0]);
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001467 ptr = data->mfrId;
1468 std::vector<uint8_t> mfrIdData(ptr, ptr + 3);
1469 std::string mfrIdStr;
1470 toHexStr(mfrIdData, mfrIdStr);
1471
1472 ptr = data->oemData;
1473 std::vector<uint8_t> oemData(ptr, ptr + 6);
1474 std::string oemDataStr;
1475 toHexStr(oemData, oemDataStr);
1476
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001477 errType = oemTSErr;
1478 parseOemSel(data, errLog);
1479
Peter Yin0d053ef2024-10-11 23:39:58 +08001480 msgLog += errType + " (0x" + recTypeStream.str() + "), MFG ID: " +
1481 mfrIdStr + ", OEM Data: (" + oemDataStr + ") " + errLog;
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001482 }
Vijay Khemka34a875f2019-08-09 15:08:15 -07001483 else if (recType == fbUniErrType)
1484 {
Vijay Khemka63c99be2020-05-27 19:14:35 -07001485 NtsOemSELEntry* data = reinterpret_cast<NtsOemSELEntry*>(&reqData[0]);
Vijay Khemka34a875f2019-08-09 15:08:15 -07001486 errType = fbUniSELErr;
1487 parseOemUnifiedSel(data, errLog);
1488 msgLog += errType + " (0x" + recTypeStream.str() + "), " + errLog;
1489 }
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001490 else if ((recType >= oemNTSErrTypeMin) && (recType <= oemNTSErrTypeMax))
1491 {
1492 /* Non timestamped OEM SEL records */
Vijay Khemka63c99be2020-05-27 19:14:35 -07001493 NtsOemSELEntry* data = reinterpret_cast<NtsOemSELEntry*>(&reqData[0]);
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001494 errType = oemNTSErr;
1495
1496 ptr = data->oemData;
1497 std::vector<uint8_t> oemData(ptr, ptr + 13);
1498 std::string oemDataStr;
1499 toHexStr(oemData, oemDataStr);
1500
Vijay Khemka63c99be2020-05-27 19:14:35 -07001501 parseOemSel((TsOemSELEntry*)data, errLog);
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001502 msgLog += errType + " (0x" + recTypeStream.str() + "), OEM Data: (" +
1503 oemDataStr + ") " + errLog;
1504 }
1505 else
1506 {
1507 errType = unknownErr;
1508 toHexStr(reqData, errLog);
Patrick Williams2405ae92023-05-10 07:50:09 -05001509 msgLog += errType + " (0x" + recTypeStream.str() +
1510 ") RawData: " + errLog;
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001511 }
1512}
1513
Vijay Khemka11b9c3b2019-08-21 15:21:42 -07001514} // namespace fb_oem::ipmi::sel
1515
1516namespace ipmi
1517{
1518
1519namespace storage
1520{
1521
1522static void registerSELFunctions() __attribute__((constructor));
1523static fb_oem::ipmi::sel::SELData selObj __attribute__((init_priority(101)));
1524
1525ipmi::RspType<uint8_t, // SEL version
1526 uint16_t, // SEL entry count
1527 uint16_t, // free space
1528 uint32_t, // last add timestamp
1529 uint32_t, // last erase timestamp
1530 uint8_t> // operation support
1531 ipmiStorageGetSELInfo()
1532{
Vijay Khemka11b9c3b2019-08-21 15:21:42 -07001533 fb_oem::ipmi::sel::GetSELInfoData info;
1534
1535 selObj.getInfo(info);
1536 return ipmi::responseSuccess(info.selVersion, info.entries, info.freeSpace,
1537 info.addTimeStamp, info.eraseTimeStamp,
1538 info.operationSupport);
1539}
1540
1541ipmi::RspType<uint16_t, std::vector<uint8_t>>
1542 ipmiStorageGetSELEntry(std::vector<uint8_t> data)
1543{
Vijay Khemka11b9c3b2019-08-21 15:21:42 -07001544 if (data.size() != sizeof(fb_oem::ipmi::sel::GetSELEntryRequest))
1545 {
1546 return ipmi::responseReqDataLenInvalid();
1547 }
1548
Vijay Khemka63c99be2020-05-27 19:14:35 -07001549 fb_oem::ipmi::sel::GetSELEntryRequest* reqData =
1550 reinterpret_cast<fb_oem::ipmi::sel::GetSELEntryRequest*>(&data[0]);
Vijay Khemka11b9c3b2019-08-21 15:21:42 -07001551
1552 if (reqData->reservID != 0)
1553 {
1554 if (!checkSELReservation(reqData->reservID))
1555 {
1556 return ipmi::responseInvalidReservationId();
1557 }
1558 }
1559
1560 uint16_t selCnt = selObj.getCount();
1561 if (selCnt == 0)
1562 {
1563 return ipmi::responseSensorInvalid();
1564 }
1565
1566 /* If it is asked for first entry */
1567 if (reqData->recordID == fb_oem::ipmi::sel::firstEntry)
1568 {
1569 /* First Entry (0x0000) as per Spec */
1570 reqData->recordID = 1;
1571 }
1572 else if (reqData->recordID == fb_oem::ipmi::sel::lastEntry)
1573 {
1574 /* Last entry (0xFFFF) as per Spec */
1575 reqData->recordID = selCnt;
1576 }
1577
1578 std::string ipmiRaw;
1579
1580 if (selObj.getEntry(reqData->recordID, ipmiRaw) < 0)
1581 {
1582 return ipmi::responseSensorInvalid();
1583 }
1584
1585 std::vector<uint8_t> recDataBytes;
1586 if (fromHexStr(ipmiRaw, recDataBytes) < 0)
1587 {
1588 return ipmi::responseUnspecifiedError();
1589 }
1590
1591 /* Identify the next SEL record ID. If recordID is same as
1592 * total SeL count then next id should be last entry else
1593 * it should be incremented by 1 to current RecordID
1594 */
1595 uint16_t nextRecord;
1596 if (reqData->recordID == selCnt)
1597 {
1598 nextRecord = fb_oem::ipmi::sel::lastEntry;
1599 }
1600 else
1601 {
1602 nextRecord = reqData->recordID + 1;
1603 }
1604
1605 if (reqData->readLen == fb_oem::ipmi::sel::entireRecord)
1606 {
1607 return ipmi::responseSuccess(nextRecord, recDataBytes);
1608 }
1609 else
1610 {
1611 if (reqData->offset >= fb_oem::ipmi::sel::selRecordSize ||
1612 reqData->readLen > fb_oem::ipmi::sel::selRecordSize)
1613 {
1614 return ipmi::responseUnspecifiedError();
1615 }
1616 std::vector<uint8_t> recPartData;
1617
1618 auto diff = fb_oem::ipmi::sel::selRecordSize - reqData->offset;
1619 auto readLength = std::min(diff, static_cast<int>(reqData->readLen));
1620
1621 for (int i = 0; i < readLength; i++)
1622 {
1623 recPartData.push_back(recDataBytes[i + reqData->offset]);
1624 }
1625 return ipmi::responseSuccess(nextRecord, recPartData);
1626 }
1627}
1628
Patrick Williams010dee02024-08-16 15:19:44 -04001629ipmi::RspType<uint16_t>
1630 ipmiStorageAddSELEntry(ipmi::Context::ptr ctx, std::vector<uint8_t> data)
Vijay Khemka11b9c3b2019-08-21 15:21:42 -07001631{
1632 /* Per the IPMI spec, need to cancel any reservation when a
1633 * SEL entry is added
1634 */
1635 cancelSELReservation();
1636
1637 if (data.size() != fb_oem::ipmi::sel::selRecordSize)
1638 {
1639 return ipmi::responseReqDataLenInvalid();
1640 }
1641
1642 std::string ipmiRaw, logErr;
1643 toHexStr(data, ipmiRaw);
1644
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001645 /* Parse sel data and get an error log to be filed */
Manikandan Elumalaic056dc02020-12-11 06:20:32 +05301646 fb_oem::ipmi::sel::parseSelData((ctx->hostIdx + 1), data, logErr);
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001647
Vijay Khemka15a7ae82019-08-20 12:08:14 -07001648 static const std::string openBMCMessageRegistryVersion("0.1");
Patrick Williams010dee02024-08-16 15:19:44 -04001649 std::string messageID =
1650 "OpenBMC." + openBMCMessageRegistryVersion + ".SELEntryAdded";
Vijay Khemka15a7ae82019-08-20 12:08:14 -07001651
Vijay Khemka11b9c3b2019-08-21 15:21:42 -07001652 /* Log the Raw SEL message to the journal */
1653 std::string journalMsg = "SEL Entry Added: " + ipmiRaw;
Vijay Khemkaf36f3452019-08-09 13:24:45 -07001654
Vijay Khemka15a7ae82019-08-20 12:08:14 -07001655 phosphor::logging::log<phosphor::logging::level::INFO>(
1656 journalMsg.c_str(),
1657 phosphor::logging::entry("IPMISEL_MESSAGE_ID=%s", messageID.c_str()),
1658 phosphor::logging::entry("IPMISEL_MESSAGE_ARGS=%s", logErr.c_str()));
Vijay Khemka11b9c3b2019-08-21 15:21:42 -07001659
BonnieLo-wiwynn21a79232023-03-09 16:42:48 +08001660 std::map<std::string, std::string> ad;
1661 std::string severity = "xyz.openbmc_project.Logging.Entry.Level.Critical";
1662 ad.emplace("IPMI_RAW", ipmiRaw);
1663
1664 auto bus = sdbusplus::bus::new_default();
1665 auto reqMsg = bus.new_method_call(
1666 "xyz.openbmc_project.Logging", "/xyz/openbmc_project/logging",
1667 "xyz.openbmc_project.Logging.Create", "Create");
1668 reqMsg.append(logErr, severity, ad);
1669
1670 try
1671 {
1672 bus.call(reqMsg);
1673 }
1674 catch (sdbusplus::exception_t& e)
1675 {
1676 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
1677 }
1678
Vijay Khemka11b9c3b2019-08-21 15:21:42 -07001679 int responseID = selObj.addEntry(ipmiRaw.c_str());
1680 if (responseID < 0)
1681 {
1682 return ipmi::responseUnspecifiedError();
1683 }
1684 return ipmi::responseSuccess((uint16_t)responseID);
1685}
1686
Vijay Khemkac1921c62019-08-09 13:11:31 -07001687ipmi::RspType<uint8_t> ipmiStorageClearSEL(uint16_t reservationID,
Vijay Khemka63c99be2020-05-27 19:14:35 -07001688 const std::array<uint8_t, 3>& clr,
Vijay Khemkac1921c62019-08-09 13:11:31 -07001689 uint8_t eraseOperation)
1690{
1691 if (!checkSELReservation(reservationID))
1692 {
1693 return ipmi::responseInvalidReservationId();
1694 }
1695
1696 static constexpr std::array<uint8_t, 3> clrExpected = {'C', 'L', 'R'};
1697 if (clr != clrExpected)
1698 {
1699 return ipmi::responseInvalidFieldRequest();
1700 }
1701
1702 /* If there is no sel then return erase complete */
1703 if (selObj.getCount() == 0)
1704 {
1705 return ipmi::responseSuccess(fb_oem::ipmi::sel::eraseComplete);
1706 }
1707
1708 /* Erasure status cannot be fetched, so always return erasure
1709 * status as `erase completed`.
1710 */
1711 if (eraseOperation == fb_oem::ipmi::sel::getEraseStatus)
1712 {
1713 return ipmi::responseSuccess(fb_oem::ipmi::sel::eraseComplete);
1714 }
1715
1716 /* Check that initiate erase is correct */
1717 if (eraseOperation != fb_oem::ipmi::sel::initiateErase)
1718 {
1719 return ipmi::responseInvalidFieldRequest();
1720 }
1721
1722 /* Per the IPMI spec, need to cancel any reservation when the
1723 * SEL is cleared
1724 */
1725 cancelSELReservation();
1726
1727 /* Clear the complete Sel Json object */
1728 if (selObj.clear() < 0)
1729 {
1730 return ipmi::responseUnspecifiedError();
1731 }
1732
1733 return ipmi::responseSuccess(fb_oem::ipmi::sel::eraseComplete);
1734}
1735
1736ipmi::RspType<uint32_t> ipmiStorageGetSELTime()
1737{
1738 struct timespec selTime = {};
1739
1740 if (clock_gettime(CLOCK_REALTIME, &selTime) < 0)
1741 {
1742 return ipmi::responseUnspecifiedError();
1743 }
1744
1745 return ipmi::responseSuccess(selTime.tv_sec);
1746}
1747
Willy Tue39f9392022-06-15 13:24:20 -07001748ipmi::RspType<> ipmiStorageSetSELTime(uint32_t)
Vijay Khemkac1921c62019-08-09 13:11:31 -07001749{
1750 // Set SEL Time is not supported
1751 return ipmi::responseInvalidCommand();
1752}
1753
1754ipmi::RspType<uint16_t> ipmiStorageGetSELTimeUtcOffset()
1755{
1756 /* TODO: For now, the SEL time stamp is based on UTC time,
1757 * so return 0x0000 as offset. Might need to change once
1758 * supporting zones in SEL time stamps
1759 */
1760
1761 uint16_t utcOffset = 0x0000;
1762 return ipmi::responseSuccess(utcOffset);
1763}
1764
Vijay Khemka11b9c3b2019-08-21 15:21:42 -07001765void registerSELFunctions()
1766{
1767 // <Get SEL Info>
1768 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
1769 ipmi::storage::cmdGetSelInfo, ipmi::Privilege::User,
1770 ipmiStorageGetSELInfo);
1771
1772 // <Get SEL Entry>
1773 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
1774 ipmi::storage::cmdGetSelEntry, ipmi::Privilege::User,
1775 ipmiStorageGetSELEntry);
1776
1777 // <Add SEL Entry>
1778 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
1779 ipmi::storage::cmdAddSelEntry,
1780 ipmi::Privilege::Operator, ipmiStorageAddSELEntry);
1781
Vijay Khemkac1921c62019-08-09 13:11:31 -07001782 // <Clear SEL>
1783 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
1784 ipmi::storage::cmdClearSel, ipmi::Privilege::Operator,
1785 ipmiStorageClearSEL);
1786
1787 // <Get SEL Time>
1788 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
1789 ipmi::storage::cmdGetSelTime, ipmi::Privilege::User,
1790 ipmiStorageGetSELTime);
1791
1792 // <Set SEL Time>
1793 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
1794 ipmi::storage::cmdSetSelTime,
1795 ipmi::Privilege::Operator, ipmiStorageSetSELTime);
1796
1797 // <Get SEL Time UTC Offset>
1798 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
1799 ipmi::storage::cmdGetSelTimeUtcOffset,
1800 ipmi::Privilege::User,
1801 ipmiStorageGetSELTimeUtcOffset);
1802
Vijay Khemka11b9c3b2019-08-21 15:21:42 -07001803 return;
1804}
1805
1806} // namespace storage
1807} // namespace ipmi