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