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 {
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
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                         default:
270                             return defaultMessageHook(ipmiRaw);
271                             break;
272                     }
273                     break;
274                 }
275                 default:
276                     return defaultMessageHook(ipmiRaw);
277                     break;
278             }
279             break;
280         default:
281             return defaultMessageHook(ipmiRaw);
282             break;
283     }
284 
285     // Log the Redfish message to the journal with the appropriate metadata
286     std::string journalMsg = "BIOS POST IPMI event: " + ipmiRaw;
287     if (messageArgs.empty())
288     {
289         phosphor::logging::log<phosphor::logging::level::INFO>(
290             journalMsg.c_str(),
291             phosphor::logging::entry("REDFISH_MESSAGE_ID=%s",
292                                      messageID.c_str()));
293     }
294     else
295     {
296         std::string messageArgsString =
297             boost::algorithm::join(messageArgs, ",");
298         phosphor::logging::log<phosphor::logging::level::INFO>(
299             journalMsg.c_str(),
300             phosphor::logging::entry("REDFISH_MESSAGE_ID=%s",
301                                      messageID.c_str()),
302             phosphor::logging::entry("REDFISH_MESSAGE_ARGS=%s",
303                                      messageArgsString.c_str()));
304     }
305 
306     return true;
307 }
308 
309 // Record a BIOS SMI message as a Redfish message instead of a SEL record
310 static bool biosSMIMessageHook(const SELData& selData,
311                                const std::string& ipmiRaw)
312 {
313     // This is a BIOS SMI message, so record it as a Redfish message instead
314     // of a SEL record
315 
316     // Walk through the SEL request record to build the appropriate Redfish
317     // message
318     static constexpr std::string_view openBMCMessageRegistryVersion = "0.1";
319     std::string messageID =
320         "OpenBMC." + std::string(openBMCMessageRegistryVersion);
321     std::vector<std::string> messageArgs;
322     BIOSSMISensors sensor = static_cast<BIOSSMISensors>(selData.sensorNum);
323     BIOSEventTypes eventType = static_cast<BIOSEventTypes>(selData.eventType);
324     switch (sensor)
325     {
326         case BIOSSMISensors::mirroringRedundancyState:
327             switch (eventType)
328             {
329                 case BIOSEventTypes::discreteRedundancyStates:
330                 {
331                     switch (selData.offset)
332                     {
333                         case 0x00:
334                             messageID += ".MirroringRedundancyFull";
335                             break;
336                         case 0x02:
337                             messageID += ".MirroringRedundancyDegraded";
338                             break;
339                         default:
340                             return defaultMessageHook(ipmiRaw);
341                             break;
342                     }
343                     // Get the message data from eventData2 and eventData3
344 
345                     // pair = eventData2 bits [7:4]
346                     int pair = selData.eventData2 >> 4 & 0x0F;
347                     // rank = eventData2 bits [1:0]
348                     int rank = selData.eventData2 & 0x03;
349 
350                     // Socket ID = eventData3 bits [7:5]
351                     int socket = selData.eventData3 >> 5 & 0x07;
352                     // Channel = eventData3 bits [4:2]
353                     int channel = selData.eventData3 >> 2 & 0x07;
354                     char channelLetter[4] = {'A'};
355                     channelLetter[0] += channel;
356                     // DIMM = eventData3 bits [1:0]
357                     int dimm = selData.eventData3 & 0x03;
358 
359                     // Save the messageArgs
360                     messageArgs.push_back(std::to_string(socket + 1));
361                     messageArgs.push_back(std::string(channelLetter));
362                     messageArgs.push_back(std::to_string(dimm + 1));
363                     messageArgs.push_back(std::to_string(pair));
364                     messageArgs.push_back(std::to_string(rank));
365 
366                     break;
367                 }
368                 default:
369                     return defaultMessageHook(ipmiRaw);
370                     break;
371             }
372             break;
373         case BIOSSMISensors::memoryECCError:
374             switch (eventType)
375             {
376                 case BIOSEventTypes::sensorSpecificOffset:
377                 {
378                     switch (selData.offset)
379                     {
380                         case 0x00:
381                             messageID += ".MemoryECCCorrectable";
382                             break;
383                         case 0x01:
384                             messageID += ".MemoryECCUncorrectable";
385                             break;
386                         default:
387                             return defaultMessageHook(ipmiRaw);
388                             break;
389                     }
390                     // Get the message data from eventData2 and eventData3
391 
392                     // dimm = eventData2 bits [7:4]
393                     int dimm = selData.eventData2 >> 4 & 0x0F;
394                     // rank = eventData2 bits [3:0]
395                     int rank = selData.eventData2 & 0x0F;
396 
397                     // Socket ID = eventData3 bits [7:4]
398                     int socket = selData.eventData3 >> 4 & 0x0F;
399                     // Channel = eventData3 bits [3:0]
400                     int channel = selData.eventData3 & 0x0F;
401                     char channelLetter[4] = {'A'};
402                     channelLetter[0] += channel;
403 
404                     // Save the messageArgs
405                     messageArgs.push_back(std::to_string(socket + 1));
406                     messageArgs.push_back(std::string(channelLetter));
407                     messageArgs.push_back(std::to_string(dimm));
408                     messageArgs.push_back(std::to_string(rank));
409 
410                     break;
411                 }
412                 default:
413                     return defaultMessageHook(ipmiRaw);
414                     break;
415             }
416             break;
417         case BIOSSMISensors::legacyPCIError:
418             switch (eventType)
419             {
420                 case BIOSEventTypes::sensorSpecificOffset:
421                 {
422                     switch (selData.offset)
423                     {
424                         case 0x04:
425                             messageID += ".LegacyPCIPERR";
426                             break;
427                         case 0x05:
428                             messageID += ".LegacyPCISERR";
429                             break;
430                         default:
431                             return defaultMessageHook(ipmiRaw);
432                             break;
433                     }
434                     // Get the message data from eventData2 and eventData3
435 
436                     // Bus = eventData2 bits [7:0]
437                     int bus = selData.eventData2;
438                     // Device = eventData3 bits [7:3]
439                     int device = selData.eventData3 >> 3 & 0x1F;
440                     // Function = eventData3 bits [2:0]
441                     int function = selData.eventData3 >> 0x07;
442 
443                     // Save the messageArgs
444                     messageArgs.push_back(std::to_string(bus));
445                     messageArgs.push_back(std::to_string(device));
446                     messageArgs.push_back(std::to_string(function));
447 
448                     break;
449                 }
450                 default:
451                     return defaultMessageHook(ipmiRaw);
452                     break;
453             }
454             break;
455         case BIOSSMISensors::pcieFatalError:
456             switch (eventType)
457             {
458                 case BIOSEventTypes::oemDiscrete0:
459                 {
460                     switch (selData.offset)
461                     {
462                         case 0x00:
463                             messageID += ".PCIeFatalDataLinkLayerProtocol";
464                             break;
465                         case 0x01:
466                             messageID += ".PCIeFatalSurpriseLinkDown";
467                             break;
468                         case 0x02:
469                             messageID += ".PCIeFatalCompleterAbort";
470                             break;
471                         case 0x03:
472                             messageID += ".PCIeFatalUnsupportedRequest";
473                             break;
474                         case 0x04:
475                             messageID += ".PCIeFatalPoisonedTLP";
476                             break;
477                         case 0x05:
478                             messageID += ".PCIeFatalFlowControlProtocol";
479                             break;
480                         case 0x06:
481                             messageID += ".PCIeFatalCompletionTimeout";
482                             break;
483                         case 0x07:
484                             messageID += ".PCIeFatalReceiverBufferOverflow";
485                             break;
486                         case 0x08:
487                             messageID += ".PCIeFatalACSViolation";
488                             break;
489                         case 0x09:
490                             messageID += ".PCIeFatalMalformedTLP";
491                             break;
492                         case 0x0a:
493                             messageID += ".PCIeFatalECRCError";
494                             break;
495                         case 0x0b:
496                             messageID +=
497                                 ".PCIeFatalReceivedFatalMessageFromDownstream";
498                             break;
499                         case 0x0c:
500                             messageID += ".PCIeFatalUnexpectedCompletion";
501                             break;
502                         case 0x0d:
503                             messageID += ".PCIeFatalReceivedErrNonFatalMessage";
504                             break;
505                         case 0x0e:
506                             messageID += ".PCIeFatalUncorrectableInternal";
507                             break;
508                         case 0x0f:
509                             messageID += ".PCIeFatalMCBlockedTLP";
510                             break;
511                         default:
512                             return defaultMessageHook(ipmiRaw);
513                             break;
514                     }
515                     // Get the message data from eventData2 and eventData3
516 
517                     // Bus = eventData2 bits [7:0]
518                     int bus = selData.eventData2;
519                     // Device = eventData3 bits [7:3]
520                     int device = selData.eventData3 >> 3 & 0x1F;
521                     // Function = eventData3 bits [2:0]
522                     int function = selData.eventData3 >> 0x07;
523 
524                     // Save the messageArgs
525                     messageArgs.push_back(std::to_string(bus));
526                     messageArgs.push_back(std::to_string(device));
527                     messageArgs.push_back(std::to_string(function));
528 
529                     break;
530                 }
531                 default:
532                     return defaultMessageHook(ipmiRaw);
533                     break;
534             }
535             break;
536         case BIOSSMISensors::pcieCorrectableError:
537             switch (eventType)
538             {
539                 case BIOSEventTypes::oemDiscrete1:
540                 {
541                     switch (selData.offset)
542                     {
543                         case 0x00:
544                             messageID += ".PCIeCorrectableReceiverError";
545                             break;
546                         case 0x01:
547                             messageID += ".PCIeCorrectableBadDLLP";
548                             break;
549                         case 0x02:
550                             messageID += ".PCIeCorrectableBadTLP";
551                             break;
552                         case 0x03:
553                             messageID += ".PCIeCorrectableReplayNumRollover";
554                             break;
555                         case 0x04:
556                             messageID += ".PCIeCorrectableReplayTimerTimeout";
557                             break;
558                         case 0x05:
559                             messageID += ".PCIeCorrectableAdvisoryNonFatal";
560                             break;
561                         case 0x06:
562                             messageID += ".PCIeCorrectableLinkBWChanged";
563                             break;
564                         case 0x07:
565                             messageID += ".PCIeCorrectableInternal";
566                             break;
567                         case 0x08:
568                             messageID += ".PCIeCorrectableHeaderLogOverflow";
569                             break;
570                         case 0x0f:
571                             messageID += ".PCIeCorrectableUnspecifiedAERError";
572                             break;
573                         default:
574                             return defaultMessageHook(ipmiRaw);
575                             break;
576                     }
577                     // Get the message data from eventData2 and eventData3
578 
579                     // Bus = eventData2 bits [7:0]
580                     int bus = selData.eventData2;
581                     // Device = eventData3 bits [7:3]
582                     int device = selData.eventData3 >> 3 & 0x1F;
583                     // Function = eventData3 bits [2:0]
584                     int function = selData.eventData3 >> 0x07;
585 
586                     // Save the messageArgs
587                     messageArgs.push_back(std::to_string(bus));
588                     messageArgs.push_back(std::to_string(device));
589                     messageArgs.push_back(std::to_string(function));
590 
591                     break;
592                 }
593                 default:
594                     return defaultMessageHook(ipmiRaw);
595                     break;
596             }
597             break;
598         case BIOSSMISensors::sparingRedundancyState:
599             switch (eventType)
600             {
601                 case BIOSEventTypes::discreteRedundancyStates:
602                 {
603                     switch (selData.offset)
604                     {
605                         case 0x00:
606                             messageID += ".SparingRedundancyFull";
607                             break;
608                         case 0x02:
609                             messageID += ".SparingRedundancyDegraded";
610                             break;
611                         default:
612                             return defaultMessageHook(ipmiRaw);
613                             break;
614                     }
615                     // Get the message data from eventData2 and eventData3
616 
617                     // domain = eventData2 bits [7:4]
618                     int domain = selData.eventData2 >> 4 & 0x0F;
619                     char domainLetter[4] = {'A'};
620                     domainLetter[0] += domain;
621                     // rank = eventData2 bits [1:0]
622                     int rank = selData.eventData2 & 0x03;
623 
624                     // Socket ID = eventData3 bits [7:5]
625                     int socket = selData.eventData3 >> 5 & 0x07;
626                     // Channel = eventData3 bits [4:2]
627                     int channel = selData.eventData3 >> 2 & 0x07;
628                     char channelLetter[4] = {'A'};
629                     channelLetter[0] += channel;
630                     // DIMM = eventData3 bits [1:0]
631                     int dimm = selData.eventData3 & 0x03;
632 
633                     // Save the messageArgs
634                     messageArgs.push_back(std::to_string(socket + 1));
635                     messageArgs.push_back(std::string(channelLetter));
636                     messageArgs.push_back(std::to_string(dimm + 1));
637                     messageArgs.push_back(std::string(domainLetter));
638                     messageArgs.push_back(std::to_string(rank));
639 
640                     break;
641                 }
642                 default:
643                     return defaultMessageHook(ipmiRaw);
644                     break;
645             }
646             break;
647         case BIOSSMISensors::memoryParityError:
648             switch (eventType)
649             {
650                 case BIOSEventTypes::sensorSpecificOffset:
651                 {
652                     switch (selData.offset)
653                     {
654                         case 0x03:
655                         {
656                             // type = eventData2 bits [2:0]
657                             int type = selData.eventData2 & 0x07;
658                             switch (type)
659                             {
660                                 case 0x00:
661                                     messageID += ".MemoryParityNotKnown";
662                                     break;
663                                 case 0x03:
664                                     messageID +=
665                                         ".MemoryParityCommandAndAddress";
666                                     break;
667                                 default:
668                                     return defaultMessageHook(ipmiRaw);
669                                     break;
670                             }
671                             break;
672                         }
673                         default:
674                             return defaultMessageHook(ipmiRaw);
675                             break;
676                     }
677                     // Get the message data from eventData2 and eventData3
678 
679                     // channelValid = eventData2 bit [4]
680                     int channelValid = selData.eventData2 >> 4 & 0x01;
681                     // dimmValid = eventData2 bit [3]
682                     int dimmValid = selData.eventData2 >> 3 & 0x01;
683 
684                     // Socket ID = eventData3 bits [7:5]
685                     int socket = selData.eventData3 >> 5 & 0x07;
686                     // Channel = eventData3 bits [4:2]
687                     int channel = selData.eventData3 >> 2 & 0x07;
688                     char channelLetter[4] = {'A'};
689                     channelLetter[0] += channel;
690                     // DIMM = eventData3 bits [1:0]
691                     int dimm = selData.eventData3 & 0x03;
692 
693                     // Save the messageArgs
694                     messageArgs.push_back(std::to_string(socket + 1));
695                     messageArgs.push_back(std::string(channelLetter));
696                     messageArgs.push_back(std::to_string(dimm + 1));
697                     messageArgs.push_back(std::to_string(channelValid));
698                     messageArgs.push_back(std::to_string(dimmValid));
699 
700                     break;
701                 }
702                 default:
703                     return defaultMessageHook(ipmiRaw);
704                     break;
705             }
706             break;
707         case BIOSSMISensors::pcieFatalError2:
708             switch (eventType)
709             {
710                 case BIOSEventTypes::oemDiscrete6:
711                 {
712                     switch (selData.offset)
713                     {
714                         case 0x00:
715                             messageID += ".PCIeFatalAtomicEgressBlocked";
716                             break;
717                         case 0x01:
718                             messageID += ".PCIeFatalTLPPrefixBlocked";
719                             break;
720                         case 0x0f:
721                             messageID +=
722                                 ".PCIeFatalUnspecifiedNonAERFatalError";
723                             break;
724                         default:
725                             return defaultMessageHook(ipmiRaw);
726                             break;
727                     }
728                     // Get the message data from eventData2 and eventData3
729 
730                     // Bus = eventData2 bits [7:0]
731                     int bus = selData.eventData2;
732                     // Device = eventData3 bits [7:3]
733                     int device = selData.eventData3 >> 3 & 0x1F;
734                     // Function = eventData3 bits [2:0]
735                     int function = selData.eventData3 >> 0x07;
736 
737                     // Save the messageArgs
738                     messageArgs.push_back(std::to_string(bus));
739                     messageArgs.push_back(std::to_string(device));
740                     messageArgs.push_back(std::to_string(function));
741 
742                     break;
743                 }
744                 default:
745                     return defaultMessageHook(ipmiRaw);
746                     break;
747             }
748             break;
749         case BIOSSMISensors::biosRecovery:
750             switch (eventType)
751             {
752                 case BIOSEventTypes::oemDiscrete0:
753                 {
754                     switch (selData.offset)
755                     {
756                         case 0x01:
757                             messageID += ".BIOSRecoveryStart";
758                             break;
759                         default:
760                             return defaultMessageHook(ipmiRaw);
761                             break;
762                     }
763                     break;
764                 }
765                 case BIOSEventTypes::reservedF0:
766                 {
767                     switch (selData.offset)
768                     {
769                         case 0x01:
770                             messageID += ".BIOSRecoveryComplete";
771                             break;
772                         default:
773                             return defaultMessageHook(ipmiRaw);
774                             break;
775                     }
776                     break;
777                 }
778                 default:
779                     return defaultMessageHook(ipmiRaw);
780                     break;
781             }
782             break;
783         case BIOSSMISensors::adddcError:
784             switch (eventType)
785             {
786                 case BIOSEventTypes::reservedA0:
787                 {
788                     messageID += ".ADDDCCorrectable";
789 
790                     // Get the message data from eventData2 and eventData3
791 
792                     // dimm = eventData2 bits [7:4]
793                     int dimm = selData.eventData2 >> 4 & 0x0F;
794                     // rank = eventData2 bits [3:0]
795                     int rank = selData.eventData2 & 0x0F;
796 
797                     // Socket ID = eventData3 bits [7:4]
798                     int socket = selData.eventData3 >> 4 & 0x0F;
799                     // Channel = eventData3 bits [3:0]
800                     int channel = selData.eventData3 & 0x0F;
801                     char channelLetter[4] = {'A'};
802                     channelLetter[0] += channel;
803 
804                     // Save the messageArgs
805                     messageArgs.push_back(std::to_string(socket + 1));
806                     messageArgs.push_back(std::string(channelLetter));
807                     messageArgs.push_back(std::to_string(dimm));
808                     messageArgs.push_back(std::to_string(rank));
809 
810                     break;
811                 }
812                 default:
813                     return defaultMessageHook(ipmiRaw);
814                     break;
815             }
816             break;
817         default:
818             return defaultMessageHook(ipmiRaw);
819             break;
820     }
821 
822     // Log the Redfish message to the journal with the appropriate metadata
823     std::string journalMsg = "BIOS SMI IPMI event: " + ipmiRaw;
824     std::string messageArgsString = boost::algorithm::join(messageArgs, ",");
825     phosphor::logging::log<phosphor::logging::level::INFO>(
826         journalMsg.c_str(),
827         phosphor::logging::entry("REDFISH_MESSAGE_ID=%s", messageID.c_str()),
828         phosphor::logging::entry("REDFISH_MESSAGE_ARGS=%s",
829                                  messageArgsString.c_str()));
830 
831     return true;
832 }
833 
834 static bool startRedfishHook(const SELData& selData, const std::string& ipmiRaw)
835 {
836     switch (selData.generatorID)
837     {
838         case 0x01: // Check if this message is from the BIOS Generator ID
839             // Let the BIOS hook handle this request
840             return biosMessageHook(selData, ipmiRaw);
841             break;
842 
843         case 0x33: // Check if this message is from the BIOS SMI Generator ID
844             // Let the BIOS SMI hook handle this request
845             return biosSMIMessageHook(selData, ipmiRaw);
846             break;
847 
848         case 0x2C: // Message from Intel ME
849             return me::messageHook(selData, ipmiRaw);
850             break;
851     }
852 
853     // No hooks handled the request, so let it go to default
854     return defaultMessageHook(ipmiRaw);
855 }
856 } // namespace redfish_hooks
857 
858 bool checkRedfishHooks(uint16_t recordID, uint8_t recordType,
859                        uint32_t timestamp, uint16_t generatorID, uint8_t evmRev,
860                        uint8_t sensorType, uint8_t sensorNum, uint8_t eventType,
861                        uint8_t eventData1, uint8_t eventData2,
862                        uint8_t eventData3)
863 {
864     // Save the raw IPMI string of the request
865     std::string ipmiRaw;
866     std::array selBytes = {static_cast<uint8_t>(recordID),
867                            static_cast<uint8_t>(recordID >> 8),
868                            recordType,
869                            static_cast<uint8_t>(timestamp),
870                            static_cast<uint8_t>(timestamp >> 8),
871                            static_cast<uint8_t>(timestamp >> 16),
872                            static_cast<uint8_t>(timestamp >> 24),
873                            static_cast<uint8_t>(generatorID),
874                            static_cast<uint8_t>(generatorID >> 8),
875                            evmRev,
876                            sensorType,
877                            sensorNum,
878                            eventType,
879                            eventData1,
880                            eventData2,
881                            eventData3};
882     redfish_hooks::toHexStr(boost::beast::span<uint8_t>(selBytes), ipmiRaw);
883 
884     // First check that this is a system event record type since that
885     // determines the definition of the rest of the data
886     if (recordType != ipmi::sel::systemEvent)
887     {
888         // OEM record type, so let it go to the SEL
889         return redfish_hooks::defaultMessageHook(ipmiRaw);
890     }
891 
892     // Extract the SEL data for the hook
893     redfish_hooks::SELData selData = {.generatorID = generatorID,
894                                       .sensorNum = sensorNum,
895                                       .eventType = eventType,
896                                       .offset = eventData1 & 0x0F,
897                                       .eventData2 = eventData2,
898                                       .eventData3 = eventData3};
899 
900     return redfish_hooks::startRedfishHook(selData, ipmiRaw);
901 }
902 
903 bool checkRedfishHooks(uint8_t generatorID, uint8_t evmRev, uint8_t sensorType,
904                        uint8_t sensorNum, uint8_t eventType, uint8_t eventData1,
905                        uint8_t eventData2, uint8_t eventData3)
906 {
907     // Save the raw IPMI string of the selData
908     std::string ipmiRaw;
909     std::array selBytes = {generatorID, evmRev,     sensorType, sensorNum,
910                            eventType,   eventData1, eventData2, eventData3};
911     redfish_hooks::toHexStr(boost::beast::span<uint8_t>(selBytes), ipmiRaw);
912 
913     // Extract the SEL data for the hook
914     redfish_hooks::SELData selData = {.generatorID = generatorID,
915                                       .sensorNum = sensorNum,
916                                       .eventType = eventType,
917                                       .offset = eventData1 & 0x0F,
918                                       .eventData2 = eventData2,
919                                       .eventData3 = eventData3};
920 
921     return redfish_hooks::startRedfishHook(selData, ipmiRaw);
922 }
923 
924 } // namespace intel_oem::ipmi::sel
925