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 <me_to_redfish_hooks.hpp>
19 #include <phosphor-logging/log.hpp>
20 
21 #include <string_view>
22 
23 namespace intel_oem::ipmi::sel::redfish_hooks::me
24 {
25 namespace health_event
26 {
27 namespace smbus_failure
28 {
29 
messageHook(const SELData & selData,std::string & eventId,std::vector<std::string> & args)30 static bool messageHook(const SELData& selData, std::string& eventId,
31                         std::vector<std::string>& args)
32 {
33     static const boost::container::flat_map<uint8_t, std::string> smlink = {
34         {0x01, "SmLink0/0B"},
35         {0x02, "SmLink1"},
36         {0x03, "SmLink2"},
37         {0x04, "SmLink3"},
38         {0x05, "SmLink4"}};
39 
40     const auto errorDetails = selData.eventData3;
41     const auto faultySmlink = smlink.find(selData.eventData2);
42     if (faultySmlink == smlink.end())
43     {
44         return false;
45     }
46 
47     eventId = "MESmbusLinkFailure";
48 
49     args.push_back(faultySmlink->second);
50     args.push_back(utils::toHex(errorDetails));
51 
52     return true;
53 }
54 } // namespace smbus_failure
55 
56 namespace fw_status
57 {
58 static const boost::container::flat_map<uint8_t, std::string>
59     manufacturingError = {
60         {0x00, "Generic error"},
61         {0x01, "Wrong or missing VSCC table"},
62         {0x02, "Wrong sensor scanning period in PIA"},
63         {0x03, "Wrong device definition in PIA"},
64         {0x04, "Reserved (Wrong SMART/CLST configuration)"},
65         {0x05, "Intel ME FW configuration is inconsistent or out of range"},
66         {0x06, "Reserved"},
67         {0x07, "Intel ME FW configuration is corrupted"},
68         {0x08, "SMLink0/0B misconfiguration"}};
69 
70 static const boost::container::flat_map<uint8_t, std::string> peciOverDmiError =
71     {{0x01, "DRAM Init Done HECI message not received by Intel ME before EOP"},
72      {0x02, "System PCIe bus configuration not known or not valid on DID HECI "
73             "message arrival to Intel ME"},
74      {0x03, "PECI over DMI run-time failure"}};
75 
76 static const boost::container::flat_map<uint8_t, std::string>
77     mctpInterfaceError = {
78         {0x01, "No DID HECI message received before EOP"},
79         {0x02, "No MCTP_SET_BUS_OWNER HECI message received by Intel ME on EOP "
80                "arrival "
81                "to ME while MCTP stack is configured in Bus Owner Proxy mode"}};
82 
83 static const boost::container::flat_map<uint8_t, std::string>
84     unsupportedFeature = {
85         {0x00, "Other Segment Defined Feature"},
86         {0x01, "Fast NM limiting"},
87         {0x02, "Volumetric Airflow and Outlet Temperature"},
88         {0x03, "CUPS"},
89         {0x04, "Thermal policies and Inlet Temperature"},
90         {0x05, "Platform limiting with MICs"},
91         {0x07, "Shared power supplies"},
92         {0x08, "MIC Proxy"},
93         {0x09, "Reset warning"},
94         {0x0A, "PMBus Proxy"},
95         {0x0B, "Always on"},
96         {0x0C, "IPMI Intel ME FW update"},
97         {0x0D, "MCTP bus owner"},
98         {0x0E, "MCTP bus owner proxy"},
99         {0x0F, "Dual BIOS"},
100         {0x10, "Battery less"}};
101 
102 static const boost::container::flat_map<uint8_t, std::string> umaError = {
103     {0x00, "UMA Read integrity error. Checksum of data read from UMA differs "
104            "from expected one."},
105     {0x01, "UMA Read/Write timeout. Timeout occurred during copying data "
106            "from/to UMA."},
107     {0x02,
108      "UMA not granted. BIOS did not grant any UMA or DRAM INIT done message "
109      "was not received from BIOS before EOP. Intel ME FW goes to recovery."},
110     {0x03, "UMA size granted by BIOS differs from requested. ME FW goes to "
111            "recovery."}};
112 
113 static const boost::container::flat_map<uint8_t, std::string> pttHealthEvent = {
114     {0x00, "Intel PTT disabled (PTT region is not present)."},
115     {0x01, "Intel PTT downgrade (PTT data should be not available)."},
116     {0x02, "Intel PTT disabled (battery less configuration)."}};
117 
118 static const boost::container::flat_map<uint8_t, std::string>
119     bootGuardHealthEvent = {
120         {0x00, "Boot Guard flow error (possible reasons: verification timeout; "
121                "verification error; BIOS Protection error)."}};
122 
123 static const boost::container::flat_map<uint8_t, std::string> restrictedMode = {
124     {0x01, "Firmware entered restricted mode – UMA is not available. "
125            "Restricted features set."},
126     {0x02, "Firmware exited restricted mode."}};
127 
128 static const boost::container::flat_map<uint8_t, std::string>
129     multiPchModeMisconfig = {
130         {0x01, "BIOS did not set reset synchronization in multiPCH mode"},
131         {0x02,
132          "PMC indicates different non/legacy mode for the PCH than BMC set "
133          "on the GPIO"},
134         {0x03,
135          "Misconfiguration MPCH support enabled due to BTG support enabled"}};
136 
137 static const boost::container::flat_map<uint8_t, std::string>
138     flashVerificationError = {
139         {0x00, "OEM Public Key verification error"},
140         {0x01, "Flash Descriptor Region Manifest verification error"},
141         {0x02, "Soft Straps verification error"}};
142 
143 namespace autoconfiguration
144 {
145 
messageHook(const SELData & selData,std::string & eventId,std::vector<std::string> & args)146 bool messageHook(const SELData& selData, std::string& eventId,
147                  std::vector<std::string>& args)
148 {
149     static const boost::container::flat_map<uint8_t, std::string> dcSource = {
150         {0b00, "BMC"}, {0b01, "PSU"}, {0b10, "On-board power sensor"}};
151 
152     static const boost::container::flat_map<uint8_t, std::string>
153         chassisSource = {{0b00, "BMC"},
154                          {0b01, "PSU"},
155                          {0b10, "On-board power sensor"},
156                          {0b11, "Not supported"}};
157 
158     static const boost::container::flat_map<uint8_t, std::string>
159         efficiencySource = {
160             {0b00, "BMC"}, {0b01, "PSU"}, {0b11, "Not supported"}};
161 
162     static const boost::container::flat_map<uint8_t, std::string>
163         unmanagedSource = {{0b00, "BMC"}, {0b01, "Estimated"}};
164 
165     static const boost::container::flat_map<uint8_t, std::string>
166         failureReason = {{0b00, "BMC discovery failure"},
167                          {0b01, "Insufficient factory configuration"},
168                          {0b10, "Unknown sensor type"},
169                          {0b11, "Other error encountered"}};
170 
171     auto succeeded = selData.eventData3 >> 7 & 0b1;
172     if (succeeded)
173     {
174         eventId = "MEAutoConfigSuccess";
175 
176         auto dc = dcSource.find(selData.eventData3 >> 5 & 0b11);
177         auto chassis = chassisSource.find(selData.eventData3 >> 3 & 0b11);
178         auto efficiency = efficiencySource.find(selData.eventData3 >> 1 & 0b11);
179         auto unmanaged = unmanagedSource.find(selData.eventData3 & 0b1);
180         if (dc == dcSource.end() || chassis == chassisSource.end() ||
181             efficiency == efficiencySource.end() ||
182             unmanaged == unmanagedSource.end())
183         {
184             return false;
185         }
186 
187         args.push_back(dc->second);
188         args.push_back(chassis->second);
189         args.push_back(efficiency->second);
190         args.push_back(unmanaged->second);
191     }
192     else
193     {
194         eventId = "MEAutoConfigFailed";
195 
196         const auto it = failureReason.find(selData.eventData3 >> 5 & 0b11);
197         if (it == failureReason.end())
198         {
199             return false;
200         }
201 
202         args.push_back(it->second);
203     }
204 
205     return true;
206 }
207 } // namespace autoconfiguration
208 
209 namespace factory_reset
210 {
messageHook(const SELData & selData,std::string & eventId,std::vector<std::string> & args)211 bool messageHook(const SELData& selData, std::string& eventId,
212                  std::vector<std::string>& args)
213 {
214     static const boost::container::flat_map<uint8_t, std::string>
215         restoreToFactoryPreset = {
216             {0x00,
217              "Flash file system error detected. Automatic restore to factory "
218              "presets has been triggered."},
219             {0x01, "Automatic restore to factory presets has been completed."},
220             {0x02, "Restore to factory presets triggered by Force ME Recovery "
221                    "IPMI command has been completed."},
222             {0x03,
223              "Restore to factory presets triggered by AC power cycle with "
224              "Recovery jumper asserted has been completed."}};
225 
226     auto param = restoreToFactoryPreset.find(selData.eventData3);
227     if (param == restoreToFactoryPreset.end())
228     {
229         return false;
230     }
231 
232     if (selData.eventData3 == 0x00)
233     {
234         eventId = "MEFactoryResetError";
235     }
236     else
237     {
238         eventId = "MEFactoryRestore";
239     }
240 
241     args.push_back(param->second);
242     return true;
243 }
244 } // namespace factory_reset
245 
246 namespace flash_state
247 {
messageHook(const SELData & selData,std::string & eventId,std::vector<std::string> & args)248 bool messageHook(const SELData& selData, std::string& eventId,
249                  std::vector<std::string>& args)
250 {
251     static const boost::container::flat_map<uint8_t, std::string>
252         flashStateInformation = {
253             {0x00,
254              "Flash partition table, recovery image or factory presets image "
255              "corrupted"},
256             {0x01, "Flash erase limit has been reached"},
257             {0x02,
258              "Flash write limit has been reached. Writing to flash has been "
259              "disabled"},
260             {0x03, "Writing to the flash has been enabled"}};
261 
262     auto param = flashStateInformation.find(selData.eventData3);
263     if (param == flashStateInformation.end())
264     {
265         return false;
266     }
267 
268     if (selData.eventData3 == 0x03)
269     {
270         eventId = "MEFlashStateInformationWritingEnabled";
271     }
272     else
273     {
274         eventId = "MEFlashStateInformation";
275     }
276 
277     args.push_back(param->second);
278     return true;
279 }
280 } // namespace flash_state
281 
messageHook(const SELData & selData,std::string & eventId,std::vector<std::string> & args)282 static bool messageHook(const SELData& selData, std::string& eventId,
283                         std::vector<std::string>& args)
284 {
285     static const boost::container::flat_map<
286         uint8_t,
287         std::pair<std::string, std::optional<std::variant<utils::ParserFunc,
288                                                           utils::MessageMap>>>>
289         eventMap = {
290             {0x00, {"MERecoveryGpioForced", {}}},
291             {0x01, {"MEImageExecutionFailed", {}}},
292             {0x02, {"MEFlashEraseError", {}}},
293             {0x03, {{}, flash_state::messageHook}},
294             {0x04, {"MEInternalError", {}}},
295             {0x05, {"MEExceptionDuringShutdown", {}}},
296             {0x06, {"MEDirectFlashUpdateRequested", {}}},
297             {0x07, {"MEManufacturingError", manufacturingError}},
298             {0x08, {{}, factory_reset::messageHook}},
299             {0x09, {"MEFirmwareException", utils::logByteHex<2>}},
300             {0x0A, {"MEFlashWearOutWarning", utils::logByteDec<2>}},
301             {0x0D, {"MEPeciOverDmiError", peciOverDmiError}},
302             {0x0E, {"MEMctpInterfaceError", mctpInterfaceError}},
303             {0x0F, {{}, autoconfiguration::messageHook}},
304             {0x10, {"MEUnsupportedFeature", unsupportedFeature}},
305             {0x12, {"MECpuDebugCapabilityDisabled", {}}},
306             {0x13, {"MEUmaError", umaError}},
307             {0x16, {"MEPttHealthEvent", pttHealthEvent}},
308             {0x17, {"MEBootGuardHealthEvent", bootGuardHealthEvent}},
309             {0x18, {"MERestrictedMode", restrictedMode}},
310             {0x19, {"MEMultiPchModeMisconfig", multiPchModeMisconfig}},
311             {0x1A, {"MEFlashVerificationError", flashVerificationError}}};
312 
313     return utils::genericMessageHook(eventMap, selData, eventId, args);
314 }
315 } // namespace fw_status
316 
messageHook(const SELData & selData,std::string & eventId,std::vector<std::string> & args)317 static bool messageHook(const SELData& selData, std::string& eventId,
318                         std::vector<std::string>& args)
319 {
320     const HealthEventType healthEventType =
321         static_cast<HealthEventType>(selData.offset);
322 
323     switch (healthEventType)
324     {
325         case HealthEventType::FirmwareStatus:
326             return fw_status::messageHook(selData, eventId, args);
327             break;
328 
329         case HealthEventType::SmbusLinkFailure:
330             return smbus_failure::messageHook(selData, eventId, args);
331             break;
332     }
333 
334     return false;
335 }
336 } // namespace health_event
337 
338 /**
339  * @brief Main entry point for parsing ME IPMI Platform Events
340  *
341  * @brief selData - IPMI Platform Event structure
342  * @brief ipmiRaw - the same event in raw binary form
343  *
344  * @returns true if event was successfully parsed and consumed
345  */
messageHook(const SELData & selData,const std::string & ipmiRaw)346 bool messageHook(const SELData& selData, const std::string& ipmiRaw)
347 {
348     const EventSensor meSensor = static_cast<EventSensor>(selData.sensorNum);
349     std::string eventId;
350     std::vector<std::string> args;
351 
352     switch (meSensor)
353     {
354         case EventSensor::MeFirmwareHealth:
355             if (health_event::messageHook(selData, eventId, args))
356             {
357                 utils::storeRedfishEvent(ipmiRaw, eventId, args);
358                 return true;
359             }
360             break;
361     }
362 
363     return defaultMessageHook(ipmiRaw);
364 }
365 } // namespace intel_oem::ipmi::sel::redfish_hooks::me
366