xref: /openbmc/phosphor-logging/extensions/openpower-pels/user_header.cpp (revision 40fb54935ce7367636a7156039396ee91cc4d5e2)
1 // SPDX-License-Identifier: Apache-2.0
2 // SPDX-FileCopyrightText: Copyright 2019 IBM Corporation
3 
4 #include "user_header.hpp"
5 
6 #include "json_utils.hpp"
7 #include "pel_types.hpp"
8 #include "pel_values.hpp"
9 #include "severity.hpp"
10 
11 #include <phosphor-logging/lg2.hpp>
12 
13 namespace openpower
14 {
15 namespace pels
16 {
17 
18 namespace pv = openpower::pels::pel_values;
19 
unflatten(Stream & stream)20 void UserHeader::unflatten(Stream& stream)
21 {
22     stream >> _header >> _eventSubsystem >> _eventScope >> _eventSeverity >>
23         _eventType >> _reserved4Byte1 >> _problemDomain >> _problemVector >>
24         _actionFlags >> _states;
25 }
26 
flatten(Stream & stream) const27 void UserHeader::flatten(Stream& stream) const
28 {
29     stream << _header << _eventSubsystem << _eventScope << _eventSeverity
30            << _eventType << _reserved4Byte1 << _problemDomain << _problemVector
31            << _actionFlags << _states;
32 }
33 
UserHeader(const message::Entry & entry,phosphor::logging::Entry::Level severity,const AdditionalData & additionalData,const DataInterfaceBase & dataIface)34 UserHeader::UserHeader(const message::Entry& entry,
35                        phosphor::logging::Entry::Level severity,
36                        const AdditionalData& additionalData,
37                        const DataInterfaceBase& dataIface)
38 {
39     _header.id = static_cast<uint16_t>(SectionID::userHeader);
40     _header.size = UserHeader::flattenedSize();
41     _header.version = userHeaderVersion;
42     _header.subType = 0;
43     _header.componentID = static_cast<uint16_t>(ComponentID::phosphorLogging);
44 
45     std::optional<uint8_t> subsys;
46 
47     // Check for additional data - PEL_SUBSYSTEM
48     auto ss = additionalData.getValue("PEL_SUBSYSTEM");
49     if (ss)
50     {
51         auto eventSubsystem = std::stoul(*ss, nullptr, 16);
52         std::string subsystemString =
53             pv::getValue(eventSubsystem, pel_values::subsystemValues);
54         if (subsystemString == "invalid")
55         {
56             lg2::warning(
57                 "UH: Invalid SubSystem value in PEL_SUBSYSTEM: {PEL_SUBSYSTEM}",
58                 "PEL_SUBSYSTEM", lg2::hex, eventSubsystem);
59         }
60         else
61         {
62             subsys = eventSubsystem;
63         }
64     }
65     else
66     {
67         subsys = entry.subsystem;
68     }
69 
70     if (subsys)
71     {
72         _eventSubsystem = *subsys;
73     }
74     else
75     {
76         // Gotta use something, how about 'others'.
77         lg2::warning(
78             "No PEL subystem value supplied for error, using 'others'");
79         _eventSubsystem = 0x70;
80     }
81 
82     _eventScope = entry.eventScope.value_or(
83         static_cast<uint8_t>(EventScope::entirePlatform));
84 
85     {
86         bool mfgSevStatus = false;
87         bool mfgActionFlagStatus = false;
88 
89         // Get the mfg severity & action flags
90         if (entry.mfgSeverity || entry.mfgActionFlags)
91         {
92             std::optional<uint8_t> sev = std::nullopt;
93             uint16_t val = 0;
94 
95             if (entry.mfgSeverity)
96             {
97                 // Find the mf severity possibly dependent on the system type.
98                 sev = getSeverity(entry.mfgSeverity.value(), dataIface);
99             }
100 
101             if (entry.mfgActionFlags)
102             {
103                 // Find the mfg action flags
104                 val = entry.mfgActionFlags.value();
105             }
106 
107             if (sev || val)
108             {
109                 bool mfgProp = dataIface.getQuiesceOnError();
110                 if (mfgProp)
111                 {
112                     if (sev)
113                     {
114                         _eventSeverity = *sev;
115                         mfgSevStatus = true;
116                     }
117 
118                     if (val)
119                     {
120                         _actionFlags = val;
121                         mfgActionFlagStatus = true;
122                     }
123                 }
124             }
125         }
126 
127         if (!mfgSevStatus)
128         {
129             // Get the severity from the registry if it's there, otherwise get
130             // it from the OpenBMC event log severity value.
131             if (!entry.severity)
132             {
133                 _eventSeverity = convertOBMCSeverityToPEL(severity);
134             }
135             else
136             {
137                 // Find the severity possibly dependent on the system type.
138                 auto sev = getSeverity(entry.severity.value(), dataIface);
139                 if (sev)
140                 {
141                     _eventSeverity = *sev;
142                 }
143                 else
144                 {
145                     // Either someone  screwed up the message registry
146                     // or getSystemNames failed.
147                     lg2::error(
148                         "Failed finding the severity in the message registry ERROR={ERROR}",
149                         "ERROR", entry.name);
150 
151                     // Have to choose something, just use informational.
152                     _eventSeverity = 0;
153                 }
154             }
155         }
156 
157         // Convert Critical error (0x50) to Critical Error-System Termination
158         // (0x51), if the AdditionalData is set to SYSTEM_TERM
159         auto sevLevel = additionalData.getValue("SEVERITY_DETAIL");
160         if ((_eventSeverity & 0xF0) == 0x50)
161         {
162             if (sevLevel.value_or("") == "SYSTEM_TERM")
163             {
164                 // Change to Critical Error, System Termination
165                 _eventSeverity = 0x51;
166             }
167         }
168 
169         if (entry.eventType)
170         {
171             _eventType = *entry.eventType;
172         }
173         else
174         {
175             // There are different default event types for info errors
176             // vs non info ones.
177             auto sevType = static_cast<SeverityType>(_eventSeverity & 0xF0);
178             _eventType =
179                 (sevType == SeverityType::nonError)
180                     ? static_cast<uint8_t>(EventType::miscInformational)
181                     : static_cast<uint8_t>(EventType::notApplicable);
182         }
183 
184         _reserved4Byte1 = 0;
185 
186         // No uses for problem domain or vector
187         _problemDomain = 0;
188         _problemVector = 0;
189 
190         // These will be set in pel_rules::check() if they're still
191         // at the default value.
192         if (!mfgActionFlagStatus)
193         {
194             _actionFlags = entry.actionFlags.value_or(actionFlagsDefault);
195         }
196 
197         _states = 0;
198 
199         _valid = true;
200     }
201 }
202 
UserHeader(Stream & pel)203 UserHeader::UserHeader(Stream& pel)
204 {
205     try
206     {
207         unflatten(pel);
208         validate();
209     }
210     catch (const std::exception& e)
211     {
212         lg2::error("Cannot unflatten user header: {EXCEPTION}", "EXCEPTION", e);
213         _valid = false;
214     }
215 }
216 
validate()217 void UserHeader::validate()
218 {
219     bool failed = false;
220     if (header().id != static_cast<uint16_t>(SectionID::userHeader))
221     {
222         lg2::error("Invalid user header section ID: {HEADER_ID}", "HEADER_ID",
223                    lg2::hex, header().id);
224         failed = true;
225     }
226 
227     if (header().version != userHeaderVersion)
228     {
229         lg2::error("Invalid user header version: {HEADER_VERSION}",
230                    "HEADER_VERSION", lg2::hex, header().version);
231         failed = true;
232     }
233 
234     _valid = (failed) ? false : true;
235 }
236 
getJSON(uint8_t creatorID) const237 std::optional<std::string> UserHeader::getJSON(uint8_t creatorID) const
238 {
239     std::string severity;
240     std::string subsystem;
241     std::string eventScope;
242     std::string eventType;
243     std::vector<std::string> actionFlags;
244     severity = pv::getValue(_eventSeverity, pel_values::severityValues);
245     subsystem = pv::getValue(_eventSubsystem, pel_values::subsystemValues);
246     eventScope = pv::getValue(_eventScope, pel_values::eventScopeValues);
247     eventType = pv::getValue(_eventType, pel_values::eventTypeValues);
248     actionFlags =
249         pv::getValuesBitwise(_actionFlags, pel_values::actionFlagsValues);
250 
251     std::string hostState{"Invalid"};
252     std::string hmcState{"Invalid"};
253     auto iter = pv::transmissionStates.find(
254         static_cast<TransmissionState>(hostTransmissionState()));
255     if (iter != pv::transmissionStates.end())
256     {
257         hostState = iter->second;
258     }
259     auto iter1 = pv::transmissionStates.find(
260         static_cast<TransmissionState>(hmcTransmissionState()));
261     if (iter1 != pv::transmissionStates.end())
262     {
263         hmcState = iter1->second;
264     }
265 
266     std::string uh;
267     jsonInsert(uh, pv::sectionVer, getNumberString("%d", userHeaderVersion), 1);
268     jsonInsert(uh, pv::subSection, getNumberString("%d", _header.subType), 1);
269     jsonInsert(uh, "Log Committed by",
270                getComponentName(_header.componentID, creatorID), 1);
271     jsonInsert(uh, "Subsystem", subsystem, 1);
272     jsonInsert(uh, "Event Scope", eventScope, 1);
273     jsonInsert(uh, "Event Severity", severity, 1);
274     jsonInsert(uh, "Event Type", eventType, 1);
275     jsonInsertArray(uh, "Action Flags", actionFlags, 1);
276     jsonInsert(uh, "Host Transmission", hostState, 1);
277     jsonInsert(uh, "HMC Transmission", hmcState, 1);
278     uh.erase(uh.size() - 2);
279     return uh;
280 }
281 
getSeverity(const std::vector<message::RegistrySeverity> & severities,const DataInterfaceBase & dataIface) const282 std::optional<uint8_t> UserHeader::getSeverity(
283     const std::vector<message::RegistrySeverity>& severities,
284     const DataInterfaceBase& dataIface) const
285 {
286     const uint8_t* s = nullptr;
287     std::vector<std::string> systemNames;
288 
289     // getSystemNames makes D-Bus calls, so only call it if we
290     // know we'll need it because there is a system name in the sev list
291     if (std::any_of(severities.begin(), severities.end(),
292                     [](const auto& sev) { return !sev.system.empty(); }))
293     {
294         try
295         {
296             systemNames = dataIface.getSystemNames();
297         }
298         catch (const std::exception& e)
299         {
300             lg2::error(
301                 "Failed trying to look up system names on D-Bus ERROR={ERROR}",
302                 "ERROR", e);
303             return std::nullopt;
304         }
305     }
306 
307     // Find the severity to use for this system type, or use the default
308     // entry (where no system type is specified).
309     for (const auto& sev : severities)
310     {
311         if (std::find(systemNames.begin(), systemNames.end(), sev.system) !=
312             systemNames.end())
313         {
314             s = &sev.severity;
315             break;
316         }
317         else if (sev.system.empty())
318         {
319             s = &sev.severity;
320         }
321     }
322 
323     if (s)
324     {
325         return *s;
326     }
327 
328     return std::nullopt;
329 }
330 
331 } // namespace pels
332 } // namespace openpower
333