blob: 1f284e52baab7c90c63538651cf4525bbc62b092 [file] [log] [blame]
Alexander Hansen40fb5492025-10-28 17:56:12 +01001// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright 2019 IBM Corporation
3
Matt Spinler4e8078c2019-07-09 13:22:32 -05004#include "manager.hpp"
5
6#include "additional_data.hpp"
Matt Spinler3387eac2023-07-06 14:56:02 -05007#include "elog_serialize.hpp"
Matt Spinler05c2c6c2019-12-18 14:02:09 -06008#include "json_utils.hpp"
Matt Spinler89fa0822019-07-17 13:54:30 -05009#include "pel.hpp"
Vijay Lobo2fb10212021-08-22 23:24:16 -050010#include "pel_entry.hpp"
Matt Spinler8a09b982025-05-09 14:09:10 -050011#include "pel_values.hpp"
Matt Spinler1962e082020-08-05 13:44:53 -050012#include "service_indicators.hpp"
Matt Spinler8b81ec02022-07-12 13:25:37 -050013#include "severity.hpp"
Matt Spinler89fa0822019-07-17 13:54:30 -050014
Matt Spinlerff9cec22020-07-15 13:06:35 -050015#include <sys/inotify.h>
Matt Spinler6b1a5c82020-01-07 08:48:53 -060016#include <unistd.h>
17
Matt Spinlerfbdfc762023-06-30 15:15:44 -050018#include <phosphor-logging/lg2.hpp>
Patrick Williams2544b412022-10-04 08:41:06 -050019#include <xyz/openbmc_project/Common/error.hpp>
20#include <xyz/openbmc_project/Logging/Create/server.hpp>
21
Matt Spinler89fa0822019-07-17 13:54:30 -050022#include <filesystem>
Jayanth Othayoth1aa90d42023-09-13 04:25:45 -050023#include <format>
Matt Spinler89fa0822019-07-17 13:54:30 -050024#include <fstream>
Matt Spinler4e8078c2019-07-09 13:22:32 -050025
26namespace openpower
27{
28namespace pels
29{
30
31using namespace phosphor::logging;
Matt Spinler89fa0822019-07-17 13:54:30 -050032namespace fs = std::filesystem;
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +080033namespace rg = openpower::pels::message;
Matt Spinler4e8078c2019-07-09 13:22:32 -050034
Matt Spinlera34ab722019-12-16 10:39:32 -060035namespace common_error = sdbusplus::xyz::openbmc_project::Common::Error;
36
Willy Tu6ddbf692023-09-05 10:54:16 -070037using Create = sdbusplus::server::xyz::openbmc_project::logging::Create;
Matt Spinler56ad2a02020-03-26 14:00:52 -050038
Matt Spinler4e8078c2019-07-09 13:22:32 -050039namespace additional_data
40{
41constexpr auto rawPEL = "RAWPEL";
Matt Spinler19e72902020-01-24 11:05:20 -060042constexpr auto esel = "ESEL";
Matt Spinler30ddc9f2020-07-16 15:39:59 -050043constexpr auto error = "ERROR_NAME";
Matt Spinler19e72902020-01-24 11:05:20 -060044} // namespace additional_data
Matt Spinler4e8078c2019-07-09 13:22:32 -050045
Matt Spinler30ddc9f2020-07-16 15:39:59 -050046constexpr auto defaultLogMessage = "xyz.openbmc_project.Logging.Error.Default";
Matt Spinler0dd22c82023-05-04 15:28:12 -050047constexpr uint32_t bmcThermalCompID = 0x2700;
48constexpr uint32_t bmcFansCompID = 0x2800;
Matt Spinler30ddc9f2020-07-16 15:39:59 -050049
Matt Spinlerff9cec22020-07-15 13:06:35 -050050Manager::~Manager()
51{
52 if (_pelFileDeleteFD != -1)
53 {
54 if (_pelFileDeleteWatchFD != -1)
55 {
56 inotify_rm_watch(_pelFileDeleteFD, _pelFileDeleteWatchFD);
57 }
58 close(_pelFileDeleteFD);
59 }
60}
61
Matt Spinler4e8078c2019-07-09 13:22:32 -050062void Manager::create(const std::string& message, uint32_t obmcLogID,
63 uint64_t timestamp, Entry::Level severity,
Patrick Williamse5940632024-11-22 20:47:58 -050064 const std::map<std::string, std::string>& additionalData,
Matt Spinler56ad2a02020-03-26 14:00:52 -050065 const std::vector<std::string>& associations,
66 const FFDCEntries& ffdc)
Matt Spinler4e8078c2019-07-09 13:22:32 -050067{
68 AdditionalData ad{additionalData};
69
Matt Spinler19e72902020-01-24 11:05:20 -060070 // If a PEL was passed in via a filename or in an ESEL,
71 // use that. Otherwise, create one.
Matt Spinler4e8078c2019-07-09 13:22:32 -050072 auto rawPelPath = ad.getValue(additional_data::rawPEL);
73 if (rawPelPath)
74 {
75 addRawPEL(*rawPelPath, obmcLogID);
76 }
77 else
78 {
Matt Spinler19e72902020-01-24 11:05:20 -060079 auto esel = ad.getValue(additional_data::esel);
80 if (esel)
81 {
82 addESELPEL(*esel, obmcLogID);
83 }
84 else
85 {
86 createPEL(message, obmcLogID, timestamp, severity, additionalData,
Matt Spinler56ad2a02020-03-26 14:00:52 -050087 associations, ffdc);
Matt Spinler19e72902020-01-24 11:05:20 -060088 }
Matt Spinler4e8078c2019-07-09 13:22:32 -050089 }
Adriana Kobylake7d271a2020-12-07 14:32:44 -060090
91 setEntryPath(obmcLogID);
Vijay Lobocbc93a42021-05-20 19:04:07 -050092 setServiceProviderNotifyFlag(obmcLogID);
Matt Spinler4e8078c2019-07-09 13:22:32 -050093}
94
95void Manager::addRawPEL(const std::string& rawPelPath, uint32_t obmcLogID)
96{
Matt Spinler89fa0822019-07-17 13:54:30 -050097 if (fs::exists(rawPelPath))
98 {
99 std::ifstream file(rawPelPath, std::ios::in | std::ios::binary);
100
101 auto data = std::vector<uint8_t>(std::istreambuf_iterator<char>(file),
102 std::istreambuf_iterator<char>());
103 if (file.fail())
104 {
Matt Spinlerfbdfc762023-06-30 15:15:44 -0500105 lg2::error(
106 "Filesystem error reading a raw PEL. File = {FILE}, obmcLogID = {LOGID}",
107 "FILE", rawPelPath, "LOGID", obmcLogID);
Matt Spinler89fa0822019-07-17 13:54:30 -0500108 // TODO, Decide what to do here. Maybe nothing.
109 return;
110 }
111
112 file.close();
113
Matt Spinler19e72902020-01-24 11:05:20 -0600114 addPEL(data, obmcLogID);
Matt Spinler67416922021-07-19 12:34:57 -0600115
116 std::error_code ec;
117 fs::remove(rawPelPath, ec);
Matt Spinler89fa0822019-07-17 13:54:30 -0500118 }
119 else
120 {
Matt Spinlerfbdfc762023-06-30 15:15:44 -0500121 lg2::error(
122 "Raw PEL file from BMC event log does not exit. File = {FILE}, obmcLogID = {LOGID}",
123 "FILE", rawPelPath, "LOGID", obmcLogID);
Matt Spinler89fa0822019-07-17 13:54:30 -0500124 }
Matt Spinler4e8078c2019-07-09 13:22:32 -0500125}
126
Matt Spinler19e72902020-01-24 11:05:20 -0600127void Manager::addPEL(std::vector<uint8_t>& pelData, uint32_t obmcLogID)
128{
Matt Spinler19e72902020-01-24 11:05:20 -0600129 auto pel = std::make_unique<openpower::pels::PEL>(pelData, obmcLogID);
130 if (pel->valid())
131 {
Sumit Kumar8ec41562021-10-29 05:39:37 -0500132 // PELs created by others still need this field set by us.
133 pel->setCommitTime();
134
Sumit Kumara1e40842021-06-23 09:52:25 -0500135 // Assign Id other than to Hostbot PEL
136 if ((pel->privateHeader()).creatorID() !=
137 static_cast<uint8_t>(CreatorID::hostboot))
138 {
139 pel->assignID();
140 }
Sumit Kumar2ccdcef2021-07-31 10:04:58 -0500141 else
142 {
143 const Repository::LogID id{Repository::LogID::Pel(pel->id())};
144 auto result = _repo.hasPEL(id);
145 if (result)
146 {
Matt Spinlerfbdfc762023-06-30 15:15:44 -0500147 lg2::warning(
148 "Duplicate HostBoot PEL ID {ID} found, moving it to archive folder",
149 "ID", lg2::hex, pel->id());
Sumit Kumar2ccdcef2021-07-31 10:04:58 -0500150
151 _repo.archivePEL(*pel);
Matt Spinlerd8fb5ba2022-01-25 13:01:14 -0600152
153 // No need to keep around the openBMC event log entry
154 scheduleObmcLogDelete(obmcLogID);
Sumit Kumar2ccdcef2021-07-31 10:04:58 -0500155 return;
156 }
157 }
Sumit Kumara1e40842021-06-23 09:52:25 -0500158
Sumit Kumar3160a542021-04-26 08:07:04 -0500159 // Update System Info to Extended User Data
160 pel->updateSysInfoInExtendedUserDataSection(*_dataIface);
161
Sumit Kumar3e274432021-09-14 06:37:56 -0500162 // Check for severity 0x51 and update boot progress SRC
163 updateProgressSRC(pel);
164
Matt Spinler19e72902020-01-24 11:05:20 -0600165 try
166 {
Matt Spinlerfbdfc762023-06-30 15:15:44 -0500167 lg2::debug("Adding external PEL {ID} (BMC ID {BMCID}) to repo",
168 "ID", lg2::hex, pel->id(), "BMCID", obmcLogID);
Matt Spinler19e72902020-01-24 11:05:20 -0600169 _repo.add(pel);
Matt Spinler7e727a32020-07-07 15:00:17 -0500170
171 if (_repo.sizeWarning())
172 {
173 scheduleRepoPrune();
174 }
Matt Spinler1962e082020-08-05 13:44:53 -0500175
176 // Activate any resulting service indicators if necessary
177 auto policy = service_indicators::getPolicy(*_dataIface);
178 policy->activate(*pel);
Matt Spinler19e72902020-01-24 11:05:20 -0600179 }
Patrick Williams66491c62021-10-06 12:23:37 -0500180 catch (const std::exception& e)
Matt Spinler19e72902020-01-24 11:05:20 -0600181 {
182 // Probably a full or r/o filesystem, not much we can do.
Matt Spinlerfbdfc762023-06-30 15:15:44 -0500183 lg2::error("Unable to add PEL {ID} to Repository", "ID", lg2::hex,
184 pel->id());
Matt Spinler19e72902020-01-24 11:05:20 -0600185 }
Andrew Geissler44fc3162020-07-09 09:21:31 -0500186
Vijay Lobod354a392021-06-01 16:21:02 -0500187 updateEventId(pel);
Matt Spinler28d6ae22022-03-18 11:18:27 -0500188 updateResolution(*pel);
Matt Spinler3387eac2023-07-06 14:56:02 -0500189 serializeLogEntry(obmcLogID);
Vijay Loboafb1b462021-07-21 23:29:13 -0500190 createPELEntry(obmcLogID);
Matt Spinlerdf5cb832022-07-12 12:47:26 -0500191
192 // Check if firmware should quiesce system due to error
193 checkPelAndQuiesce(pel);
Matt Spinler19e72902020-01-24 11:05:20 -0600194 }
195 else
196 {
Matt Spinlerfbdfc762023-06-30 15:15:44 -0500197 lg2::error("Invalid PEL received from the host. BMC ID = {ID}", "ID",
198 obmcLogID);
Matt Spinler19e72902020-01-24 11:05:20 -0600199
200 AdditionalData ad;
201 ad.add("PLID", getNumberString("0x%08X", pel->plid()));
202 ad.add("OBMC_LOG_ID", std::to_string(obmcLogID));
203 ad.add("PEL_SIZE", std::to_string(pelData.size()));
204
205 std::string asciiString;
206 auto src = pel->primarySRC();
207 if (src)
208 {
209 asciiString = (*src)->asciiString();
210 }
211
212 ad.add("SRC", asciiString);
213
214 _eventLogger.log("org.open_power.Logging.Error.BadHostPEL",
215 Entry::Level::Error, ad);
Matt Spinlerfe721892020-04-02 10:28:08 -0500216
217 // Save it to a file for debug in the lab. Just keep the latest.
218 // Not adding it to the PEL because it could already be max size
219 // and don't want to truncate an already invalid PEL.
220 std::ofstream pelFile{getPELRepoPath() / "badPEL"};
221 pelFile.write(reinterpret_cast<const char*>(pelData.data()),
222 pelData.size());
Matt Spinlerd8fb5ba2022-01-25 13:01:14 -0600223
224 // No need to keep around the openBMC event log entry
225 scheduleObmcLogDelete(obmcLogID);
Matt Spinler19e72902020-01-24 11:05:20 -0600226 }
227}
228
229void Manager::addESELPEL(const std::string& esel, uint32_t obmcLogID)
230{
231 std::vector<uint8_t> data;
232
Matt Spinlerfbdfc762023-06-30 15:15:44 -0500233 lg2::debug("Adding PEL from ESEL. BMC ID = {ID}", "ID", obmcLogID);
Matt Spinler5f5352e2020-03-05 16:23:27 -0600234
Matt Spinler19e72902020-01-24 11:05:20 -0600235 try
236 {
Matt Spinlerf904caf2025-05-09 11:46:45 -0500237 data = eselToRawData(esel);
Matt Spinler19e72902020-01-24 11:05:20 -0600238 }
Patrick Williams66491c62021-10-06 12:23:37 -0500239 catch (const std::exception& e)
Matt Spinler19e72902020-01-24 11:05:20 -0600240 {
241 // Try to add it below anyway, so it follows the usual bad data path.
Matt Spinlerfbdfc762023-06-30 15:15:44 -0500242 lg2::error("Problems converting ESEL string to a byte vector");
Matt Spinler19e72902020-01-24 11:05:20 -0600243 }
244
245 addPEL(data, obmcLogID);
246}
247
248std::vector<uint8_t> Manager::eselToRawData(const std::string& esel)
249{
250 std::vector<uint8_t> data;
251 std::string byteString;
252
253 // As the eSEL string looks like: "50 48 00 ab ..." there are 3
254 // characters per raw byte, and since the actual PEL data starts
255 // at the 16th byte, the code will grab the PEL data starting at
256 // offset 48 in the string.
257 static constexpr size_t pelStart = 16 * 3;
258
259 if (esel.size() <= pelStart)
260 {
Matt Spinlerfbdfc762023-06-30 15:15:44 -0500261 lg2::error("ESEL data too short, length = {LEN}", "LEN", esel.size());
Matt Spinler19e72902020-01-24 11:05:20 -0600262 throw std::length_error("ESEL data too short");
263 }
264
265 for (size_t i = pelStart; i < esel.size(); i += 3)
266 {
267 if (i + 1 < esel.size())
268 {
269 byteString = esel.substr(i, 2);
270 data.push_back(std::stoi(byteString, nullptr, 16));
271 }
272 else
273 {
Matt Spinlerfbdfc762023-06-30 15:15:44 -0500274 lg2::error("ESEL data too short, length = {LEN}", "LEN",
275 esel.size());
Matt Spinler19e72902020-01-24 11:05:20 -0600276 throw std::length_error("ESEL data too short");
277 }
278 }
279
280 return data;
281}
282
Matt Spinler4e8078c2019-07-09 13:22:32 -0500283void Manager::erase(uint32_t obmcLogID)
284{
Matt Spinler475e5742019-07-18 16:09:49 -0500285 Repository::LogID id{Repository::LogID::Obmc(obmcLogID)};
286
Vijay Loboafb1b462021-07-21 23:29:13 -0500287 auto path = std::string(OBJ_ENTRY) + '/' + std::to_string(obmcLogID);
288 _pelEntries.erase(path);
Matt Spinler475e5742019-07-18 16:09:49 -0500289 _repo.remove(id);
Matt Spinler4e8078c2019-07-09 13:22:32 -0500290}
291
harsh-agarwal1d763db32024-09-03 09:18:50 -0500292void Manager::getLogIDWithHwIsolation(std::vector<uint32_t>& idsWithHwIsoEntry)
Matt Spinler4e8078c2019-07-09 13:22:32 -0500293{
harsh-agarwal1d763db32024-09-03 09:18:50 -0500294 idsWithHwIsoEntry = _dataIface->getLogIDWithHwIsolation();
295}
296
297bool Manager::isDeleteProhibited(uint32_t obmcLogID)
298{
harsh-agarwal1760b9812025-03-18 23:23:24 -0500299 Repository::LogID id{Repository::LogID::Obmc(obmcLogID)};
300 if (!_repo.hasPEL(id))
301 {
302 return false;
303 }
harsh-agarwal1d763db32024-09-03 09:18:50 -0500304 auto entryPath{std::string(OBJ_ENTRY) + '/' + std::to_string(obmcLogID)};
305 auto entry = _pelEntries.find(entryPath);
306 if (entry != _pelEntries.end())
307 {
308 if (entry->second->guard())
309 {
310 auto hwIsolationAssocPaths = _dataIface->getAssociatedPaths(
311 entryPath += "/isolated_hw_entry", "/", 0,
312 {"xyz.openbmc_project.HardwareIsolation.Entry"});
313 if (!hwIsolationAssocPaths.empty())
314 {
315 return true;
316 }
317 }
318 }
Matt Spinler4e8078c2019-07-09 13:22:32 -0500319 return false;
320}
321
Matt Spinler56ad2a02020-03-26 14:00:52 -0500322PelFFDC Manager::convertToPelFFDC(const FFDCEntries& ffdc)
323{
324 PelFFDC pelFFDC;
325
326 std::for_each(ffdc.begin(), ffdc.end(), [&pelFFDC](const auto& f) {
327 PelFFDCfile pf;
328 pf.subType = std::get<ffdcSubtypePos>(f);
329 pf.version = std::get<ffdcVersionPos>(f);
330 pf.fd = std::get<ffdcFDPos>(f);
331
332 switch (std::get<ffdcFormatPos>(f))
333 {
334 case Create::FFDCFormat::JSON:
335 pf.format = UserDataFormat::json;
336 break;
337 case Create::FFDCFormat::CBOR:
338 pf.format = UserDataFormat::cbor;
339 break;
340 case Create::FFDCFormat::Text:
341 pf.format = UserDataFormat::text;
342 break;
343 case Create::FFDCFormat::Custom:
344 pf.format = UserDataFormat::custom;
345 break;
346 }
347
348 pelFFDC.push_back(pf);
349 });
350
351 return pelFFDC;
352}
353
Patrick Williams075c7922024-08-16 15:19:49 -0400354void Manager::createPEL(
355 const std::string& message, uint32_t obmcLogID, uint64_t timestamp,
356 phosphor::logging::Entry::Level severity,
Patrick Williamse5940632024-11-22 20:47:58 -0500357 const std::map<std::string, std::string>& additionalData,
Patrick Williams075c7922024-08-16 15:19:49 -0400358 const std::vector<std::string>& /*associations*/, const FFDCEntries& ffdc)
Matt Spinler4e8078c2019-07-09 13:22:32 -0500359{
Matt Spinler085efbb2025-07-18 12:54:39 -0500360 auto start = std::chrono::steady_clock::now();
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800361 auto entry = _registry.lookup(message, rg::LookupType::name);
Matt Spinler30ddc9f2020-07-16 15:39:59 -0500362 auto pelFFDC = convertToPelFFDC(ffdc);
363 AdditionalData ad{additionalData};
Matt Spinler1d4c74a2019-12-16 14:40:21 -0600364 std::string msg;
Matt Spinler67456c22019-10-21 12:22:49 -0500365
Matt Spinler30ddc9f2020-07-16 15:39:59 -0500366 if (!entry)
Matt Spinler67456c22019-10-21 12:22:49 -0500367 {
Matt Spinler30ddc9f2020-07-16 15:39:59 -0500368 // Instead, get the default entry that means there is no
369 // other matching entry. This error will still use the
370 // AdditionalData values of the original error, and this
371 // code will add the error message value that wasn't found
372 // to this AD. This way, there will at least be a PEL,
373 // possibly with callouts, to allow users to debug the
374 // issue that caused the error even without its own PEL.
Matt Spinlerfbdfc762023-06-30 15:15:44 -0500375 lg2::error("Event not found in PEL message registry: {MSG}", "MSG",
376 message);
Matt Spinler30ddc9f2020-07-16 15:39:59 -0500377
378 entry = _registry.lookup(defaultLogMessage, rg::LookupType::name);
379 if (!entry)
380 {
Matt Spinlerfbdfc762023-06-30 15:15:44 -0500381 lg2::error("Default event not found in PEL message registry");
Matt Spinler30ddc9f2020-07-16 15:39:59 -0500382 return;
383 }
384
385 ad.add(additional_data::error, message);
386 }
387
388 auto pel = std::make_unique<openpower::pels::PEL>(
Matt Spinler9d921092022-12-15 11:54:49 -0600389 *entry, obmcLogID, timestamp, severity, ad, pelFFDC, *_dataIface,
390 *_journal);
Matt Spinler30ddc9f2020-07-16 15:39:59 -0500391
392 _repo.add(pel);
393
394 if (_repo.sizeWarning())
395 {
396 scheduleRepoPrune();
397 }
398
Sumit Kumar3e274432021-09-14 06:37:56 -0500399 // Check for severity 0x51 and update boot progress SRC
400 updateProgressSRC(pel);
401
Matt Spinler1962e082020-08-05 13:44:53 -0500402 // Activate any resulting service indicators if necessary
403 auto policy = service_indicators::getPolicy(*_dataIface);
404 policy->activate(*pel);
Andrew Geissler44fc3162020-07-09 09:21:31 -0500405
Matt Spinler8b81ec02022-07-12 13:25:37 -0500406 updateDBusSeverity(*pel);
Vijay Lobod354a392021-06-01 16:21:02 -0500407 updateEventId(pel);
Matt Spinler28d6ae22022-03-18 11:18:27 -0500408 updateResolution(*pel);
Matt Spinler3387eac2023-07-06 14:56:02 -0500409 serializeLogEntry(obmcLogID);
Vijay Loboafb1b462021-07-21 23:29:13 -0500410 createPELEntry(obmcLogID);
Matt Spinlerdf5cb832022-07-12 12:47:26 -0500411
Matt Spinler085efbb2025-07-18 12:54:39 -0500412 auto src = pel->primarySRC();
413 if (src)
414 {
415 auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(
416 std::chrono::steady_clock::now() - start);
417
418 auto asciiString = (*src)->asciiString();
419 while (asciiString.back() == ' ')
420 {
421 asciiString.pop_back();
422 }
423 lg2::info("Created PEL {ID} (BMC ID {BMCID}) with SRC {SRC}", "ID",
424 lg2::hex, pel->id(), "BMCID", pel->obmcLogID(), "SRC",
425 asciiString, "PEL_CREATE_DURATION", duration.count());
426 }
427
Matt Spinlerdf5cb832022-07-12 12:47:26 -0500428 // Check if firmware should quiesce system due to error
429 checkPelAndQuiesce(pel);
Matt Spinler4e8078c2019-07-09 13:22:32 -0500430}
431
Matt Spinlera34ab722019-12-16 10:39:32 -0600432sdbusplus::message::unix_fd Manager::getPEL(uint32_t pelID)
433{
434 Repository::LogID id{Repository::LogID::Pel(pelID)};
435 std::optional<int> fd;
436
Matt Spinlerfbdfc762023-06-30 15:15:44 -0500437 lg2::debug("getPEL {ID}", "ID", lg2::hex, pelID);
Matt Spinler5f5352e2020-03-05 16:23:27 -0600438
Matt Spinlera34ab722019-12-16 10:39:32 -0600439 try
440 {
441 fd = _repo.getPELFD(id);
442 }
Patrick Williams66491c62021-10-06 12:23:37 -0500443 catch (const std::exception& e)
Matt Spinlera34ab722019-12-16 10:39:32 -0600444 {
445 throw common_error::InternalFailure();
446 }
447
448 if (!fd)
449 {
450 throw common_error::InvalidArgument();
451 }
452
Matt Spinler6b1a5c82020-01-07 08:48:53 -0600453 scheduleFDClose(*fd);
454
Matt Spinlera34ab722019-12-16 10:39:32 -0600455 return *fd;
456}
457
Matt Spinler6b1a5c82020-01-07 08:48:53 -0600458void Manager::scheduleFDClose(int fd)
459{
460 _fdCloserEventSource = std::make_unique<sdeventplus::source::Defer>(
Matt Spinlerff9cec22020-07-15 13:06:35 -0500461 _event, std::bind(std::mem_fn(&Manager::closeFD), this, fd,
462 std::placeholders::_1));
Matt Spinler6b1a5c82020-01-07 08:48:53 -0600463}
464
Patrick Williamsd26fa3e2021-04-21 15:22:23 -0500465void Manager::closeFD(int fd, sdeventplus::source::EventBase& /*source*/)
Matt Spinler6b1a5c82020-01-07 08:48:53 -0600466{
467 close(fd);
468 _fdCloserEventSource.reset();
469}
470
Matt Spinlera34ab722019-12-16 10:39:32 -0600471std::vector<uint8_t> Manager::getPELFromOBMCID(uint32_t obmcLogID)
472{
473 Repository::LogID id{Repository::LogID::Obmc(obmcLogID)};
474 std::optional<std::vector<uint8_t>> data;
475
Matt Spinlerfbdfc762023-06-30 15:15:44 -0500476 lg2::debug("getPELFromOBMCID {BMCID}", "BMCID", obmcLogID);
Matt Spinler5f5352e2020-03-05 16:23:27 -0600477
Matt Spinlera34ab722019-12-16 10:39:32 -0600478 try
479 {
480 data = _repo.getPELData(id);
481 }
Patrick Williams66491c62021-10-06 12:23:37 -0500482 catch (const std::exception& e)
Matt Spinlera34ab722019-12-16 10:39:32 -0600483 {
484 throw common_error::InternalFailure();
485 }
486
487 if (!data)
488 {
489 throw common_error::InvalidArgument();
490 }
491
492 return *data;
493}
494
495void Manager::hostAck(uint32_t pelID)
496{
497 Repository::LogID id{Repository::LogID::Pel(pelID)};
498
Matt Spinlerfbdfc762023-06-30 15:15:44 -0500499 lg2::debug("HostHack {ID}", "ID", lg2::hex, pelID);
Matt Spinler5f5352e2020-03-05 16:23:27 -0600500
Matt Spinlera34ab722019-12-16 10:39:32 -0600501 if (!_repo.hasPEL(id))
502 {
503 throw common_error::InvalidArgument();
504 }
505
506 if (_hostNotifier)
507 {
508 _hostNotifier->ackPEL(pelID);
509 }
510}
511
512void Manager::hostReject(uint32_t pelID, RejectionReason reason)
513{
514 Repository::LogID id{Repository::LogID::Pel(pelID)};
515
Matt Spinlerfbdfc762023-06-30 15:15:44 -0500516 lg2::debug("HostReject {ID}, reason = {REASON}", "ID", lg2::hex, pelID,
517 "REASON", reason);
Matt Spinler5f5352e2020-03-05 16:23:27 -0600518
Matt Spinlera34ab722019-12-16 10:39:32 -0600519 if (!_repo.hasPEL(id))
520 {
521 throw common_error::InvalidArgument();
522 }
523
Matt Spinler05c2c6c2019-12-18 14:02:09 -0600524 if (reason == RejectionReason::BadPEL)
Matt Spinlera34ab722019-12-16 10:39:32 -0600525 {
Matt Spinler05c2c6c2019-12-18 14:02:09 -0600526 AdditionalData data;
527 data.add("BAD_ID", getNumberString("0x%08X", pelID));
528 _eventLogger.log("org.open_power.Logging.Error.SentBadPELToHost",
529 Entry::Level::Informational, data);
530 if (_hostNotifier)
Matt Spinlera34ab722019-12-16 10:39:32 -0600531 {
532 _hostNotifier->setBadPEL(pelID);
533 }
Matt Spinler05c2c6c2019-12-18 14:02:09 -0600534 }
535 else if ((reason == RejectionReason::HostFull) && _hostNotifier)
536 {
537 _hostNotifier->setHostFull(pelID);
Matt Spinlera34ab722019-12-16 10:39:32 -0600538 }
539}
540
Matt Spinler7e727a32020-07-07 15:00:17 -0500541void Manager::scheduleRepoPrune()
542{
Matt Spinler7e727a32020-07-07 15:00:17 -0500543 _repoPrunerEventSource = std::make_unique<sdeventplus::source::Defer>(
Matt Spinlerff9cec22020-07-15 13:06:35 -0500544 _event, std::bind(std::mem_fn(&Manager::pruneRepo), this,
545 std::placeholders::_1));
Matt Spinler7e727a32020-07-07 15:00:17 -0500546}
547
Patrick Williamsd26fa3e2021-04-21 15:22:23 -0500548void Manager::pruneRepo(sdeventplus::source::EventBase& /*source*/)
Matt Spinler7e727a32020-07-07 15:00:17 -0500549{
Sumit Kumar027bf282022-01-24 11:25:19 -0600550 auto idsWithHwIsoEntry = _dataIface->getLogIDWithHwIsolation();
551
552 auto idsToDelete = _repo.prune(idsWithHwIsoEntry);
Matt Spinler7e727a32020-07-07 15:00:17 -0500553
554 // Remove the OpenBMC event logs for the PELs that were just removed.
555 std::for_each(idsToDelete.begin(), idsToDelete.end(),
556 [this](auto id) { this->_logManager.erase(id); });
557
558 _repoPrunerEventSource.reset();
559}
560
Matt Spinlerff9cec22020-07-15 13:06:35 -0500561void Manager::setupPELDeleteWatch()
562{
563 _pelFileDeleteFD = inotify_init1(IN_NONBLOCK);
564 if (-1 == _pelFileDeleteFD)
565 {
566 auto e = errno;
Matt Spinlerfbdfc762023-06-30 15:15:44 -0500567 lg2::error("inotify_init1 failed with errno {ERRNO}", "ERRNO", e);
Matt Spinlerff9cec22020-07-15 13:06:35 -0500568 abort();
569 }
570
571 _pelFileDeleteWatchFD = inotify_add_watch(
572 _pelFileDeleteFD, _repo.repoPath().c_str(), IN_DELETE);
573 if (-1 == _pelFileDeleteWatchFD)
574 {
575 auto e = errno;
Matt Spinlerfbdfc762023-06-30 15:15:44 -0500576 lg2::error("inotify_add_watch failed with errno {ERRNO}", "ERRNO", e);
Matt Spinlerff9cec22020-07-15 13:06:35 -0500577 abort();
578 }
579
580 _pelFileDeleteEventSource = std::make_unique<sdeventplus::source::IO>(
581 _event, _pelFileDeleteFD, EPOLLIN,
582 std::bind(std::mem_fn(&Manager::pelFileDeleted), this,
583 std::placeholders::_1, std::placeholders::_2,
584 std::placeholders::_3));
585}
586
Patrick Williamsd26fa3e2021-04-21 15:22:23 -0500587void Manager::pelFileDeleted(sdeventplus::source::IO& /*io*/, int /*fd*/,
Matt Spinlerff9cec22020-07-15 13:06:35 -0500588 uint32_t revents)
589{
590 if (!(revents & EPOLLIN))
591 {
592 return;
593 }
594
595 // An event for 1 PEL uses 48B. When all PELs are deleted at once,
596 // as many events as there is room for can be handled in one callback.
597 // A size of 2000 will allow 41 to be processed, with additional
598 // callbacks being needed to process the remaining ones.
Matt Spinler9d59d582021-05-19 07:57:10 -0600599 std::array<uint8_t, 2000> data{};
Matt Spinlerff9cec22020-07-15 13:06:35 -0500600 auto bytesRead = read(_pelFileDeleteFD, data.data(), data.size());
601 if (bytesRead < 0)
602 {
603 auto e = errno;
Matt Spinlerfbdfc762023-06-30 15:15:44 -0500604 lg2::error("Failed reading data from inotify event, errno = {ERRNO}",
605 "ERRNO", e);
Matt Spinlerff9cec22020-07-15 13:06:35 -0500606 abort();
607 }
608
609 auto offset = 0;
610 while (offset < bytesRead)
611 {
612 auto event = reinterpret_cast<inotify_event*>(&data[offset]);
613 if (event->mask & IN_DELETE)
614 {
615 std::string filename{event->name};
616
617 // Get the PEL ID from the filename and tell the
618 // repo it's been removed, and then delete the BMC
619 // event log if it's there.
620 auto pos = filename.find_first_of('_');
621 if (pos != std::string::npos)
622 {
623 try
624 {
625 auto idString = filename.substr(pos + 1);
626 auto pelID = std::stoul(idString, nullptr, 16);
627
628 Repository::LogID id{Repository::LogID::Pel(pelID)};
629 auto removedLogID = _repo.remove(id);
630 if (removedLogID)
631 {
632 _logManager.erase(removedLogID->obmcID.id);
633 }
634 }
635 catch (const std::exception& e)
636 {
Matt Spinlerfbdfc762023-06-30 15:15:44 -0500637 lg2::info("Could not find PEL ID from its filename {NAME}",
638 "NAME", filename);
Matt Spinlerff9cec22020-07-15 13:06:35 -0500639 }
640 }
641 }
642
643 offset += offsetof(inotify_event, name) + event->len;
644 }
645}
Matt Spinler9cc30072020-09-16 15:39:34 -0500646
647std::tuple<uint32_t, uint32_t> Manager::createPELWithFFDCFiles(
648 std::string message, Entry::Level severity,
649 std::map<std::string, std::string> additionalData,
650 std::vector<std::tuple<
Willy Tu6ddbf692023-09-05 10:54:16 -0700651 sdbusplus::server::xyz::openbmc_project::logging::Create::FFDCFormat,
Matt Spinler9cc30072020-09-16 15:39:34 -0500652 uint8_t, uint8_t, sdbusplus::message::unix_fd>>
653 fFDC)
654{
Paul Fertser221b79b2024-03-04 15:40:23 +0000655 _logManager.create(message, severity, additionalData, fFDC);
Matt Spinler44893cc2020-08-26 11:34:17 -0500656
657 return {_logManager.lastEntryID(), _repo.lastPelID()};
Matt Spinler9cc30072020-09-16 15:39:34 -0500658}
659
Matt Spinler8bd4ca42022-04-01 16:06:06 -0500660std::string Manager::getPELJSON(uint32_t obmcLogID)
Matt Spinleraa85a072022-03-23 11:26:41 -0500661{
Matt Spinler8bd4ca42022-04-01 16:06:06 -0500662 // Throws InvalidArgument if not found
663 auto pelID = getPELIdFromBMCLogId(obmcLogID);
664
Jayanth Othayoth1aa90d42023-09-13 04:25:45 -0500665 auto cmd = std::format("/usr/bin/peltool -i {:#x}", pelID);
Matt Spinler8bd4ca42022-04-01 16:06:06 -0500666
667 FILE* pipe = popen(cmd.c_str(), "r");
668 if (!pipe)
669 {
Matt Spinlerfbdfc762023-06-30 15:15:44 -0500670 lg2::error("Error running cmd: {CMD}", "CMD", cmd);
Matt Spinler8bd4ca42022-04-01 16:06:06 -0500671 throw common_error::InternalFailure();
672 }
673
674 std::string output;
675 std::array<char, 1024> buffer;
676 while (fgets(buffer.data(), buffer.size(), pipe) != nullptr)
677 {
678 output.append(buffer.data());
679 }
680
681 int rc = pclose(pipe);
682 if (WEXITSTATUS(rc) != 0)
683 {
Matt Spinlerfbdfc762023-06-30 15:15:44 -0500684 lg2::error("Error running cmd: {CMD}, rc = {RC}", "CMD", cmd, "RC", rc);
Matt Spinler8bd4ca42022-04-01 16:06:06 -0500685 throw common_error::InternalFailure();
686 }
687
688 return output;
Matt Spinleraa85a072022-03-23 11:26:41 -0500689}
690
Andrew Geissler44fc3162020-07-09 09:21:31 -0500691void Manager::checkPelAndQuiesce(std::unique_ptr<openpower::pels::PEL>& pel)
692{
Matt Spinlerb2abc042021-05-17 15:32:50 -0600693 if ((pel->userHeader().severity() ==
694 static_cast<uint8_t>(SeverityType::nonError)) ||
695 (pel->userHeader().severity() ==
696 static_cast<uint8_t>(SeverityType::recovered)))
Andrew Geissler44fc3162020-07-09 09:21:31 -0500697 {
Matt Spinlerfbdfc762023-06-30 15:15:44 -0500698 lg2::debug(
Matt Spinlerb2abc042021-05-17 15:32:50 -0600699 "PEL severity informational or recovered. no quiesce needed");
Andrew Geissler44fc3162020-07-09 09:21:31 -0500700 return;
701 }
702 if (!_logManager.isQuiesceOnErrorEnabled())
703 {
Matt Spinlerfbdfc762023-06-30 15:15:44 -0500704 lg2::debug("QuiesceOnHwError not enabled, no quiesce needed");
Andrew Geissler44fc3162020-07-09 09:21:31 -0500705 return;
706 }
707
Matt Spinler845c6242022-03-01 16:45:08 -0600708 CreatorID creatorID{pel->privateHeader().creatorID()};
709
710 if ((creatorID != CreatorID::openBMC) &&
711 (creatorID != CreatorID::hostboot) &&
712 (creatorID != CreatorID::ioDrawer) && (creatorID != CreatorID::occ) &&
713 (creatorID != CreatorID::phyp))
714 {
715 return;
716 }
717
Andrew Geissler44fc3162020-07-09 09:21:31 -0500718 // Now check if it has any type of callout
Andrew Geisslerf8e750d2022-01-14 14:56:13 -0600719 if (pel->isHwCalloutPresent())
Andrew Geissler44fc3162020-07-09 09:21:31 -0500720 {
Matt Spinlerfbdfc762023-06-30 15:15:44 -0500721 lg2::info(
Matt Spinlerb2abc042021-05-17 15:32:50 -0600722 "QuiesceOnHwError enabled, PEL severity not nonError or recovered, "
723 "and callout is present");
Andrew Geissler44fc3162020-07-09 09:21:31 -0500724
725 _logManager.quiesceOnError(pel->obmcLogID());
726 }
727}
728
Vijay Lobod354a392021-06-01 16:21:02 -0500729std::string Manager::getEventId(const openpower::pels::PEL& pel) const
730{
731 std::string str;
732 auto src = pel.primarySRC();
733 if (src)
734 {
735 const auto& hexwords = (*src)->hexwordData();
736
737 std::string refcode = (*src)->asciiString();
738 size_t pos = refcode.find_last_not_of(0x20);
739 if (pos != std::string::npos)
740 {
741 refcode.erase(pos + 1);
742 }
743 str = refcode;
744
745 for (auto& value : hexwords)
746 {
747 str += " ";
748 str += getNumberString("%08X", value);
749 }
750 }
Matt Spinler0003af12022-06-08 10:46:17 -0500751 return sanitizeFieldForDBus(str);
Vijay Lobod354a392021-06-01 16:21:02 -0500752}
753
754void Manager::updateEventId(std::unique_ptr<openpower::pels::PEL>& pel)
755{
756 std::string eventIdStr = getEventId(*pel);
757
758 auto entryN = _logManager.entries.find(pel->obmcLogID());
759 if (entryN != _logManager.entries.end())
760 {
Matt Spinlerb25e8a32023-06-07 16:05:36 -0500761 entryN->second->eventId(eventIdStr, true);
Vijay Lobod354a392021-06-01 16:21:02 -0500762 }
763}
764
Matt Spinler0003af12022-06-08 10:46:17 -0500765std::string Manager::sanitizeFieldForDBus(std::string field)
766{
767 std::for_each(field.begin(), field.end(), [](char& ch) {
768 if (((ch < ' ') || (ch > '~')) && (ch != '\n') && (ch != '\t'))
769 {
770 ch = ' ';
771 }
772 });
773 return field;
774}
775
Vijay Lobo593a4c62021-06-16 14:25:26 -0500776std::string Manager::getResolution(const openpower::pels::PEL& pel) const
777{
778 std::string str;
779 std::string resolution;
780 auto src = pel.primarySRC();
781 if (src)
782 {
783 // First extract the callout pointer and then go through
784 const auto& callouts = (*src)->callouts();
785 namespace pv = openpower::pels::pel_values;
786 // All PELs dont have callout, check before parsing callout data
787 if (callouts)
788 {
789 const auto& entries = callouts->callouts();
790 // Entry starts with index 1
791 uint8_t index = 1;
792 for (auto& entry : entries)
793 {
794 resolution += std::to_string(index) + ". ";
795 // Adding Location code to resolution
796 if (!entry->locationCode().empty())
Patrick Williams2544b412022-10-04 08:41:06 -0500797 resolution += "Location Code: " + entry->locationCode() +
798 ", ";
Vijay Lobo593a4c62021-06-16 14:25:26 -0500799 if (entry->fruIdentity())
800 {
801 // Get priority and set the resolution string
802 str = pv::getValue(entry->priority(),
803 pel_values::calloutPriorityValues,
804 pel_values::registryNamePos);
805 str[0] = toupper(str[0]);
806 resolution += "Priority: " + str + ", ";
807 if (entry->fruIdentity()->getPN().has_value())
808 {
809 resolution +=
810 "PN: " + entry->fruIdentity()->getPN().value() +
811 ", ";
812 }
813 if (entry->fruIdentity()->getSN().has_value())
814 {
815 resolution +=
816 "SN: " + entry->fruIdentity()->getSN().value() +
817 ", ";
818 }
819 if (entry->fruIdentity()->getCCIN().has_value())
820 {
821 resolution +=
822 "CCIN: " + entry->fruIdentity()->getCCIN().value() +
823 ", ";
824 }
825 // Add the maintenance procedure
826 if (entry->fruIdentity()->getMaintProc().has_value())
827 {
828 resolution +=
829 "Procedure: " +
830 entry->fruIdentity()->getMaintProc().value() + ", ";
831 }
832 }
833 resolution.resize(resolution.size() - 2);
834 resolution += "\n";
835 index++;
836 }
837 }
838 }
Matt Spinler0003af12022-06-08 10:46:17 -0500839 return sanitizeFieldForDBus(resolution);
Vijay Lobo593a4c62021-06-16 14:25:26 -0500840}
841
Matt Spinler28d6ae22022-03-18 11:18:27 -0500842bool Manager::updateResolution(const openpower::pels::PEL& pel)
Vijay Lobo593a4c62021-06-16 14:25:26 -0500843{
Matt Spinler28d6ae22022-03-18 11:18:27 -0500844 std::string callouts = getResolution(pel);
845 auto entryN = _logManager.entries.find(pel.obmcLogID());
Vijay Lobo593a4c62021-06-16 14:25:26 -0500846 if (entryN != _logManager.entries.end())
847 {
Matt Spinler734ed2b2022-01-21 09:31:46 -0600848 entryN->second->resolution(callouts, true);
Vijay Lobo593a4c62021-06-16 14:25:26 -0500849 }
Matt Spinler28d6ae22022-03-18 11:18:27 -0500850
851 return false;
Vijay Lobo593a4c62021-06-16 14:25:26 -0500852}
853
Matt Spinler3387eac2023-07-06 14:56:02 -0500854void Manager::serializeLogEntry(uint32_t obmcLogID)
855{
856 auto entryN = _logManager.entries.find(obmcLogID);
857 if (entryN != _logManager.entries.end())
858 {
859 serialize(*entryN->second);
860 }
861}
862
Matt Spinler8b81ec02022-07-12 13:25:37 -0500863void Manager::updateDBusSeverity(const openpower::pels::PEL& pel)
864{
865 // The final severity of the PEL may not agree with the
866 // original severity of the D-Bus event log. Update the
867 // D-Bus property to match in some cases. This is to
868 // ensure there isn't a Critical or Warning Redfish event
869 // log for an informational or recovered PEL (or vice versa).
870 // This doesn't make an explicit call to serialize the new
871 // event log property value because updateEventId() is called
872 // right after this and will do it.
873 auto sevType =
874 static_cast<SeverityType>(pel.userHeader().severity() & 0xF0);
875
876 auto entryN = _logManager.entries.find(pel.obmcLogID());
877 if (entryN != _logManager.entries.end())
878 {
Patrick Williams075c7922024-08-16 15:19:49 -0400879 auto newSeverity =
880 fixupLogSeverity(entryN->second->severity(), sevType);
Matt Spinler8b81ec02022-07-12 13:25:37 -0500881 if (newSeverity)
882 {
Matt Spinlerfbdfc762023-06-30 15:15:44 -0500883 lg2::info("Changing event log {ID} severity from {OLD} "
884 "to {NEW} to match PEL",
885 "ID", lg2::hex, entryN->second->id(), "OLD",
886 Entry::convertLevelToString(entryN->second->severity()),
887 "NEW", Entry::convertLevelToString(*newSeverity));
Matt Spinler8b81ec02022-07-12 13:25:37 -0500888
889 entryN->second->severity(*newSeverity, true);
890 }
891 }
892}
893
Adriana Kobylake7d271a2020-12-07 14:32:44 -0600894void Manager::setEntryPath(uint32_t obmcLogID)
895{
896 Repository::LogID id{Repository::LogID::Obmc(obmcLogID)};
897 if (auto attributes = _repo.getPELAttributes(id); attributes)
898 {
899 auto& attr = attributes.value().get();
900 auto entry = _logManager.entries.find(obmcLogID);
901 if (entry != _logManager.entries.end())
902 {
Matt Spinler734ed2b2022-01-21 09:31:46 -0600903 entry->second->path(attr.path, true);
Adriana Kobylake7d271a2020-12-07 14:32:44 -0600904 }
905 }
906}
907
Vijay Lobocbc93a42021-05-20 19:04:07 -0500908void Manager::setServiceProviderNotifyFlag(uint32_t obmcLogID)
909{
910 Repository::LogID id{Repository::LogID::Obmc(obmcLogID)};
911 if (auto attributes = _repo.getPELAttributes(id); attributes)
912 {
913 auto& attr = attributes.value().get();
914 auto entry = _logManager.entries.find(obmcLogID);
915 if (entry != _logManager.entries.end())
916 {
Lakshmi Yadlapati7a3ede52022-11-18 13:26:17 -0600917 if (attr.actionFlags.test(callHomeFlagBit))
918 {
Matt Spinlerb25e8a32023-06-07 16:05:36 -0500919 entry->second->serviceProviderNotify(Entry::Notify::Notify,
920 true);
Lakshmi Yadlapati7a3ede52022-11-18 13:26:17 -0600921 }
922 else
923 {
Matt Spinlerb25e8a32023-06-07 16:05:36 -0500924 entry->second->serviceProviderNotify(Entry::Notify::Inhibit,
925 true);
Lakshmi Yadlapati7a3ede52022-11-18 13:26:17 -0600926 }
Vijay Lobocbc93a42021-05-20 19:04:07 -0500927 }
928 }
929}
930
Matt Spinler734ed2b2022-01-21 09:31:46 -0600931void Manager::createPELEntry(uint32_t obmcLogID, bool skipIaSignal)
Vijay Loboafb1b462021-07-21 23:29:13 -0500932{
933 std::map<std::string, PropertiesVariant> varData;
934 Repository::LogID id{Repository::LogID::Obmc(obmcLogID)};
935 if (auto attributes = _repo.getPELAttributes(id); attributes)
936 {
937 namespace pv = openpower::pels::pel_values;
938 auto& attr = attributes.value().get();
Vijay Lobob2e541e2021-08-31 23:12:47 -0500939
940 // get the hidden flag values
941 auto sevType = static_cast<SeverityType>(attr.severity & 0xF0);
942 auto isHidden = true;
943 if (((sevType != SeverityType::nonError) &&
944 attr.actionFlags.test(reportFlagBit) &&
945 !attr.actionFlags.test(hiddenFlagBit)) ||
946 ((sevType == SeverityType::nonError) &&
947 attr.actionFlags.test(serviceActionFlagBit)))
948 {
949 isHidden = false;
950 }
951 varData.emplace(std::string("Hidden"), isHidden);
Vijay Loboafb1b462021-07-21 23:29:13 -0500952 varData.emplace(
953 std::string("Subsystem"),
954 pv::getValue(attr.subsystem, pel_values::subsystemValues));
Vijay Lobo2fb10212021-08-22 23:24:16 -0500955
956 varData.emplace(
957 std::string("ManagementSystemAck"),
958 (attr.hmcState == TransmissionState::acked ? true : false));
959
Matt Spinler8e65f4e2023-05-02 13:40:08 -0500960 varData.emplace("PlatformLogID", attr.plid);
961 varData.emplace("Deconfig", attr.deconfig);
962 varData.emplace("Guard", attr.guard);
963 varData.emplace("Timestamp", attr.creationTime);
964
Vijay Loboafb1b462021-07-21 23:29:13 -0500965 // Path to create PELEntry Interface is same as PEL
966 auto path = std::string(OBJ_ENTRY) + '/' + std::to_string(obmcLogID);
967 // Create Interface for PELEntry and set properties
Vijay Lobo2fb10212021-08-22 23:24:16 -0500968 auto pelEntry = std::make_unique<PELEntry>(_logManager.getBus(), path,
969 varData, obmcLogID, &_repo);
Matt Spinler734ed2b2022-01-21 09:31:46 -0600970 if (!skipIaSignal)
971 {
972 pelEntry->emit_added();
973 }
Vijay Loboafb1b462021-07-21 23:29:13 -0500974 _pelEntries.emplace(std::move(path), std::move(pelEntry));
975 }
976}
977
Ramesh Iyyarf4203c42021-06-24 06:09:23 -0500978uint32_t Manager::getPELIdFromBMCLogId(uint32_t bmcLogId)
979{
980 Repository::LogID id{Repository::LogID::Obmc(bmcLogId)};
981 if (auto logId = _repo.getLogID(id); !logId.has_value())
982 {
983 throw common_error::InvalidArgument();
984 }
985 else
986 {
987 return logId->pelID.id;
988 }
989}
990
Ramesh Iyyar530efbf2021-06-24 06:22:22 -0500991uint32_t Manager::getBMCLogIdFromPELId(uint32_t pelId)
992{
993 Repository::LogID id{Repository::LogID::Pel(pelId)};
994 if (auto logId = _repo.getLogID(id); !logId.has_value())
995 {
996 throw common_error::InvalidArgument();
997 }
998 else
999 {
1000 return logId->obmcID.id;
1001 }
1002}
1003
Patrick Williams25291152025-02-01 08:21:42 -05001004void Manager::updateProgressSRC(
1005 std::unique_ptr<openpower::pels::PEL>& pel) const
Sumit Kumar3e274432021-09-14 06:37:56 -05001006{
Matt Spinler931cafe2025-04-22 12:31:28 -05001007 const size_t refcodeBegin = 40;
1008 const size_t refcodeSize = 8;
1009
Sumit Kumar3e274432021-09-14 06:37:56 -05001010 // Check for pel severity of type - 0x51 = critical error, system
1011 // termination
1012 if (pel->userHeader().severity() == 0x51)
1013 {
1014 auto src = pel->primarySRC();
1015 if (src)
1016 {
1017 std::vector<uint8_t> asciiSRC = (*src)->getSrcStruct();
Sumit Kumar3e274432021-09-14 06:37:56 -05001018
Matt Spinler931cafe2025-04-22 12:31:28 -05001019 if (asciiSRC.size() < (refcodeBegin + refcodeSize))
Sumit Kumar3e274432021-09-14 06:37:56 -05001020 {
Matt Spinler931cafe2025-04-22 12:31:28 -05001021 lg2::error(
1022 "SRC struct is too short to get progress code ({SIZE})",
1023 "SIZE", asciiSRC.size());
1024 return;
Sumit Kumar3e274432021-09-14 06:37:56 -05001025 }
1026
Matt Spinler931cafe2025-04-22 12:31:28 -05001027 // Pull the ASCII SRC from offset [40-47] e.g. BD8D1001
1028 std::vector<uint8_t> srcRefCode(
1029 asciiSRC.begin() + refcodeBegin,
1030 asciiSRC.begin() + refcodeBegin + refcodeSize);
1031
Sumit Kumar3e274432021-09-14 06:37:56 -05001032 try
1033 {
1034 _dataIface->createProgressSRC(srcRefCode, asciiSRC);
1035 }
Matt Spinler87f39242023-05-01 11:36:18 -05001036 catch (const std::exception&)
Sumit Kumar3e274432021-09-14 06:37:56 -05001037 {
1038 // Exception - may be no boot progress interface on dbus
1039 }
1040 }
1041 }
1042}
1043
Matt Spinlerd8fb5ba2022-01-25 13:01:14 -06001044void Manager::scheduleObmcLogDelete(uint32_t obmcLogID)
1045{
1046 _obmcLogDeleteEventSource = std::make_unique<sdeventplus::source::Defer>(
1047 _event, std::bind(std::mem_fn(&Manager::deleteObmcLog), this,
1048 std::placeholders::_1, obmcLogID));
1049}
1050
1051void Manager::deleteObmcLog(sdeventplus::source::EventBase&, uint32_t obmcLogID)
1052{
Matt Spinlerfbdfc762023-06-30 15:15:44 -05001053 lg2::info("Removing event log with no PEL: {BMCID}", "BMCID", obmcLogID);
Matt Spinlerd8fb5ba2022-01-25 13:01:14 -06001054 _logManager.erase(obmcLogID);
1055 _obmcLogDeleteEventSource.reset();
1056}
1057
Matt Spinler0dd22c82023-05-04 15:28:12 -05001058bool Manager::clearPowerThermalDeconfigFlag(const std::string& locationCode,
1059 openpower::pels::PEL& pel)
1060{
1061 // The requirements state that only power-thermal or
1062 // fan PELs need their deconfig flag cleared.
1063 static const std::vector<uint32_t> compIDs{bmcThermalCompID, bmcFansCompID};
1064
1065 if (std::find(compIDs.begin(), compIDs.end(),
1066 pel.privateHeader().header().componentID) == compIDs.end())
1067 {
1068 return false;
1069 }
1070
1071 auto src = pel.primarySRC();
1072 const auto& callouts = (*src)->callouts();
1073 if (!callouts)
1074 {
1075 return false;
1076 }
1077
1078 for (const auto& callout : callouts->callouts())
1079 {
1080 // Look for the passed in location code in a callout that
1081 // is either a normal HW callout or a symbolic FRU with
1082 // a trusted location code callout.
1083 if ((callout->locationCode() != locationCode) ||
1084 !callout->fruIdentity())
1085 {
1086 continue;
1087 }
1088
1089 if ((callout->fruIdentity()->failingComponentType() !=
1090 src::FRUIdentity::hardwareFRU) &&
1091 (callout->fruIdentity()->failingComponentType() !=
1092 src::FRUIdentity::symbolicFRUTrustedLocCode))
1093 {
1094 continue;
1095 }
1096
Matt Spinlerfbdfc762023-06-30 15:15:44 -05001097 lg2::info(
1098 "Clearing deconfig flag in PEL {ID} with SRC {SRC} because {LOC} was replaced",
1099 "ID", lg2::hex, pel.id(), "SRC", (*src)->asciiString().substr(0, 8),
1100 "LOC", locationCode);
Matt Spinler0dd22c82023-05-04 15:28:12 -05001101 (*src)->clearErrorStatusFlag(SRC::ErrorStatusFlags::deconfigured);
1102 return true;
1103 }
1104 return false;
1105}
1106
1107void Manager::hardwarePresent(const std::string& locationCode)
1108{
1109 Repository::PELUpdateFunc handlePowerThermalHardwarePresent =
1110 [locationCode](openpower::pels::PEL& pel) {
Patrick Williams075c7922024-08-16 15:19:49 -04001111 return Manager::clearPowerThermalDeconfigFlag(locationCode, pel);
1112 };
Matt Spinler0dd22c82023-05-04 15:28:12 -05001113
1114 // If the PEL was created by the BMC and has the deconfig flag set,
1115 // it's a candidate to have the deconfig flag cleared.
1116 for (const auto& [id, attributes] : _repo.getAttributesMap())
1117 {
1118 if ((attributes.creator == static_cast<uint8_t>(CreatorID::openBMC)) &&
1119 attributes.deconfig)
1120 {
Matt Spinler1cb59f72023-07-20 09:49:50 -05001121 auto updated = _repo.updatePEL(attributes.path,
1122 handlePowerThermalHardwarePresent);
1123
1124 if (updated)
1125 {
1126 // Also update the property on D-Bus
1127 auto objPath = std::string(OBJ_ENTRY) + '/' +
1128 std::to_string(id.obmcID.id);
1129 auto entryN = _pelEntries.find(objPath);
1130 if (entryN != _pelEntries.end())
1131 {
1132 entryN->second->deconfig(false);
1133 }
1134 else
1135 {
1136 lg2::error(
1137 "Could not find PEL Entry D-Bus object for {PATH}",
1138 "PATH", objPath);
1139 }
1140 }
Matt Spinler0dd22c82023-05-04 15:28:12 -05001141 }
1142 }
1143}
1144
Matt Spinler4e8078c2019-07-09 13:22:32 -05001145} // namespace pels
1146} // namespace openpower