1 /*
2 // Copyright (c) 2019 Intel Corporation
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 */
16
17 #include <boost/beast/core/span.hpp>
18 #include <ipmi_to_redfish_hooks.hpp>
19 #include <me_to_redfish_hooks.hpp>
20 #include <storagecommands.hpp>
21
22 #include <iomanip>
23 #include <sstream>
24 #include <string_view>
25
26 namespace intel_oem::ipmi::sel
27 {
28
29 namespace redfish_hooks
30 {
toHexStr(const boost::beast::span<uint8_t> bytes,std::string & hexStr)31 static void toHexStr(const boost::beast::span<uint8_t> bytes,
32 std::string& hexStr)
33 {
34 std::stringstream stream;
35 stream << std::hex << std::uppercase << std::setfill('0');
36 for (const uint8_t& byte : bytes)
37 {
38 stream << std::setw(2) << static_cast<int>(byte);
39 }
40 hexStr = stream.str();
41 }
42
43 // Record a BIOS message as a Redfish message instead of a SEL record
biosMessageHook(const SELData & selData,const std::string & ipmiRaw)44 static bool biosMessageHook(const SELData& selData, const std::string& ipmiRaw)
45 {
46 // This is a BIOS message, so record it as a Redfish message instead
47 // of a SEL record
48
49 // Walk through the SEL request record to build the appropriate Redfish
50 // message
51 static constexpr std::string_view openBMCMessageRegistryVersion = "0.1";
52 std::string messageID =
53 "OpenBMC." + std::string(openBMCMessageRegistryVersion);
54 std::vector<std::string> messageArgs;
55 BIOSSensors sensor = static_cast<BIOSSensors>(selData.sensorNum);
56 BIOSEventTypes eventType = static_cast<BIOSEventTypes>(selData.eventType);
57 switch (sensor)
58 {
59 case BIOSSensors::memoryRASConfigStatus:
60 switch (eventType)
61 {
62 case BIOSEventTypes::digitalDiscrete:
63 {
64 switch (selData.offset)
65 {
66 case 0x00:
67 messageID += ".MemoryRASConfigurationDisabled";
68 break;
69 case 0x01:
70 messageID += ".MemoryRASConfigurationEnabled";
71 break;
72 default:
73 return defaultMessageHook(ipmiRaw);
74 break;
75 }
76 // Get the message data from eventData2 and eventData3
77
78 // error = eventData2 bits [3:0]
79 int error = selData.eventData2 & 0x0F;
80
81 // mode = eventData3 bits [3:0]
82 int mode = selData.eventData3 & 0x0F;
83
84 // Save the messageArgs
85 switch (error)
86 {
87 case 0x00:
88 messageArgs.push_back("None");
89 break;
90 case 0x03:
91 messageArgs.push_back("Invalid DIMM Config");
92 break;
93 default:
94 messageArgs.push_back(std::to_string(error));
95 break;
96 }
97 switch (mode)
98 {
99 case 0x00:
100 messageArgs.push_back("None");
101 break;
102 case 0x01:
103 messageArgs.push_back("Mirroring");
104 break;
105 case 0x02:
106 messageArgs.push_back("Lockstep");
107 break;
108 case 0x04:
109 messageArgs.push_back("Rank Sparing");
110 break;
111 default:
112 messageArgs.push_back(std::to_string(mode));
113 break;
114 }
115
116 break;
117 }
118 default:
119 return defaultMessageHook(ipmiRaw);
120 break;
121 }
122 break;
123 case BIOSSensors::biosPOSTError:
124 switch (eventType)
125 {
126 case BIOSEventTypes::sensorSpecificOffset:
127 {
128 switch (selData.offset)
129 {
130 case 0x00:
131 messageID += ".BIOSPOSTError";
132 break;
133 default:
134 return defaultMessageHook(ipmiRaw);
135 break;
136 }
137 // Get the message data from eventData2 and eventData3
138
139 std::array<uint8_t, 2> post;
140 // post LSB = eventData2 bits [7:0]
141 post[1] = selData.eventData2;
142 // post MSB = eventData3 bits [7:0]
143 post[0] = selData.eventData3;
144
145 // Save the messageArgs
146 messageArgs.emplace_back();
147 std::string& postStr = messageArgs.back();
148 toHexStr(boost::beast::span<uint8_t>(post), postStr);
149
150 break;
151 }
152 default:
153 return defaultMessageHook(ipmiRaw);
154 break;
155 }
156 break;
157 case BIOSSensors::intelUPILinkWidthReduced:
158 switch (eventType)
159 {
160 case BIOSEventTypes::oemDiscrete7:
161 {
162 switch (selData.offset)
163 {
164 case 0x01:
165 messageID += ".IntelUPILinkWidthReducedToHalf";
166 break;
167 case 0x02:
168 messageID += ".IntelUPILinkWidthReducedToQuarter";
169 break;
170 default:
171 return defaultMessageHook(ipmiRaw);
172 break;
173 }
174 // Get the message data from eventData2
175
176 // Node ID = eventData2 bits [7:0]
177 int node = selData.eventData2;
178
179 // Save the messageArgs
180 messageArgs.push_back(std::to_string(node + 1));
181
182 break;
183 }
184 default:
185 return defaultMessageHook(ipmiRaw);
186 break;
187 }
188 break;
189 case BIOSSensors::memoryRASModeSelect:
190 switch (eventType)
191 {
192 case BIOSEventTypes::digitalDiscrete:
193 {
194 switch (selData.offset)
195 {
196 case 0x00:
197 messageID += ".MemoryRASModeDisabled";
198 break;
199 case 0x01:
200 messageID += ".MemoryRASModeEnabled";
201 break;
202 default:
203 return defaultMessageHook(ipmiRaw);
204 break;
205 }
206 // Get the message data from eventData2 and eventData3
207
208 // prior mode = eventData2 bits [3:0]
209 int priorMode = selData.eventData2 & 0x0F;
210
211 // selected mode = eventData3 bits [3:0]
212 int selectedMode = selData.eventData3 & 0x0F;
213
214 // Save the messageArgs
215 switch (priorMode)
216 {
217 case 0x00:
218 messageArgs.push_back("None");
219 break;
220 case 0x01:
221 messageArgs.push_back("Mirroring");
222 break;
223 case 0x02:
224 messageArgs.push_back("Lockstep");
225 break;
226 case 0x04:
227 messageArgs.push_back("Rank Sparing");
228 break;
229 default:
230 messageArgs.push_back(std::to_string(priorMode));
231 break;
232 }
233 switch (selectedMode)
234 {
235 case 0x00:
236 messageArgs.push_back("None");
237 break;
238 case 0x01:
239 messageArgs.push_back("Mirroring");
240 break;
241 case 0x02:
242 messageArgs.push_back("Lockstep");
243 break;
244 case 0x04:
245 messageArgs.push_back("Rank Sparing");
246 break;
247 default:
248 messageArgs.push_back(std::to_string(selectedMode));
249 break;
250 }
251
252 break;
253 }
254 default:
255 return defaultMessageHook(ipmiRaw);
256 break;
257 }
258 break;
259 case BIOSSensors::bootEvent:
260 switch (eventType)
261 {
262 case BIOSEventTypes::sensorSpecificOffset:
263 {
264 switch (selData.offset)
265 {
266 case 0x01:
267 messageID += ".BIOSBoot";
268 break;
269 case 0x09:
270 messageID += ".BIOSAttributesChanged";
271 break;
272 default:
273 return defaultMessageHook(ipmiRaw);
274 break;
275 }
276 break;
277 }
278 default:
279 return defaultMessageHook(ipmiRaw);
280 break;
281 }
282 break;
283 default:
284 return defaultMessageHook(ipmiRaw);
285 break;
286 }
287
288 // Log the Redfish message to the journal with the appropriate metadata
289 std::string journalMsg = "BIOS POST IPMI event: " + ipmiRaw;
290 if (messageArgs.empty())
291 {
292 phosphor::logging::log<phosphor::logging::level::INFO>(
293 journalMsg.c_str(),
294 phosphor::logging::entry("REDFISH_MESSAGE_ID=%s",
295 messageID.c_str()));
296 }
297 else
298 {
299 std::string messageArgsString =
300 boost::algorithm::join(messageArgs, ",");
301 phosphor::logging::log<phosphor::logging::level::INFO>(
302 journalMsg.c_str(),
303 phosphor::logging::entry("REDFISH_MESSAGE_ID=%s",
304 messageID.c_str()),
305 phosphor::logging::entry("REDFISH_MESSAGE_ARGS=%s",
306 messageArgsString.c_str()));
307 }
308
309 return true;
310 }
311
312 // Record a BIOS SMI message as a Redfish message instead of a SEL record
biosSMIMessageHook(const SELData & selData,const std::string & ipmiRaw)313 static bool biosSMIMessageHook(const SELData& selData,
314 const std::string& ipmiRaw)
315 {
316 // This is a BIOS SMI message, so record it as a Redfish message instead
317 // of a SEL record
318
319 // Walk through the SEL request record to build the appropriate Redfish
320 // message
321 static constexpr std::string_view openBMCMessageRegistryVersion = "0.1";
322 std::string messageID =
323 "OpenBMC." + std::string(openBMCMessageRegistryVersion);
324 std::vector<std::string> messageArgs;
325 BIOSSMISensors sensor = static_cast<BIOSSMISensors>(selData.sensorNum);
326 BIOSEventTypes eventType = static_cast<BIOSEventTypes>(selData.eventType);
327 switch (sensor)
328 {
329 case BIOSSMISensors::mirroringRedundancyState:
330 switch (eventType)
331 {
332 case BIOSEventTypes::discreteRedundancyStates:
333 {
334 switch (selData.offset)
335 {
336 case 0x00:
337 messageID += ".MirroringRedundancyFull";
338 break;
339 case 0x02:
340 messageID += ".MirroringRedundancyDegraded";
341 break;
342 default:
343 return defaultMessageHook(ipmiRaw);
344 break;
345 }
346 // Get the message data from eventData2 and eventData3
347
348 // pair = eventData2 bits [7:4]
349 int pair = selData.eventData2 >> 4 & 0x0F;
350 // rank = eventData2 bits [1:0]
351 int rank = selData.eventData2 & 0x03;
352
353 // Socket ID = eventData3 bits [7:5]
354 int socket = selData.eventData3 >> 5 & 0x07;
355 // Channel = eventData3 bits [4:2]
356 int channel = selData.eventData3 >> 2 & 0x07;
357 char channelLetter[4] = {'A'};
358 channelLetter[0] += channel;
359 // DIMM = eventData3 bits [1:0]
360 int dimm = selData.eventData3 & 0x03;
361
362 // Save the messageArgs
363 messageArgs.push_back(std::to_string(socket + 1));
364 messageArgs.push_back(std::string(channelLetter));
365 messageArgs.push_back(std::to_string(dimm + 1));
366 messageArgs.push_back(std::to_string(pair));
367 messageArgs.push_back(std::to_string(rank));
368
369 break;
370 }
371 default:
372 return defaultMessageHook(ipmiRaw);
373 break;
374 }
375 break;
376 case BIOSSMISensors::memoryECCError:
377 switch (eventType)
378 {
379 case BIOSEventTypes::sensorSpecificOffset:
380 {
381 switch (selData.offset)
382 {
383 case 0x00:
384 messageID += ".MemoryECCCorrectable";
385 break;
386 case 0x01:
387 messageID += ".MemoryECCUncorrectable";
388 break;
389 default:
390 return defaultMessageHook(ipmiRaw);
391 break;
392 }
393 // Get the message data from eventData2 and eventData3
394
395 // dimm = eventData2 bits [7:4]
396 int dimm = selData.eventData2 >> 4 & 0x0F;
397 // rank = eventData2 bits [3:0]
398 int rank = selData.eventData2 & 0x0F;
399
400 // Socket ID = eventData3 bits [7:4]
401 int socket = selData.eventData3 >> 4 & 0x0F;
402 // Channel = eventData3 bits [3:0]
403 int channel = selData.eventData3 & 0x0F;
404 char channelLetter[4] = {'A'};
405 channelLetter[0] += channel;
406
407 // Save the messageArgs
408 messageArgs.push_back(std::to_string(socket + 1));
409 messageArgs.push_back(std::string(channelLetter));
410 messageArgs.push_back(std::to_string(dimm));
411 messageArgs.push_back(std::to_string(rank));
412
413 break;
414 }
415 default:
416 return defaultMessageHook(ipmiRaw);
417 break;
418 }
419 break;
420 case BIOSSMISensors::legacyPCIError:
421 switch (eventType)
422 {
423 case BIOSEventTypes::sensorSpecificOffset:
424 {
425 switch (selData.offset)
426 {
427 case 0x04:
428 messageID += ".LegacyPCIPERR";
429 break;
430 case 0x05:
431 messageID += ".LegacyPCISERR";
432 break;
433 default:
434 return defaultMessageHook(ipmiRaw);
435 break;
436 }
437 // Get the message data from eventData2 and eventData3
438
439 // Bus = eventData2 bits [7:0]
440 int bus = selData.eventData2;
441 // Device = eventData3 bits [7:3]
442 int device = selData.eventData3 >> 3 & 0x1F;
443 // Function = eventData3 bits [2:0]
444 int function = selData.eventData3 >> 0x07;
445
446 // Save the messageArgs
447 messageArgs.push_back(std::to_string(bus));
448 messageArgs.push_back(std::to_string(device));
449 messageArgs.push_back(std::to_string(function));
450
451 break;
452 }
453 default:
454 return defaultMessageHook(ipmiRaw);
455 break;
456 }
457 break;
458 case BIOSSMISensors::pcieFatalError:
459 switch (eventType)
460 {
461 case BIOSEventTypes::oemDiscrete0:
462 {
463 switch (selData.offset)
464 {
465 case 0x00:
466 messageID += ".PCIeFatalDataLinkLayerProtocol";
467 break;
468 case 0x01:
469 messageID += ".PCIeFatalSurpriseLinkDown";
470 break;
471 case 0x02:
472 messageID += ".PCIeFatalCompleterAbort";
473 break;
474 case 0x03:
475 messageID += ".PCIeFatalUnsupportedRequest";
476 break;
477 case 0x04:
478 messageID += ".PCIeFatalPoisonedTLP";
479 break;
480 case 0x05:
481 messageID += ".PCIeFatalFlowControlProtocol";
482 break;
483 case 0x06:
484 messageID += ".PCIeFatalCompletionTimeout";
485 break;
486 case 0x07:
487 messageID += ".PCIeFatalReceiverBufferOverflow";
488 break;
489 case 0x08:
490 messageID += ".PCIeFatalACSViolation";
491 break;
492 case 0x09:
493 messageID += ".PCIeFatalMalformedTLP";
494 break;
495 case 0x0a:
496 messageID += ".PCIeFatalECRCError";
497 break;
498 case 0x0b:
499 messageID +=
500 ".PCIeFatalReceivedFatalMessageFromDownstream";
501 break;
502 case 0x0c:
503 messageID += ".PCIeFatalUnexpectedCompletion";
504 break;
505 case 0x0d:
506 messageID += ".PCIeFatalReceivedErrNonFatalMessage";
507 break;
508 case 0x0e:
509 messageID += ".PCIeFatalUncorrectableInternal";
510 break;
511 case 0x0f:
512 messageID += ".PCIeFatalMCBlockedTLP";
513 break;
514 default:
515 return defaultMessageHook(ipmiRaw);
516 break;
517 }
518 // Get the message data from eventData2 and eventData3
519
520 // Bus = eventData2 bits [7:0]
521 int bus = selData.eventData2;
522 // Device = eventData3 bits [7:3]
523 int device = selData.eventData3 >> 3 & 0x1F;
524 // Function = eventData3 bits [2:0]
525 int function = selData.eventData3 >> 0x07;
526
527 // Save the messageArgs
528 messageArgs.push_back(std::to_string(bus));
529 messageArgs.push_back(std::to_string(device));
530 messageArgs.push_back(std::to_string(function));
531
532 break;
533 }
534 default:
535 return defaultMessageHook(ipmiRaw);
536 break;
537 }
538 break;
539 case BIOSSMISensors::pcieCorrectableError:
540 switch (eventType)
541 {
542 case BIOSEventTypes::oemDiscrete1:
543 {
544 switch (selData.offset)
545 {
546 case 0x00:
547 messageID += ".PCIeCorrectableReceiverError";
548 break;
549 case 0x01:
550 messageID += ".PCIeCorrectableBadDLLP";
551 break;
552 case 0x02:
553 messageID += ".PCIeCorrectableBadTLP";
554 break;
555 case 0x03:
556 messageID += ".PCIeCorrectableReplayNumRollover";
557 break;
558 case 0x04:
559 messageID += ".PCIeCorrectableReplayTimerTimeout";
560 break;
561 case 0x05:
562 messageID += ".PCIeCorrectableAdvisoryNonFatal";
563 break;
564 case 0x06:
565 messageID += ".PCIeCorrectableLinkBWChanged";
566 break;
567 case 0x07:
568 messageID += ".PCIeCorrectableInternal";
569 break;
570 case 0x08:
571 messageID += ".PCIeCorrectableHeaderLogOverflow";
572 break;
573 case 0x0f:
574 messageID += ".PCIeCorrectableUnspecifiedAERError";
575 break;
576 default:
577 return defaultMessageHook(ipmiRaw);
578 break;
579 }
580 // Get the message data from eventData2 and eventData3
581
582 // Bus = eventData2 bits [7:0]
583 int bus = selData.eventData2;
584 // Device = eventData3 bits [7:3]
585 int device = selData.eventData3 >> 3 & 0x1F;
586 // Function = eventData3 bits [2:0]
587 int function = selData.eventData3 >> 0x07;
588
589 // Save the messageArgs
590 messageArgs.push_back(std::to_string(bus));
591 messageArgs.push_back(std::to_string(device));
592 messageArgs.push_back(std::to_string(function));
593
594 break;
595 }
596 default:
597 return defaultMessageHook(ipmiRaw);
598 break;
599 }
600 break;
601 case BIOSSMISensors::sparingRedundancyState:
602 switch (eventType)
603 {
604 case BIOSEventTypes::discreteRedundancyStates:
605 {
606 switch (selData.offset)
607 {
608 case 0x00:
609 messageID += ".SparingRedundancyFull";
610 break;
611 case 0x02:
612 messageID += ".SparingRedundancyDegraded";
613 break;
614 default:
615 return defaultMessageHook(ipmiRaw);
616 break;
617 }
618 // Get the message data from eventData2 and eventData3
619
620 // domain = eventData2 bits [7:4]
621 int domain = selData.eventData2 >> 4 & 0x0F;
622 char domainLetter[4] = {'A'};
623 domainLetter[0] += domain;
624 // rank = eventData2 bits [1:0]
625 int rank = selData.eventData2 & 0x03;
626
627 // Socket ID = eventData3 bits [7:5]
628 int socket = selData.eventData3 >> 5 & 0x07;
629 // Channel = eventData3 bits [4:2]
630 int channel = selData.eventData3 >> 2 & 0x07;
631 char channelLetter[4] = {'A'};
632 channelLetter[0] += channel;
633 // DIMM = eventData3 bits [1:0]
634 int dimm = selData.eventData3 & 0x03;
635
636 // Save the messageArgs
637 messageArgs.push_back(std::to_string(socket + 1));
638 messageArgs.push_back(std::string(channelLetter));
639 messageArgs.push_back(std::to_string(dimm + 1));
640 messageArgs.push_back(std::string(domainLetter));
641 messageArgs.push_back(std::to_string(rank));
642
643 break;
644 }
645 default:
646 return defaultMessageHook(ipmiRaw);
647 break;
648 }
649 break;
650 case BIOSSMISensors::memoryParityError:
651 switch (eventType)
652 {
653 case BIOSEventTypes::sensorSpecificOffset:
654 {
655 switch (selData.offset)
656 {
657 case 0x03:
658 {
659 // type = eventData2 bits [2:0]
660 int type = selData.eventData2 & 0x07;
661 switch (type)
662 {
663 case 0x00:
664 messageID += ".MemoryParityNotKnown";
665 break;
666 case 0x03:
667 messageID +=
668 ".MemoryParityCommandAndAddress";
669 break;
670 default:
671 return defaultMessageHook(ipmiRaw);
672 break;
673 }
674 break;
675 }
676 default:
677 return defaultMessageHook(ipmiRaw);
678 break;
679 }
680 // Get the message data from eventData2 and eventData3
681
682 // channelValid = eventData2 bit [4]
683 int channelValid = selData.eventData2 >> 4 & 0x01;
684 // dimmValid = eventData2 bit [3]
685 int dimmValid = selData.eventData2 >> 3 & 0x01;
686
687 // Socket ID = eventData3 bits [7:5]
688 int socket = selData.eventData3 >> 5 & 0x07;
689 // Channel = eventData3 bits [4:2]
690 int channel = selData.eventData3 >> 2 & 0x07;
691 char channelLetter[4] = {'A'};
692 channelLetter[0] += channel;
693 // DIMM = eventData3 bits [1:0]
694 int dimm = selData.eventData3 & 0x03;
695
696 // Save the messageArgs
697 messageArgs.push_back(std::to_string(socket + 1));
698 messageArgs.push_back(std::string(channelLetter));
699 messageArgs.push_back(std::to_string(dimm + 1));
700 messageArgs.push_back(std::to_string(channelValid));
701 messageArgs.push_back(std::to_string(dimmValid));
702
703 break;
704 }
705 default:
706 return defaultMessageHook(ipmiRaw);
707 break;
708 }
709 break;
710 case BIOSSMISensors::pcieFatalError2:
711 switch (eventType)
712 {
713 case BIOSEventTypes::oemDiscrete6:
714 {
715 switch (selData.offset)
716 {
717 case 0x00:
718 messageID += ".PCIeFatalAtomicEgressBlocked";
719 break;
720 case 0x01:
721 messageID += ".PCIeFatalTLPPrefixBlocked";
722 break;
723 case 0x0f:
724 messageID +=
725 ".PCIeFatalUnspecifiedNonAERFatalError";
726 break;
727 default:
728 return defaultMessageHook(ipmiRaw);
729 break;
730 }
731 // Get the message data from eventData2 and eventData3
732
733 // Bus = eventData2 bits [7:0]
734 int bus = selData.eventData2;
735 // Device = eventData3 bits [7:3]
736 int device = selData.eventData3 >> 3 & 0x1F;
737 // Function = eventData3 bits [2:0]
738 int function = selData.eventData3 >> 0x07;
739
740 // Save the messageArgs
741 messageArgs.push_back(std::to_string(bus));
742 messageArgs.push_back(std::to_string(device));
743 messageArgs.push_back(std::to_string(function));
744
745 break;
746 }
747 default:
748 return defaultMessageHook(ipmiRaw);
749 break;
750 }
751 break;
752 case BIOSSMISensors::biosRecovery:
753 switch (eventType)
754 {
755 case BIOSEventTypes::oemDiscrete0:
756 {
757 switch (selData.offset)
758 {
759 case 0x01:
760 messageID += ".BIOSRecoveryStart";
761 break;
762 default:
763 return defaultMessageHook(ipmiRaw);
764 break;
765 }
766 break;
767 }
768 case BIOSEventTypes::reservedF0:
769 {
770 switch (selData.offset)
771 {
772 case 0x01:
773 messageID += ".BIOSRecoveryComplete";
774 break;
775 default:
776 return defaultMessageHook(ipmiRaw);
777 break;
778 }
779 break;
780 }
781 default:
782 return defaultMessageHook(ipmiRaw);
783 break;
784 }
785 break;
786 case BIOSSMISensors::adddcError:
787 switch (eventType)
788 {
789 case BIOSEventTypes::reservedA0:
790 {
791 messageID += ".ADDDCCorrectable";
792
793 // Get the message data from eventData2 and eventData3
794
795 // dimm = eventData2 bits [7:4]
796 int dimm = selData.eventData2 >> 4 & 0x0F;
797 // rank = eventData2 bits [3:0]
798 int rank = selData.eventData2 & 0x0F;
799
800 // Socket ID = eventData3 bits [7:4]
801 int socket = selData.eventData3 >> 4 & 0x0F;
802 // Channel = eventData3 bits [3:0]
803 int channel = selData.eventData3 & 0x0F;
804 char channelLetter[4] = {'A'};
805 channelLetter[0] += channel;
806
807 // Save the messageArgs
808 messageArgs.push_back(std::to_string(socket + 1));
809 messageArgs.push_back(std::string(channelLetter));
810 messageArgs.push_back(std::to_string(dimm));
811 messageArgs.push_back(std::to_string(rank));
812
813 break;
814 }
815 default:
816 return defaultMessageHook(ipmiRaw);
817 break;
818 }
819 break;
820 default:
821 return defaultMessageHook(ipmiRaw);
822 break;
823 }
824
825 // Log the Redfish message to the journal with the appropriate metadata
826 std::string journalMsg = "BIOS SMI IPMI event: " + ipmiRaw;
827 std::string messageArgsString = boost::algorithm::join(messageArgs, ",");
828 phosphor::logging::log<phosphor::logging::level::INFO>(
829 journalMsg.c_str(),
830 phosphor::logging::entry("REDFISH_MESSAGE_ID=%s", messageID.c_str()),
831 phosphor::logging::entry("REDFISH_MESSAGE_ARGS=%s",
832 messageArgsString.c_str()));
833
834 return true;
835 }
836
startRedfishHook(const SELData & selData,const std::string & ipmiRaw)837 static bool startRedfishHook(const SELData& selData, const std::string& ipmiRaw)
838 {
839 uint8_t generatorIDLowByte = static_cast<uint8_t>(selData.generatorID);
840 // Generator ID is 7 bit and LS Bit contains '1' or '0' depending on the
841 // source. Refer IPMI SPEC, Table 32, SEL Event Records.
842 switch (generatorIDLowByte)
843 {
844 case 0x01: // Check if this message is from the BIOS Generator ID
845 // Let the BIOS hook handle this request
846 return biosMessageHook(selData, ipmiRaw);
847 break;
848
849 case 0x33: // Check if this message is from the BIOS SMI Generator ID
850 // Let the BIOS SMI hook handle this request
851 return biosSMIMessageHook(selData, ipmiRaw);
852 break;
853
854 case 0x2C: // Message from Intel ME
855 return me::messageHook(selData, ipmiRaw);
856 break;
857 }
858
859 // No hooks handled the request, so let it go to default
860 return defaultMessageHook(ipmiRaw);
861 }
862 } // namespace redfish_hooks
863
checkRedfishHooks(uint16_t recordID,uint8_t recordType,uint32_t timestamp,uint16_t generatorID,uint8_t evmRev,uint8_t sensorType,uint8_t sensorNum,uint8_t eventType,uint8_t eventData1,uint8_t eventData2,uint8_t eventData3)864 bool checkRedfishHooks(uint16_t recordID, uint8_t recordType,
865 uint32_t timestamp, uint16_t generatorID, uint8_t evmRev,
866 uint8_t sensorType, uint8_t sensorNum, uint8_t eventType,
867 uint8_t eventData1, uint8_t eventData2,
868 uint8_t eventData3)
869 {
870 // Save the raw IPMI string of the request
871 std::string ipmiRaw;
872 std::array selBytes = {
873 static_cast<uint8_t>(recordID),
874 static_cast<uint8_t>(recordID >> 8),
875 recordType,
876 static_cast<uint8_t>(timestamp),
877 static_cast<uint8_t>(timestamp >> 8),
878 static_cast<uint8_t>(timestamp >> 16),
879 static_cast<uint8_t>(timestamp >> 24),
880 static_cast<uint8_t>(generatorID),
881 static_cast<uint8_t>(generatorID >> 8),
882 evmRev,
883 sensorType,
884 sensorNum,
885 eventType,
886 eventData1,
887 eventData2,
888 eventData3};
889 redfish_hooks::toHexStr(boost::beast::span<uint8_t>(selBytes), ipmiRaw);
890
891 // First check that this is a system event record type since that
892 // determines the definition of the rest of the data
893 if (recordType != ipmi::sel::systemEvent)
894 {
895 // OEM record type, so let it go to the SEL
896 return redfish_hooks::defaultMessageHook(ipmiRaw);
897 }
898
899 // Extract the SEL data for the hook
900 redfish_hooks::SELData selData = {
901 .generatorID = generatorID,
902 .sensorNum = sensorNum,
903 .eventType = eventType,
904 .offset = eventData1 & 0x0F,
905 .eventData2 = eventData2,
906 .eventData3 = eventData3};
907
908 return redfish_hooks::startRedfishHook(selData, ipmiRaw);
909 }
910
checkRedfishHooks(uint16_t generatorID,uint8_t evmRev,uint8_t sensorType,uint8_t sensorNum,uint8_t eventType,uint8_t eventData1,uint8_t eventData2,uint8_t eventData3)911 bool checkRedfishHooks(uint16_t generatorID, uint8_t evmRev, uint8_t sensorType,
912 uint8_t sensorNum, uint8_t eventType, uint8_t eventData1,
913 uint8_t eventData2, uint8_t eventData3)
914 {
915 // Save the raw IPMI string of the selData
916 std::string ipmiRaw;
917 std::array selBytes = {
918 static_cast<uint8_t>(generatorID),
919 static_cast<uint8_t>(generatorID >> 8),
920 evmRev,
921 sensorType,
922 sensorNum,
923 eventType,
924 eventData1,
925 eventData2,
926 eventData3};
927 redfish_hooks::toHexStr(boost::beast::span<uint8_t>(selBytes), ipmiRaw);
928
929 // Extract the SEL data for the hook
930 redfish_hooks::SELData selData = {
931 .generatorID = generatorID,
932 .sensorNum = sensorNum,
933 .eventType = eventType,
934 .offset = eventData1 & 0x0F,
935 .eventData2 = eventData2,
936 .eventData3 = eventData3};
937
938 return redfish_hooks::startRedfishHook(selData, ipmiRaw);
939 }
940
941 } // namespace intel_oem::ipmi::sel
942