blob: abc7be4bf2183b441b7cc27db10546300df02960 [file] [log] [blame]
Matt Spinler711d51d2019-11-06 09:36:51 -06001/**
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 */
Matt Spinler4e8078c2019-07-09 13:22:32 -050016#include "manager.hpp"
17
18#include "additional_data.hpp"
Matt Spinler05c2c6c2019-12-18 14:02:09 -060019#include "json_utils.hpp"
Matt Spinler89fa0822019-07-17 13:54:30 -050020#include "pel.hpp"
Vijay Lobo2fb10212021-08-22 23:24:16 -050021#include "pel_entry.hpp"
Matt Spinler1962e082020-08-05 13:44:53 -050022#include "service_indicators.hpp"
Matt Spinler8b81ec02022-07-12 13:25:37 -050023#include "severity.hpp"
Matt Spinler89fa0822019-07-17 13:54:30 -050024
Matt Spinler22421b92020-07-17 09:41:08 -050025#include <fmt/format.h>
Matt Spinlerff9cec22020-07-15 13:06:35 -050026#include <sys/inotify.h>
Matt Spinler6b1a5c82020-01-07 08:48:53 -060027#include <unistd.h>
28
Patrick Williams2544b412022-10-04 08:41:06 -050029#include <xyz/openbmc_project/Common/error.hpp>
30#include <xyz/openbmc_project/Logging/Create/server.hpp>
31
Matt Spinler89fa0822019-07-17 13:54:30 -050032#include <filesystem>
33#include <fstream>
Matt Spinler0003af12022-06-08 10:46:17 -050034#include <locale>
Matt Spinler4e8078c2019-07-09 13:22:32 -050035
36namespace openpower
37{
38namespace pels
39{
40
41using namespace phosphor::logging;
Matt Spinler89fa0822019-07-17 13:54:30 -050042namespace fs = std::filesystem;
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +080043namespace rg = openpower::pels::message;
Matt Spinler4e8078c2019-07-09 13:22:32 -050044
Matt Spinlera34ab722019-12-16 10:39:32 -060045namespace common_error = sdbusplus::xyz::openbmc_project::Common::Error;
46
Matt Spinler56ad2a02020-03-26 14:00:52 -050047using Create = sdbusplus::xyz::openbmc_project::Logging::server::Create;
48
Matt Spinler4e8078c2019-07-09 13:22:32 -050049namespace additional_data
50{
51constexpr auto rawPEL = "RAWPEL";
Matt Spinler19e72902020-01-24 11:05:20 -060052constexpr auto esel = "ESEL";
Matt Spinler30ddc9f2020-07-16 15:39:59 -050053constexpr auto error = "ERROR_NAME";
Matt Spinler19e72902020-01-24 11:05:20 -060054} // namespace additional_data
Matt Spinler4e8078c2019-07-09 13:22:32 -050055
Matt Spinler30ddc9f2020-07-16 15:39:59 -050056constexpr auto defaultLogMessage = "xyz.openbmc_project.Logging.Error.Default";
Matt Spinler0dd22c82023-05-04 15:28:12 -050057constexpr uint32_t bmcThermalCompID = 0x2700;
58constexpr uint32_t bmcFansCompID = 0x2800;
Matt Spinler30ddc9f2020-07-16 15:39:59 -050059
Matt Spinlerff9cec22020-07-15 13:06:35 -050060Manager::~Manager()
61{
62 if (_pelFileDeleteFD != -1)
63 {
64 if (_pelFileDeleteWatchFD != -1)
65 {
66 inotify_rm_watch(_pelFileDeleteFD, _pelFileDeleteWatchFD);
67 }
68 close(_pelFileDeleteFD);
69 }
70}
71
Matt Spinler4e8078c2019-07-09 13:22:32 -050072void Manager::create(const std::string& message, uint32_t obmcLogID,
73 uint64_t timestamp, Entry::Level severity,
74 const std::vector<std::string>& additionalData,
Matt Spinler56ad2a02020-03-26 14:00:52 -050075 const std::vector<std::string>& associations,
76 const FFDCEntries& ffdc)
Matt Spinler4e8078c2019-07-09 13:22:32 -050077{
78 AdditionalData ad{additionalData};
79
Matt Spinler19e72902020-01-24 11:05:20 -060080 // If a PEL was passed in via a filename or in an ESEL,
81 // use that. Otherwise, create one.
Matt Spinler4e8078c2019-07-09 13:22:32 -050082 auto rawPelPath = ad.getValue(additional_data::rawPEL);
83 if (rawPelPath)
84 {
85 addRawPEL(*rawPelPath, obmcLogID);
86 }
87 else
88 {
Matt Spinler19e72902020-01-24 11:05:20 -060089 auto esel = ad.getValue(additional_data::esel);
90 if (esel)
91 {
92 addESELPEL(*esel, obmcLogID);
93 }
94 else
95 {
96 createPEL(message, obmcLogID, timestamp, severity, additionalData,
Matt Spinler56ad2a02020-03-26 14:00:52 -050097 associations, ffdc);
Matt Spinler19e72902020-01-24 11:05:20 -060098 }
Matt Spinler4e8078c2019-07-09 13:22:32 -050099 }
Adriana Kobylake7d271a2020-12-07 14:32:44 -0600100
101 setEntryPath(obmcLogID);
Vijay Lobocbc93a42021-05-20 19:04:07 -0500102 setServiceProviderNotifyFlag(obmcLogID);
Matt Spinler4e8078c2019-07-09 13:22:32 -0500103}
104
105void Manager::addRawPEL(const std::string& rawPelPath, uint32_t obmcLogID)
106{
Matt Spinler89fa0822019-07-17 13:54:30 -0500107 if (fs::exists(rawPelPath))
108 {
109 std::ifstream file(rawPelPath, std::ios::in | std::ios::binary);
110
111 auto data = std::vector<uint8_t>(std::istreambuf_iterator<char>(file),
112 std::istreambuf_iterator<char>());
113 if (file.fail())
114 {
115 log<level::ERR>("Filesystem error reading a raw PEL",
116 entry("PELFILE=%s", rawPelPath.c_str()),
117 entry("OBMCLOGID=%d", obmcLogID));
118 // TODO, Decide what to do here. Maybe nothing.
119 return;
120 }
121
122 file.close();
123
Matt Spinler19e72902020-01-24 11:05:20 -0600124 addPEL(data, obmcLogID);
Matt Spinler67416922021-07-19 12:34:57 -0600125
126 std::error_code ec;
127 fs::remove(rawPelPath, ec);
Matt Spinler89fa0822019-07-17 13:54:30 -0500128 }
129 else
130 {
131 log<level::ERR>("Raw PEL file from BMC event log does not exist",
132 entry("PELFILE=%s", (rawPelPath).c_str()),
133 entry("OBMCLOGID=%d", obmcLogID));
134 }
Matt Spinler4e8078c2019-07-09 13:22:32 -0500135}
136
Matt Spinler19e72902020-01-24 11:05:20 -0600137void Manager::addPEL(std::vector<uint8_t>& pelData, uint32_t obmcLogID)
138{
Matt Spinler19e72902020-01-24 11:05:20 -0600139 auto pel = std::make_unique<openpower::pels::PEL>(pelData, obmcLogID);
140 if (pel->valid())
141 {
Sumit Kumar8ec41562021-10-29 05:39:37 -0500142 // PELs created by others still need this field set by us.
143 pel->setCommitTime();
144
Sumit Kumara1e40842021-06-23 09:52:25 -0500145 // Assign Id other than to Hostbot PEL
146 if ((pel->privateHeader()).creatorID() !=
147 static_cast<uint8_t>(CreatorID::hostboot))
148 {
149 pel->assignID();
150 }
Sumit Kumar2ccdcef2021-07-31 10:04:58 -0500151 else
152 {
153 const Repository::LogID id{Repository::LogID::Pel(pel->id())};
154 auto result = _repo.hasPEL(id);
155 if (result)
156 {
157 log<level::WARNING>(
158 fmt::format("Duplicate HostBoot PEL Id {:#X} found; "
159 "moving it to archive folder",
160 pel->id())
161 .c_str());
162
163 _repo.archivePEL(*pel);
Matt Spinlerd8fb5ba2022-01-25 13:01:14 -0600164
165 // No need to keep around the openBMC event log entry
166 scheduleObmcLogDelete(obmcLogID);
Sumit Kumar2ccdcef2021-07-31 10:04:58 -0500167 return;
168 }
169 }
Sumit Kumara1e40842021-06-23 09:52:25 -0500170
Sumit Kumar3160a542021-04-26 08:07:04 -0500171 // Update System Info to Extended User Data
172 pel->updateSysInfoInExtendedUserDataSection(*_dataIface);
173
Sumit Kumar3e274432021-09-14 06:37:56 -0500174 // Check for severity 0x51 and update boot progress SRC
175 updateProgressSRC(pel);
176
Matt Spinler19e72902020-01-24 11:05:20 -0600177 try
178 {
Matt Spinlerd0ab1cf2021-02-10 13:26:18 -0600179 log<level::DEBUG>(
Matt Spinler6321ba32020-07-17 09:58:19 -0500180 fmt::format("Adding external PEL {:#x} (BMC ID {}) to repo",
181 pel->id(), obmcLogID)
182 .c_str());
Matt Spinler5f5352e2020-03-05 16:23:27 -0600183
Matt Spinler19e72902020-01-24 11:05:20 -0600184 _repo.add(pel);
Matt Spinler7e727a32020-07-07 15:00:17 -0500185
186 if (_repo.sizeWarning())
187 {
188 scheduleRepoPrune();
189 }
Matt Spinler1962e082020-08-05 13:44:53 -0500190
191 // Activate any resulting service indicators if necessary
192 auto policy = service_indicators::getPolicy(*_dataIface);
193 policy->activate(*pel);
Matt Spinler19e72902020-01-24 11:05:20 -0600194 }
Patrick Williams66491c62021-10-06 12:23:37 -0500195 catch (const std::exception& e)
Matt Spinler19e72902020-01-24 11:05:20 -0600196 {
197 // Probably a full or r/o filesystem, not much we can do.
198 log<level::ERR>("Unable to add PEL to Repository",
199 entry("PEL_ID=0x%X", pel->id()));
200 }
Andrew Geissler44fc3162020-07-09 09:21:31 -0500201
Vijay Lobod354a392021-06-01 16:21:02 -0500202 updateEventId(pel);
Matt Spinler28d6ae22022-03-18 11:18:27 -0500203 updateResolution(*pel);
Vijay Loboafb1b462021-07-21 23:29:13 -0500204 createPELEntry(obmcLogID);
Matt Spinlerdf5cb832022-07-12 12:47:26 -0500205
206 // Check if firmware should quiesce system due to error
207 checkPelAndQuiesce(pel);
Matt Spinler19e72902020-01-24 11:05:20 -0600208 }
209 else
210 {
211 log<level::ERR>("Invalid PEL received from the host",
212 entry("OBMCLOGID=%d", obmcLogID));
213
214 AdditionalData ad;
215 ad.add("PLID", getNumberString("0x%08X", pel->plid()));
216 ad.add("OBMC_LOG_ID", std::to_string(obmcLogID));
217 ad.add("PEL_SIZE", std::to_string(pelData.size()));
218
219 std::string asciiString;
220 auto src = pel->primarySRC();
221 if (src)
222 {
223 asciiString = (*src)->asciiString();
224 }
225
226 ad.add("SRC", asciiString);
227
228 _eventLogger.log("org.open_power.Logging.Error.BadHostPEL",
229 Entry::Level::Error, ad);
Matt Spinlerfe721892020-04-02 10:28:08 -0500230
231 // Save it to a file for debug in the lab. Just keep the latest.
232 // Not adding it to the PEL because it could already be max size
233 // and don't want to truncate an already invalid PEL.
234 std::ofstream pelFile{getPELRepoPath() / "badPEL"};
235 pelFile.write(reinterpret_cast<const char*>(pelData.data()),
236 pelData.size());
Matt Spinlerd8fb5ba2022-01-25 13:01:14 -0600237
238 // No need to keep around the openBMC event log entry
239 scheduleObmcLogDelete(obmcLogID);
Matt Spinler19e72902020-01-24 11:05:20 -0600240 }
241}
242
243void Manager::addESELPEL(const std::string& esel, uint32_t obmcLogID)
244{
245 std::vector<uint8_t> data;
246
Matt Spinler5f5352e2020-03-05 16:23:27 -0600247 log<level::DEBUG>("Adding PEL from ESEL",
248 entry("OBMC_LOG_ID=%d", obmcLogID));
249
Matt Spinler19e72902020-01-24 11:05:20 -0600250 try
251 {
252 data = std::move(eselToRawData(esel));
253 }
Patrick Williams66491c62021-10-06 12:23:37 -0500254 catch (const std::exception& e)
Matt Spinler19e72902020-01-24 11:05:20 -0600255 {
256 // Try to add it below anyway, so it follows the usual bad data path.
257 log<level::ERR>("Problems converting ESEL string to a byte vector");
258 }
259
260 addPEL(data, obmcLogID);
261}
262
263std::vector<uint8_t> Manager::eselToRawData(const std::string& esel)
264{
265 std::vector<uint8_t> data;
266 std::string byteString;
267
268 // As the eSEL string looks like: "50 48 00 ab ..." there are 3
269 // characters per raw byte, and since the actual PEL data starts
270 // at the 16th byte, the code will grab the PEL data starting at
271 // offset 48 in the string.
272 static constexpr size_t pelStart = 16 * 3;
273
274 if (esel.size() <= pelStart)
275 {
276 log<level::ERR>("ESEL data too short",
277 entry("ESEL_SIZE=%d", esel.size()));
278
279 throw std::length_error("ESEL data too short");
280 }
281
282 for (size_t i = pelStart; i < esel.size(); i += 3)
283 {
284 if (i + 1 < esel.size())
285 {
286 byteString = esel.substr(i, 2);
287 data.push_back(std::stoi(byteString, nullptr, 16));
288 }
289 else
290 {
291 log<level::ERR>("ESEL data too short",
292 entry("ESEL_SIZE=%d", esel.size()));
293 throw std::length_error("ESEL data too short");
294 }
295 }
296
297 return data;
298}
299
Matt Spinler4e8078c2019-07-09 13:22:32 -0500300void Manager::erase(uint32_t obmcLogID)
301{
Matt Spinler475e5742019-07-18 16:09:49 -0500302 Repository::LogID id{Repository::LogID::Obmc(obmcLogID)};
303
Vijay Loboafb1b462021-07-21 23:29:13 -0500304 auto path = std::string(OBJ_ENTRY) + '/' + std::to_string(obmcLogID);
305 _pelEntries.erase(path);
Matt Spinler475e5742019-07-18 16:09:49 -0500306 _repo.remove(id);
Matt Spinler4e8078c2019-07-09 13:22:32 -0500307}
308
Patrick Williamsd26fa3e2021-04-21 15:22:23 -0500309bool Manager::isDeleteProhibited(uint32_t /*obmcLogID*/)
Matt Spinler4e8078c2019-07-09 13:22:32 -0500310{
311 return false;
312}
313
Matt Spinler56ad2a02020-03-26 14:00:52 -0500314PelFFDC Manager::convertToPelFFDC(const FFDCEntries& ffdc)
315{
316 PelFFDC pelFFDC;
317
318 std::for_each(ffdc.begin(), ffdc.end(), [&pelFFDC](const auto& f) {
319 PelFFDCfile pf;
320 pf.subType = std::get<ffdcSubtypePos>(f);
321 pf.version = std::get<ffdcVersionPos>(f);
322 pf.fd = std::get<ffdcFDPos>(f);
323
324 switch (std::get<ffdcFormatPos>(f))
325 {
326 case Create::FFDCFormat::JSON:
327 pf.format = UserDataFormat::json;
328 break;
329 case Create::FFDCFormat::CBOR:
330 pf.format = UserDataFormat::cbor;
331 break;
332 case Create::FFDCFormat::Text:
333 pf.format = UserDataFormat::text;
334 break;
335 case Create::FFDCFormat::Custom:
336 pf.format = UserDataFormat::custom;
337 break;
338 }
339
340 pelFFDC.push_back(pf);
341 });
342
343 return pelFFDC;
344}
345
Matt Spinler4e8078c2019-07-09 13:22:32 -0500346void Manager::createPEL(const std::string& message, uint32_t obmcLogID,
347 uint64_t timestamp,
348 phosphor::logging::Entry::Level severity,
349 const std::vector<std::string>& additionalData,
Patrick Williamsd26fa3e2021-04-21 15:22:23 -0500350 const std::vector<std::string>& /*associations*/,
Matt Spinler56ad2a02020-03-26 14:00:52 -0500351 const FFDCEntries& ffdc)
Matt Spinler4e8078c2019-07-09 13:22:32 -0500352{
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800353 auto entry = _registry.lookup(message, rg::LookupType::name);
Matt Spinler30ddc9f2020-07-16 15:39:59 -0500354 auto pelFFDC = convertToPelFFDC(ffdc);
355 AdditionalData ad{additionalData};
Matt Spinler1d4c74a2019-12-16 14:40:21 -0600356 std::string msg;
Matt Spinler67456c22019-10-21 12:22:49 -0500357
Matt Spinler30ddc9f2020-07-16 15:39:59 -0500358 if (!entry)
Matt Spinler67456c22019-10-21 12:22:49 -0500359 {
Matt Spinler30ddc9f2020-07-16 15:39:59 -0500360 // Instead, get the default entry that means there is no
361 // other matching entry. This error will still use the
362 // AdditionalData values of the original error, and this
363 // code will add the error message value that wasn't found
364 // to this AD. This way, there will at least be a PEL,
365 // possibly with callouts, to allow users to debug the
366 // issue that caused the error even without its own PEL.
Matt Spinler1d4c74a2019-12-16 14:40:21 -0600367 msg = "Event not found in PEL message registry: " + message;
368 log<level::INFO>(msg.c_str());
Matt Spinler30ddc9f2020-07-16 15:39:59 -0500369
370 entry = _registry.lookup(defaultLogMessage, rg::LookupType::name);
371 if (!entry)
372 {
373 log<level::ERR>("Default event not found in PEL message registry");
374 return;
375 }
376
377 ad.add(additional_data::error, message);
378 }
379
380 auto pel = std::make_unique<openpower::pels::PEL>(
Matt Spinler9d921092022-12-15 11:54:49 -0600381 *entry, obmcLogID, timestamp, severity, ad, pelFFDC, *_dataIface,
382 *_journal);
Matt Spinler30ddc9f2020-07-16 15:39:59 -0500383
384 _repo.add(pel);
385
386 if (_repo.sizeWarning())
387 {
388 scheduleRepoPrune();
389 }
390
391 auto src = pel->primarySRC();
392 if (src)
393 {
Patrick Williams2544b412022-10-04 08:41:06 -0500394 auto m = fmt::format("Created PEL {:#x} (BMC ID {}) with SRC {}",
395 pel->id(), pel->obmcLogID(),
396 (*src)->asciiString());
Matt Spinler45796e82022-07-01 11:25:27 -0500397 while (m.back() == ' ')
Matt Spinler30ddc9f2020-07-16 15:39:59 -0500398 {
Matt Spinler45796e82022-07-01 11:25:27 -0500399 m.pop_back();
Matt Spinler30ddc9f2020-07-16 15:39:59 -0500400 }
Matt Spinler45796e82022-07-01 11:25:27 -0500401 log<level::INFO>(m.c_str());
Matt Spinler1d4c74a2019-12-16 14:40:21 -0600402 }
Matt Spinler1962e082020-08-05 13:44:53 -0500403
Sumit Kumar3e274432021-09-14 06:37:56 -0500404 // Check for severity 0x51 and update boot progress SRC
405 updateProgressSRC(pel);
406
Matt Spinler1962e082020-08-05 13:44:53 -0500407 // Activate any resulting service indicators if necessary
408 auto policy = service_indicators::getPolicy(*_dataIface);
409 policy->activate(*pel);
Andrew Geissler44fc3162020-07-09 09:21:31 -0500410
Matt Spinler8b81ec02022-07-12 13:25:37 -0500411 updateDBusSeverity(*pel);
Vijay Lobod354a392021-06-01 16:21:02 -0500412 updateEventId(pel);
Matt Spinler28d6ae22022-03-18 11:18:27 -0500413 updateResolution(*pel);
Vijay Loboafb1b462021-07-21 23:29:13 -0500414 createPELEntry(obmcLogID);
Matt Spinlerdf5cb832022-07-12 12:47:26 -0500415
416 // Check if firmware should quiesce system due to error
417 checkPelAndQuiesce(pel);
Matt Spinler4e8078c2019-07-09 13:22:32 -0500418}
419
Matt Spinlera34ab722019-12-16 10:39:32 -0600420sdbusplus::message::unix_fd Manager::getPEL(uint32_t pelID)
421{
422 Repository::LogID id{Repository::LogID::Pel(pelID)};
423 std::optional<int> fd;
424
Matt Spinler5f5352e2020-03-05 16:23:27 -0600425 log<level::DEBUG>("getPEL", entry("PEL_ID=0x%X", pelID));
426
Matt Spinlera34ab722019-12-16 10:39:32 -0600427 try
428 {
429 fd = _repo.getPELFD(id);
430 }
Patrick Williams66491c62021-10-06 12:23:37 -0500431 catch (const std::exception& e)
Matt Spinlera34ab722019-12-16 10:39:32 -0600432 {
433 throw common_error::InternalFailure();
434 }
435
436 if (!fd)
437 {
438 throw common_error::InvalidArgument();
439 }
440
Matt Spinler6b1a5c82020-01-07 08:48:53 -0600441 scheduleFDClose(*fd);
442
Matt Spinlera34ab722019-12-16 10:39:32 -0600443 return *fd;
444}
445
Matt Spinler6b1a5c82020-01-07 08:48:53 -0600446void Manager::scheduleFDClose(int fd)
447{
448 _fdCloserEventSource = std::make_unique<sdeventplus::source::Defer>(
Matt Spinlerff9cec22020-07-15 13:06:35 -0500449 _event, std::bind(std::mem_fn(&Manager::closeFD), this, fd,
450 std::placeholders::_1));
Matt Spinler6b1a5c82020-01-07 08:48:53 -0600451}
452
Patrick Williamsd26fa3e2021-04-21 15:22:23 -0500453void Manager::closeFD(int fd, sdeventplus::source::EventBase& /*source*/)
Matt Spinler6b1a5c82020-01-07 08:48:53 -0600454{
455 close(fd);
456 _fdCloserEventSource.reset();
457}
458
Matt Spinlera34ab722019-12-16 10:39:32 -0600459std::vector<uint8_t> Manager::getPELFromOBMCID(uint32_t obmcLogID)
460{
461 Repository::LogID id{Repository::LogID::Obmc(obmcLogID)};
462 std::optional<std::vector<uint8_t>> data;
463
Matt Spinler5f5352e2020-03-05 16:23:27 -0600464 log<level::DEBUG>("getPELFromOBMCID", entry("OBMC_LOG_ID=%d", obmcLogID));
465
Matt Spinlera34ab722019-12-16 10:39:32 -0600466 try
467 {
468 data = _repo.getPELData(id);
469 }
Patrick Williams66491c62021-10-06 12:23:37 -0500470 catch (const std::exception& e)
Matt Spinlera34ab722019-12-16 10:39:32 -0600471 {
472 throw common_error::InternalFailure();
473 }
474
475 if (!data)
476 {
477 throw common_error::InvalidArgument();
478 }
479
480 return *data;
481}
482
483void Manager::hostAck(uint32_t pelID)
484{
485 Repository::LogID id{Repository::LogID::Pel(pelID)};
486
Matt Spinler5f5352e2020-03-05 16:23:27 -0600487 log<level::DEBUG>("HostAck", entry("PEL_ID=0x%X", pelID));
488
Matt Spinlera34ab722019-12-16 10:39:32 -0600489 if (!_repo.hasPEL(id))
490 {
491 throw common_error::InvalidArgument();
492 }
493
494 if (_hostNotifier)
495 {
496 _hostNotifier->ackPEL(pelID);
497 }
498}
499
500void Manager::hostReject(uint32_t pelID, RejectionReason reason)
501{
502 Repository::LogID id{Repository::LogID::Pel(pelID)};
503
Matt Spinler5f5352e2020-03-05 16:23:27 -0600504 log<level::DEBUG>("HostReject", entry("PEL_ID=0x%X", pelID),
505 entry("REASON=%d", static_cast<int>(reason)));
506
Matt Spinlera34ab722019-12-16 10:39:32 -0600507 if (!_repo.hasPEL(id))
508 {
509 throw common_error::InvalidArgument();
510 }
511
Matt Spinler05c2c6c2019-12-18 14:02:09 -0600512 if (reason == RejectionReason::BadPEL)
Matt Spinlera34ab722019-12-16 10:39:32 -0600513 {
Matt Spinler05c2c6c2019-12-18 14:02:09 -0600514 AdditionalData data;
515 data.add("BAD_ID", getNumberString("0x%08X", pelID));
516 _eventLogger.log("org.open_power.Logging.Error.SentBadPELToHost",
517 Entry::Level::Informational, data);
518 if (_hostNotifier)
Matt Spinlera34ab722019-12-16 10:39:32 -0600519 {
520 _hostNotifier->setBadPEL(pelID);
521 }
Matt Spinler05c2c6c2019-12-18 14:02:09 -0600522 }
523 else if ((reason == RejectionReason::HostFull) && _hostNotifier)
524 {
525 _hostNotifier->setHostFull(pelID);
Matt Spinlera34ab722019-12-16 10:39:32 -0600526 }
527}
528
Matt Spinler7e727a32020-07-07 15:00:17 -0500529void Manager::scheduleRepoPrune()
530{
Matt Spinler7e727a32020-07-07 15:00:17 -0500531 _repoPrunerEventSource = std::make_unique<sdeventplus::source::Defer>(
Matt Spinlerff9cec22020-07-15 13:06:35 -0500532 _event, std::bind(std::mem_fn(&Manager::pruneRepo), this,
533 std::placeholders::_1));
Matt Spinler7e727a32020-07-07 15:00:17 -0500534}
535
Patrick Williamsd26fa3e2021-04-21 15:22:23 -0500536void Manager::pruneRepo(sdeventplus::source::EventBase& /*source*/)
Matt Spinler7e727a32020-07-07 15:00:17 -0500537{
Sumit Kumar027bf282022-01-24 11:25:19 -0600538 auto idsWithHwIsoEntry = _dataIface->getLogIDWithHwIsolation();
539
540 auto idsToDelete = _repo.prune(idsWithHwIsoEntry);
Matt Spinler7e727a32020-07-07 15:00:17 -0500541
542 // Remove the OpenBMC event logs for the PELs that were just removed.
543 std::for_each(idsToDelete.begin(), idsToDelete.end(),
544 [this](auto id) { this->_logManager.erase(id); });
545
546 _repoPrunerEventSource.reset();
547}
548
Matt Spinlerff9cec22020-07-15 13:06:35 -0500549void Manager::setupPELDeleteWatch()
550{
551 _pelFileDeleteFD = inotify_init1(IN_NONBLOCK);
552 if (-1 == _pelFileDeleteFD)
553 {
554 auto e = errno;
Patrick Williams2544b412022-10-04 08:41:06 -0500555 std::string msg = "inotify_init1 failed with errno " +
556 std::to_string(e);
Matt Spinlerff9cec22020-07-15 13:06:35 -0500557 log<level::ERR>(msg.c_str());
558 abort();
559 }
560
561 _pelFileDeleteWatchFD = inotify_add_watch(
562 _pelFileDeleteFD, _repo.repoPath().c_str(), IN_DELETE);
563 if (-1 == _pelFileDeleteWatchFD)
564 {
565 auto e = errno;
Patrick Williams2544b412022-10-04 08:41:06 -0500566 std::string msg = "inotify_add_watch failed with error " +
567 std::to_string(e);
Matt Spinlerff9cec22020-07-15 13:06:35 -0500568 log<level::ERR>(msg.c_str());
569 abort();
570 }
571
572 _pelFileDeleteEventSource = std::make_unique<sdeventplus::source::IO>(
573 _event, _pelFileDeleteFD, EPOLLIN,
574 std::bind(std::mem_fn(&Manager::pelFileDeleted), this,
575 std::placeholders::_1, std::placeholders::_2,
576 std::placeholders::_3));
577}
578
Patrick Williamsd26fa3e2021-04-21 15:22:23 -0500579void Manager::pelFileDeleted(sdeventplus::source::IO& /*io*/, int /*fd*/,
Matt Spinlerff9cec22020-07-15 13:06:35 -0500580 uint32_t revents)
581{
582 if (!(revents & EPOLLIN))
583 {
584 return;
585 }
586
587 // An event for 1 PEL uses 48B. When all PELs are deleted at once,
588 // as many events as there is room for can be handled in one callback.
589 // A size of 2000 will allow 41 to be processed, with additional
590 // callbacks being needed to process the remaining ones.
Matt Spinler9d59d582021-05-19 07:57:10 -0600591 std::array<uint8_t, 2000> data{};
Matt Spinlerff9cec22020-07-15 13:06:35 -0500592 auto bytesRead = read(_pelFileDeleteFD, data.data(), data.size());
593 if (bytesRead < 0)
594 {
595 auto e = errno;
596 std::string msg = "Failed reading data from inotify event, errno = " +
597 std::to_string(e);
598 log<level::ERR>(msg.c_str());
599 abort();
600 }
601
602 auto offset = 0;
603 while (offset < bytesRead)
604 {
605 auto event = reinterpret_cast<inotify_event*>(&data[offset]);
606 if (event->mask & IN_DELETE)
607 {
608 std::string filename{event->name};
609
610 // Get the PEL ID from the filename and tell the
611 // repo it's been removed, and then delete the BMC
612 // event log if it's there.
613 auto pos = filename.find_first_of('_');
614 if (pos != std::string::npos)
615 {
616 try
617 {
618 auto idString = filename.substr(pos + 1);
619 auto pelID = std::stoul(idString, nullptr, 16);
620
621 Repository::LogID id{Repository::LogID::Pel(pelID)};
622 auto removedLogID = _repo.remove(id);
623 if (removedLogID)
624 {
625 _logManager.erase(removedLogID->obmcID.id);
626 }
627 }
628 catch (const std::exception& e)
629 {
630 log<level::INFO>("Could not find PEL ID from its filename",
631 entry("FILENAME=%s", filename.c_str()));
632 }
633 }
634 }
635
636 offset += offsetof(inotify_event, name) + event->len;
637 }
638}
Matt Spinler9cc30072020-09-16 15:39:34 -0500639
640std::tuple<uint32_t, uint32_t> Manager::createPELWithFFDCFiles(
641 std::string message, Entry::Level severity,
642 std::map<std::string, std::string> additionalData,
643 std::vector<std::tuple<
644 sdbusplus::xyz::openbmc_project::Logging::server::Create::FFDCFormat,
645 uint8_t, uint8_t, sdbusplus::message::unix_fd>>
646 fFDC)
647{
Matt Spinler44893cc2020-08-26 11:34:17 -0500648 _logManager.createWithFFDC(message, severity, additionalData, fFDC);
649
650 return {_logManager.lastEntryID(), _repo.lastPelID()};
Matt Spinler9cc30072020-09-16 15:39:34 -0500651}
652
Matt Spinler8bd4ca42022-04-01 16:06:06 -0500653std::string Manager::getPELJSON(uint32_t obmcLogID)
Matt Spinleraa85a072022-03-23 11:26:41 -0500654{
Matt Spinler8bd4ca42022-04-01 16:06:06 -0500655 // Throws InvalidArgument if not found
656 auto pelID = getPELIdFromBMCLogId(obmcLogID);
657
658 auto cmd = fmt::format("/usr/bin/peltool -i {:#x}", pelID);
659
660 FILE* pipe = popen(cmd.c_str(), "r");
661 if (!pipe)
662 {
663 log<level::ERR>(fmt::format("Error running {}", cmd).c_str());
664 throw common_error::InternalFailure();
665 }
666
667 std::string output;
668 std::array<char, 1024> buffer;
669 while (fgets(buffer.data(), buffer.size(), pipe) != nullptr)
670 {
671 output.append(buffer.data());
672 }
673
674 int rc = pclose(pipe);
675 if (WEXITSTATUS(rc) != 0)
676 {
677 log<level::ERR>(
678 fmt::format("Error running {}, rc = {}", cmd, rc).c_str());
679 throw common_error::InternalFailure();
680 }
681
682 return output;
Matt Spinleraa85a072022-03-23 11:26:41 -0500683}
684
Andrew Geissler44fc3162020-07-09 09:21:31 -0500685void Manager::checkPelAndQuiesce(std::unique_ptr<openpower::pels::PEL>& pel)
686{
Matt Spinlerb2abc042021-05-17 15:32:50 -0600687 if ((pel->userHeader().severity() ==
688 static_cast<uint8_t>(SeverityType::nonError)) ||
689 (pel->userHeader().severity() ==
690 static_cast<uint8_t>(SeverityType::recovered)))
Andrew Geissler44fc3162020-07-09 09:21:31 -0500691 {
Matt Spinlerb2abc042021-05-17 15:32:50 -0600692 log<level::DEBUG>(
693 "PEL severity informational or recovered. no quiesce needed");
Andrew Geissler44fc3162020-07-09 09:21:31 -0500694 return;
695 }
696 if (!_logManager.isQuiesceOnErrorEnabled())
697 {
698 log<level::DEBUG>("QuiesceOnHwError not enabled, no quiesce needed");
699 return;
700 }
701
Matt Spinler845c6242022-03-01 16:45:08 -0600702 CreatorID creatorID{pel->privateHeader().creatorID()};
703
704 if ((creatorID != CreatorID::openBMC) &&
705 (creatorID != CreatorID::hostboot) &&
706 (creatorID != CreatorID::ioDrawer) && (creatorID != CreatorID::occ) &&
707 (creatorID != CreatorID::phyp))
708 {
709 return;
710 }
711
Andrew Geissler44fc3162020-07-09 09:21:31 -0500712 // Now check if it has any type of callout
Andrew Geisslerf8e750d2022-01-14 14:56:13 -0600713 if (pel->isHwCalloutPresent())
Andrew Geissler44fc3162020-07-09 09:21:31 -0500714 {
Matt Spinlerb2abc042021-05-17 15:32:50 -0600715 log<level::INFO>(
716 "QuiesceOnHwError enabled, PEL severity not nonError or recovered, "
717 "and callout is present");
Andrew Geissler44fc3162020-07-09 09:21:31 -0500718
719 _logManager.quiesceOnError(pel->obmcLogID());
720 }
721}
722
Vijay Lobod354a392021-06-01 16:21:02 -0500723std::string Manager::getEventId(const openpower::pels::PEL& pel) const
724{
725 std::string str;
726 auto src = pel.primarySRC();
727 if (src)
728 {
729 const auto& hexwords = (*src)->hexwordData();
730
731 std::string refcode = (*src)->asciiString();
732 size_t pos = refcode.find_last_not_of(0x20);
733 if (pos != std::string::npos)
734 {
735 refcode.erase(pos + 1);
736 }
737 str = refcode;
738
739 for (auto& value : hexwords)
740 {
741 str += " ";
742 str += getNumberString("%08X", value);
743 }
744 }
Matt Spinler0003af12022-06-08 10:46:17 -0500745 return sanitizeFieldForDBus(str);
Vijay Lobod354a392021-06-01 16:21:02 -0500746}
747
748void Manager::updateEventId(std::unique_ptr<openpower::pels::PEL>& pel)
749{
750 std::string eventIdStr = getEventId(*pel);
751
752 auto entryN = _logManager.entries.find(pel->obmcLogID());
753 if (entryN != _logManager.entries.end())
754 {
Matt Spinlerb25e8a32023-06-07 16:05:36 -0500755 entryN->second->eventId(eventIdStr, true);
Vijay Lobod354a392021-06-01 16:21:02 -0500756 }
757}
758
Matt Spinler0003af12022-06-08 10:46:17 -0500759std::string Manager::sanitizeFieldForDBus(std::string field)
760{
761 std::for_each(field.begin(), field.end(), [](char& ch) {
762 if (((ch < ' ') || (ch > '~')) && (ch != '\n') && (ch != '\t'))
763 {
764 ch = ' ';
765 }
766 });
767 return field;
768}
769
Vijay Lobo593a4c62021-06-16 14:25:26 -0500770std::string Manager::getResolution(const openpower::pels::PEL& pel) const
771{
772 std::string str;
773 std::string resolution;
774 auto src = pel.primarySRC();
775 if (src)
776 {
777 // First extract the callout pointer and then go through
778 const auto& callouts = (*src)->callouts();
779 namespace pv = openpower::pels::pel_values;
780 // All PELs dont have callout, check before parsing callout data
781 if (callouts)
782 {
783 const auto& entries = callouts->callouts();
784 // Entry starts with index 1
785 uint8_t index = 1;
786 for (auto& entry : entries)
787 {
788 resolution += std::to_string(index) + ". ";
789 // Adding Location code to resolution
790 if (!entry->locationCode().empty())
Patrick Williams2544b412022-10-04 08:41:06 -0500791 resolution += "Location Code: " + entry->locationCode() +
792 ", ";
Vijay Lobo593a4c62021-06-16 14:25:26 -0500793 if (entry->fruIdentity())
794 {
795 // Get priority and set the resolution string
796 str = pv::getValue(entry->priority(),
797 pel_values::calloutPriorityValues,
798 pel_values::registryNamePos);
799 str[0] = toupper(str[0]);
800 resolution += "Priority: " + str + ", ";
801 if (entry->fruIdentity()->getPN().has_value())
802 {
803 resolution +=
804 "PN: " + entry->fruIdentity()->getPN().value() +
805 ", ";
806 }
807 if (entry->fruIdentity()->getSN().has_value())
808 {
809 resolution +=
810 "SN: " + entry->fruIdentity()->getSN().value() +
811 ", ";
812 }
813 if (entry->fruIdentity()->getCCIN().has_value())
814 {
815 resolution +=
816 "CCIN: " + entry->fruIdentity()->getCCIN().value() +
817 ", ";
818 }
819 // Add the maintenance procedure
820 if (entry->fruIdentity()->getMaintProc().has_value())
821 {
822 resolution +=
823 "Procedure: " +
824 entry->fruIdentity()->getMaintProc().value() + ", ";
825 }
826 }
827 resolution.resize(resolution.size() - 2);
828 resolution += "\n";
829 index++;
830 }
831 }
832 }
Matt Spinler0003af12022-06-08 10:46:17 -0500833 return sanitizeFieldForDBus(resolution);
Vijay Lobo593a4c62021-06-16 14:25:26 -0500834}
835
Matt Spinler28d6ae22022-03-18 11:18:27 -0500836bool Manager::updateResolution(const openpower::pels::PEL& pel)
Vijay Lobo593a4c62021-06-16 14:25:26 -0500837{
Matt Spinler28d6ae22022-03-18 11:18:27 -0500838 std::string callouts = getResolution(pel);
839 auto entryN = _logManager.entries.find(pel.obmcLogID());
Vijay Lobo593a4c62021-06-16 14:25:26 -0500840 if (entryN != _logManager.entries.end())
841 {
Matt Spinler734ed2b2022-01-21 09:31:46 -0600842 entryN->second->resolution(callouts, true);
Vijay Lobo593a4c62021-06-16 14:25:26 -0500843 }
Matt Spinler28d6ae22022-03-18 11:18:27 -0500844
845 return false;
Vijay Lobo593a4c62021-06-16 14:25:26 -0500846}
847
Matt Spinler8b81ec02022-07-12 13:25:37 -0500848void Manager::updateDBusSeverity(const openpower::pels::PEL& pel)
849{
850 // The final severity of the PEL may not agree with the
851 // original severity of the D-Bus event log. Update the
852 // D-Bus property to match in some cases. This is to
853 // ensure there isn't a Critical or Warning Redfish event
854 // log for an informational or recovered PEL (or vice versa).
855 // This doesn't make an explicit call to serialize the new
856 // event log property value because updateEventId() is called
857 // right after this and will do it.
858 auto sevType =
859 static_cast<SeverityType>(pel.userHeader().severity() & 0xF0);
860
861 auto entryN = _logManager.entries.find(pel.obmcLogID());
862 if (entryN != _logManager.entries.end())
863 {
Patrick Williams2544b412022-10-04 08:41:06 -0500864 auto newSeverity = fixupLogSeverity(entryN->second->severity(),
865 sevType);
Matt Spinler8b81ec02022-07-12 13:25:37 -0500866 if (newSeverity)
867 {
868 log<level::INFO>(
869 fmt::format(
870 "Changing event log {} severity from {} "
871 "to {} to match PEL",
872 entryN->second->id(),
873 Entry::convertLevelToString(entryN->second->severity()),
874 Entry::convertLevelToString(*newSeverity))
875 .c_str());
876
877 entryN->second->severity(*newSeverity, true);
878 }
879 }
880}
881
Adriana Kobylake7d271a2020-12-07 14:32:44 -0600882void Manager::setEntryPath(uint32_t obmcLogID)
883{
884 Repository::LogID id{Repository::LogID::Obmc(obmcLogID)};
885 if (auto attributes = _repo.getPELAttributes(id); attributes)
886 {
887 auto& attr = attributes.value().get();
888 auto entry = _logManager.entries.find(obmcLogID);
889 if (entry != _logManager.entries.end())
890 {
Matt Spinler734ed2b2022-01-21 09:31:46 -0600891 entry->second->path(attr.path, true);
Adriana Kobylake7d271a2020-12-07 14:32:44 -0600892 }
893 }
894}
895
Vijay Lobocbc93a42021-05-20 19:04:07 -0500896void Manager::setServiceProviderNotifyFlag(uint32_t obmcLogID)
897{
898 Repository::LogID id{Repository::LogID::Obmc(obmcLogID)};
899 if (auto attributes = _repo.getPELAttributes(id); attributes)
900 {
901 auto& attr = attributes.value().get();
902 auto entry = _logManager.entries.find(obmcLogID);
903 if (entry != _logManager.entries.end())
904 {
Lakshmi Yadlapati7a3ede52022-11-18 13:26:17 -0600905 if (attr.actionFlags.test(callHomeFlagBit))
906 {
Matt Spinlerb25e8a32023-06-07 16:05:36 -0500907 entry->second->serviceProviderNotify(Entry::Notify::Notify,
908 true);
Lakshmi Yadlapati7a3ede52022-11-18 13:26:17 -0600909 }
910 else
911 {
Matt Spinlerb25e8a32023-06-07 16:05:36 -0500912 entry->second->serviceProviderNotify(Entry::Notify::Inhibit,
913 true);
Lakshmi Yadlapati7a3ede52022-11-18 13:26:17 -0600914 }
Vijay Lobocbc93a42021-05-20 19:04:07 -0500915 }
916 }
917}
918
Matt Spinler734ed2b2022-01-21 09:31:46 -0600919void Manager::createPELEntry(uint32_t obmcLogID, bool skipIaSignal)
Vijay Loboafb1b462021-07-21 23:29:13 -0500920{
921 std::map<std::string, PropertiesVariant> varData;
922 Repository::LogID id{Repository::LogID::Obmc(obmcLogID)};
923 if (auto attributes = _repo.getPELAttributes(id); attributes)
924 {
925 namespace pv = openpower::pels::pel_values;
926 auto& attr = attributes.value().get();
Vijay Lobob2e541e2021-08-31 23:12:47 -0500927
928 // get the hidden flag values
929 auto sevType = static_cast<SeverityType>(attr.severity & 0xF0);
930 auto isHidden = true;
931 if (((sevType != SeverityType::nonError) &&
932 attr.actionFlags.test(reportFlagBit) &&
933 !attr.actionFlags.test(hiddenFlagBit)) ||
934 ((sevType == SeverityType::nonError) &&
935 attr.actionFlags.test(serviceActionFlagBit)))
936 {
937 isHidden = false;
938 }
939 varData.emplace(std::string("Hidden"), isHidden);
Vijay Loboafb1b462021-07-21 23:29:13 -0500940 varData.emplace(
941 std::string("Subsystem"),
942 pv::getValue(attr.subsystem, pel_values::subsystemValues));
Vijay Lobo2fb10212021-08-22 23:24:16 -0500943
944 varData.emplace(
945 std::string("ManagementSystemAck"),
946 (attr.hmcState == TransmissionState::acked ? true : false));
947
Matt Spinler8e65f4e2023-05-02 13:40:08 -0500948 varData.emplace("PlatformLogID", attr.plid);
949 varData.emplace("Deconfig", attr.deconfig);
950 varData.emplace("Guard", attr.guard);
951 varData.emplace("Timestamp", attr.creationTime);
952
Vijay Loboafb1b462021-07-21 23:29:13 -0500953 // Path to create PELEntry Interface is same as PEL
954 auto path = std::string(OBJ_ENTRY) + '/' + std::to_string(obmcLogID);
955 // Create Interface for PELEntry and set properties
Vijay Lobo2fb10212021-08-22 23:24:16 -0500956 auto pelEntry = std::make_unique<PELEntry>(_logManager.getBus(), path,
957 varData, obmcLogID, &_repo);
Matt Spinler734ed2b2022-01-21 09:31:46 -0600958 if (!skipIaSignal)
959 {
960 pelEntry->emit_added();
961 }
Vijay Loboafb1b462021-07-21 23:29:13 -0500962 _pelEntries.emplace(std::move(path), std::move(pelEntry));
963 }
964}
965
Ramesh Iyyarf4203c42021-06-24 06:09:23 -0500966uint32_t Manager::getPELIdFromBMCLogId(uint32_t bmcLogId)
967{
968 Repository::LogID id{Repository::LogID::Obmc(bmcLogId)};
969 if (auto logId = _repo.getLogID(id); !logId.has_value())
970 {
971 throw common_error::InvalidArgument();
972 }
973 else
974 {
975 return logId->pelID.id;
976 }
977}
978
Ramesh Iyyar530efbf2021-06-24 06:22:22 -0500979uint32_t Manager::getBMCLogIdFromPELId(uint32_t pelId)
980{
981 Repository::LogID id{Repository::LogID::Pel(pelId)};
982 if (auto logId = _repo.getLogID(id); !logId.has_value())
983 {
984 throw common_error::InvalidArgument();
985 }
986 else
987 {
988 return logId->obmcID.id;
989 }
990}
991
Sumit Kumar3e274432021-09-14 06:37:56 -0500992void Manager::updateProgressSRC(
993 std::unique_ptr<openpower::pels::PEL>& pel) const
994{
995 // Check for pel severity of type - 0x51 = critical error, system
996 // termination
997 if (pel->userHeader().severity() == 0x51)
998 {
999 auto src = pel->primarySRC();
1000 if (src)
1001 {
1002 std::vector<uint8_t> asciiSRC = (*src)->getSrcStruct();
1003 uint64_t srcRefCode = 0;
1004
1005 // Read bytes from offset [40-47] e.g. BD8D1001
1006 for (int i = 0; i < 8; i++)
1007 {
Patrick Williams2544b412022-10-04 08:41:06 -05001008 srcRefCode |= (static_cast<uint64_t>(asciiSRC[40 + i])
1009 << (8 * i));
Sumit Kumar3e274432021-09-14 06:37:56 -05001010 }
1011
1012 try
1013 {
1014 _dataIface->createProgressSRC(srcRefCode, asciiSRC);
1015 }
Matt Spinler87f39242023-05-01 11:36:18 -05001016 catch (const std::exception&)
Sumit Kumar3e274432021-09-14 06:37:56 -05001017 {
1018 // Exception - may be no boot progress interface on dbus
1019 }
1020 }
1021 }
1022}
1023
Matt Spinlerd8fb5ba2022-01-25 13:01:14 -06001024void Manager::scheduleObmcLogDelete(uint32_t obmcLogID)
1025{
1026 _obmcLogDeleteEventSource = std::make_unique<sdeventplus::source::Defer>(
1027 _event, std::bind(std::mem_fn(&Manager::deleteObmcLog), this,
1028 std::placeholders::_1, obmcLogID));
1029}
1030
1031void Manager::deleteObmcLog(sdeventplus::source::EventBase&, uint32_t obmcLogID)
1032{
1033 log<level::INFO>(
1034 fmt::format("Removing event log with no PEL: {}", obmcLogID).c_str());
1035 _logManager.erase(obmcLogID);
1036 _obmcLogDeleteEventSource.reset();
1037}
1038
Matt Spinler0dd22c82023-05-04 15:28:12 -05001039bool Manager::clearPowerThermalDeconfigFlag(const std::string& locationCode,
1040 openpower::pels::PEL& pel)
1041{
1042 // The requirements state that only power-thermal or
1043 // fan PELs need their deconfig flag cleared.
1044 static const std::vector<uint32_t> compIDs{bmcThermalCompID, bmcFansCompID};
1045
1046 if (std::find(compIDs.begin(), compIDs.end(),
1047 pel.privateHeader().header().componentID) == compIDs.end())
1048 {
1049 return false;
1050 }
1051
1052 auto src = pel.primarySRC();
1053 const auto& callouts = (*src)->callouts();
1054 if (!callouts)
1055 {
1056 return false;
1057 }
1058
1059 for (const auto& callout : callouts->callouts())
1060 {
1061 // Look for the passed in location code in a callout that
1062 // is either a normal HW callout or a symbolic FRU with
1063 // a trusted location code callout.
1064 if ((callout->locationCode() != locationCode) ||
1065 !callout->fruIdentity())
1066 {
1067 continue;
1068 }
1069
1070 if ((callout->fruIdentity()->failingComponentType() !=
1071 src::FRUIdentity::hardwareFRU) &&
1072 (callout->fruIdentity()->failingComponentType() !=
1073 src::FRUIdentity::symbolicFRUTrustedLocCode))
1074 {
1075 continue;
1076 }
1077
1078 log<level::INFO>(
1079 fmt::format(
1080 "Clearing deconfig flag in PEL {:#x} with SRC {} because {} was replaced",
1081 pel.id(), (*src)->asciiString().substr(0, 8), locationCode)
1082 .c_str());
1083 (*src)->clearErrorStatusFlag(SRC::ErrorStatusFlags::deconfigured);
1084 return true;
1085 }
1086 return false;
1087}
1088
1089void Manager::hardwarePresent(const std::string& locationCode)
1090{
1091 Repository::PELUpdateFunc handlePowerThermalHardwarePresent =
1092 [locationCode](openpower::pels::PEL& pel) {
1093 return Manager::clearPowerThermalDeconfigFlag(locationCode, pel);
1094 };
1095
1096 // If the PEL was created by the BMC and has the deconfig flag set,
1097 // it's a candidate to have the deconfig flag cleared.
1098 for (const auto& [id, attributes] : _repo.getAttributesMap())
1099 {
1100 if ((attributes.creator == static_cast<uint8_t>(CreatorID::openBMC)) &&
1101 attributes.deconfig)
1102 {
1103 _repo.updatePEL(attributes.path, handlePowerThermalHardwarePresent);
1104 }
1105 }
1106}
1107
Matt Spinler4e8078c2019-07-09 13:22:32 -05001108} // namespace pels
1109} // namespace openpower