1711d51d8SMatt Spinler /**
2711d51d8SMatt Spinler  * Copyright © 2019 IBM Corporation
3711d51d8SMatt Spinler  *
4711d51d8SMatt Spinler  * Licensed under the Apache License, Version 2.0 (the "License");
5711d51d8SMatt Spinler  * you may not use this file except in compliance with the License.
6711d51d8SMatt Spinler  * You may obtain a copy of the License at
7711d51d8SMatt Spinler  *
8711d51d8SMatt Spinler  *     http://www.apache.org/licenses/LICENSE-2.0
9711d51d8SMatt Spinler  *
10711d51d8SMatt Spinler  * Unless required by applicable law or agreed to in writing, software
11711d51d8SMatt Spinler  * distributed under the License is distributed on an "AS IS" BASIS,
12711d51d8SMatt Spinler  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13711d51d8SMatt Spinler  * See the License for the specific language governing permissions and
14711d51d8SMatt Spinler  * limitations under the License.
15711d51d8SMatt Spinler  */
1603c1d915SMatt Spinler #include "user_header.hpp"
1703c1d915SMatt Spinler 
18600d15afSHarisuddin Mohamed Isa #include "json_utils.hpp"
191a94cc38SMatt Spinler #include "pel_types.hpp"
20c1489351SAatir #include "pel_values.hpp"
21fdb6a202SMatt Spinler #include "severity.hpp"
221a94cc38SMatt Spinler 
23ad0e0476SAatir Manzur #include <iostream>
2403c1d915SMatt Spinler #include <phosphor-logging/log.hpp>
2503c1d915SMatt Spinler 
2603c1d915SMatt Spinler namespace openpower
2703c1d915SMatt Spinler {
2803c1d915SMatt Spinler namespace pels
2903c1d915SMatt Spinler {
3003c1d915SMatt Spinler 
31c1489351SAatir namespace pv = openpower::pels::pel_values;
3203c1d915SMatt Spinler using namespace phosphor::logging;
3303c1d915SMatt Spinler 
34cf5a8d0fSMatt Spinler void UserHeader::unflatten(Stream& stream)
3503c1d915SMatt Spinler {
36cf5a8d0fSMatt Spinler     stream >> _header >> _eventSubsystem >> _eventScope >> _eventSeverity >>
37cf5a8d0fSMatt Spinler         _eventType >> _reserved4Byte1 >> _problemDomain >> _problemVector >>
38eb111447SMatt Spinler         _actionFlags >> _states;
3903c1d915SMatt Spinler }
4003c1d915SMatt Spinler 
410688545bSMatt Spinler void UserHeader::flatten(Stream& stream) const
4203c1d915SMatt Spinler {
43cf5a8d0fSMatt Spinler     stream << _header << _eventSubsystem << _eventScope << _eventSeverity
44cf5a8d0fSMatt Spinler            << _eventType << _reserved4Byte1 << _problemDomain << _problemVector
45eb111447SMatt Spinler            << _actionFlags << _states;
4603c1d915SMatt Spinler }
4703c1d915SMatt Spinler 
48fdb6a202SMatt Spinler UserHeader::UserHeader(const message::Entry& entry,
49aadccc85SMatt Spinler                        phosphor::logging::Entry::Level severity,
50aadccc85SMatt Spinler                        const DataInterfaceBase& dataIface)
51fdb6a202SMatt Spinler {
52fdb6a202SMatt Spinler     _header.id = static_cast<uint16_t>(SectionID::userHeader);
53fdb6a202SMatt Spinler     _header.size = UserHeader::flattenedSize();
54fdb6a202SMatt Spinler     _header.version = userHeaderVersion;
55fdb6a202SMatt Spinler     _header.subType = 0;
56fdb6a202SMatt Spinler     _header.componentID = static_cast<uint16_t>(ComponentID::phosphorLogging);
57fdb6a202SMatt Spinler 
58fdb6a202SMatt Spinler     _eventSubsystem = entry.subsystem;
59fdb6a202SMatt Spinler 
60fdb6a202SMatt Spinler     _eventScope = entry.eventScope.value_or(
61fdb6a202SMatt Spinler         static_cast<uint8_t>(EventScope::entirePlatform));
62fdb6a202SMatt Spinler 
63fdb6a202SMatt Spinler     // Get the severity from the registry if it's there, otherwise get it
64fdb6a202SMatt Spinler     // from the OpenBMC event log severity value.
65aadccc85SMatt Spinler     if (!entry.severity)
66aadccc85SMatt Spinler     {
67aadccc85SMatt Spinler         _eventSeverity = convertOBMCSeverityToPEL(severity);
68aadccc85SMatt Spinler     }
69aadccc85SMatt Spinler     else
70aadccc85SMatt Spinler     {
71aadccc85SMatt Spinler         // Find the severity possibly dependent on the system type.
72aadccc85SMatt Spinler         auto sev =
73*6ea4d5f7SMatt Spinler             getSeverity(entry.severity.value(), dataIface.getSystemNames());
74aadccc85SMatt Spinler         if (sev)
75aadccc85SMatt Spinler         {
76aadccc85SMatt Spinler             _eventSeverity = *sev;
77aadccc85SMatt Spinler         }
78aadccc85SMatt Spinler         else
79aadccc85SMatt Spinler         {
80aadccc85SMatt Spinler             // Someone screwed up the message registry.
81*6ea4d5f7SMatt Spinler             std::string types;
82*6ea4d5f7SMatt Spinler             const auto& compatibles = dataIface.getSystemNames();
83*6ea4d5f7SMatt Spinler             std::for_each(compatibles.begin(), compatibles.end(),
84*6ea4d5f7SMatt Spinler                           [&types](const auto& t) { types += t + '|'; });
85*6ea4d5f7SMatt Spinler 
86aadccc85SMatt Spinler             log<level::ERR>(
87*6ea4d5f7SMatt Spinler                 "No severity entry found for this error and system name",
88aadccc85SMatt Spinler                 phosphor::logging::entry("ERROR=%s", entry.name.c_str()),
89*6ea4d5f7SMatt Spinler                 phosphor::logging::entry("SYSTEMNAMES=%s", types.c_str()));
90aadccc85SMatt Spinler 
91aadccc85SMatt Spinler             // Have to choose something, just use informational.
92aadccc85SMatt Spinler             _eventSeverity = 0;
93aadccc85SMatt Spinler         }
94aadccc85SMatt Spinler     }
95fdb6a202SMatt Spinler 
96fdb6a202SMatt Spinler     // TODO: ibm-dev/dev/#1144 Handle manufacturing sev & action flags
97fdb6a202SMatt Spinler 
98f1e85e20SMatt Spinler     if (entry.eventType)
99f1e85e20SMatt Spinler     {
100f1e85e20SMatt Spinler         _eventType = *entry.eventType;
101f1e85e20SMatt Spinler     }
102f1e85e20SMatt Spinler     else
103f1e85e20SMatt Spinler     {
104f1e85e20SMatt Spinler         // There are different default event types for info errors
105f1e85e20SMatt Spinler         // vs non info ones.
106f1e85e20SMatt Spinler         auto sevType = static_cast<SeverityType>(_eventSeverity & 0xF0);
107f1e85e20SMatt Spinler 
108f1e85e20SMatt Spinler         _eventType = (sevType == SeverityType::nonError)
109f1e85e20SMatt Spinler                          ? static_cast<uint8_t>(EventType::miscInformational)
110f1e85e20SMatt Spinler                          : static_cast<uint8_t>(EventType::notApplicable);
111f1e85e20SMatt Spinler     }
112fdb6a202SMatt Spinler 
113fdb6a202SMatt Spinler     _reserved4Byte1 = 0;
114fdb6a202SMatt Spinler 
115fdb6a202SMatt Spinler     // No uses for problem domain or vector
116fdb6a202SMatt Spinler     _problemDomain = 0;
117fdb6a202SMatt Spinler     _problemVector = 0;
118fdb6a202SMatt Spinler 
119f1e85e20SMatt Spinler     // These will be cleaned up later in pel_rules::check()
120e07f915bSMatt Spinler     _actionFlags = entry.actionFlags.value_or(0);
121fdb6a202SMatt Spinler 
122eb111447SMatt Spinler     _states = 0;
123fdb6a202SMatt Spinler 
124fdb6a202SMatt Spinler     _valid = true;
125fdb6a202SMatt Spinler }
126fdb6a202SMatt Spinler 
12703c1d915SMatt Spinler UserHeader::UserHeader(Stream& pel)
12803c1d915SMatt Spinler {
12903c1d915SMatt Spinler     try
13003c1d915SMatt Spinler     {
131cf5a8d0fSMatt Spinler         unflatten(pel);
13203c1d915SMatt Spinler         validate();
13303c1d915SMatt Spinler     }
13403c1d915SMatt Spinler     catch (const std::exception& e)
13503c1d915SMatt Spinler     {
13603c1d915SMatt Spinler         log<level::ERR>("Cannot unflatten user header",
13703c1d915SMatt Spinler                         entry("ERROR=%s", e.what()));
13803c1d915SMatt Spinler         _valid = false;
13903c1d915SMatt Spinler     }
14003c1d915SMatt Spinler }
14103c1d915SMatt Spinler 
14203c1d915SMatt Spinler void UserHeader::validate()
14303c1d915SMatt Spinler {
14403c1d915SMatt Spinler     bool failed = false;
1451a94cc38SMatt Spinler     if (header().id != static_cast<uint16_t>(SectionID::userHeader))
14603c1d915SMatt Spinler     {
14703c1d915SMatt Spinler         log<level::ERR>("Invalid user header section ID",
14803c1d915SMatt Spinler                         entry("ID=0x%X", header().id));
14903c1d915SMatt Spinler         failed = true;
15003c1d915SMatt Spinler     }
15103c1d915SMatt Spinler 
15203c1d915SMatt Spinler     if (header().version != userHeaderVersion)
15303c1d915SMatt Spinler     {
15403c1d915SMatt Spinler         log<level::ERR>("Invalid user header version",
15503c1d915SMatt Spinler                         entry("VERSION=0x%X", header().version));
15603c1d915SMatt Spinler         failed = true;
15703c1d915SMatt Spinler     }
15803c1d915SMatt Spinler 
15903c1d915SMatt Spinler     _valid = (failed) ? false : true;
16003c1d915SMatt Spinler }
16103c1d915SMatt Spinler 
162ad0e0476SAatir Manzur std::optional<std::string> UserHeader::getJSON() const
163ad0e0476SAatir Manzur {
164ad0e0476SAatir Manzur     std::string severity;
165ad0e0476SAatir Manzur     std::string subsystem;
166ad0e0476SAatir Manzur     std::string eventScope;
167ad0e0476SAatir Manzur     std::string eventType;
168600d15afSHarisuddin Mohamed Isa     std::vector<std::string> actionFlags;
169c1489351SAatir     severity = pv::getValue(_eventSeverity, pel_values::severityValues);
170c1489351SAatir     subsystem = pv::getValue(_eventSubsystem, pel_values::subsystemValues);
171c1489351SAatir     eventScope = pv::getValue(_eventScope, pel_values::eventScopeValues);
172c1489351SAatir     eventType = pv::getValue(_eventType, pel_values::eventTypeValues);
173600d15afSHarisuddin Mohamed Isa     actionFlags =
174600d15afSHarisuddin Mohamed Isa         pv::getValuesBitwise(_actionFlags, pel_values::actionFlagsValues);
175455587e5SMatt Spinler 
176455587e5SMatt Spinler     std::string hostState{"Invalid"};
177455587e5SMatt Spinler     auto iter = pv::transmissionStates.find(
178455587e5SMatt Spinler         static_cast<TransmissionState>(hostTransmissionState()));
179455587e5SMatt Spinler     if (iter != pv::transmissionStates.end())
180455587e5SMatt Spinler     {
181455587e5SMatt Spinler         hostState = iter->second;
182455587e5SMatt Spinler     }
183455587e5SMatt Spinler 
184600d15afSHarisuddin Mohamed Isa     std::string uh;
185bebeb948SHarisuddin Mohamed Isa     jsonInsert(uh, pv::sectionVer, getNumberString("%d", userHeaderVersion), 1);
186bebeb948SHarisuddin Mohamed Isa     jsonInsert(uh, pv::subSection, getNumberString("%d", _header.subType), 1);
187bebeb948SHarisuddin Mohamed Isa     jsonInsert(uh, "Log Committed by",
188bebeb948SHarisuddin Mohamed Isa                getNumberString("0x%X", _header.componentID), 1);
189600d15afSHarisuddin Mohamed Isa     jsonInsert(uh, "Subsystem", subsystem, 1);
190600d15afSHarisuddin Mohamed Isa     jsonInsert(uh, "Event Scope", eventScope, 1);
191600d15afSHarisuddin Mohamed Isa     jsonInsert(uh, "Event Severity", severity, 1);
192600d15afSHarisuddin Mohamed Isa     jsonInsert(uh, "Event Type", eventType, 1);
193600d15afSHarisuddin Mohamed Isa     jsonInsertArray(uh, "Action Flags", actionFlags, 1);
194455587e5SMatt Spinler     jsonInsert(uh, "Host Transmission", hostState, 1);
195600d15afSHarisuddin Mohamed Isa     uh.erase(uh.size() - 2);
196ad0e0476SAatir Manzur     return uh;
197ad0e0476SAatir Manzur }
198aadccc85SMatt Spinler 
199aadccc85SMatt Spinler std::optional<uint8_t> UserHeader::getSeverity(
200aadccc85SMatt Spinler     const std::vector<message::RegistrySeverity>& severities,
201*6ea4d5f7SMatt Spinler     const std::vector<std::string>& systemNames) const
202aadccc85SMatt Spinler {
203aadccc85SMatt Spinler     const uint8_t* s = nullptr;
204aadccc85SMatt Spinler 
205aadccc85SMatt Spinler     // Find the severity to use for this system type, or use the default
206aadccc85SMatt Spinler     // entry (where no system type is specified).
207aadccc85SMatt Spinler     for (const auto& sev : severities)
208aadccc85SMatt Spinler     {
209*6ea4d5f7SMatt Spinler         if (std::find(systemNames.begin(), systemNames.end(), sev.system) !=
210*6ea4d5f7SMatt Spinler             systemNames.end())
211aadccc85SMatt Spinler         {
212aadccc85SMatt Spinler             s = &sev.severity;
213aadccc85SMatt Spinler             break;
214aadccc85SMatt Spinler         }
215aadccc85SMatt Spinler         else if (sev.system.empty())
216aadccc85SMatt Spinler         {
217aadccc85SMatt Spinler             s = &sev.severity;
218aadccc85SMatt Spinler         }
219aadccc85SMatt Spinler     }
220aadccc85SMatt Spinler 
221aadccc85SMatt Spinler     if (s)
222aadccc85SMatt Spinler     {
223aadccc85SMatt Spinler         return *s;
224aadccc85SMatt Spinler     }
225aadccc85SMatt Spinler 
226aadccc85SMatt Spinler     return std::nullopt;
227aadccc85SMatt Spinler }
228aadccc85SMatt Spinler 
22903c1d915SMatt Spinler } // namespace pels
23003c1d915SMatt Spinler } // namespace openpower
231