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