1 #include "create_pel.hpp" 2 3 #include "dump_utils.hpp" 4 #include "sbe_consts.hpp" 5 6 #include <fcntl.h> 7 #include <libekb.H> 8 #include <unistd.h> 9 10 #include <phosphor-logging/elog.hpp> 11 #include <phosphor-logging/lg2.hpp> 12 #include <xyz/openbmc_project/Logging/Create/server.hpp> 13 #include <xyz/openbmc_project/Logging/Entry/server.hpp> 14 15 #include <cerrno> 16 #include <cstdio> 17 #include <cstdlib> 18 #include <cstring> 19 #include <format> 20 #include <map> 21 #include <stdexcept> 22 #include <string> 23 #include <tuple> 24 #include <vector> 25 26 namespace openpower::dump::pel 27 { 28 29 using namespace phosphor::logging; 30 using namespace openpower::dump::SBE; 31 constexpr auto loggingObjectPath = "/xyz/openbmc_project/logging"; 32 constexpr auto loggingInterface = "xyz.openbmc_project.Logging.Create"; 33 constexpr auto opLoggingInterface = "org.open_power.Logging.PEL"; 34 35 uint32_t createSbeErrorPEL(const std::string& event, const sbeError_t& sbeError, 36 const FFDCData& ffdcData, const Severity severity, 37 const std::optional<PELFFDCInfo>& pelFFDCInfoOpt) 38 { 39 uint32_t plid = 0; 40 std::unordered_map<std::string, std::string> additionalData = { 41 {"_PID", std::to_string(getpid())}, {"SBE_ERR_MSG", sbeError.what()}}; 42 auto bus = sdbusplus::bus::new_default(); 43 44 additionalData.emplace("_PID", std::to_string(getpid())); 45 additionalData.emplace("SBE_ERR_MSG", sbeError.what()); 46 47 for (auto& data : ffdcData) 48 { 49 additionalData.emplace(data); 50 } 51 52 PELFFDCInfo pelFFDCInfo; 53 if (pelFFDCInfoOpt) 54 { 55 pelFFDCInfo = *pelFFDCInfoOpt; 56 } 57 58 // Negative fd value indicates error case or invalid file 59 // No need of special processing , just log error with additional ffdc. 60 else if (sbeError.getFd() > 0) 61 { 62 // Refer phosphor-logging/extensions/openpower-pels/README.md section 63 // "Self Boot Engine(SBE) First Failure Data Capture(FFDC) Support" 64 // for details of related to createPEL with SBE FFDC information 65 // using CreateWithFFDCFiles api. 66 pelFFDCInfo.emplace_back(std::make_tuple( 67 sdbusplus::xyz::openbmc_project::Logging::server::Create:: 68 FFDCFormat::Custom, 69 FFDC_FORMAT_SUBTYPE, FFDC_FORMAT_VERSION, sbeError.getFd())); 70 } 71 try 72 { 73 auto service = 74 util::getService(bus, opLoggingInterface, loggingObjectPath); 75 auto method = 76 bus.new_method_call(service.c_str(), loggingObjectPath, 77 opLoggingInterface, "CreatePELWithFFDCFiles"); 78 auto level = 79 sdbusplus::xyz::openbmc_project::Logging::server::convertForMessage( 80 severity); 81 method.append(event, level, additionalData, pelFFDCInfo); 82 auto response = bus.call(method); 83 84 // reply will be tuple containing bmc log id, platform log id 85 std::tuple<uint32_t, uint32_t> reply = {0, 0}; 86 87 // parse dbus response into reply 88 response.read(reply); 89 plid = std::get<1>(reply); // platform log id is tuple "second" 90 } 91 catch (const sdbusplus::exception_t& e) 92 { 93 lg2::error( 94 "D-Bus call exception OBJPATH={OBJPATH}, INTERFACE={INTERFACE}, " 95 "EXCEPTION={ERROR}", 96 "OBJPATH", loggingObjectPath, "INTERFACE", loggingInterface, 97 "ERROR", e); 98 99 throw; 100 } 101 catch (const std::exception& e) 102 { 103 throw; 104 } 105 106 return plid; 107 } 108 109 openpower::dump::pel::Severity convertSeverityToEnum(uint8_t severity) 110 { 111 switch (severity) 112 { 113 case openpower::phal::FAPI2_ERRL_SEV_RECOVERED: 114 return openpower::dump::pel::Severity::Informational; 115 case openpower::phal::FAPI2_ERRL_SEV_PREDICTIVE: 116 return openpower::dump::pel::Severity::Warning; 117 case openpower::phal::FAPI2_ERRL_SEV_UNRECOVERABLE: 118 return openpower::dump::pel::Severity::Error; 119 default: 120 return openpower::dump::pel::Severity::Error; 121 } 122 } 123 124 void processFFDCPackets(const openpower::phal::sbeError_t& sbeError, 125 const std::string& event, 126 openpower::dump::pel::FFDCData& pelAdditionalData) 127 { 128 const auto& ffdcFileList = sbeError.getFfdcFileList(); 129 for (const auto& [slid, ffdcTuple] : ffdcFileList) 130 { 131 uint8_t severity; 132 int fd; 133 std::filesystem::path path; 134 std::tie(severity, fd, path) = ffdcTuple; 135 136 Severity logSeverity = convertSeverityToEnum(severity); 137 138 if (logSeverity != openpower::dump::pel::Severity::Informational) 139 { 140 lg2::info( 141 "Changing severity from {SEV_ORIG} to informational in the " 142 "dumping path", 143 "SEV_ORIG", logSeverity); 144 logSeverity = openpower::dump::pel::Severity::Informational; 145 } 146 147 PELFFDCInfo pelFFDCInfo; 148 pelFFDCInfo.emplace_back( 149 std::make_tuple(sdbusplus::xyz::openbmc_project::Logging::server:: 150 Create::FFDCFormat::Custom, 151 FFDC_FORMAT_SUBTYPE, FFDC_FORMAT_VERSION, fd)); 152 153 auto logId = openpower::dump::pel::createSbeErrorPEL( 154 event, sbeError, pelAdditionalData, logSeverity); 155 lg2::info("Logged PEL {PELID} for SLID {SLID}", "PELID", logId, "SLID", 156 slid); 157 } 158 } 159 160 FFDCFile::FFDCFile(const json& pHALCalloutData) : 161 calloutData(pHALCalloutData.dump()), 162 calloutFile("/tmp/phalPELCalloutsJson.XXXXXX"), fileFD(-1) 163 { 164 prepareFFDCFile(); 165 } 166 167 FFDCFile::~FFDCFile() 168 { 169 removeCalloutFile(); 170 } 171 172 int FFDCFile::getFileFD() const 173 { 174 return fileFD; 175 } 176 177 void FFDCFile::prepareFFDCFile() 178 { 179 createCalloutFile(); 180 writeCalloutData(); 181 setCalloutFileSeekPos(); 182 } 183 184 void FFDCFile::createCalloutFile() 185 { 186 fileFD = mkostemp(const_cast<char*>(calloutFile.c_str()), O_RDWR); 187 188 if (fileFD == -1) 189 { 190 lg2::error("Failed to create phalPELCallouts file({FILE}), " 191 "errorno({ERRNO}) and errormsg({ERRORMSG})", 192 "FILE", calloutFile, "ERRNO", errno, "ERRORMSG", 193 strerror(errno)); 194 throw std::runtime_error("Failed to create phalPELCallouts file"); 195 } 196 } 197 198 void FFDCFile::writeCalloutData() 199 { 200 ssize_t rc = write(fileFD, calloutData.c_str(), calloutData.size()); 201 202 if (rc == -1) 203 { 204 lg2::error("Failed to write phaPELCallout info in file({FILE}), " 205 "errorno({ERRNO}), errormsg({ERRORMSG})", 206 "FILE", calloutFile, "ERRNO", errno, "ERRORMSG", 207 strerror(errno)); 208 throw std::runtime_error("Failed to write phalPELCallouts info"); 209 } 210 else if (rc != static_cast<ssize_t>(calloutData.size())) 211 { 212 lg2::warning("Could not write all phal callout info in file({FILE}), " 213 "written byte({WRITTEN}), total byte({TOTAL})", 214 "FILE", calloutFile, "WRITTEN", rc, "TOTAL", 215 calloutData.size()); 216 } 217 } 218 219 void FFDCFile::setCalloutFileSeekPos() 220 { 221 int rc = lseek(fileFD, 0, SEEK_SET); 222 223 if (rc == -1) 224 { 225 lg2::error("Failed to set SEEK_SET for phalPELCallouts in " 226 "file({FILE}), errorno({ERRNO}), errormsg({ERRORMSG})", 227 "FILE", calloutFile, "ERRNO", errno, "ERRORMSG", 228 strerror(errno)); 229 230 throw std::runtime_error( 231 "Failed to set SEEK_SET for phalPELCallouts file"); 232 } 233 } 234 235 void FFDCFile::removeCalloutFile() 236 { 237 close(fileFD); 238 std::remove(calloutFile.c_str()); 239 } 240 241 } // namespace openpower::dump::pel 242