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