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