blob: 0aa29883929daf66c601ba0b8d82983fb257335d [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"
Matt Spinler1962e082020-08-05 13:44:53 -050021#include "service_indicators.hpp"
Matt Spinler89fa0822019-07-17 13:54:30 -050022
Matt Spinler22421b92020-07-17 09:41:08 -050023#include <fmt/format.h>
Matt Spinlerff9cec22020-07-15 13:06:35 -050024#include <sys/inotify.h>
Matt Spinler6b1a5c82020-01-07 08:48:53 -060025#include <unistd.h>
26
Matt Spinler89fa0822019-07-17 13:54:30 -050027#include <filesystem>
28#include <fstream>
Matt Spinlera34ab722019-12-16 10:39:32 -060029#include <xyz/openbmc_project/Common/error.hpp>
Matt Spinler56ad2a02020-03-26 14:00:52 -050030#include <xyz/openbmc_project/Logging/Create/server.hpp>
Matt Spinler4e8078c2019-07-09 13:22:32 -050031
32namespace openpower
33{
34namespace pels
35{
36
37using namespace phosphor::logging;
Matt Spinler89fa0822019-07-17 13:54:30 -050038namespace fs = std::filesystem;
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +080039namespace rg = openpower::pels::message;
Matt Spinler4e8078c2019-07-09 13:22:32 -050040
Matt Spinlera34ab722019-12-16 10:39:32 -060041namespace common_error = sdbusplus::xyz::openbmc_project::Common::Error;
42
Matt Spinler56ad2a02020-03-26 14:00:52 -050043using Create = sdbusplus::xyz::openbmc_project::Logging::server::Create;
44
Matt Spinler4e8078c2019-07-09 13:22:32 -050045namespace additional_data
46{
47constexpr auto rawPEL = "RAWPEL";
Matt Spinler19e72902020-01-24 11:05:20 -060048constexpr auto esel = "ESEL";
Matt Spinler30ddc9f2020-07-16 15:39:59 -050049constexpr auto error = "ERROR_NAME";
Matt Spinler19e72902020-01-24 11:05:20 -060050} // namespace additional_data
Matt Spinler4e8078c2019-07-09 13:22:32 -050051
Matt Spinler30ddc9f2020-07-16 15:39:59 -050052constexpr auto defaultLogMessage = "xyz.openbmc_project.Logging.Error.Default";
53
Matt Spinlerff9cec22020-07-15 13:06:35 -050054Manager::~Manager()
55{
56 if (_pelFileDeleteFD != -1)
57 {
58 if (_pelFileDeleteWatchFD != -1)
59 {
60 inotify_rm_watch(_pelFileDeleteFD, _pelFileDeleteWatchFD);
61 }
62 close(_pelFileDeleteFD);
63 }
64}
65
Matt Spinler4e8078c2019-07-09 13:22:32 -050066void Manager::create(const std::string& message, uint32_t obmcLogID,
67 uint64_t timestamp, Entry::Level severity,
68 const std::vector<std::string>& additionalData,
Matt Spinler56ad2a02020-03-26 14:00:52 -050069 const std::vector<std::string>& associations,
70 const FFDCEntries& ffdc)
Matt Spinler4e8078c2019-07-09 13:22:32 -050071{
72 AdditionalData ad{additionalData};
73
Matt Spinler19e72902020-01-24 11:05:20 -060074 // If a PEL was passed in via a filename or in an ESEL,
75 // use that. Otherwise, create one.
Matt Spinler4e8078c2019-07-09 13:22:32 -050076 auto rawPelPath = ad.getValue(additional_data::rawPEL);
77 if (rawPelPath)
78 {
79 addRawPEL(*rawPelPath, obmcLogID);
80 }
81 else
82 {
Matt Spinler19e72902020-01-24 11:05:20 -060083 auto esel = ad.getValue(additional_data::esel);
84 if (esel)
85 {
86 addESELPEL(*esel, obmcLogID);
87 }
88 else
89 {
90 createPEL(message, obmcLogID, timestamp, severity, additionalData,
Matt Spinler56ad2a02020-03-26 14:00:52 -050091 associations, ffdc);
Matt Spinler19e72902020-01-24 11:05:20 -060092 }
Matt Spinler4e8078c2019-07-09 13:22:32 -050093 }
Adriana Kobylake7d271a2020-12-07 14:32:44 -060094
95 setEntryPath(obmcLogID);
Vijay Lobocbc93a42021-05-20 19:04:07 -050096 setServiceProviderNotifyFlag(obmcLogID);
Matt Spinler4e8078c2019-07-09 13:22:32 -050097}
98
99void Manager::addRawPEL(const std::string& rawPelPath, uint32_t obmcLogID)
100{
Matt Spinler89fa0822019-07-17 13:54:30 -0500101 if (fs::exists(rawPelPath))
102 {
103 std::ifstream file(rawPelPath, std::ios::in | std::ios::binary);
104
105 auto data = std::vector<uint8_t>(std::istreambuf_iterator<char>(file),
106 std::istreambuf_iterator<char>());
107 if (file.fail())
108 {
109 log<level::ERR>("Filesystem error reading a raw PEL",
110 entry("PELFILE=%s", rawPelPath.c_str()),
111 entry("OBMCLOGID=%d", obmcLogID));
112 // TODO, Decide what to do here. Maybe nothing.
113 return;
114 }
115
116 file.close();
117
Matt Spinler19e72902020-01-24 11:05:20 -0600118 addPEL(data, obmcLogID);
Matt Spinler89fa0822019-07-17 13:54:30 -0500119 }
120 else
121 {
122 log<level::ERR>("Raw PEL file from BMC event log does not exist",
123 entry("PELFILE=%s", (rawPelPath).c_str()),
124 entry("OBMCLOGID=%d", obmcLogID));
125 }
Matt Spinler4e8078c2019-07-09 13:22:32 -0500126}
127
Matt Spinler19e72902020-01-24 11:05:20 -0600128void Manager::addPEL(std::vector<uint8_t>& pelData, uint32_t obmcLogID)
129{
130
131 auto pel = std::make_unique<openpower::pels::PEL>(pelData, obmcLogID);
132 if (pel->valid())
133 {
Sumit Kumara1e40842021-06-23 09:52:25 -0500134 // Assign Id other than to Hostbot PEL
135 if ((pel->privateHeader()).creatorID() !=
136 static_cast<uint8_t>(CreatorID::hostboot))
137 {
138 pel->assignID();
139 }
140
141 // PELs created by others still need this field set by us.
Matt Spinler19e72902020-01-24 11:05:20 -0600142 pel->setCommitTime();
143
Sumit Kumar3160a542021-04-26 08:07:04 -0500144 // Update System Info to Extended User Data
145 pel->updateSysInfoInExtendedUserDataSection(*_dataIface);
146
Matt Spinler19e72902020-01-24 11:05:20 -0600147 try
148 {
Matt Spinlerd0ab1cf2021-02-10 13:26:18 -0600149 log<level::DEBUG>(
Matt Spinler6321ba32020-07-17 09:58:19 -0500150 fmt::format("Adding external PEL {:#x} (BMC ID {}) to repo",
151 pel->id(), obmcLogID)
152 .c_str());
Matt Spinler5f5352e2020-03-05 16:23:27 -0600153
Matt Spinler19e72902020-01-24 11:05:20 -0600154 _repo.add(pel);
Matt Spinler7e727a32020-07-07 15:00:17 -0500155
156 if (_repo.sizeWarning())
157 {
158 scheduleRepoPrune();
159 }
Matt Spinler1962e082020-08-05 13:44:53 -0500160
161 // Activate any resulting service indicators if necessary
162 auto policy = service_indicators::getPolicy(*_dataIface);
163 policy->activate(*pel);
Matt Spinler19e72902020-01-24 11:05:20 -0600164 }
165 catch (std::exception& e)
166 {
167 // Probably a full or r/o filesystem, not much we can do.
168 log<level::ERR>("Unable to add PEL to Repository",
169 entry("PEL_ID=0x%X", pel->id()));
170 }
Andrew Geissler44fc3162020-07-09 09:21:31 -0500171
172 // Check if firmware should quiesce system due to error
173 checkPelAndQuiesce(pel);
Vijay Lobod354a392021-06-01 16:21:02 -0500174 updateEventId(pel);
Matt Spinler19e72902020-01-24 11:05:20 -0600175 }
176 else
177 {
178 log<level::ERR>("Invalid PEL received from the host",
179 entry("OBMCLOGID=%d", obmcLogID));
180
181 AdditionalData ad;
182 ad.add("PLID", getNumberString("0x%08X", pel->plid()));
183 ad.add("OBMC_LOG_ID", std::to_string(obmcLogID));
184 ad.add("PEL_SIZE", std::to_string(pelData.size()));
185
186 std::string asciiString;
187 auto src = pel->primarySRC();
188 if (src)
189 {
190 asciiString = (*src)->asciiString();
191 }
192
193 ad.add("SRC", asciiString);
194
195 _eventLogger.log("org.open_power.Logging.Error.BadHostPEL",
196 Entry::Level::Error, ad);
Matt Spinlerfe721892020-04-02 10:28:08 -0500197
198 // Save it to a file for debug in the lab. Just keep the latest.
199 // Not adding it to the PEL because it could already be max size
200 // and don't want to truncate an already invalid PEL.
201 std::ofstream pelFile{getPELRepoPath() / "badPEL"};
202 pelFile.write(reinterpret_cast<const char*>(pelData.data()),
203 pelData.size());
Matt Spinler19e72902020-01-24 11:05:20 -0600204 }
205}
206
207void Manager::addESELPEL(const std::string& esel, uint32_t obmcLogID)
208{
209 std::vector<uint8_t> data;
210
Matt Spinler5f5352e2020-03-05 16:23:27 -0600211 log<level::DEBUG>("Adding PEL from ESEL",
212 entry("OBMC_LOG_ID=%d", obmcLogID));
213
Matt Spinler19e72902020-01-24 11:05:20 -0600214 try
215 {
216 data = std::move(eselToRawData(esel));
217 }
218 catch (std::exception& e)
219 {
220 // Try to add it below anyway, so it follows the usual bad data path.
221 log<level::ERR>("Problems converting ESEL string to a byte vector");
222 }
223
224 addPEL(data, obmcLogID);
225}
226
227std::vector<uint8_t> Manager::eselToRawData(const std::string& esel)
228{
229 std::vector<uint8_t> data;
230 std::string byteString;
231
232 // As the eSEL string looks like: "50 48 00 ab ..." there are 3
233 // characters per raw byte, and since the actual PEL data starts
234 // at the 16th byte, the code will grab the PEL data starting at
235 // offset 48 in the string.
236 static constexpr size_t pelStart = 16 * 3;
237
238 if (esel.size() <= pelStart)
239 {
240 log<level::ERR>("ESEL data too short",
241 entry("ESEL_SIZE=%d", esel.size()));
242
243 throw std::length_error("ESEL data too short");
244 }
245
246 for (size_t i = pelStart; i < esel.size(); i += 3)
247 {
248 if (i + 1 < esel.size())
249 {
250 byteString = esel.substr(i, 2);
251 data.push_back(std::stoi(byteString, nullptr, 16));
252 }
253 else
254 {
255 log<level::ERR>("ESEL data too short",
256 entry("ESEL_SIZE=%d", esel.size()));
257 throw std::length_error("ESEL data too short");
258 }
259 }
260
261 return data;
262}
263
Matt Spinler4e8078c2019-07-09 13:22:32 -0500264void Manager::erase(uint32_t obmcLogID)
265{
Matt Spinler475e5742019-07-18 16:09:49 -0500266 Repository::LogID id{Repository::LogID::Obmc(obmcLogID)};
267
268 _repo.remove(id);
Matt Spinler4e8078c2019-07-09 13:22:32 -0500269}
270
Patrick Williamsd26fa3e2021-04-21 15:22:23 -0500271bool Manager::isDeleteProhibited(uint32_t /*obmcLogID*/)
Matt Spinler4e8078c2019-07-09 13:22:32 -0500272{
273 return false;
274}
275
Matt Spinler56ad2a02020-03-26 14:00:52 -0500276PelFFDC Manager::convertToPelFFDC(const FFDCEntries& ffdc)
277{
278 PelFFDC pelFFDC;
279
280 std::for_each(ffdc.begin(), ffdc.end(), [&pelFFDC](const auto& f) {
281 PelFFDCfile pf;
282 pf.subType = std::get<ffdcSubtypePos>(f);
283 pf.version = std::get<ffdcVersionPos>(f);
284 pf.fd = std::get<ffdcFDPos>(f);
285
286 switch (std::get<ffdcFormatPos>(f))
287 {
288 case Create::FFDCFormat::JSON:
289 pf.format = UserDataFormat::json;
290 break;
291 case Create::FFDCFormat::CBOR:
292 pf.format = UserDataFormat::cbor;
293 break;
294 case Create::FFDCFormat::Text:
295 pf.format = UserDataFormat::text;
296 break;
297 case Create::FFDCFormat::Custom:
298 pf.format = UserDataFormat::custom;
299 break;
300 }
301
302 pelFFDC.push_back(pf);
303 });
304
305 return pelFFDC;
306}
307
Matt Spinler4e8078c2019-07-09 13:22:32 -0500308void Manager::createPEL(const std::string& message, uint32_t obmcLogID,
309 uint64_t timestamp,
310 phosphor::logging::Entry::Level severity,
311 const std::vector<std::string>& additionalData,
Patrick Williamsd26fa3e2021-04-21 15:22:23 -0500312 const std::vector<std::string>& /*associations*/,
Matt Spinler56ad2a02020-03-26 14:00:52 -0500313 const FFDCEntries& ffdc)
Matt Spinler4e8078c2019-07-09 13:22:32 -0500314{
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800315 auto entry = _registry.lookup(message, rg::LookupType::name);
Matt Spinler30ddc9f2020-07-16 15:39:59 -0500316 auto pelFFDC = convertToPelFFDC(ffdc);
317 AdditionalData ad{additionalData};
Matt Spinler1d4c74a2019-12-16 14:40:21 -0600318 std::string msg;
Matt Spinler67456c22019-10-21 12:22:49 -0500319
Matt Spinler30ddc9f2020-07-16 15:39:59 -0500320 if (!entry)
Matt Spinler67456c22019-10-21 12:22:49 -0500321 {
Matt Spinler30ddc9f2020-07-16 15:39:59 -0500322 // Instead, get the default entry that means there is no
323 // other matching entry. This error will still use the
324 // AdditionalData values of the original error, and this
325 // code will add the error message value that wasn't found
326 // to this AD. This way, there will at least be a PEL,
327 // possibly with callouts, to allow users to debug the
328 // issue that caused the error even without its own PEL.
Matt Spinler1d4c74a2019-12-16 14:40:21 -0600329 msg = "Event not found in PEL message registry: " + message;
330 log<level::INFO>(msg.c_str());
Matt Spinler30ddc9f2020-07-16 15:39:59 -0500331
332 entry = _registry.lookup(defaultLogMessage, rg::LookupType::name);
333 if (!entry)
334 {
335 log<level::ERR>("Default event not found in PEL message registry");
336 return;
337 }
338
339 ad.add(additional_data::error, message);
340 }
341
342 auto pel = std::make_unique<openpower::pels::PEL>(
343 *entry, obmcLogID, timestamp, severity, ad, pelFFDC, *_dataIface);
344
345 _repo.add(pel);
346
347 if (_repo.sizeWarning())
348 {
349 scheduleRepoPrune();
350 }
351
352 auto src = pel->primarySRC();
353 if (src)
354 {
Matt Spinler22421b92020-07-17 09:41:08 -0500355 auto msg =
356 fmt::format("Created PEL {:#x} (BMC ID {}) with SRC {}", pel->id(),
357 pel->obmcLogID(), (*src)->asciiString());
Matt Spinler30ddc9f2020-07-16 15:39:59 -0500358 while (msg.back() == ' ')
359 {
360 msg.pop_back();
361 }
362 log<level::INFO>(msg.c_str());
Matt Spinler1d4c74a2019-12-16 14:40:21 -0600363 }
Matt Spinler1962e082020-08-05 13:44:53 -0500364
365 // Activate any resulting service indicators if necessary
366 auto policy = service_indicators::getPolicy(*_dataIface);
367 policy->activate(*pel);
Andrew Geissler44fc3162020-07-09 09:21:31 -0500368
369 // Check if firmware should quiesce system due to error
370 checkPelAndQuiesce(pel);
Vijay Lobod354a392021-06-01 16:21:02 -0500371 updateEventId(pel);
Matt Spinler4e8078c2019-07-09 13:22:32 -0500372}
373
Matt Spinlera34ab722019-12-16 10:39:32 -0600374sdbusplus::message::unix_fd Manager::getPEL(uint32_t pelID)
375{
376 Repository::LogID id{Repository::LogID::Pel(pelID)};
377 std::optional<int> fd;
378
Matt Spinler5f5352e2020-03-05 16:23:27 -0600379 log<level::DEBUG>("getPEL", entry("PEL_ID=0x%X", pelID));
380
Matt Spinlera34ab722019-12-16 10:39:32 -0600381 try
382 {
383 fd = _repo.getPELFD(id);
384 }
385 catch (std::exception& e)
386 {
387 throw common_error::InternalFailure();
388 }
389
390 if (!fd)
391 {
392 throw common_error::InvalidArgument();
393 }
394
Matt Spinler6b1a5c82020-01-07 08:48:53 -0600395 scheduleFDClose(*fd);
396
Matt Spinlera34ab722019-12-16 10:39:32 -0600397 return *fd;
398}
399
Matt Spinler6b1a5c82020-01-07 08:48:53 -0600400void Manager::scheduleFDClose(int fd)
401{
402 _fdCloserEventSource = std::make_unique<sdeventplus::source::Defer>(
Matt Spinlerff9cec22020-07-15 13:06:35 -0500403 _event, std::bind(std::mem_fn(&Manager::closeFD), this, fd,
404 std::placeholders::_1));
Matt Spinler6b1a5c82020-01-07 08:48:53 -0600405}
406
Patrick Williamsd26fa3e2021-04-21 15:22:23 -0500407void Manager::closeFD(int fd, sdeventplus::source::EventBase& /*source*/)
Matt Spinler6b1a5c82020-01-07 08:48:53 -0600408{
409 close(fd);
410 _fdCloserEventSource.reset();
411}
412
Matt Spinlera34ab722019-12-16 10:39:32 -0600413std::vector<uint8_t> Manager::getPELFromOBMCID(uint32_t obmcLogID)
414{
415 Repository::LogID id{Repository::LogID::Obmc(obmcLogID)};
416 std::optional<std::vector<uint8_t>> data;
417
Matt Spinler5f5352e2020-03-05 16:23:27 -0600418 log<level::DEBUG>("getPELFromOBMCID", entry("OBMC_LOG_ID=%d", obmcLogID));
419
Matt Spinlera34ab722019-12-16 10:39:32 -0600420 try
421 {
422 data = _repo.getPELData(id);
423 }
424 catch (std::exception& e)
425 {
426 throw common_error::InternalFailure();
427 }
428
429 if (!data)
430 {
431 throw common_error::InvalidArgument();
432 }
433
434 return *data;
435}
436
437void Manager::hostAck(uint32_t pelID)
438{
439 Repository::LogID id{Repository::LogID::Pel(pelID)};
440
Matt Spinler5f5352e2020-03-05 16:23:27 -0600441 log<level::DEBUG>("HostAck", entry("PEL_ID=0x%X", pelID));
442
Matt Spinlera34ab722019-12-16 10:39:32 -0600443 if (!_repo.hasPEL(id))
444 {
445 throw common_error::InvalidArgument();
446 }
447
448 if (_hostNotifier)
449 {
450 _hostNotifier->ackPEL(pelID);
451 }
452}
453
454void Manager::hostReject(uint32_t pelID, RejectionReason reason)
455{
456 Repository::LogID id{Repository::LogID::Pel(pelID)};
457
Matt Spinler5f5352e2020-03-05 16:23:27 -0600458 log<level::DEBUG>("HostReject", entry("PEL_ID=0x%X", pelID),
459 entry("REASON=%d", static_cast<int>(reason)));
460
Matt Spinlera34ab722019-12-16 10:39:32 -0600461 if (!_repo.hasPEL(id))
462 {
463 throw common_error::InvalidArgument();
464 }
465
Matt Spinler05c2c6c2019-12-18 14:02:09 -0600466 if (reason == RejectionReason::BadPEL)
Matt Spinlera34ab722019-12-16 10:39:32 -0600467 {
Matt Spinler05c2c6c2019-12-18 14:02:09 -0600468 AdditionalData data;
469 data.add("BAD_ID", getNumberString("0x%08X", pelID));
470 _eventLogger.log("org.open_power.Logging.Error.SentBadPELToHost",
471 Entry::Level::Informational, data);
472 if (_hostNotifier)
Matt Spinlera34ab722019-12-16 10:39:32 -0600473 {
474 _hostNotifier->setBadPEL(pelID);
475 }
Matt Spinler05c2c6c2019-12-18 14:02:09 -0600476 }
477 else if ((reason == RejectionReason::HostFull) && _hostNotifier)
478 {
479 _hostNotifier->setHostFull(pelID);
Matt Spinlera34ab722019-12-16 10:39:32 -0600480 }
481}
482
Matt Spinler7e727a32020-07-07 15:00:17 -0500483void Manager::scheduleRepoPrune()
484{
Matt Spinler7e727a32020-07-07 15:00:17 -0500485 _repoPrunerEventSource = std::make_unique<sdeventplus::source::Defer>(
Matt Spinlerff9cec22020-07-15 13:06:35 -0500486 _event, std::bind(std::mem_fn(&Manager::pruneRepo), this,
487 std::placeholders::_1));
Matt Spinler7e727a32020-07-07 15:00:17 -0500488}
489
Patrick Williamsd26fa3e2021-04-21 15:22:23 -0500490void Manager::pruneRepo(sdeventplus::source::EventBase& /*source*/)
Matt Spinler7e727a32020-07-07 15:00:17 -0500491{
492 auto idsToDelete = _repo.prune();
493
494 // Remove the OpenBMC event logs for the PELs that were just removed.
495 std::for_each(idsToDelete.begin(), idsToDelete.end(),
496 [this](auto id) { this->_logManager.erase(id); });
497
498 _repoPrunerEventSource.reset();
499}
500
Matt Spinlerff9cec22020-07-15 13:06:35 -0500501void Manager::setupPELDeleteWatch()
502{
503 _pelFileDeleteFD = inotify_init1(IN_NONBLOCK);
504 if (-1 == _pelFileDeleteFD)
505 {
506 auto e = errno;
507 std::string msg =
508 "inotify_init1 failed with errno " + std::to_string(e);
509 log<level::ERR>(msg.c_str());
510 abort();
511 }
512
513 _pelFileDeleteWatchFD = inotify_add_watch(
514 _pelFileDeleteFD, _repo.repoPath().c_str(), IN_DELETE);
515 if (-1 == _pelFileDeleteWatchFD)
516 {
517 auto e = errno;
518 std::string msg =
519 "inotify_add_watch failed with error " + std::to_string(e);
520 log<level::ERR>(msg.c_str());
521 abort();
522 }
523
524 _pelFileDeleteEventSource = std::make_unique<sdeventplus::source::IO>(
525 _event, _pelFileDeleteFD, EPOLLIN,
526 std::bind(std::mem_fn(&Manager::pelFileDeleted), this,
527 std::placeholders::_1, std::placeholders::_2,
528 std::placeholders::_3));
529}
530
Patrick Williamsd26fa3e2021-04-21 15:22:23 -0500531void Manager::pelFileDeleted(sdeventplus::source::IO& /*io*/, int /*fd*/,
Matt Spinlerff9cec22020-07-15 13:06:35 -0500532 uint32_t revents)
533{
534 if (!(revents & EPOLLIN))
535 {
536 return;
537 }
538
539 // An event for 1 PEL uses 48B. When all PELs are deleted at once,
540 // as many events as there is room for can be handled in one callback.
541 // A size of 2000 will allow 41 to be processed, with additional
542 // callbacks being needed to process the remaining ones.
Matt Spinler9d59d582021-05-19 07:57:10 -0600543 std::array<uint8_t, 2000> data{};
Matt Spinlerff9cec22020-07-15 13:06:35 -0500544 auto bytesRead = read(_pelFileDeleteFD, data.data(), data.size());
545 if (bytesRead < 0)
546 {
547 auto e = errno;
548 std::string msg = "Failed reading data from inotify event, errno = " +
549 std::to_string(e);
550 log<level::ERR>(msg.c_str());
551 abort();
552 }
553
554 auto offset = 0;
555 while (offset < bytesRead)
556 {
557 auto event = reinterpret_cast<inotify_event*>(&data[offset]);
558 if (event->mask & IN_DELETE)
559 {
560 std::string filename{event->name};
561
562 // Get the PEL ID from the filename and tell the
563 // repo it's been removed, and then delete the BMC
564 // event log if it's there.
565 auto pos = filename.find_first_of('_');
566 if (pos != std::string::npos)
567 {
568 try
569 {
570 auto idString = filename.substr(pos + 1);
571 auto pelID = std::stoul(idString, nullptr, 16);
572
573 Repository::LogID id{Repository::LogID::Pel(pelID)};
574 auto removedLogID = _repo.remove(id);
575 if (removedLogID)
576 {
577 _logManager.erase(removedLogID->obmcID.id);
578 }
579 }
580 catch (const std::exception& e)
581 {
582 log<level::INFO>("Could not find PEL ID from its filename",
583 entry("FILENAME=%s", filename.c_str()));
584 }
585 }
586 }
587
588 offset += offsetof(inotify_event, name) + event->len;
589 }
590}
Matt Spinler9cc30072020-09-16 15:39:34 -0500591
592std::tuple<uint32_t, uint32_t> Manager::createPELWithFFDCFiles(
593 std::string message, Entry::Level severity,
594 std::map<std::string, std::string> additionalData,
595 std::vector<std::tuple<
596 sdbusplus::xyz::openbmc_project::Logging::server::Create::FFDCFormat,
597 uint8_t, uint8_t, sdbusplus::message::unix_fd>>
598 fFDC)
599{
Matt Spinler44893cc2020-08-26 11:34:17 -0500600 _logManager.createWithFFDC(message, severity, additionalData, fFDC);
601
602 return {_logManager.lastEntryID(), _repo.lastPelID()};
Matt Spinler9cc30072020-09-16 15:39:34 -0500603}
604
Andrew Geissler44fc3162020-07-09 09:21:31 -0500605void Manager::checkPelAndQuiesce(std::unique_ptr<openpower::pels::PEL>& pel)
606{
Matt Spinlerb2abc042021-05-17 15:32:50 -0600607 if ((pel->userHeader().severity() ==
608 static_cast<uint8_t>(SeverityType::nonError)) ||
609 (pel->userHeader().severity() ==
610 static_cast<uint8_t>(SeverityType::recovered)))
Andrew Geissler44fc3162020-07-09 09:21:31 -0500611 {
Matt Spinlerb2abc042021-05-17 15:32:50 -0600612 log<level::DEBUG>(
613 "PEL severity informational or recovered. no quiesce needed");
Andrew Geissler44fc3162020-07-09 09:21:31 -0500614 return;
615 }
616 if (!_logManager.isQuiesceOnErrorEnabled())
617 {
618 log<level::DEBUG>("QuiesceOnHwError not enabled, no quiesce needed");
619 return;
620 }
621
622 // Now check if it has any type of callout
623 if (pel->isCalloutPresent())
624 {
Matt Spinlerb2abc042021-05-17 15:32:50 -0600625 log<level::INFO>(
626 "QuiesceOnHwError enabled, PEL severity not nonError or recovered, "
627 "and callout is present");
Andrew Geissler44fc3162020-07-09 09:21:31 -0500628
629 _logManager.quiesceOnError(pel->obmcLogID());
630 }
631}
632
Vijay Lobod354a392021-06-01 16:21:02 -0500633std::string Manager::getEventId(const openpower::pels::PEL& pel) const
634{
635 std::string str;
636 auto src = pel.primarySRC();
637 if (src)
638 {
639 const auto& hexwords = (*src)->hexwordData();
640
641 std::string refcode = (*src)->asciiString();
642 size_t pos = refcode.find_last_not_of(0x20);
643 if (pos != std::string::npos)
644 {
645 refcode.erase(pos + 1);
646 }
647 str = refcode;
648
649 for (auto& value : hexwords)
650 {
651 str += " ";
652 str += getNumberString("%08X", value);
653 }
654 }
655 return str;
656}
657
658void Manager::updateEventId(std::unique_ptr<openpower::pels::PEL>& pel)
659{
660 std::string eventIdStr = getEventId(*pel);
661
662 auto entryN = _logManager.entries.find(pel->obmcLogID());
663 if (entryN != _logManager.entries.end())
664 {
665 entryN->second->eventId(eventIdStr);
666 }
667}
668
Adriana Kobylake7d271a2020-12-07 14:32:44 -0600669void Manager::setEntryPath(uint32_t obmcLogID)
670{
671 Repository::LogID id{Repository::LogID::Obmc(obmcLogID)};
672 if (auto attributes = _repo.getPELAttributes(id); attributes)
673 {
674 auto& attr = attributes.value().get();
675 auto entry = _logManager.entries.find(obmcLogID);
676 if (entry != _logManager.entries.end())
677 {
678 entry->second->path(attr.path);
679 }
680 }
681}
682
Vijay Lobocbc93a42021-05-20 19:04:07 -0500683void Manager::setServiceProviderNotifyFlag(uint32_t obmcLogID)
684{
685 Repository::LogID id{Repository::LogID::Obmc(obmcLogID)};
686 if (auto attributes = _repo.getPELAttributes(id); attributes)
687 {
688 auto& attr = attributes.value().get();
689 auto entry = _logManager.entries.find(obmcLogID);
690 if (entry != _logManager.entries.end())
691 {
692 if (attr.actionFlags.test(callHomeFlagBit))
693 {
694 entry->second->serviceProviderNotify(true);
695 }
696 else
697 {
698 entry->second->serviceProviderNotify(false);
699 }
700 }
701 }
702}
703
Ramesh Iyyarf4203c42021-06-24 06:09:23 -0500704uint32_t Manager::getPELIdFromBMCLogId(uint32_t bmcLogId)
705{
706 Repository::LogID id{Repository::LogID::Obmc(bmcLogId)};
707 if (auto logId = _repo.getLogID(id); !logId.has_value())
708 {
709 throw common_error::InvalidArgument();
710 }
711 else
712 {
713 return logId->pelID.id;
714 }
715}
716
Matt Spinler4e8078c2019-07-09 13:22:32 -0500717} // namespace pels
718} // namespace openpower