xref: /openbmc/phosphor-logging/extensions/openpower-pels/user_header.cpp (revision 81a91e3ee4bf962111cf555ab9d3c3c51000fa3b)
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 DataInterfaceBase& dataIface)
51 {
52     _header.id = static_cast<uint16_t>(SectionID::userHeader);
53     _header.size = UserHeader::flattenedSize();
54     _header.version = userHeaderVersion;
55     _header.subType = 0;
56     _header.componentID = static_cast<uint16_t>(ComponentID::phosphorLogging);
57 
58     _eventSubsystem = entry.subsystem;
59 
60     _eventScope = entry.eventScope.value_or(
61         static_cast<uint8_t>(EventScope::entirePlatform));
62 
63     // Get the severity from the registry if it's there, otherwise get it
64     // from the OpenBMC event log severity value.
65     if (!entry.severity)
66     {
67         _eventSeverity = convertOBMCSeverityToPEL(severity);
68     }
69     else
70     {
71         // Find the severity possibly dependent on the system type.
72         auto sev =
73             getSeverity(entry.severity.value(), dataIface.getSystemType());
74         if (sev)
75         {
76             _eventSeverity = *sev;
77         }
78         else
79         {
80             // Someone screwed up the message registry.
81             log<level::ERR>(
82                 "No severity entry found for this error and system type",
83                 phosphor::logging::entry("ERROR=%s", entry.name.c_str()),
84                 phosphor::logging::entry("SYSTEMTYPE=%s",
85                                          dataIface.getSystemType().c_str()));
86 
87             // Have to choose something, just use informational.
88             _eventSeverity = 0;
89         }
90     }
91 
92     // TODO: ibm-dev/dev/#1144 Handle manufacturing sev & action flags
93 
94     if (entry.eventType)
95     {
96         _eventType = *entry.eventType;
97     }
98     else
99     {
100         // There are different default event types for info errors
101         // vs non info ones.
102         auto sevType = static_cast<SeverityType>(_eventSeverity & 0xF0);
103 
104         _eventType = (sevType == SeverityType::nonError)
105                          ? static_cast<uint8_t>(EventType::miscInformational)
106                          : static_cast<uint8_t>(EventType::notApplicable);
107     }
108 
109     _reserved4Byte1 = 0;
110 
111     // No uses for problem domain or vector
112     _problemDomain = 0;
113     _problemVector = 0;
114 
115     // These will be cleaned up later in pel_rules::check()
116     _actionFlags = entry.actionFlags.value_or(0);
117 
118     _states = 0;
119 
120     _valid = true;
121 }
122 
123 UserHeader::UserHeader(Stream& pel)
124 {
125     try
126     {
127         unflatten(pel);
128         validate();
129     }
130     catch (const std::exception& e)
131     {
132         log<level::ERR>("Cannot unflatten user header",
133                         entry("ERROR=%s", e.what()));
134         _valid = false;
135     }
136 }
137 
138 void UserHeader::validate()
139 {
140     bool failed = false;
141     if (header().id != static_cast<uint16_t>(SectionID::userHeader))
142     {
143         log<level::ERR>("Invalid user header section ID",
144                         entry("ID=0x%X", header().id));
145         failed = true;
146     }
147 
148     if (header().version != userHeaderVersion)
149     {
150         log<level::ERR>("Invalid user header version",
151                         entry("VERSION=0x%X", header().version));
152         failed = true;
153     }
154 
155     _valid = (failed) ? false : true;
156 }
157 
158 std::optional<std::string> UserHeader::getJSON() const
159 {
160     std::string severity;
161     std::string subsystem;
162     std::string eventScope;
163     std::string eventType;
164     std::vector<std::string> actionFlags;
165     severity = pv::getValue(_eventSeverity, pel_values::severityValues);
166     subsystem = pv::getValue(_eventSubsystem, pel_values::subsystemValues);
167     eventScope = pv::getValue(_eventScope, pel_values::eventScopeValues);
168     eventType = pv::getValue(_eventType, pel_values::eventTypeValues);
169     actionFlags =
170         pv::getValuesBitwise(_actionFlags, pel_values::actionFlagsValues);
171 
172     std::string hostState{"Invalid"};
173     auto iter = pv::transmissionStates.find(
174         static_cast<TransmissionState>(hostTransmissionState()));
175     if (iter != pv::transmissionStates.end())
176     {
177         hostState = iter->second;
178     }
179 
180     std::string uh;
181     jsonInsert(uh, pv::sectionVer, getNumberString("%d", userHeaderVersion), 1);
182     jsonInsert(uh, pv::subSection, getNumberString("%d", _header.subType), 1);
183     jsonInsert(uh, "Log Committed by",
184                getNumberString("0x%X", _header.componentID), 1);
185     jsonInsert(uh, "Subsystem", subsystem, 1);
186     jsonInsert(uh, "Event Scope", eventScope, 1);
187     jsonInsert(uh, "Event Severity", severity, 1);
188     jsonInsert(uh, "Event Type", eventType, 1);
189     jsonInsertArray(uh, "Action Flags", actionFlags, 1);
190     jsonInsert(uh, "Host Transmission", hostState, 1);
191     uh.erase(uh.size() - 2);
192     return uh;
193 }
194 
195 std::optional<uint8_t> UserHeader::getSeverity(
196     const std::vector<message::RegistrySeverity>& severities,
197     const std::string& systemType) const
198 {
199     const uint8_t* s = nullptr;
200 
201     // Find the severity to use for this system type, or use the default
202     // entry (where no system type is specified).
203     for (const auto& sev : severities)
204     {
205         if (sev.system == systemType)
206         {
207             s = &sev.severity;
208             break;
209         }
210         else if (sev.system.empty())
211         {
212             s = &sev.severity;
213         }
214     }
215 
216     if (s)
217     {
218         return *s;
219     }
220 
221     return std::nullopt;
222 }
223 
224 } // namespace pels
225 } // namespace openpower
226