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,
506b3f345bSVijay Lobo                        const AdditionalData& additionalData,
51aadccc85SMatt Spinler                        const DataInterfaceBase& dataIface)
52fdb6a202SMatt Spinler {
53fdb6a202SMatt Spinler     _header.id = static_cast<uint16_t>(SectionID::userHeader);
54fdb6a202SMatt Spinler     _header.size = UserHeader::flattenedSize();
55fdb6a202SMatt Spinler     _header.version = userHeaderVersion;
56fdb6a202SMatt Spinler     _header.subType = 0;
57fdb6a202SMatt Spinler     _header.componentID = static_cast<uint16_t>(ComponentID::phosphorLogging);
58fdb6a202SMatt Spinler 
59fdb6a202SMatt Spinler     _eventSubsystem = entry.subsystem;
60fdb6a202SMatt Spinler 
61fdb6a202SMatt Spinler     _eventScope = entry.eventScope.value_or(
62fdb6a202SMatt Spinler         static_cast<uint8_t>(EventScope::entirePlatform));
63fdb6a202SMatt Spinler 
643b8ed7f2SSumit Kumar     {
653b8ed7f2SSumit Kumar         bool mfgSevStatus = false;
663b8ed7f2SSumit Kumar         bool mfgActionFlagStatus = false;
673b8ed7f2SSumit Kumar         std::optional<uint8_t> sev = std::nullopt;
683b8ed7f2SSumit Kumar         uint16_t val = 0;
693b8ed7f2SSumit Kumar 
703b8ed7f2SSumit Kumar         // Get the mfg severity & action flags
713b8ed7f2SSumit Kumar         if (entry.mfgSeverity || entry.mfgActionFlags)
723b8ed7f2SSumit Kumar         {
733b8ed7f2SSumit Kumar             if (entry.mfgSeverity)
743b8ed7f2SSumit Kumar             {
753b8ed7f2SSumit Kumar                 // Find the mf severity possibly dependent on the system type.
763b8ed7f2SSumit Kumar                 sev = getSeverity(entry.mfgSeverity.value(), dataIface);
773b8ed7f2SSumit Kumar             }
783b8ed7f2SSumit Kumar 
793b8ed7f2SSumit Kumar             if (entry.mfgActionFlags)
803b8ed7f2SSumit Kumar             {
813b8ed7f2SSumit Kumar                 // Find the mfg action flags
823b8ed7f2SSumit Kumar                 val = entry.mfgActionFlags.value();
833b8ed7f2SSumit Kumar             }
843b8ed7f2SSumit Kumar 
853b8ed7f2SSumit Kumar             if (sev || val)
863b8ed7f2SSumit Kumar             {
873b8ed7f2SSumit Kumar                 bool mfgProp = dataIface.getQuiesceOnError();
883b8ed7f2SSumit Kumar                 if (mfgProp)
893b8ed7f2SSumit Kumar                 {
903b8ed7f2SSumit Kumar                     if (sev)
913b8ed7f2SSumit Kumar                     {
923b8ed7f2SSumit Kumar                         _eventSeverity = *sev;
933b8ed7f2SSumit Kumar                         mfgSevStatus = true;
943b8ed7f2SSumit Kumar                     }
953b8ed7f2SSumit Kumar 
963b8ed7f2SSumit Kumar                     if (val)
973b8ed7f2SSumit Kumar                     {
983b8ed7f2SSumit Kumar                         _actionFlags = val;
993b8ed7f2SSumit Kumar                         mfgActionFlagStatus = true;
1003b8ed7f2SSumit Kumar                     }
1013b8ed7f2SSumit Kumar                 }
1023b8ed7f2SSumit Kumar             }
1033b8ed7f2SSumit Kumar         }
1043b8ed7f2SSumit Kumar 
1053b8ed7f2SSumit Kumar         if (!mfgSevStatus)
1063b8ed7f2SSumit Kumar         {
1073b8ed7f2SSumit Kumar             // Get the severity from the registry if it's there, otherwise get
1083b8ed7f2SSumit Kumar             // it from the OpenBMC event log severity value.
109aadccc85SMatt Spinler             if (!entry.severity)
110aadccc85SMatt Spinler             {
111aadccc85SMatt Spinler                 _eventSeverity = convertOBMCSeverityToPEL(severity);
112aadccc85SMatt Spinler             }
113aadccc85SMatt Spinler             else
114aadccc85SMatt Spinler             {
115aadccc85SMatt Spinler                 // Find the severity possibly dependent on the system type.
1161ab6696fSMatt Spinler                 auto sev = getSeverity(entry.severity.value(), dataIface);
117aadccc85SMatt Spinler                 if (sev)
118aadccc85SMatt Spinler                 {
119aadccc85SMatt Spinler                     _eventSeverity = *sev;
120aadccc85SMatt Spinler                 }
121aadccc85SMatt Spinler                 else
122aadccc85SMatt Spinler                 {
1231ab6696fSMatt Spinler                     // Either someone  screwed up the message registry
1241ab6696fSMatt Spinler                     // or getSystemNames failed.
1256ea4d5f7SMatt Spinler                     std::string types;
126aadccc85SMatt Spinler                     log<level::ERR>(
1271ab6696fSMatt Spinler                         "Failed finding the severity in the message registry",
1283b8ed7f2SSumit Kumar                         phosphor::logging::entry("ERROR=%s",
1293b8ed7f2SSumit Kumar                                                  entry.name.c_str()));
130aadccc85SMatt Spinler 
131aadccc85SMatt Spinler                     // Have to choose something, just use informational.
132aadccc85SMatt Spinler                     _eventSeverity = 0;
133aadccc85SMatt Spinler                 }
134aadccc85SMatt Spinler             }
1353b8ed7f2SSumit Kumar         }
136fdb6a202SMatt Spinler 
1376b3f345bSVijay Lobo         // Convert Critical error (0x50) to Critical Error-System Termination
1386b3f345bSVijay Lobo         // (0x51), if the AdditionalData is set to SYSTEM_TERM
1396b3f345bSVijay Lobo         auto sevLevel = additionalData.getValue("SEVERITY_DETAIL");
1406b3f345bSVijay Lobo         if ((_eventSeverity & 0xF0) == 0x50)
1416b3f345bSVijay Lobo         {
1426b3f345bSVijay Lobo             if (sevLevel.value_or("") == "SYSTEM_TERM")
1436b3f345bSVijay Lobo             {
1446b3f345bSVijay Lobo                 // Change to Critical Error, System Termination
1456b3f345bSVijay Lobo                 _eventSeverity = 0x51;
1466b3f345bSVijay Lobo             }
1476b3f345bSVijay Lobo         }
1486b3f345bSVijay Lobo 
149f1e85e20SMatt Spinler         if (entry.eventType)
150f1e85e20SMatt Spinler         {
151f1e85e20SMatt Spinler             _eventType = *entry.eventType;
152f1e85e20SMatt Spinler         }
153f1e85e20SMatt Spinler         else
154f1e85e20SMatt Spinler         {
155f1e85e20SMatt Spinler             // There are different default event types for info errors
156f1e85e20SMatt Spinler             // vs non info ones.
157f1e85e20SMatt Spinler             auto sevType = static_cast<SeverityType>(_eventSeverity & 0xF0);
1583b8ed7f2SSumit Kumar             _eventType =
1593b8ed7f2SSumit Kumar                 (sevType == SeverityType::nonError)
160f1e85e20SMatt Spinler                     ? static_cast<uint8_t>(EventType::miscInformational)
161f1e85e20SMatt Spinler                     : static_cast<uint8_t>(EventType::notApplicable);
162f1e85e20SMatt Spinler         }
163fdb6a202SMatt Spinler 
164fdb6a202SMatt Spinler         _reserved4Byte1 = 0;
165fdb6a202SMatt Spinler 
166fdb6a202SMatt Spinler         // No uses for problem domain or vector
167fdb6a202SMatt Spinler         _problemDomain = 0;
168fdb6a202SMatt Spinler         _problemVector = 0;
169fdb6a202SMatt Spinler 
1701f93c590SMatt Spinler         // These will be set in pel_rules::check() if they're still
1711f93c590SMatt Spinler         // at the default value.
1723b8ed7f2SSumit Kumar         if (!mfgActionFlagStatus)
1733b8ed7f2SSumit Kumar         {
1741f93c590SMatt Spinler             _actionFlags = entry.actionFlags.value_or(actionFlagsDefault);
1753b8ed7f2SSumit Kumar         }
176fdb6a202SMatt Spinler 
177eb111447SMatt Spinler         _states = 0;
178fdb6a202SMatt Spinler 
179fdb6a202SMatt Spinler         _valid = true;
180fdb6a202SMatt Spinler     }
1813b8ed7f2SSumit Kumar }
182fdb6a202SMatt Spinler 
18303c1d915SMatt Spinler UserHeader::UserHeader(Stream& pel)
18403c1d915SMatt Spinler {
18503c1d915SMatt Spinler     try
18603c1d915SMatt Spinler     {
187cf5a8d0fSMatt Spinler         unflatten(pel);
18803c1d915SMatt Spinler         validate();
18903c1d915SMatt Spinler     }
19003c1d915SMatt Spinler     catch (const std::exception& e)
19103c1d915SMatt Spinler     {
19203c1d915SMatt Spinler         log<level::ERR>("Cannot unflatten user header",
19303c1d915SMatt Spinler                         entry("ERROR=%s", e.what()));
19403c1d915SMatt Spinler         _valid = false;
19503c1d915SMatt Spinler     }
19603c1d915SMatt Spinler }
19703c1d915SMatt Spinler 
19803c1d915SMatt Spinler void UserHeader::validate()
19903c1d915SMatt Spinler {
20003c1d915SMatt Spinler     bool failed = false;
2011a94cc38SMatt Spinler     if (header().id != static_cast<uint16_t>(SectionID::userHeader))
20203c1d915SMatt Spinler     {
20303c1d915SMatt Spinler         log<level::ERR>("Invalid user header section ID",
20403c1d915SMatt Spinler                         entry("ID=0x%X", header().id));
20503c1d915SMatt Spinler         failed = true;
20603c1d915SMatt Spinler     }
20703c1d915SMatt Spinler 
20803c1d915SMatt Spinler     if (header().version != userHeaderVersion)
20903c1d915SMatt Spinler     {
21003c1d915SMatt Spinler         log<level::ERR>("Invalid user header version",
21103c1d915SMatt Spinler                         entry("VERSION=0x%X", header().version));
21203c1d915SMatt Spinler         failed = true;
21303c1d915SMatt Spinler     }
21403c1d915SMatt Spinler 
21503c1d915SMatt Spinler     _valid = (failed) ? false : true;
21603c1d915SMatt Spinler }
21703c1d915SMatt Spinler 
218ad0e0476SAatir Manzur std::optional<std::string> UserHeader::getJSON() const
219ad0e0476SAatir Manzur {
220ad0e0476SAatir Manzur     std::string severity;
221ad0e0476SAatir Manzur     std::string subsystem;
222ad0e0476SAatir Manzur     std::string eventScope;
223ad0e0476SAatir Manzur     std::string eventType;
224600d15afSHarisuddin Mohamed Isa     std::vector<std::string> actionFlags;
225c1489351SAatir     severity = pv::getValue(_eventSeverity, pel_values::severityValues);
226c1489351SAatir     subsystem = pv::getValue(_eventSubsystem, pel_values::subsystemValues);
227c1489351SAatir     eventScope = pv::getValue(_eventScope, pel_values::eventScopeValues);
228c1489351SAatir     eventType = pv::getValue(_eventType, pel_values::eventTypeValues);
229600d15afSHarisuddin Mohamed Isa     actionFlags =
230600d15afSHarisuddin Mohamed Isa         pv::getValuesBitwise(_actionFlags, pel_values::actionFlagsValues);
231455587e5SMatt Spinler 
232455587e5SMatt Spinler     std::string hostState{"Invalid"};
233*2fb10211SVijay Lobo     std::string hmcState{"Invalid"};
234455587e5SMatt Spinler     auto iter = pv::transmissionStates.find(
235455587e5SMatt Spinler         static_cast<TransmissionState>(hostTransmissionState()));
236455587e5SMatt Spinler     if (iter != pv::transmissionStates.end())
237455587e5SMatt Spinler     {
238455587e5SMatt Spinler         hostState = iter->second;
239455587e5SMatt Spinler     }
240*2fb10211SVijay Lobo     auto iter1 = pv::transmissionStates.find(
241*2fb10211SVijay Lobo         static_cast<TransmissionState>(hmcTransmissionState()));
242*2fb10211SVijay Lobo     if (iter1 != pv::transmissionStates.end())
243*2fb10211SVijay Lobo     {
244*2fb10211SVijay Lobo         hmcState = iter1->second;
245*2fb10211SVijay Lobo     }
246455587e5SMatt Spinler 
247600d15afSHarisuddin Mohamed Isa     std::string uh;
248bebeb948SHarisuddin Mohamed Isa     jsonInsert(uh, pv::sectionVer, getNumberString("%d", userHeaderVersion), 1);
249bebeb948SHarisuddin Mohamed Isa     jsonInsert(uh, pv::subSection, getNumberString("%d", _header.subType), 1);
250bebeb948SHarisuddin Mohamed Isa     jsonInsert(uh, "Log Committed by",
251bebeb948SHarisuddin Mohamed Isa                getNumberString("0x%X", _header.componentID), 1);
252600d15afSHarisuddin Mohamed Isa     jsonInsert(uh, "Subsystem", subsystem, 1);
253600d15afSHarisuddin Mohamed Isa     jsonInsert(uh, "Event Scope", eventScope, 1);
254600d15afSHarisuddin Mohamed Isa     jsonInsert(uh, "Event Severity", severity, 1);
255600d15afSHarisuddin Mohamed Isa     jsonInsert(uh, "Event Type", eventType, 1);
256600d15afSHarisuddin Mohamed Isa     jsonInsertArray(uh, "Action Flags", actionFlags, 1);
257455587e5SMatt Spinler     jsonInsert(uh, "Host Transmission", hostState, 1);
258*2fb10211SVijay Lobo     jsonInsert(uh, "HMC Transmission", hmcState, 1);
259600d15afSHarisuddin Mohamed Isa     uh.erase(uh.size() - 2);
260ad0e0476SAatir Manzur     return uh;
261ad0e0476SAatir Manzur }
262aadccc85SMatt Spinler 
263aadccc85SMatt Spinler std::optional<uint8_t> UserHeader::getSeverity(
264aadccc85SMatt Spinler     const std::vector<message::RegistrySeverity>& severities,
2651ab6696fSMatt Spinler     const DataInterfaceBase& dataIface) const
266aadccc85SMatt Spinler {
267aadccc85SMatt Spinler     const uint8_t* s = nullptr;
2681ab6696fSMatt Spinler     std::vector<std::string> systemNames;
2691ab6696fSMatt Spinler 
2701ab6696fSMatt Spinler     // getSystemNames makes D-Bus calls, so only call it if we
2711ab6696fSMatt Spinler     // know we'll need it because there is a system name in the sev list
2721ab6696fSMatt Spinler     if (std::any_of(severities.begin(), severities.end(),
2731ab6696fSMatt Spinler                     [](const auto& sev) { return !sev.system.empty(); }))
2741ab6696fSMatt Spinler     {
2751ab6696fSMatt Spinler         try
2761ab6696fSMatt Spinler         {
2771ab6696fSMatt Spinler             systemNames = dataIface.getSystemNames();
2781ab6696fSMatt Spinler         }
2791ab6696fSMatt Spinler         catch (const std::exception& e)
2801ab6696fSMatt Spinler         {
2811ab6696fSMatt Spinler             log<level::ERR>("Failed trying to look up system names on D-Bus",
2821ab6696fSMatt Spinler                             entry("ERROR=%s", e.what()));
2831ab6696fSMatt Spinler             return std::nullopt;
2841ab6696fSMatt Spinler         }
2851ab6696fSMatt Spinler     }
286aadccc85SMatt Spinler 
287aadccc85SMatt Spinler     // Find the severity to use for this system type, or use the default
288aadccc85SMatt Spinler     // entry (where no system type is specified).
289aadccc85SMatt Spinler     for (const auto& sev : severities)
290aadccc85SMatt Spinler     {
2916ea4d5f7SMatt Spinler         if (std::find(systemNames.begin(), systemNames.end(), sev.system) !=
2926ea4d5f7SMatt Spinler             systemNames.end())
293aadccc85SMatt Spinler         {
294aadccc85SMatt Spinler             s = &sev.severity;
295aadccc85SMatt Spinler             break;
296aadccc85SMatt Spinler         }
297aadccc85SMatt Spinler         else if (sev.system.empty())
298aadccc85SMatt Spinler         {
299aadccc85SMatt Spinler             s = &sev.severity;
300aadccc85SMatt Spinler         }
301aadccc85SMatt Spinler     }
302aadccc85SMatt Spinler 
303aadccc85SMatt Spinler     if (s)
304aadccc85SMatt Spinler     {
305aadccc85SMatt Spinler         return *s;
306aadccc85SMatt Spinler     }
307aadccc85SMatt Spinler 
308aadccc85SMatt Spinler     return std::nullopt;
309aadccc85SMatt Spinler }
310aadccc85SMatt Spinler 
31103c1d915SMatt Spinler } // namespace pels
31203c1d915SMatt Spinler } // namespace openpower
313