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