1 #include "occ_ffdc.hpp" 2 3 #include "elog-errors.hpp" 4 #include "utils.hpp" 5 6 #include <errno.h> 7 #include <fcntl.h> 8 #include <fmt/core.h> 9 #include <stdio.h> 10 #include <sys/ioctl.h> 11 #include <unistd.h> 12 13 #include <org/open_power/OCC/Device/error.hpp> 14 #include <phosphor-logging/elog.hpp> 15 #include <phosphor-logging/log.hpp> 16 #include <xyz/openbmc_project/Common/error.hpp> 17 #include <xyz/openbmc_project/Logging/Create/server.hpp> 18 19 namespace open_power 20 { 21 namespace occ 22 { 23 24 static constexpr size_t max_ffdc_size = 8192; 25 static constexpr size_t sbe_status_header_size = 8; 26 27 static constexpr auto loggingObjectPath = "/xyz/openbmc_project/logging"; 28 static constexpr auto loggingInterface = "xyz.openbmc_project.Logging.Create"; 29 static constexpr auto opLoggingInterface = "org.open_power.Logging.PEL"; 30 31 using namespace phosphor::logging; 32 using namespace sdbusplus::org::open_power::OCC::Device::Error; 33 using InternalFailure = 34 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure; 35 36 uint32_t FFDC::createPEL(const char* path, uint32_t src6, const char* msg, 37 int fd) 38 { 39 uint32_t plid = 0; 40 std::vector<std::tuple< 41 sdbusplus::xyz::openbmc_project::Logging::server::Create::FFDCFormat, 42 uint8_t, uint8_t, sdbusplus::message::unix_fd>> 43 pelFFDCInfo; 44 45 log<level::INFO>("Creating PEL with SBE FFDC", entry("SRC6=%08x", src6)); 46 47 if (fd > 0) 48 { 49 pelFFDCInfo.push_back(std::make_tuple( 50 sdbusplus::xyz::openbmc_project::Logging::server::Create:: 51 FFDCFormat::Custom, 52 static_cast<uint8_t>(0xCB), static_cast<uint8_t>(0x01), fd)); 53 } 54 55 std::map<std::string, std::string> additionalData; 56 additionalData.emplace("SRC6", std::to_string(src6)); 57 additionalData.emplace("_PID", std::to_string(getpid())); 58 additionalData.emplace("SBE_ERR_MSG", msg); 59 60 auto& bus = utils::getBus(); 61 62 try 63 { 64 std::string service = 65 utils::getService(loggingObjectPath, opLoggingInterface); 66 auto method = 67 bus.new_method_call(service.c_str(), loggingObjectPath, 68 opLoggingInterface, "CreatePELWithFFDCFiles"); 69 auto level = 70 sdbusplus::xyz::openbmc_project::Logging::server::convertForMessage( 71 sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level:: 72 Error); 73 method.append(path, level, additionalData, pelFFDCInfo); 74 auto response = bus.call(method); 75 std::tuple<uint32_t, uint32_t> reply = {0, 0}; 76 77 response.read(reply); 78 plid = std::get<1>(reply); 79 } 80 catch (const sdbusplus::exception_t& e) 81 { 82 log<level::ERR>("Failed to create PEL"); 83 } 84 85 return plid; 86 } 87 88 void FFDC::createOCCResetPEL(unsigned int instance, const char* path, int err, 89 const char* callout) 90 { 91 std::map<std::string, std::string> additionalData; 92 93 additionalData.emplace("_PID", std::to_string(getpid())); 94 95 if (err) 96 { 97 additionalData.emplace("CALLOUT_ERRNO", std::to_string(-err)); 98 } 99 100 if (callout) 101 { 102 additionalData.emplace("CALLOUT_DEVICE_PATH", std::string(callout)); 103 } 104 105 additionalData.emplace("OCC", std::to_string(instance)); 106 107 auto& bus = utils::getBus(); 108 109 try 110 { 111 std::string service = 112 utils::getService(loggingObjectPath, loggingInterface); 113 auto method = bus.new_method_call(service.c_str(), loggingObjectPath, 114 loggingInterface, "Create"); 115 auto level = 116 sdbusplus::xyz::openbmc_project::Logging::server::convertForMessage( 117 sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level:: 118 Error); 119 method.append(path, level, additionalData); 120 bus.call(method); 121 } 122 catch (const sdbusplus::exception_t& e) 123 { 124 log<level::ERR>( 125 fmt::format("Failed to create PEL: {}", e.what()).c_str()); 126 } 127 } 128 129 // Reads the FFDC file and create an error log 130 void FFDC::analyzeEvent() 131 { 132 int tfd = -1; 133 size_t total = 0; 134 auto data = std::make_unique<unsigned char[]>(max_ffdc_size); 135 while (total < max_ffdc_size) 136 { 137 auto r = read(fd, data.get() + total, max_ffdc_size - total); 138 if (r < 0) 139 { 140 elog<ReadFailure>( 141 phosphor::logging::org::open_power::OCC::Device::ReadFailure:: 142 CALLOUT_ERRNO(errno), 143 phosphor::logging::org::open_power::OCC::Device::ReadFailure:: 144 CALLOUT_DEVICE_PATH(file.c_str())); 145 return; 146 } 147 if (!r) 148 { 149 break; 150 } 151 total += r; 152 } 153 154 lseek(fd, 0, SEEK_SET); 155 156 if (!total) 157 { 158 // no error 159 return; 160 } 161 162 uint32_t src6 = instance << 16; 163 src6 |= *(data.get() + 2) << 8; 164 src6 |= *(data.get() + 3); 165 166 if (total > sbe_status_header_size) 167 { 168 std::string templateString = 169 fs::temp_directory_path() / "OCC_FFDC_XXXXXX"; 170 tfd = mkostemp(templateString.data(), O_RDWR); 171 if (tfd < 0) 172 { 173 log<level::ERR>("Couldn't create temporary FFDC file"); 174 } 175 else 176 { 177 temporaryFiles.emplace_back(templateString, tfd); 178 size_t written = sbe_status_header_size; 179 while (written < total) 180 { 181 auto r = write(tfd, data.get() + written, total - written); 182 if (r < 0) 183 { 184 close(temporaryFiles.back().second); 185 fs::remove(temporaryFiles.back().first); 186 temporaryFiles.pop_back(); 187 tfd = -1; 188 log<level::ERR>("Couldn't write temporary FFDC file"); 189 break; 190 } 191 if (!r) 192 { 193 break; 194 } 195 written += r; 196 } 197 } 198 } 199 200 createPEL("org.open_power.Processor.Error.SbeChipOpFailure", src6, 201 "SBE command reported error", tfd); 202 } 203 204 } // namespace occ 205 } // namespace open_power 206