blob: 1372bf61fc5c878905db1f5b703a556ed65a895d [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);
Matt Spinler4e8078c2019-07-09 13:22:32 -050096}
97
98void Manager::addRawPEL(const std::string& rawPelPath, uint32_t obmcLogID)
99{
Matt Spinler89fa0822019-07-17 13:54:30 -0500100 if (fs::exists(rawPelPath))
101 {
102 std::ifstream file(rawPelPath, std::ios::in | std::ios::binary);
103
104 auto data = std::vector<uint8_t>(std::istreambuf_iterator<char>(file),
105 std::istreambuf_iterator<char>());
106 if (file.fail())
107 {
108 log<level::ERR>("Filesystem error reading a raw PEL",
109 entry("PELFILE=%s", rawPelPath.c_str()),
110 entry("OBMCLOGID=%d", obmcLogID));
111 // TODO, Decide what to do here. Maybe nothing.
112 return;
113 }
114
115 file.close();
116
Matt Spinler19e72902020-01-24 11:05:20 -0600117 addPEL(data, obmcLogID);
Matt Spinler89fa0822019-07-17 13:54:30 -0500118 }
119 else
120 {
121 log<level::ERR>("Raw PEL file from BMC event log does not exist",
122 entry("PELFILE=%s", (rawPelPath).c_str()),
123 entry("OBMCLOGID=%d", obmcLogID));
124 }
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{
129
130 auto pel = std::make_unique<openpower::pels::PEL>(pelData, obmcLogID);
131 if (pel->valid())
132 {
Sumit Kumara1e40842021-06-23 09:52:25 -0500133 // Assign Id other than to Hostbot PEL
134 if ((pel->privateHeader()).creatorID() !=
135 static_cast<uint8_t>(CreatorID::hostboot))
136 {
137 pel->assignID();
138 }
139
140 // PELs created by others still need this field set by us.
Matt Spinler19e72902020-01-24 11:05:20 -0600141 pel->setCommitTime();
142
Sumit Kumar3160a542021-04-26 08:07:04 -0500143 // Update System Info to Extended User Data
144 pel->updateSysInfoInExtendedUserDataSection(*_dataIface);
145
Matt Spinler19e72902020-01-24 11:05:20 -0600146 try
147 {
Matt Spinlerd0ab1cf2021-02-10 13:26:18 -0600148 log<level::DEBUG>(
Matt Spinler6321ba32020-07-17 09:58:19 -0500149 fmt::format("Adding external PEL {:#x} (BMC ID {}) to repo",
150 pel->id(), obmcLogID)
151 .c_str());
Matt Spinler5f5352e2020-03-05 16:23:27 -0600152
Matt Spinler19e72902020-01-24 11:05:20 -0600153 _repo.add(pel);
Matt Spinler7e727a32020-07-07 15:00:17 -0500154
155 if (_repo.sizeWarning())
156 {
157 scheduleRepoPrune();
158 }
Matt Spinler1962e082020-08-05 13:44:53 -0500159
160 // Activate any resulting service indicators if necessary
161 auto policy = service_indicators::getPolicy(*_dataIface);
162 policy->activate(*pel);
Matt Spinler19e72902020-01-24 11:05:20 -0600163 }
164 catch (std::exception& e)
165 {
166 // Probably a full or r/o filesystem, not much we can do.
167 log<level::ERR>("Unable to add PEL to Repository",
168 entry("PEL_ID=0x%X", pel->id()));
169 }
Andrew Geissler44fc3162020-07-09 09:21:31 -0500170
171 // Check if firmware should quiesce system due to error
172 checkPelAndQuiesce(pel);
Vijay Lobod354a392021-06-01 16:21:02 -0500173 updateEventId(pel);
Matt Spinler19e72902020-01-24 11:05:20 -0600174 }
175 else
176 {
177 log<level::ERR>("Invalid PEL received from the host",
178 entry("OBMCLOGID=%d", obmcLogID));
179
180 AdditionalData ad;
181 ad.add("PLID", getNumberString("0x%08X", pel->plid()));
182 ad.add("OBMC_LOG_ID", std::to_string(obmcLogID));
183 ad.add("PEL_SIZE", std::to_string(pelData.size()));
184
185 std::string asciiString;
186 auto src = pel->primarySRC();
187 if (src)
188 {
189 asciiString = (*src)->asciiString();
190 }
191
192 ad.add("SRC", asciiString);
193
194 _eventLogger.log("org.open_power.Logging.Error.BadHostPEL",
195 Entry::Level::Error, ad);
Matt Spinlerfe721892020-04-02 10:28:08 -0500196
197 // Save it to a file for debug in the lab. Just keep the latest.
198 // Not adding it to the PEL because it could already be max size
199 // and don't want to truncate an already invalid PEL.
200 std::ofstream pelFile{getPELRepoPath() / "badPEL"};
201 pelFile.write(reinterpret_cast<const char*>(pelData.data()),
202 pelData.size());
Matt Spinler19e72902020-01-24 11:05:20 -0600203 }
204}
205
206void Manager::addESELPEL(const std::string& esel, uint32_t obmcLogID)
207{
208 std::vector<uint8_t> data;
209
Matt Spinler5f5352e2020-03-05 16:23:27 -0600210 log<level::DEBUG>("Adding PEL from ESEL",
211 entry("OBMC_LOG_ID=%d", obmcLogID));
212
Matt Spinler19e72902020-01-24 11:05:20 -0600213 try
214 {
215 data = std::move(eselToRawData(esel));
216 }
217 catch (std::exception& e)
218 {
219 // Try to add it below anyway, so it follows the usual bad data path.
220 log<level::ERR>("Problems converting ESEL string to a byte vector");
221 }
222
223 addPEL(data, obmcLogID);
224}
225
226std::vector<uint8_t> Manager::eselToRawData(const std::string& esel)
227{
228 std::vector<uint8_t> data;
229 std::string byteString;
230
231 // As the eSEL string looks like: "50 48 00 ab ..." there are 3
232 // characters per raw byte, and since the actual PEL data starts
233 // at the 16th byte, the code will grab the PEL data starting at
234 // offset 48 in the string.
235 static constexpr size_t pelStart = 16 * 3;
236
237 if (esel.size() <= pelStart)
238 {
239 log<level::ERR>("ESEL data too short",
240 entry("ESEL_SIZE=%d", esel.size()));
241
242 throw std::length_error("ESEL data too short");
243 }
244
245 for (size_t i = pelStart; i < esel.size(); i += 3)
246 {
247 if (i + 1 < esel.size())
248 {
249 byteString = esel.substr(i, 2);
250 data.push_back(std::stoi(byteString, nullptr, 16));
251 }
252 else
253 {
254 log<level::ERR>("ESEL data too short",
255 entry("ESEL_SIZE=%d", esel.size()));
256 throw std::length_error("ESEL data too short");
257 }
258 }
259
260 return data;
261}
262
Matt Spinler4e8078c2019-07-09 13:22:32 -0500263void Manager::erase(uint32_t obmcLogID)
264{
Matt Spinler475e5742019-07-18 16:09:49 -0500265 Repository::LogID id{Repository::LogID::Obmc(obmcLogID)};
266
267 _repo.remove(id);
Matt Spinler4e8078c2019-07-09 13:22:32 -0500268}
269
Patrick Williamsd26fa3e2021-04-21 15:22:23 -0500270bool Manager::isDeleteProhibited(uint32_t /*obmcLogID*/)
Matt Spinler4e8078c2019-07-09 13:22:32 -0500271{
272 return false;
273}
274
Matt Spinler56ad2a02020-03-26 14:00:52 -0500275PelFFDC Manager::convertToPelFFDC(const FFDCEntries& ffdc)
276{
277 PelFFDC pelFFDC;
278
279 std::for_each(ffdc.begin(), ffdc.end(), [&pelFFDC](const auto& f) {
280 PelFFDCfile pf;
281 pf.subType = std::get<ffdcSubtypePos>(f);
282 pf.version = std::get<ffdcVersionPos>(f);
283 pf.fd = std::get<ffdcFDPos>(f);
284
285 switch (std::get<ffdcFormatPos>(f))
286 {
287 case Create::FFDCFormat::JSON:
288 pf.format = UserDataFormat::json;
289 break;
290 case Create::FFDCFormat::CBOR:
291 pf.format = UserDataFormat::cbor;
292 break;
293 case Create::FFDCFormat::Text:
294 pf.format = UserDataFormat::text;
295 break;
296 case Create::FFDCFormat::Custom:
297 pf.format = UserDataFormat::custom;
298 break;
299 }
300
301 pelFFDC.push_back(pf);
302 });
303
304 return pelFFDC;
305}
306
Matt Spinler4e8078c2019-07-09 13:22:32 -0500307void Manager::createPEL(const std::string& message, uint32_t obmcLogID,
308 uint64_t timestamp,
309 phosphor::logging::Entry::Level severity,
310 const std::vector<std::string>& additionalData,
Patrick Williamsd26fa3e2021-04-21 15:22:23 -0500311 const std::vector<std::string>& /*associations*/,
Matt Spinler56ad2a02020-03-26 14:00:52 -0500312 const FFDCEntries& ffdc)
Matt Spinler4e8078c2019-07-09 13:22:32 -0500313{
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800314 auto entry = _registry.lookup(message, rg::LookupType::name);
Matt Spinler30ddc9f2020-07-16 15:39:59 -0500315 auto pelFFDC = convertToPelFFDC(ffdc);
316 AdditionalData ad{additionalData};
Matt Spinler1d4c74a2019-12-16 14:40:21 -0600317 std::string msg;
Matt Spinler67456c22019-10-21 12:22:49 -0500318
Matt Spinler30ddc9f2020-07-16 15:39:59 -0500319 if (!entry)
Matt Spinler67456c22019-10-21 12:22:49 -0500320 {
Matt Spinler30ddc9f2020-07-16 15:39:59 -0500321 // Instead, get the default entry that means there is no
322 // other matching entry. This error will still use the
323 // AdditionalData values of the original error, and this
324 // code will add the error message value that wasn't found
325 // to this AD. This way, there will at least be a PEL,
326 // possibly with callouts, to allow users to debug the
327 // issue that caused the error even without its own PEL.
Matt Spinler1d4c74a2019-12-16 14:40:21 -0600328 msg = "Event not found in PEL message registry: " + message;
329 log<level::INFO>(msg.c_str());
Matt Spinler30ddc9f2020-07-16 15:39:59 -0500330
331 entry = _registry.lookup(defaultLogMessage, rg::LookupType::name);
332 if (!entry)
333 {
334 log<level::ERR>("Default event not found in PEL message registry");
335 return;
336 }
337
338 ad.add(additional_data::error, message);
339 }
340
341 auto pel = std::make_unique<openpower::pels::PEL>(
342 *entry, obmcLogID, timestamp, severity, ad, pelFFDC, *_dataIface);
343
344 _repo.add(pel);
345
346 if (_repo.sizeWarning())
347 {
348 scheduleRepoPrune();
349 }
350
351 auto src = pel->primarySRC();
352 if (src)
353 {
Matt Spinler22421b92020-07-17 09:41:08 -0500354 auto msg =
355 fmt::format("Created PEL {:#x} (BMC ID {}) with SRC {}", pel->id(),
356 pel->obmcLogID(), (*src)->asciiString());
Matt Spinler30ddc9f2020-07-16 15:39:59 -0500357 while (msg.back() == ' ')
358 {
359 msg.pop_back();
360 }
361 log<level::INFO>(msg.c_str());
Matt Spinler1d4c74a2019-12-16 14:40:21 -0600362 }
Matt Spinler1962e082020-08-05 13:44:53 -0500363
364 // Activate any resulting service indicators if necessary
365 auto policy = service_indicators::getPolicy(*_dataIface);
366 policy->activate(*pel);
Andrew Geissler44fc3162020-07-09 09:21:31 -0500367
368 // Check if firmware should quiesce system due to error
369 checkPelAndQuiesce(pel);
Vijay Lobod354a392021-06-01 16:21:02 -0500370 updateEventId(pel);
Matt Spinler4e8078c2019-07-09 13:22:32 -0500371}
372
Matt Spinlera34ab722019-12-16 10:39:32 -0600373sdbusplus::message::unix_fd Manager::getPEL(uint32_t pelID)
374{
375 Repository::LogID id{Repository::LogID::Pel(pelID)};
376 std::optional<int> fd;
377
Matt Spinler5f5352e2020-03-05 16:23:27 -0600378 log<level::DEBUG>("getPEL", entry("PEL_ID=0x%X", pelID));
379
Matt Spinlera34ab722019-12-16 10:39:32 -0600380 try
381 {
382 fd = _repo.getPELFD(id);
383 }
384 catch (std::exception& e)
385 {
386 throw common_error::InternalFailure();
387 }
388
389 if (!fd)
390 {
391 throw common_error::InvalidArgument();
392 }
393
Matt Spinler6b1a5c82020-01-07 08:48:53 -0600394 scheduleFDClose(*fd);
395
Matt Spinlera34ab722019-12-16 10:39:32 -0600396 return *fd;
397}
398
Matt Spinler6b1a5c82020-01-07 08:48:53 -0600399void Manager::scheduleFDClose(int fd)
400{
401 _fdCloserEventSource = std::make_unique<sdeventplus::source::Defer>(
Matt Spinlerff9cec22020-07-15 13:06:35 -0500402 _event, std::bind(std::mem_fn(&Manager::closeFD), this, fd,
403 std::placeholders::_1));
Matt Spinler6b1a5c82020-01-07 08:48:53 -0600404}
405
Patrick Williamsd26fa3e2021-04-21 15:22:23 -0500406void Manager::closeFD(int fd, sdeventplus::source::EventBase& /*source*/)
Matt Spinler6b1a5c82020-01-07 08:48:53 -0600407{
408 close(fd);
409 _fdCloserEventSource.reset();
410}
411
Matt Spinlera34ab722019-12-16 10:39:32 -0600412std::vector<uint8_t> Manager::getPELFromOBMCID(uint32_t obmcLogID)
413{
414 Repository::LogID id{Repository::LogID::Obmc(obmcLogID)};
415 std::optional<std::vector<uint8_t>> data;
416
Matt Spinler5f5352e2020-03-05 16:23:27 -0600417 log<level::DEBUG>("getPELFromOBMCID", entry("OBMC_LOG_ID=%d", obmcLogID));
418
Matt Spinlera34ab722019-12-16 10:39:32 -0600419 try
420 {
421 data = _repo.getPELData(id);
422 }
423 catch (std::exception& e)
424 {
425 throw common_error::InternalFailure();
426 }
427
428 if (!data)
429 {
430 throw common_error::InvalidArgument();
431 }
432
433 return *data;
434}
435
436void Manager::hostAck(uint32_t pelID)
437{
438 Repository::LogID id{Repository::LogID::Pel(pelID)};
439
Matt Spinler5f5352e2020-03-05 16:23:27 -0600440 log<level::DEBUG>("HostAck", entry("PEL_ID=0x%X", pelID));
441
Matt Spinlera34ab722019-12-16 10:39:32 -0600442 if (!_repo.hasPEL(id))
443 {
444 throw common_error::InvalidArgument();
445 }
446
447 if (_hostNotifier)
448 {
449 _hostNotifier->ackPEL(pelID);
450 }
451}
452
453void Manager::hostReject(uint32_t pelID, RejectionReason reason)
454{
455 Repository::LogID id{Repository::LogID::Pel(pelID)};
456
Matt Spinler5f5352e2020-03-05 16:23:27 -0600457 log<level::DEBUG>("HostReject", entry("PEL_ID=0x%X", pelID),
458 entry("REASON=%d", static_cast<int>(reason)));
459
Matt Spinlera34ab722019-12-16 10:39:32 -0600460 if (!_repo.hasPEL(id))
461 {
462 throw common_error::InvalidArgument();
463 }
464
Matt Spinler05c2c6c2019-12-18 14:02:09 -0600465 if (reason == RejectionReason::BadPEL)
Matt Spinlera34ab722019-12-16 10:39:32 -0600466 {
Matt Spinler05c2c6c2019-12-18 14:02:09 -0600467 AdditionalData data;
468 data.add("BAD_ID", getNumberString("0x%08X", pelID));
469 _eventLogger.log("org.open_power.Logging.Error.SentBadPELToHost",
470 Entry::Level::Informational, data);
471 if (_hostNotifier)
Matt Spinlera34ab722019-12-16 10:39:32 -0600472 {
473 _hostNotifier->setBadPEL(pelID);
474 }
Matt Spinler05c2c6c2019-12-18 14:02:09 -0600475 }
476 else if ((reason == RejectionReason::HostFull) && _hostNotifier)
477 {
478 _hostNotifier->setHostFull(pelID);
Matt Spinlera34ab722019-12-16 10:39:32 -0600479 }
480}
481
Matt Spinler7e727a32020-07-07 15:00:17 -0500482void Manager::scheduleRepoPrune()
483{
Matt Spinler7e727a32020-07-07 15:00:17 -0500484 _repoPrunerEventSource = std::make_unique<sdeventplus::source::Defer>(
Matt Spinlerff9cec22020-07-15 13:06:35 -0500485 _event, std::bind(std::mem_fn(&Manager::pruneRepo), this,
486 std::placeholders::_1));
Matt Spinler7e727a32020-07-07 15:00:17 -0500487}
488
Patrick Williamsd26fa3e2021-04-21 15:22:23 -0500489void Manager::pruneRepo(sdeventplus::source::EventBase& /*source*/)
Matt Spinler7e727a32020-07-07 15:00:17 -0500490{
491 auto idsToDelete = _repo.prune();
492
493 // Remove the OpenBMC event logs for the PELs that were just removed.
494 std::for_each(idsToDelete.begin(), idsToDelete.end(),
495 [this](auto id) { this->_logManager.erase(id); });
496
497 _repoPrunerEventSource.reset();
498}
499
Matt Spinlerff9cec22020-07-15 13:06:35 -0500500void Manager::setupPELDeleteWatch()
501{
502 _pelFileDeleteFD = inotify_init1(IN_NONBLOCK);
503 if (-1 == _pelFileDeleteFD)
504 {
505 auto e = errno;
506 std::string msg =
507 "inotify_init1 failed with errno " + std::to_string(e);
508 log<level::ERR>(msg.c_str());
509 abort();
510 }
511
512 _pelFileDeleteWatchFD = inotify_add_watch(
513 _pelFileDeleteFD, _repo.repoPath().c_str(), IN_DELETE);
514 if (-1 == _pelFileDeleteWatchFD)
515 {
516 auto e = errno;
517 std::string msg =
518 "inotify_add_watch failed with error " + std::to_string(e);
519 log<level::ERR>(msg.c_str());
520 abort();
521 }
522
523 _pelFileDeleteEventSource = std::make_unique<sdeventplus::source::IO>(
524 _event, _pelFileDeleteFD, EPOLLIN,
525 std::bind(std::mem_fn(&Manager::pelFileDeleted), this,
526 std::placeholders::_1, std::placeholders::_2,
527 std::placeholders::_3));
528}
529
Patrick Williamsd26fa3e2021-04-21 15:22:23 -0500530void Manager::pelFileDeleted(sdeventplus::source::IO& /*io*/, int /*fd*/,
Matt Spinlerff9cec22020-07-15 13:06:35 -0500531 uint32_t revents)
532{
533 if (!(revents & EPOLLIN))
534 {
535 return;
536 }
537
538 // An event for 1 PEL uses 48B. When all PELs are deleted at once,
539 // as many events as there is room for can be handled in one callback.
540 // A size of 2000 will allow 41 to be processed, with additional
541 // callbacks being needed to process the remaining ones.
Matt Spinler9d59d582021-05-19 07:57:10 -0600542 std::array<uint8_t, 2000> data{};
Matt Spinlerff9cec22020-07-15 13:06:35 -0500543 auto bytesRead = read(_pelFileDeleteFD, data.data(), data.size());
544 if (bytesRead < 0)
545 {
546 auto e = errno;
547 std::string msg = "Failed reading data from inotify event, errno = " +
548 std::to_string(e);
549 log<level::ERR>(msg.c_str());
550 abort();
551 }
552
553 auto offset = 0;
554 while (offset < bytesRead)
555 {
556 auto event = reinterpret_cast<inotify_event*>(&data[offset]);
557 if (event->mask & IN_DELETE)
558 {
559 std::string filename{event->name};
560
561 // Get the PEL ID from the filename and tell the
562 // repo it's been removed, and then delete the BMC
563 // event log if it's there.
564 auto pos = filename.find_first_of('_');
565 if (pos != std::string::npos)
566 {
567 try
568 {
569 auto idString = filename.substr(pos + 1);
570 auto pelID = std::stoul(idString, nullptr, 16);
571
572 Repository::LogID id{Repository::LogID::Pel(pelID)};
573 auto removedLogID = _repo.remove(id);
574 if (removedLogID)
575 {
576 _logManager.erase(removedLogID->obmcID.id);
577 }
578 }
579 catch (const std::exception& e)
580 {
581 log<level::INFO>("Could not find PEL ID from its filename",
582 entry("FILENAME=%s", filename.c_str()));
583 }
584 }
585 }
586
587 offset += offsetof(inotify_event, name) + event->len;
588 }
589}
Matt Spinler9cc30072020-09-16 15:39:34 -0500590
591std::tuple<uint32_t, uint32_t> Manager::createPELWithFFDCFiles(
592 std::string message, Entry::Level severity,
593 std::map<std::string, std::string> additionalData,
594 std::vector<std::tuple<
595 sdbusplus::xyz::openbmc_project::Logging::server::Create::FFDCFormat,
596 uint8_t, uint8_t, sdbusplus::message::unix_fd>>
597 fFDC)
598{
Matt Spinler44893cc2020-08-26 11:34:17 -0500599 _logManager.createWithFFDC(message, severity, additionalData, fFDC);
600
601 return {_logManager.lastEntryID(), _repo.lastPelID()};
Matt Spinler9cc30072020-09-16 15:39:34 -0500602}
603
Andrew Geissler44fc3162020-07-09 09:21:31 -0500604void Manager::checkPelAndQuiesce(std::unique_ptr<openpower::pels::PEL>& pel)
605{
Matt Spinlerb2abc042021-05-17 15:32:50 -0600606 if ((pel->userHeader().severity() ==
607 static_cast<uint8_t>(SeverityType::nonError)) ||
608 (pel->userHeader().severity() ==
609 static_cast<uint8_t>(SeverityType::recovered)))
Andrew Geissler44fc3162020-07-09 09:21:31 -0500610 {
Matt Spinlerb2abc042021-05-17 15:32:50 -0600611 log<level::DEBUG>(
612 "PEL severity informational or recovered. no quiesce needed");
Andrew Geissler44fc3162020-07-09 09:21:31 -0500613 return;
614 }
615 if (!_logManager.isQuiesceOnErrorEnabled())
616 {
617 log<level::DEBUG>("QuiesceOnHwError not enabled, no quiesce needed");
618 return;
619 }
620
621 // Now check if it has any type of callout
622 if (pel->isCalloutPresent())
623 {
Matt Spinlerb2abc042021-05-17 15:32:50 -0600624 log<level::INFO>(
625 "QuiesceOnHwError enabled, PEL severity not nonError or recovered, "
626 "and callout is present");
Andrew Geissler44fc3162020-07-09 09:21:31 -0500627
628 _logManager.quiesceOnError(pel->obmcLogID());
629 }
630}
631
Vijay Lobod354a392021-06-01 16:21:02 -0500632std::string Manager::getEventId(const openpower::pels::PEL& pel) const
633{
634 std::string str;
635 auto src = pel.primarySRC();
636 if (src)
637 {
638 const auto& hexwords = (*src)->hexwordData();
639
640 std::string refcode = (*src)->asciiString();
641 size_t pos = refcode.find_last_not_of(0x20);
642 if (pos != std::string::npos)
643 {
644 refcode.erase(pos + 1);
645 }
646 str = refcode;
647
648 for (auto& value : hexwords)
649 {
650 str += " ";
651 str += getNumberString("%08X", value);
652 }
653 }
654 return str;
655}
656
657void Manager::updateEventId(std::unique_ptr<openpower::pels::PEL>& pel)
658{
659 std::string eventIdStr = getEventId(*pel);
660
661 auto entryN = _logManager.entries.find(pel->obmcLogID());
662 if (entryN != _logManager.entries.end())
663 {
664 entryN->second->eventId(eventIdStr);
665 }
666}
667
Adriana Kobylake7d271a2020-12-07 14:32:44 -0600668void Manager::setEntryPath(uint32_t obmcLogID)
669{
670 Repository::LogID id{Repository::LogID::Obmc(obmcLogID)};
671 if (auto attributes = _repo.getPELAttributes(id); attributes)
672 {
673 auto& attr = attributes.value().get();
674 auto entry = _logManager.entries.find(obmcLogID);
675 if (entry != _logManager.entries.end())
676 {
677 entry->second->path(attr.path);
678 }
679 }
680}
681
Matt Spinler4e8078c2019-07-09 13:22:32 -0500682} // namespace pels
683} // namespace openpower