blob: afd7eb0c1c20f4d6075f5771dda6ad0b4366d62d [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 {
133 // PELs created by others still need these fields set by us.
134 pel->assignID();
135 pel->setCommitTime();
136
Sumit Kumar3160a542021-04-26 08:07:04 -0500137 // Update System Info to Extended User Data
138 pel->updateSysInfoInExtendedUserDataSection(*_dataIface);
139
Matt Spinler19e72902020-01-24 11:05:20 -0600140 try
141 {
Matt Spinlerd0ab1cf2021-02-10 13:26:18 -0600142 log<level::DEBUG>(
Matt Spinler6321ba32020-07-17 09:58:19 -0500143 fmt::format("Adding external PEL {:#x} (BMC ID {}) to repo",
144 pel->id(), obmcLogID)
145 .c_str());
Matt Spinler5f5352e2020-03-05 16:23:27 -0600146
Matt Spinler19e72902020-01-24 11:05:20 -0600147 _repo.add(pel);
Matt Spinler7e727a32020-07-07 15:00:17 -0500148
149 if (_repo.sizeWarning())
150 {
151 scheduleRepoPrune();
152 }
Matt Spinler1962e082020-08-05 13:44:53 -0500153
154 // Activate any resulting service indicators if necessary
155 auto policy = service_indicators::getPolicy(*_dataIface);
156 policy->activate(*pel);
Matt Spinler19e72902020-01-24 11:05:20 -0600157 }
158 catch (std::exception& e)
159 {
160 // Probably a full or r/o filesystem, not much we can do.
161 log<level::ERR>("Unable to add PEL to Repository",
162 entry("PEL_ID=0x%X", pel->id()));
163 }
Andrew Geissler44fc3162020-07-09 09:21:31 -0500164
165 // Check if firmware should quiesce system due to error
166 checkPelAndQuiesce(pel);
Vijay Lobod354a392021-06-01 16:21:02 -0500167 updateEventId(pel);
Matt Spinler19e72902020-01-24 11:05:20 -0600168 }
169 else
170 {
171 log<level::ERR>("Invalid PEL received from the host",
172 entry("OBMCLOGID=%d", obmcLogID));
173
174 AdditionalData ad;
175 ad.add("PLID", getNumberString("0x%08X", pel->plid()));
176 ad.add("OBMC_LOG_ID", std::to_string(obmcLogID));
177 ad.add("PEL_SIZE", std::to_string(pelData.size()));
178
179 std::string asciiString;
180 auto src = pel->primarySRC();
181 if (src)
182 {
183 asciiString = (*src)->asciiString();
184 }
185
186 ad.add("SRC", asciiString);
187
188 _eventLogger.log("org.open_power.Logging.Error.BadHostPEL",
189 Entry::Level::Error, ad);
Matt Spinlerfe721892020-04-02 10:28:08 -0500190
191 // Save it to a file for debug in the lab. Just keep the latest.
192 // Not adding it to the PEL because it could already be max size
193 // and don't want to truncate an already invalid PEL.
194 std::ofstream pelFile{getPELRepoPath() / "badPEL"};
195 pelFile.write(reinterpret_cast<const char*>(pelData.data()),
196 pelData.size());
Matt Spinler19e72902020-01-24 11:05:20 -0600197 }
198}
199
200void Manager::addESELPEL(const std::string& esel, uint32_t obmcLogID)
201{
202 std::vector<uint8_t> data;
203
Matt Spinler5f5352e2020-03-05 16:23:27 -0600204 log<level::DEBUG>("Adding PEL from ESEL",
205 entry("OBMC_LOG_ID=%d", obmcLogID));
206
Matt Spinler19e72902020-01-24 11:05:20 -0600207 try
208 {
209 data = std::move(eselToRawData(esel));
210 }
211 catch (std::exception& e)
212 {
213 // Try to add it below anyway, so it follows the usual bad data path.
214 log<level::ERR>("Problems converting ESEL string to a byte vector");
215 }
216
217 addPEL(data, obmcLogID);
218}
219
220std::vector<uint8_t> Manager::eselToRawData(const std::string& esel)
221{
222 std::vector<uint8_t> data;
223 std::string byteString;
224
225 // As the eSEL string looks like: "50 48 00 ab ..." there are 3
226 // characters per raw byte, and since the actual PEL data starts
227 // at the 16th byte, the code will grab the PEL data starting at
228 // offset 48 in the string.
229 static constexpr size_t pelStart = 16 * 3;
230
231 if (esel.size() <= pelStart)
232 {
233 log<level::ERR>("ESEL data too short",
234 entry("ESEL_SIZE=%d", esel.size()));
235
236 throw std::length_error("ESEL data too short");
237 }
238
239 for (size_t i = pelStart; i < esel.size(); i += 3)
240 {
241 if (i + 1 < esel.size())
242 {
243 byteString = esel.substr(i, 2);
244 data.push_back(std::stoi(byteString, nullptr, 16));
245 }
246 else
247 {
248 log<level::ERR>("ESEL data too short",
249 entry("ESEL_SIZE=%d", esel.size()));
250 throw std::length_error("ESEL data too short");
251 }
252 }
253
254 return data;
255}
256
Matt Spinler4e8078c2019-07-09 13:22:32 -0500257void Manager::erase(uint32_t obmcLogID)
258{
Matt Spinler475e5742019-07-18 16:09:49 -0500259 Repository::LogID id{Repository::LogID::Obmc(obmcLogID)};
260
261 _repo.remove(id);
Matt Spinler4e8078c2019-07-09 13:22:32 -0500262}
263
Patrick Williamsd26fa3e2021-04-21 15:22:23 -0500264bool Manager::isDeleteProhibited(uint32_t /*obmcLogID*/)
Matt Spinler4e8078c2019-07-09 13:22:32 -0500265{
266 return false;
267}
268
Matt Spinler56ad2a02020-03-26 14:00:52 -0500269PelFFDC Manager::convertToPelFFDC(const FFDCEntries& ffdc)
270{
271 PelFFDC pelFFDC;
272
273 std::for_each(ffdc.begin(), ffdc.end(), [&pelFFDC](const auto& f) {
274 PelFFDCfile pf;
275 pf.subType = std::get<ffdcSubtypePos>(f);
276 pf.version = std::get<ffdcVersionPos>(f);
277 pf.fd = std::get<ffdcFDPos>(f);
278
279 switch (std::get<ffdcFormatPos>(f))
280 {
281 case Create::FFDCFormat::JSON:
282 pf.format = UserDataFormat::json;
283 break;
284 case Create::FFDCFormat::CBOR:
285 pf.format = UserDataFormat::cbor;
286 break;
287 case Create::FFDCFormat::Text:
288 pf.format = UserDataFormat::text;
289 break;
290 case Create::FFDCFormat::Custom:
291 pf.format = UserDataFormat::custom;
292 break;
293 }
294
295 pelFFDC.push_back(pf);
296 });
297
298 return pelFFDC;
299}
300
Matt Spinler4e8078c2019-07-09 13:22:32 -0500301void Manager::createPEL(const std::string& message, uint32_t obmcLogID,
302 uint64_t timestamp,
303 phosphor::logging::Entry::Level severity,
304 const std::vector<std::string>& additionalData,
Patrick Williamsd26fa3e2021-04-21 15:22:23 -0500305 const std::vector<std::string>& /*associations*/,
Matt Spinler56ad2a02020-03-26 14:00:52 -0500306 const FFDCEntries& ffdc)
Matt Spinler4e8078c2019-07-09 13:22:32 -0500307{
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800308 auto entry = _registry.lookup(message, rg::LookupType::name);
Matt Spinler30ddc9f2020-07-16 15:39:59 -0500309 auto pelFFDC = convertToPelFFDC(ffdc);
310 AdditionalData ad{additionalData};
Matt Spinler1d4c74a2019-12-16 14:40:21 -0600311 std::string msg;
Matt Spinler67456c22019-10-21 12:22:49 -0500312
Matt Spinler30ddc9f2020-07-16 15:39:59 -0500313 if (!entry)
Matt Spinler67456c22019-10-21 12:22:49 -0500314 {
Matt Spinler30ddc9f2020-07-16 15:39:59 -0500315 // Instead, get the default entry that means there is no
316 // other matching entry. This error will still use the
317 // AdditionalData values of the original error, and this
318 // code will add the error message value that wasn't found
319 // to this AD. This way, there will at least be a PEL,
320 // possibly with callouts, to allow users to debug the
321 // issue that caused the error even without its own PEL.
Matt Spinler1d4c74a2019-12-16 14:40:21 -0600322 msg = "Event not found in PEL message registry: " + message;
323 log<level::INFO>(msg.c_str());
Matt Spinler30ddc9f2020-07-16 15:39:59 -0500324
325 entry = _registry.lookup(defaultLogMessage, rg::LookupType::name);
326 if (!entry)
327 {
328 log<level::ERR>("Default event not found in PEL message registry");
329 return;
330 }
331
332 ad.add(additional_data::error, message);
333 }
334
335 auto pel = std::make_unique<openpower::pels::PEL>(
336 *entry, obmcLogID, timestamp, severity, ad, pelFFDC, *_dataIface);
337
338 _repo.add(pel);
339
340 if (_repo.sizeWarning())
341 {
342 scheduleRepoPrune();
343 }
344
345 auto src = pel->primarySRC();
346 if (src)
347 {
Matt Spinler22421b92020-07-17 09:41:08 -0500348 auto msg =
349 fmt::format("Created PEL {:#x} (BMC ID {}) with SRC {}", pel->id(),
350 pel->obmcLogID(), (*src)->asciiString());
Matt Spinler30ddc9f2020-07-16 15:39:59 -0500351 while (msg.back() == ' ')
352 {
353 msg.pop_back();
354 }
355 log<level::INFO>(msg.c_str());
Matt Spinler1d4c74a2019-12-16 14:40:21 -0600356 }
Matt Spinler1962e082020-08-05 13:44:53 -0500357
358 // Activate any resulting service indicators if necessary
359 auto policy = service_indicators::getPolicy(*_dataIface);
360 policy->activate(*pel);
Andrew Geissler44fc3162020-07-09 09:21:31 -0500361
362 // Check if firmware should quiesce system due to error
363 checkPelAndQuiesce(pel);
Vijay Lobod354a392021-06-01 16:21:02 -0500364 updateEventId(pel);
Matt Spinler4e8078c2019-07-09 13:22:32 -0500365}
366
Matt Spinlera34ab722019-12-16 10:39:32 -0600367sdbusplus::message::unix_fd Manager::getPEL(uint32_t pelID)
368{
369 Repository::LogID id{Repository::LogID::Pel(pelID)};
370 std::optional<int> fd;
371
Matt Spinler5f5352e2020-03-05 16:23:27 -0600372 log<level::DEBUG>("getPEL", entry("PEL_ID=0x%X", pelID));
373
Matt Spinlera34ab722019-12-16 10:39:32 -0600374 try
375 {
376 fd = _repo.getPELFD(id);
377 }
378 catch (std::exception& e)
379 {
380 throw common_error::InternalFailure();
381 }
382
383 if (!fd)
384 {
385 throw common_error::InvalidArgument();
386 }
387
Matt Spinler6b1a5c82020-01-07 08:48:53 -0600388 scheduleFDClose(*fd);
389
Matt Spinlera34ab722019-12-16 10:39:32 -0600390 return *fd;
391}
392
Matt Spinler6b1a5c82020-01-07 08:48:53 -0600393void Manager::scheduleFDClose(int fd)
394{
395 _fdCloserEventSource = std::make_unique<sdeventplus::source::Defer>(
Matt Spinlerff9cec22020-07-15 13:06:35 -0500396 _event, std::bind(std::mem_fn(&Manager::closeFD), this, fd,
397 std::placeholders::_1));
Matt Spinler6b1a5c82020-01-07 08:48:53 -0600398}
399
Patrick Williamsd26fa3e2021-04-21 15:22:23 -0500400void Manager::closeFD(int fd, sdeventplus::source::EventBase& /*source*/)
Matt Spinler6b1a5c82020-01-07 08:48:53 -0600401{
402 close(fd);
403 _fdCloserEventSource.reset();
404}
405
Matt Spinlera34ab722019-12-16 10:39:32 -0600406std::vector<uint8_t> Manager::getPELFromOBMCID(uint32_t obmcLogID)
407{
408 Repository::LogID id{Repository::LogID::Obmc(obmcLogID)};
409 std::optional<std::vector<uint8_t>> data;
410
Matt Spinler5f5352e2020-03-05 16:23:27 -0600411 log<level::DEBUG>("getPELFromOBMCID", entry("OBMC_LOG_ID=%d", obmcLogID));
412
Matt Spinlera34ab722019-12-16 10:39:32 -0600413 try
414 {
415 data = _repo.getPELData(id);
416 }
417 catch (std::exception& e)
418 {
419 throw common_error::InternalFailure();
420 }
421
422 if (!data)
423 {
424 throw common_error::InvalidArgument();
425 }
426
427 return *data;
428}
429
430void Manager::hostAck(uint32_t pelID)
431{
432 Repository::LogID id{Repository::LogID::Pel(pelID)};
433
Matt Spinler5f5352e2020-03-05 16:23:27 -0600434 log<level::DEBUG>("HostAck", entry("PEL_ID=0x%X", pelID));
435
Matt Spinlera34ab722019-12-16 10:39:32 -0600436 if (!_repo.hasPEL(id))
437 {
438 throw common_error::InvalidArgument();
439 }
440
441 if (_hostNotifier)
442 {
443 _hostNotifier->ackPEL(pelID);
444 }
445}
446
447void Manager::hostReject(uint32_t pelID, RejectionReason reason)
448{
449 Repository::LogID id{Repository::LogID::Pel(pelID)};
450
Matt Spinler5f5352e2020-03-05 16:23:27 -0600451 log<level::DEBUG>("HostReject", entry("PEL_ID=0x%X", pelID),
452 entry("REASON=%d", static_cast<int>(reason)));
453
Matt Spinlera34ab722019-12-16 10:39:32 -0600454 if (!_repo.hasPEL(id))
455 {
456 throw common_error::InvalidArgument();
457 }
458
Matt Spinler05c2c6c2019-12-18 14:02:09 -0600459 if (reason == RejectionReason::BadPEL)
Matt Spinlera34ab722019-12-16 10:39:32 -0600460 {
Matt Spinler05c2c6c2019-12-18 14:02:09 -0600461 AdditionalData data;
462 data.add("BAD_ID", getNumberString("0x%08X", pelID));
463 _eventLogger.log("org.open_power.Logging.Error.SentBadPELToHost",
464 Entry::Level::Informational, data);
465 if (_hostNotifier)
Matt Spinlera34ab722019-12-16 10:39:32 -0600466 {
467 _hostNotifier->setBadPEL(pelID);
468 }
Matt Spinler05c2c6c2019-12-18 14:02:09 -0600469 }
470 else if ((reason == RejectionReason::HostFull) && _hostNotifier)
471 {
472 _hostNotifier->setHostFull(pelID);
Matt Spinlera34ab722019-12-16 10:39:32 -0600473 }
474}
475
Matt Spinler7e727a32020-07-07 15:00:17 -0500476void Manager::scheduleRepoPrune()
477{
Matt Spinler7e727a32020-07-07 15:00:17 -0500478 _repoPrunerEventSource = std::make_unique<sdeventplus::source::Defer>(
Matt Spinlerff9cec22020-07-15 13:06:35 -0500479 _event, std::bind(std::mem_fn(&Manager::pruneRepo), this,
480 std::placeholders::_1));
Matt Spinler7e727a32020-07-07 15:00:17 -0500481}
482
Patrick Williamsd26fa3e2021-04-21 15:22:23 -0500483void Manager::pruneRepo(sdeventplus::source::EventBase& /*source*/)
Matt Spinler7e727a32020-07-07 15:00:17 -0500484{
485 auto idsToDelete = _repo.prune();
486
487 // Remove the OpenBMC event logs for the PELs that were just removed.
488 std::for_each(idsToDelete.begin(), idsToDelete.end(),
489 [this](auto id) { this->_logManager.erase(id); });
490
491 _repoPrunerEventSource.reset();
492}
493
Matt Spinlerff9cec22020-07-15 13:06:35 -0500494void Manager::setupPELDeleteWatch()
495{
496 _pelFileDeleteFD = inotify_init1(IN_NONBLOCK);
497 if (-1 == _pelFileDeleteFD)
498 {
499 auto e = errno;
500 std::string msg =
501 "inotify_init1 failed with errno " + std::to_string(e);
502 log<level::ERR>(msg.c_str());
503 abort();
504 }
505
506 _pelFileDeleteWatchFD = inotify_add_watch(
507 _pelFileDeleteFD, _repo.repoPath().c_str(), IN_DELETE);
508 if (-1 == _pelFileDeleteWatchFD)
509 {
510 auto e = errno;
511 std::string msg =
512 "inotify_add_watch failed with error " + std::to_string(e);
513 log<level::ERR>(msg.c_str());
514 abort();
515 }
516
517 _pelFileDeleteEventSource = std::make_unique<sdeventplus::source::IO>(
518 _event, _pelFileDeleteFD, EPOLLIN,
519 std::bind(std::mem_fn(&Manager::pelFileDeleted), this,
520 std::placeholders::_1, std::placeholders::_2,
521 std::placeholders::_3));
522}
523
Patrick Williamsd26fa3e2021-04-21 15:22:23 -0500524void Manager::pelFileDeleted(sdeventplus::source::IO& /*io*/, int /*fd*/,
Matt Spinlerff9cec22020-07-15 13:06:35 -0500525 uint32_t revents)
526{
527 if (!(revents & EPOLLIN))
528 {
529 return;
530 }
531
532 // An event for 1 PEL uses 48B. When all PELs are deleted at once,
533 // as many events as there is room for can be handled in one callback.
534 // A size of 2000 will allow 41 to be processed, with additional
535 // callbacks being needed to process the remaining ones.
Matt Spinler9d59d582021-05-19 07:57:10 -0600536 std::array<uint8_t, 2000> data{};
Matt Spinlerff9cec22020-07-15 13:06:35 -0500537 auto bytesRead = read(_pelFileDeleteFD, data.data(), data.size());
538 if (bytesRead < 0)
539 {
540 auto e = errno;
541 std::string msg = "Failed reading data from inotify event, errno = " +
542 std::to_string(e);
543 log<level::ERR>(msg.c_str());
544 abort();
545 }
546
547 auto offset = 0;
548 while (offset < bytesRead)
549 {
550 auto event = reinterpret_cast<inotify_event*>(&data[offset]);
551 if (event->mask & IN_DELETE)
552 {
553 std::string filename{event->name};
554
555 // Get the PEL ID from the filename and tell the
556 // repo it's been removed, and then delete the BMC
557 // event log if it's there.
558 auto pos = filename.find_first_of('_');
559 if (pos != std::string::npos)
560 {
561 try
562 {
563 auto idString = filename.substr(pos + 1);
564 auto pelID = std::stoul(idString, nullptr, 16);
565
566 Repository::LogID id{Repository::LogID::Pel(pelID)};
567 auto removedLogID = _repo.remove(id);
568 if (removedLogID)
569 {
570 _logManager.erase(removedLogID->obmcID.id);
571 }
572 }
573 catch (const std::exception& e)
574 {
575 log<level::INFO>("Could not find PEL ID from its filename",
576 entry("FILENAME=%s", filename.c_str()));
577 }
578 }
579 }
580
581 offset += offsetof(inotify_event, name) + event->len;
582 }
583}
Matt Spinler9cc30072020-09-16 15:39:34 -0500584
585std::tuple<uint32_t, uint32_t> Manager::createPELWithFFDCFiles(
586 std::string message, Entry::Level severity,
587 std::map<std::string, std::string> additionalData,
588 std::vector<std::tuple<
589 sdbusplus::xyz::openbmc_project::Logging::server::Create::FFDCFormat,
590 uint8_t, uint8_t, sdbusplus::message::unix_fd>>
591 fFDC)
592{
Matt Spinler44893cc2020-08-26 11:34:17 -0500593 _logManager.createWithFFDC(message, severity, additionalData, fFDC);
594
595 return {_logManager.lastEntryID(), _repo.lastPelID()};
Matt Spinler9cc30072020-09-16 15:39:34 -0500596}
597
Andrew Geissler44fc3162020-07-09 09:21:31 -0500598void Manager::checkPelAndQuiesce(std::unique_ptr<openpower::pels::PEL>& pel)
599{
Matt Spinlerb2abc042021-05-17 15:32:50 -0600600 if ((pel->userHeader().severity() ==
601 static_cast<uint8_t>(SeverityType::nonError)) ||
602 (pel->userHeader().severity() ==
603 static_cast<uint8_t>(SeverityType::recovered)))
Andrew Geissler44fc3162020-07-09 09:21:31 -0500604 {
Matt Spinlerb2abc042021-05-17 15:32:50 -0600605 log<level::DEBUG>(
606 "PEL severity informational or recovered. no quiesce needed");
Andrew Geissler44fc3162020-07-09 09:21:31 -0500607 return;
608 }
609 if (!_logManager.isQuiesceOnErrorEnabled())
610 {
611 log<level::DEBUG>("QuiesceOnHwError not enabled, no quiesce needed");
612 return;
613 }
614
615 // Now check if it has any type of callout
616 if (pel->isCalloutPresent())
617 {
Matt Spinlerb2abc042021-05-17 15:32:50 -0600618 log<level::INFO>(
619 "QuiesceOnHwError enabled, PEL severity not nonError or recovered, "
620 "and callout is present");
Andrew Geissler44fc3162020-07-09 09:21:31 -0500621
622 _logManager.quiesceOnError(pel->obmcLogID());
623 }
624}
625
Vijay Lobod354a392021-06-01 16:21:02 -0500626std::string Manager::getEventId(const openpower::pels::PEL& pel) const
627{
628 std::string str;
629 auto src = pel.primarySRC();
630 if (src)
631 {
632 const auto& hexwords = (*src)->hexwordData();
633
634 std::string refcode = (*src)->asciiString();
635 size_t pos = refcode.find_last_not_of(0x20);
636 if (pos != std::string::npos)
637 {
638 refcode.erase(pos + 1);
639 }
640 str = refcode;
641
642 for (auto& value : hexwords)
643 {
644 str += " ";
645 str += getNumberString("%08X", value);
646 }
647 }
648 return str;
649}
650
651void Manager::updateEventId(std::unique_ptr<openpower::pels::PEL>& pel)
652{
653 std::string eventIdStr = getEventId(*pel);
654
655 auto entryN = _logManager.entries.find(pel->obmcLogID());
656 if (entryN != _logManager.entries.end())
657 {
658 entryN->second->eventId(eventIdStr);
659 }
660}
661
Adriana Kobylake7d271a2020-12-07 14:32:44 -0600662void Manager::setEntryPath(uint32_t obmcLogID)
663{
664 Repository::LogID id{Repository::LogID::Obmc(obmcLogID)};
665 if (auto attributes = _repo.getPELAttributes(id); attributes)
666 {
667 auto& attr = attributes.value().get();
668 auto entry = _logManager.entries.find(obmcLogID);
669 if (entry != _logManager.entries.end())
670 {
671 entry->second->path(attr.path);
672 }
673 }
674}
675
Matt Spinler4e8078c2019-07-09 13:22:32 -0500676} // namespace pels
677} // namespace openpower