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 
23*5bc26533SArya K Padman #include <phosphor-logging/lg2.hpp>
2403c1d915SMatt Spinler 
251aa90d49SJayanth Othayoth #include <format>
262544b419SPatrick Williams #include <iostream>
272544b419SPatrick Williams 
2803c1d915SMatt Spinler namespace openpower
2903c1d915SMatt Spinler {
3003c1d915SMatt Spinler namespace pels
3103c1d915SMatt Spinler {
3203c1d915SMatt Spinler 
33c1489351SAatir namespace pv = openpower::pels::pel_values;
3403c1d915SMatt Spinler 
unflatten(Stream & stream)35cf5a8d0fSMatt Spinler void UserHeader::unflatten(Stream& stream)
3603c1d915SMatt Spinler {
37cf5a8d0fSMatt Spinler     stream >> _header >> _eventSubsystem >> _eventScope >> _eventSeverity >>
38cf5a8d0fSMatt Spinler         _eventType >> _reserved4Byte1 >> _problemDomain >> _problemVector >>
39eb111447SMatt Spinler         _actionFlags >> _states;
4003c1d915SMatt Spinler }
4103c1d915SMatt Spinler 
flatten(Stream & stream) const420688545bSMatt Spinler void UserHeader::flatten(Stream& stream) const
4303c1d915SMatt Spinler {
44cf5a8d0fSMatt Spinler     stream << _header << _eventSubsystem << _eventScope << _eventSeverity
45cf5a8d0fSMatt Spinler            << _eventType << _reserved4Byte1 << _problemDomain << _problemVector
46eb111447SMatt Spinler            << _actionFlags << _states;
4703c1d915SMatt Spinler }
4803c1d915SMatt Spinler 
UserHeader(const message::Entry & entry,phosphor::logging::Entry::Level severity,const AdditionalData & additionalData,const DataInterfaceBase & dataIface)49fdb6a202SMatt Spinler UserHeader::UserHeader(const message::Entry& entry,
50aadccc85SMatt Spinler                        phosphor::logging::Entry::Level severity,
516b3f345bSVijay Lobo                        const AdditionalData& additionalData,
52aadccc85SMatt Spinler                        const DataInterfaceBase& dataIface)
53fdb6a202SMatt Spinler {
54fdb6a202SMatt Spinler     _header.id = static_cast<uint16_t>(SectionID::userHeader);
55fdb6a202SMatt Spinler     _header.size = UserHeader::flattenedSize();
56fdb6a202SMatt Spinler     _header.version = userHeaderVersion;
57fdb6a202SMatt Spinler     _header.subType = 0;
58fdb6a202SMatt Spinler     _header.componentID = static_cast<uint16_t>(ComponentID::phosphorLogging);
59fdb6a202SMatt Spinler 
6023970b0dSMatt Spinler     std::optional<uint8_t> subsys;
61fdb6a202SMatt Spinler 
6250bfa69aSSumit Kumar     // Check for additional data - PEL_SUBSYSTEM
6350bfa69aSSumit Kumar     auto ss = additionalData.getValue("PEL_SUBSYSTEM");
6450bfa69aSSumit Kumar     if (ss)
6550bfa69aSSumit Kumar     {
6650bfa69aSSumit Kumar         auto eventSubsystem = std::stoul(*ss, NULL, 16);
672544b419SPatrick Williams         std::string subsystemString = pv::getValue(eventSubsystem,
682544b419SPatrick Williams                                                    pel_values::subsystemValues);
6923970b0dSMatt Spinler         if (subsystemString == "invalid")
7050bfa69aSSumit Kumar         {
71*5bc26533SArya K Padman             lg2::warning(
72*5bc26533SArya K Padman                 "UH: Invalid SubSystem value in PEL_SUBSYSTEM: {PEL_SUBSYSTEM}",
73*5bc26533SArya K Padman                 "PEL_SUBSYSTEM", lg2::hex, eventSubsystem);
7450bfa69aSSumit Kumar         }
7550bfa69aSSumit Kumar         else
7650bfa69aSSumit Kumar         {
7723970b0dSMatt Spinler             subsys = eventSubsystem;
7850bfa69aSSumit Kumar         }
7950bfa69aSSumit Kumar     }
8023970b0dSMatt Spinler     else
8123970b0dSMatt Spinler     {
8223970b0dSMatt Spinler         subsys = entry.subsystem;
8323970b0dSMatt Spinler     }
8423970b0dSMatt Spinler 
8523970b0dSMatt Spinler     if (subsys)
8623970b0dSMatt Spinler     {
8723970b0dSMatt Spinler         _eventSubsystem = *subsys;
8823970b0dSMatt Spinler     }
8923970b0dSMatt Spinler     else
9023970b0dSMatt Spinler     {
9123970b0dSMatt Spinler         // Gotta use something, how about 'others'.
92*5bc26533SArya K Padman         lg2::warning(
9323970b0dSMatt Spinler             "No PEL subystem value supplied for error, using 'others'");
9423970b0dSMatt Spinler         _eventSubsystem = 0x70;
9523970b0dSMatt Spinler     }
9650bfa69aSSumit Kumar 
97fdb6a202SMatt Spinler     _eventScope = entry.eventScope.value_or(
98fdb6a202SMatt Spinler         static_cast<uint8_t>(EventScope::entirePlatform));
99fdb6a202SMatt Spinler 
1003b8ed7f2SSumit Kumar     {
1013b8ed7f2SSumit Kumar         bool mfgSevStatus = false;
1023b8ed7f2SSumit Kumar         bool mfgActionFlagStatus = false;
1033b8ed7f2SSumit Kumar 
1043b8ed7f2SSumit Kumar         // Get the mfg severity & action flags
1053b8ed7f2SSumit Kumar         if (entry.mfgSeverity || entry.mfgActionFlags)
1063b8ed7f2SSumit Kumar         {
107be952d2eSMatt Spinler             std::optional<uint8_t> sev = std::nullopt;
108be952d2eSMatt Spinler             uint16_t val = 0;
109be952d2eSMatt Spinler 
1103b8ed7f2SSumit Kumar             if (entry.mfgSeverity)
1113b8ed7f2SSumit Kumar             {
1123b8ed7f2SSumit Kumar                 // Find the mf severity possibly dependent on the system type.
1133b8ed7f2SSumit Kumar                 sev = getSeverity(entry.mfgSeverity.value(), dataIface);
1143b8ed7f2SSumit Kumar             }
1153b8ed7f2SSumit Kumar 
1163b8ed7f2SSumit Kumar             if (entry.mfgActionFlags)
1173b8ed7f2SSumit Kumar             {
1183b8ed7f2SSumit Kumar                 // Find the mfg action flags
1193b8ed7f2SSumit Kumar                 val = entry.mfgActionFlags.value();
1203b8ed7f2SSumit Kumar             }
1213b8ed7f2SSumit Kumar 
1223b8ed7f2SSumit Kumar             if (sev || val)
1233b8ed7f2SSumit Kumar             {
1243b8ed7f2SSumit Kumar                 bool mfgProp = dataIface.getQuiesceOnError();
1253b8ed7f2SSumit Kumar                 if (mfgProp)
1263b8ed7f2SSumit Kumar                 {
1273b8ed7f2SSumit Kumar                     if (sev)
1283b8ed7f2SSumit Kumar                     {
1293b8ed7f2SSumit Kumar                         _eventSeverity = *sev;
1303b8ed7f2SSumit Kumar                         mfgSevStatus = true;
1313b8ed7f2SSumit Kumar                     }
1323b8ed7f2SSumit Kumar 
1333b8ed7f2SSumit Kumar                     if (val)
1343b8ed7f2SSumit Kumar                     {
1353b8ed7f2SSumit Kumar                         _actionFlags = val;
1363b8ed7f2SSumit Kumar                         mfgActionFlagStatus = true;
1373b8ed7f2SSumit Kumar                     }
1383b8ed7f2SSumit Kumar                 }
1393b8ed7f2SSumit Kumar             }
1403b8ed7f2SSumit Kumar         }
1413b8ed7f2SSumit Kumar 
1423b8ed7f2SSumit Kumar         if (!mfgSevStatus)
1433b8ed7f2SSumit Kumar         {
1443b8ed7f2SSumit Kumar             // Get the severity from the registry if it's there, otherwise get
1453b8ed7f2SSumit Kumar             // it from the OpenBMC event log severity value.
146aadccc85SMatt Spinler             if (!entry.severity)
147aadccc85SMatt Spinler             {
148aadccc85SMatt Spinler                 _eventSeverity = convertOBMCSeverityToPEL(severity);
149aadccc85SMatt Spinler             }
150aadccc85SMatt Spinler             else
151aadccc85SMatt Spinler             {
152aadccc85SMatt Spinler                 // Find the severity possibly dependent on the system type.
1531ab6696fSMatt Spinler                 auto sev = getSeverity(entry.severity.value(), dataIface);
154aadccc85SMatt Spinler                 if (sev)
155aadccc85SMatt Spinler                 {
156aadccc85SMatt Spinler                     _eventSeverity = *sev;
157aadccc85SMatt Spinler                 }
158aadccc85SMatt Spinler                 else
159aadccc85SMatt Spinler                 {
1601ab6696fSMatt Spinler                     // Either someone  screwed up the message registry
1611ab6696fSMatt Spinler                     // or getSystemNames failed.
162*5bc26533SArya K Padman                     lg2::error(
163*5bc26533SArya K Padman                         "Failed finding the severity in the message registry ERROR={ERROR}",
164*5bc26533SArya K Padman                         "ERROR", entry.name);
165aadccc85SMatt Spinler 
166aadccc85SMatt Spinler                     // Have to choose something, just use informational.
167aadccc85SMatt Spinler                     _eventSeverity = 0;
168aadccc85SMatt Spinler                 }
169aadccc85SMatt Spinler             }
1703b8ed7f2SSumit Kumar         }
171fdb6a202SMatt Spinler 
1726b3f345bSVijay Lobo         // Convert Critical error (0x50) to Critical Error-System Termination
1736b3f345bSVijay Lobo         // (0x51), if the AdditionalData is set to SYSTEM_TERM
1746b3f345bSVijay Lobo         auto sevLevel = additionalData.getValue("SEVERITY_DETAIL");
1756b3f345bSVijay Lobo         if ((_eventSeverity & 0xF0) == 0x50)
1766b3f345bSVijay Lobo         {
1776b3f345bSVijay Lobo             if (sevLevel.value_or("") == "SYSTEM_TERM")
1786b3f345bSVijay Lobo             {
1796b3f345bSVijay Lobo                 // Change to Critical Error, System Termination
1806b3f345bSVijay Lobo                 _eventSeverity = 0x51;
1816b3f345bSVijay Lobo             }
1826b3f345bSVijay Lobo         }
1836b3f345bSVijay Lobo 
184f1e85e20SMatt Spinler         if (entry.eventType)
185f1e85e20SMatt Spinler         {
186f1e85e20SMatt Spinler             _eventType = *entry.eventType;
187f1e85e20SMatt Spinler         }
188f1e85e20SMatt Spinler         else
189f1e85e20SMatt Spinler         {
190f1e85e20SMatt Spinler             // There are different default event types for info errors
191f1e85e20SMatt Spinler             // vs non info ones.
192f1e85e20SMatt Spinler             auto sevType = static_cast<SeverityType>(_eventSeverity & 0xF0);
1933b8ed7f2SSumit Kumar             _eventType =
1943b8ed7f2SSumit Kumar                 (sevType == SeverityType::nonError)
195f1e85e20SMatt Spinler                     ? static_cast<uint8_t>(EventType::miscInformational)
196f1e85e20SMatt Spinler                     : static_cast<uint8_t>(EventType::notApplicable);
197f1e85e20SMatt Spinler         }
198fdb6a202SMatt Spinler 
199fdb6a202SMatt Spinler         _reserved4Byte1 = 0;
200fdb6a202SMatt Spinler 
201fdb6a202SMatt Spinler         // No uses for problem domain or vector
202fdb6a202SMatt Spinler         _problemDomain = 0;
203fdb6a202SMatt Spinler         _problemVector = 0;
204fdb6a202SMatt Spinler 
2051f93c590SMatt Spinler         // These will be set in pel_rules::check() if they're still
2061f93c590SMatt Spinler         // at the default value.
2073b8ed7f2SSumit Kumar         if (!mfgActionFlagStatus)
2083b8ed7f2SSumit Kumar         {
2091f93c590SMatt Spinler             _actionFlags = entry.actionFlags.value_or(actionFlagsDefault);
2103b8ed7f2SSumit Kumar         }
211fdb6a202SMatt Spinler 
212eb111447SMatt Spinler         _states = 0;
213fdb6a202SMatt Spinler 
214fdb6a202SMatt Spinler         _valid = true;
215fdb6a202SMatt Spinler     }
2163b8ed7f2SSumit Kumar }
217fdb6a202SMatt Spinler 
UserHeader(Stream & pel)21803c1d915SMatt Spinler UserHeader::UserHeader(Stream& pel)
21903c1d915SMatt Spinler {
22003c1d915SMatt Spinler     try
22103c1d915SMatt Spinler     {
222cf5a8d0fSMatt Spinler         unflatten(pel);
22303c1d915SMatt Spinler         validate();
22403c1d915SMatt Spinler     }
22503c1d915SMatt Spinler     catch (const std::exception& e)
22603c1d915SMatt Spinler     {
227*5bc26533SArya K Padman         lg2::error("Cannot unflatten user header: {EXCEPTION}", "EXCEPTION", e);
22803c1d915SMatt Spinler         _valid = false;
22903c1d915SMatt Spinler     }
23003c1d915SMatt Spinler }
23103c1d915SMatt Spinler 
validate()23203c1d915SMatt Spinler void UserHeader::validate()
23303c1d915SMatt Spinler {
23403c1d915SMatt Spinler     bool failed = false;
2351a94cc38SMatt Spinler     if (header().id != static_cast<uint16_t>(SectionID::userHeader))
23603c1d915SMatt Spinler     {
237*5bc26533SArya K Padman         lg2::error("Invalid user header section ID: {HEADER_ID}", "HEADER_ID",
238*5bc26533SArya K Padman                    lg2::hex, header().id);
23903c1d915SMatt Spinler         failed = true;
24003c1d915SMatt Spinler     }
24103c1d915SMatt Spinler 
24203c1d915SMatt Spinler     if (header().version != userHeaderVersion)
24303c1d915SMatt Spinler     {
244*5bc26533SArya K Padman         lg2::error("Invalid user header version: {HEADER_VERSION}",
245*5bc26533SArya K Padman                    "HEADER_VERSION", lg2::hex, header().version);
24603c1d915SMatt Spinler         failed = true;
24703c1d915SMatt Spinler     }
24803c1d915SMatt Spinler 
24903c1d915SMatt Spinler     _valid = (failed) ? false : true;
25003c1d915SMatt Spinler }
25103c1d915SMatt Spinler 
getJSON(uint8_t creatorID) const252b832aa5eSMatt Spinler std::optional<std::string> UserHeader::getJSON(uint8_t creatorID) const
253ad0e0476SAatir Manzur {
254ad0e0476SAatir Manzur     std::string severity;
255ad0e0476SAatir Manzur     std::string subsystem;
256ad0e0476SAatir Manzur     std::string eventScope;
257ad0e0476SAatir Manzur     std::string eventType;
258600d15afSHarisuddin Mohamed Isa     std::vector<std::string> actionFlags;
259c1489351SAatir     severity = pv::getValue(_eventSeverity, pel_values::severityValues);
260c1489351SAatir     subsystem = pv::getValue(_eventSubsystem, pel_values::subsystemValues);
261c1489351SAatir     eventScope = pv::getValue(_eventScope, pel_values::eventScopeValues);
262c1489351SAatir     eventType = pv::getValue(_eventType, pel_values::eventTypeValues);
2632544b419SPatrick Williams     actionFlags = pv::getValuesBitwise(_actionFlags,
2642544b419SPatrick Williams                                        pel_values::actionFlagsValues);
265455587e5SMatt Spinler 
266455587e5SMatt Spinler     std::string hostState{"Invalid"};
2672fb10211SVijay Lobo     std::string hmcState{"Invalid"};
268455587e5SMatt Spinler     auto iter = pv::transmissionStates.find(
269455587e5SMatt Spinler         static_cast<TransmissionState>(hostTransmissionState()));
270455587e5SMatt Spinler     if (iter != pv::transmissionStates.end())
271455587e5SMatt Spinler     {
272455587e5SMatt Spinler         hostState = iter->second;
273455587e5SMatt Spinler     }
2742fb10211SVijay Lobo     auto iter1 = pv::transmissionStates.find(
2752fb10211SVijay Lobo         static_cast<TransmissionState>(hmcTransmissionState()));
2762fb10211SVijay Lobo     if (iter1 != pv::transmissionStates.end())
2772fb10211SVijay Lobo     {
2782fb10211SVijay Lobo         hmcState = iter1->second;
2792fb10211SVijay Lobo     }
280455587e5SMatt Spinler 
281600d15afSHarisuddin Mohamed Isa     std::string uh;
282bebeb948SHarisuddin Mohamed Isa     jsonInsert(uh, pv::sectionVer, getNumberString("%d", userHeaderVersion), 1);
283bebeb948SHarisuddin Mohamed Isa     jsonInsert(uh, pv::subSection, getNumberString("%d", _header.subType), 1);
284bebeb948SHarisuddin Mohamed Isa     jsonInsert(uh, "Log Committed by",
285b832aa5eSMatt Spinler                getComponentName(_header.componentID, creatorID), 1);
286600d15afSHarisuddin Mohamed Isa     jsonInsert(uh, "Subsystem", subsystem, 1);
287600d15afSHarisuddin Mohamed Isa     jsonInsert(uh, "Event Scope", eventScope, 1);
288600d15afSHarisuddin Mohamed Isa     jsonInsert(uh, "Event Severity", severity, 1);
289600d15afSHarisuddin Mohamed Isa     jsonInsert(uh, "Event Type", eventType, 1);
290600d15afSHarisuddin Mohamed Isa     jsonInsertArray(uh, "Action Flags", actionFlags, 1);
291455587e5SMatt Spinler     jsonInsert(uh, "Host Transmission", hostState, 1);
2922fb10211SVijay Lobo     jsonInsert(uh, "HMC Transmission", hmcState, 1);
293600d15afSHarisuddin Mohamed Isa     uh.erase(uh.size() - 2);
294ad0e0476SAatir Manzur     return uh;
295ad0e0476SAatir Manzur }
296aadccc85SMatt Spinler 
getSeverity(const std::vector<message::RegistrySeverity> & severities,const DataInterfaceBase & dataIface) const297aadccc85SMatt Spinler std::optional<uint8_t> UserHeader::getSeverity(
298aadccc85SMatt Spinler     const std::vector<message::RegistrySeverity>& severities,
2991ab6696fSMatt Spinler     const DataInterfaceBase& dataIface) const
300aadccc85SMatt Spinler {
301aadccc85SMatt Spinler     const uint8_t* s = nullptr;
3021ab6696fSMatt Spinler     std::vector<std::string> systemNames;
3031ab6696fSMatt Spinler 
3041ab6696fSMatt Spinler     // getSystemNames makes D-Bus calls, so only call it if we
3051ab6696fSMatt Spinler     // know we'll need it because there is a system name in the sev list
3061ab6696fSMatt Spinler     if (std::any_of(severities.begin(), severities.end(),
3071ab6696fSMatt Spinler                     [](const auto& sev) { return !sev.system.empty(); }))
3081ab6696fSMatt Spinler     {
3091ab6696fSMatt Spinler         try
3101ab6696fSMatt Spinler         {
3111ab6696fSMatt Spinler             systemNames = dataIface.getSystemNames();
3121ab6696fSMatt Spinler         }
3131ab6696fSMatt Spinler         catch (const std::exception& e)
3141ab6696fSMatt Spinler         {
315*5bc26533SArya K Padman             lg2::error(
316*5bc26533SArya K Padman                 "Failed trying to look up system names on D-Bus ERROR={ERROR}",
317*5bc26533SArya K Padman                 "ERROR", e);
3181ab6696fSMatt Spinler             return std::nullopt;
3191ab6696fSMatt Spinler         }
3201ab6696fSMatt Spinler     }
321aadccc85SMatt Spinler 
322aadccc85SMatt Spinler     // Find the severity to use for this system type, or use the default
323aadccc85SMatt Spinler     // entry (where no system type is specified).
324aadccc85SMatt Spinler     for (const auto& sev : severities)
325aadccc85SMatt Spinler     {
3266ea4d5f7SMatt Spinler         if (std::find(systemNames.begin(), systemNames.end(), sev.system) !=
3276ea4d5f7SMatt Spinler             systemNames.end())
328aadccc85SMatt Spinler         {
329aadccc85SMatt Spinler             s = &sev.severity;
330aadccc85SMatt Spinler             break;
331aadccc85SMatt Spinler         }
332aadccc85SMatt Spinler         else if (sev.system.empty())
333aadccc85SMatt Spinler         {
334aadccc85SMatt Spinler             s = &sev.severity;
335aadccc85SMatt Spinler         }
336aadccc85SMatt Spinler     }
337aadccc85SMatt Spinler 
338aadccc85SMatt Spinler     if (s)
339aadccc85SMatt Spinler     {
340aadccc85SMatt Spinler         return *s;
341aadccc85SMatt Spinler     }
342aadccc85SMatt Spinler 
343aadccc85SMatt Spinler     return std::nullopt;
344aadccc85SMatt Spinler }
345aadccc85SMatt Spinler 
34603c1d915SMatt Spinler } // namespace pels
34703c1d915SMatt Spinler } // namespace openpower
348