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 <phosphor-logging/log.hpp> 24 25 #include <format> 26 #include <iostream> 27 28 namespace openpower 29 { 30 namespace pels 31 { 32 33 namespace pv = openpower::pels::pel_values; 34 using namespace phosphor::logging; 35 36 void UserHeader::unflatten(Stream& stream) 37 { 38 stream >> _header >> _eventSubsystem >> _eventScope >> _eventSeverity >> 39 _eventType >> _reserved4Byte1 >> _problemDomain >> _problemVector >> 40 _actionFlags >> _states; 41 } 42 43 void UserHeader::flatten(Stream& stream) const 44 { 45 stream << _header << _eventSubsystem << _eventScope << _eventSeverity 46 << _eventType << _reserved4Byte1 << _problemDomain << _problemVector 47 << _actionFlags << _states; 48 } 49 50 UserHeader::UserHeader(const message::Entry& entry, 51 phosphor::logging::Entry::Level severity, 52 const AdditionalData& additionalData, 53 const DataInterfaceBase& dataIface) 54 { 55 _header.id = static_cast<uint16_t>(SectionID::userHeader); 56 _header.size = UserHeader::flattenedSize(); 57 _header.version = userHeaderVersion; 58 _header.subType = 0; 59 _header.componentID = static_cast<uint16_t>(ComponentID::phosphorLogging); 60 61 std::optional<uint8_t> subsys; 62 63 // Check for additional data - PEL_SUBSYSTEM 64 auto ss = additionalData.getValue("PEL_SUBSYSTEM"); 65 if (ss) 66 { 67 auto eventSubsystem = std::stoul(*ss, NULL, 16); 68 std::string subsystemString = pv::getValue(eventSubsystem, 69 pel_values::subsystemValues); 70 if (subsystemString == "invalid") 71 { 72 log<level::WARNING>( 73 std::format( 74 "UH: Invalid SubSystem value in PEL_SUBSYSTEM: {:#X}", 75 eventSubsystem) 76 .c_str()); 77 } 78 else 79 { 80 subsys = eventSubsystem; 81 } 82 } 83 else 84 { 85 subsys = entry.subsystem; 86 } 87 88 if (subsys) 89 { 90 _eventSubsystem = *subsys; 91 } 92 else 93 { 94 // Gotta use something, how about 'others'. 95 log<level::WARNING>( 96 "No PEL subystem value supplied for error, using 'others'"); 97 _eventSubsystem = 0x70; 98 } 99 100 _eventScope = entry.eventScope.value_or( 101 static_cast<uint8_t>(EventScope::entirePlatform)); 102 103 { 104 bool mfgSevStatus = false; 105 bool mfgActionFlagStatus = false; 106 107 // Get the mfg severity & action flags 108 if (entry.mfgSeverity || entry.mfgActionFlags) 109 { 110 std::optional<uint8_t> sev = std::nullopt; 111 uint16_t val = 0; 112 113 if (entry.mfgSeverity) 114 { 115 // Find the mf severity possibly dependent on the system type. 116 sev = getSeverity(entry.mfgSeverity.value(), dataIface); 117 } 118 119 if (entry.mfgActionFlags) 120 { 121 // Find the mfg action flags 122 val = entry.mfgActionFlags.value(); 123 } 124 125 if (sev || val) 126 { 127 bool mfgProp = dataIface.getQuiesceOnError(); 128 if (mfgProp) 129 { 130 if (sev) 131 { 132 _eventSeverity = *sev; 133 mfgSevStatus = true; 134 } 135 136 if (val) 137 { 138 _actionFlags = val; 139 mfgActionFlagStatus = true; 140 } 141 } 142 } 143 } 144 145 if (!mfgSevStatus) 146 { 147 // Get the severity from the registry if it's there, otherwise get 148 // it from the OpenBMC event log severity value. 149 if (!entry.severity) 150 { 151 _eventSeverity = convertOBMCSeverityToPEL(severity); 152 } 153 else 154 { 155 // Find the severity possibly dependent on the system type. 156 auto sev = getSeverity(entry.severity.value(), dataIface); 157 if (sev) 158 { 159 _eventSeverity = *sev; 160 } 161 else 162 { 163 // Either someone screwed up the message registry 164 // or getSystemNames failed. 165 log<level::ERR>( 166 "Failed finding the severity in the message registry", 167 phosphor::logging::entry("ERROR=%s", 168 entry.name.c_str())); 169 170 // Have to choose something, just use informational. 171 _eventSeverity = 0; 172 } 173 } 174 } 175 176 // Convert Critical error (0x50) to Critical Error-System Termination 177 // (0x51), if the AdditionalData is set to SYSTEM_TERM 178 auto sevLevel = additionalData.getValue("SEVERITY_DETAIL"); 179 if ((_eventSeverity & 0xF0) == 0x50) 180 { 181 if (sevLevel.value_or("") == "SYSTEM_TERM") 182 { 183 // Change to Critical Error, System Termination 184 _eventSeverity = 0x51; 185 } 186 } 187 188 if (entry.eventType) 189 { 190 _eventType = *entry.eventType; 191 } 192 else 193 { 194 // There are different default event types for info errors 195 // vs non info ones. 196 auto sevType = static_cast<SeverityType>(_eventSeverity & 0xF0); 197 _eventType = 198 (sevType == SeverityType::nonError) 199 ? static_cast<uint8_t>(EventType::miscInformational) 200 : static_cast<uint8_t>(EventType::notApplicable); 201 } 202 203 _reserved4Byte1 = 0; 204 205 // No uses for problem domain or vector 206 _problemDomain = 0; 207 _problemVector = 0; 208 209 // These will be set in pel_rules::check() if they're still 210 // at the default value. 211 if (!mfgActionFlagStatus) 212 { 213 _actionFlags = entry.actionFlags.value_or(actionFlagsDefault); 214 } 215 216 _states = 0; 217 218 _valid = true; 219 } 220 } 221 222 UserHeader::UserHeader(Stream& pel) 223 { 224 try 225 { 226 unflatten(pel); 227 validate(); 228 } 229 catch (const std::exception& e) 230 { 231 log<level::ERR>( 232 std::format("Cannot unflatten user header: {}", e.what()).c_str()); 233 _valid = false; 234 } 235 } 236 237 void UserHeader::validate() 238 { 239 bool failed = false; 240 if (header().id != static_cast<uint16_t>(SectionID::userHeader)) 241 { 242 log<level::ERR>( 243 std::format("Invalid user header section ID: {0:#x}", header().id) 244 .c_str()); 245 failed = true; 246 } 247 248 if (header().version != userHeaderVersion) 249 { 250 log<level::ERR>( 251 std::format("Invalid user header version: {0:#x}", header().version) 252 .c_str()); 253 failed = true; 254 } 255 256 _valid = (failed) ? false : true; 257 } 258 259 std::optional<std::string> UserHeader::getJSON(uint8_t creatorID) const 260 { 261 std::string severity; 262 std::string subsystem; 263 std::string eventScope; 264 std::string eventType; 265 std::vector<std::string> actionFlags; 266 severity = pv::getValue(_eventSeverity, pel_values::severityValues); 267 subsystem = pv::getValue(_eventSubsystem, pel_values::subsystemValues); 268 eventScope = pv::getValue(_eventScope, pel_values::eventScopeValues); 269 eventType = pv::getValue(_eventType, pel_values::eventTypeValues); 270 actionFlags = pv::getValuesBitwise(_actionFlags, 271 pel_values::actionFlagsValues); 272 273 std::string hostState{"Invalid"}; 274 std::string hmcState{"Invalid"}; 275 auto iter = pv::transmissionStates.find( 276 static_cast<TransmissionState>(hostTransmissionState())); 277 if (iter != pv::transmissionStates.end()) 278 { 279 hostState = iter->second; 280 } 281 auto iter1 = pv::transmissionStates.find( 282 static_cast<TransmissionState>(hmcTransmissionState())); 283 if (iter1 != pv::transmissionStates.end()) 284 { 285 hmcState = iter1->second; 286 } 287 288 std::string uh; 289 jsonInsert(uh, pv::sectionVer, getNumberString("%d", userHeaderVersion), 1); 290 jsonInsert(uh, pv::subSection, getNumberString("%d", _header.subType), 1); 291 jsonInsert(uh, "Log Committed by", 292 getComponentName(_header.componentID, creatorID), 1); 293 jsonInsert(uh, "Subsystem", subsystem, 1); 294 jsonInsert(uh, "Event Scope", eventScope, 1); 295 jsonInsert(uh, "Event Severity", severity, 1); 296 jsonInsert(uh, "Event Type", eventType, 1); 297 jsonInsertArray(uh, "Action Flags", actionFlags, 1); 298 jsonInsert(uh, "Host Transmission", hostState, 1); 299 jsonInsert(uh, "HMC Transmission", hmcState, 1); 300 uh.erase(uh.size() - 2); 301 return uh; 302 } 303 304 std::optional<uint8_t> UserHeader::getSeverity( 305 const std::vector<message::RegistrySeverity>& severities, 306 const DataInterfaceBase& dataIface) const 307 { 308 const uint8_t* s = nullptr; 309 std::vector<std::string> systemNames; 310 311 // getSystemNames makes D-Bus calls, so only call it if we 312 // know we'll need it because there is a system name in the sev list 313 if (std::any_of(severities.begin(), severities.end(), 314 [](const auto& sev) { return !sev.system.empty(); })) 315 { 316 try 317 { 318 systemNames = dataIface.getSystemNames(); 319 } 320 catch (const std::exception& e) 321 { 322 log<level::ERR>("Failed trying to look up system names on D-Bus", 323 entry("ERROR=%s", e.what())); 324 return std::nullopt; 325 } 326 } 327 328 // Find the severity to use for this system type, or use the default 329 // entry (where no system type is specified). 330 for (const auto& sev : severities) 331 { 332 if (std::find(systemNames.begin(), systemNames.end(), sev.system) != 333 systemNames.end()) 334 { 335 s = &sev.severity; 336 break; 337 } 338 else if (sev.system.empty()) 339 { 340 s = &sev.severity; 341 } 342 } 343 344 if (s) 345 { 346 return *s; 347 } 348 349 return std::nullopt; 350 } 351 352 } // namespace pels 353 } // namespace openpower 354