blob: db2e2d648515f1c7c9c8c893522f70a99d20fc2f [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{
Matt Spinler19e72902020-01-24 11:05:20 -0600130 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 }
Sumit Kumar2ccdcef2021-07-31 10:04:58 -0500139 else
140 {
141 const Repository::LogID id{Repository::LogID::Pel(pel->id())};
142 auto result = _repo.hasPEL(id);
143 if (result)
144 {
145 log<level::WARNING>(
146 fmt::format("Duplicate HostBoot PEL Id {:#X} found; "
147 "moving it to archive folder",
148 pel->id())
149 .c_str());
150
151 _repo.archivePEL(*pel);
152 return;
153 }
154 }
Sumit Kumara1e40842021-06-23 09:52:25 -0500155
156 // PELs created by others still need this field set by us.
Matt Spinler19e72902020-01-24 11:05:20 -0600157 pel->setCommitTime();
158
Sumit Kumar3160a542021-04-26 08:07:04 -0500159 // Update System Info to Extended User Data
160 pel->updateSysInfoInExtendedUserDataSection(*_dataIface);
161
Matt Spinler19e72902020-01-24 11:05:20 -0600162 try
163 {
Matt Spinlerd0ab1cf2021-02-10 13:26:18 -0600164 log<level::DEBUG>(
Matt Spinler6321ba32020-07-17 09:58:19 -0500165 fmt::format("Adding external PEL {:#x} (BMC ID {}) to repo",
166 pel->id(), obmcLogID)
167 .c_str());
Matt Spinler5f5352e2020-03-05 16:23:27 -0600168
Matt Spinler19e72902020-01-24 11:05:20 -0600169 _repo.add(pel);
Matt Spinler7e727a32020-07-07 15:00:17 -0500170
171 if (_repo.sizeWarning())
172 {
173 scheduleRepoPrune();
174 }
Matt Spinler1962e082020-08-05 13:44:53 -0500175
176 // Activate any resulting service indicators if necessary
177 auto policy = service_indicators::getPolicy(*_dataIface);
178 policy->activate(*pel);
Matt Spinler19e72902020-01-24 11:05:20 -0600179 }
180 catch (std::exception& e)
181 {
182 // Probably a full or r/o filesystem, not much we can do.
183 log<level::ERR>("Unable to add PEL to Repository",
184 entry("PEL_ID=0x%X", pel->id()));
185 }
Andrew Geissler44fc3162020-07-09 09:21:31 -0500186
187 // Check if firmware should quiesce system due to error
188 checkPelAndQuiesce(pel);
Vijay Lobod354a392021-06-01 16:21:02 -0500189 updateEventId(pel);
Vijay Lobo593a4c62021-06-16 14:25:26 -0500190 updateResolution(pel);
Matt Spinler19e72902020-01-24 11:05:20 -0600191 }
192 else
193 {
194 log<level::ERR>("Invalid PEL received from the host",
195 entry("OBMCLOGID=%d", obmcLogID));
196
197 AdditionalData ad;
198 ad.add("PLID", getNumberString("0x%08X", pel->plid()));
199 ad.add("OBMC_LOG_ID", std::to_string(obmcLogID));
200 ad.add("PEL_SIZE", std::to_string(pelData.size()));
201
202 std::string asciiString;
203 auto src = pel->primarySRC();
204 if (src)
205 {
206 asciiString = (*src)->asciiString();
207 }
208
209 ad.add("SRC", asciiString);
210
211 _eventLogger.log("org.open_power.Logging.Error.BadHostPEL",
212 Entry::Level::Error, ad);
Matt Spinlerfe721892020-04-02 10:28:08 -0500213
214 // Save it to a file for debug in the lab. Just keep the latest.
215 // Not adding it to the PEL because it could already be max size
216 // and don't want to truncate an already invalid PEL.
217 std::ofstream pelFile{getPELRepoPath() / "badPEL"};
218 pelFile.write(reinterpret_cast<const char*>(pelData.data()),
219 pelData.size());
Matt Spinler19e72902020-01-24 11:05:20 -0600220 }
221}
222
223void Manager::addESELPEL(const std::string& esel, uint32_t obmcLogID)
224{
225 std::vector<uint8_t> data;
226
Matt Spinler5f5352e2020-03-05 16:23:27 -0600227 log<level::DEBUG>("Adding PEL from ESEL",
228 entry("OBMC_LOG_ID=%d", obmcLogID));
229
Matt Spinler19e72902020-01-24 11:05:20 -0600230 try
231 {
232 data = std::move(eselToRawData(esel));
233 }
234 catch (std::exception& e)
235 {
236 // Try to add it below anyway, so it follows the usual bad data path.
237 log<level::ERR>("Problems converting ESEL string to a byte vector");
238 }
239
240 addPEL(data, obmcLogID);
241}
242
243std::vector<uint8_t> Manager::eselToRawData(const std::string& esel)
244{
245 std::vector<uint8_t> data;
246 std::string byteString;
247
248 // As the eSEL string looks like: "50 48 00 ab ..." there are 3
249 // characters per raw byte, and since the actual PEL data starts
250 // at the 16th byte, the code will grab the PEL data starting at
251 // offset 48 in the string.
252 static constexpr size_t pelStart = 16 * 3;
253
254 if (esel.size() <= pelStart)
255 {
256 log<level::ERR>("ESEL data too short",
257 entry("ESEL_SIZE=%d", esel.size()));
258
259 throw std::length_error("ESEL data too short");
260 }
261
262 for (size_t i = pelStart; i < esel.size(); i += 3)
263 {
264 if (i + 1 < esel.size())
265 {
266 byteString = esel.substr(i, 2);
267 data.push_back(std::stoi(byteString, nullptr, 16));
268 }
269 else
270 {
271 log<level::ERR>("ESEL data too short",
272 entry("ESEL_SIZE=%d", esel.size()));
273 throw std::length_error("ESEL data too short");
274 }
275 }
276
277 return data;
278}
279
Matt Spinler4e8078c2019-07-09 13:22:32 -0500280void Manager::erase(uint32_t obmcLogID)
281{
Matt Spinler475e5742019-07-18 16:09:49 -0500282 Repository::LogID id{Repository::LogID::Obmc(obmcLogID)};
283
284 _repo.remove(id);
Matt Spinler4e8078c2019-07-09 13:22:32 -0500285}
286
Patrick Williamsd26fa3e2021-04-21 15:22:23 -0500287bool Manager::isDeleteProhibited(uint32_t /*obmcLogID*/)
Matt Spinler4e8078c2019-07-09 13:22:32 -0500288{
289 return false;
290}
291
Matt Spinler56ad2a02020-03-26 14:00:52 -0500292PelFFDC Manager::convertToPelFFDC(const FFDCEntries& ffdc)
293{
294 PelFFDC pelFFDC;
295
296 std::for_each(ffdc.begin(), ffdc.end(), [&pelFFDC](const auto& f) {
297 PelFFDCfile pf;
298 pf.subType = std::get<ffdcSubtypePos>(f);
299 pf.version = std::get<ffdcVersionPos>(f);
300 pf.fd = std::get<ffdcFDPos>(f);
301
302 switch (std::get<ffdcFormatPos>(f))
303 {
304 case Create::FFDCFormat::JSON:
305 pf.format = UserDataFormat::json;
306 break;
307 case Create::FFDCFormat::CBOR:
308 pf.format = UserDataFormat::cbor;
309 break;
310 case Create::FFDCFormat::Text:
311 pf.format = UserDataFormat::text;
312 break;
313 case Create::FFDCFormat::Custom:
314 pf.format = UserDataFormat::custom;
315 break;
316 }
317
318 pelFFDC.push_back(pf);
319 });
320
321 return pelFFDC;
322}
323
Matt Spinler4e8078c2019-07-09 13:22:32 -0500324void Manager::createPEL(const std::string& message, uint32_t obmcLogID,
325 uint64_t timestamp,
326 phosphor::logging::Entry::Level severity,
327 const std::vector<std::string>& additionalData,
Patrick Williamsd26fa3e2021-04-21 15:22:23 -0500328 const std::vector<std::string>& /*associations*/,
Matt Spinler56ad2a02020-03-26 14:00:52 -0500329 const FFDCEntries& ffdc)
Matt Spinler4e8078c2019-07-09 13:22:32 -0500330{
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800331 auto entry = _registry.lookup(message, rg::LookupType::name);
Matt Spinler30ddc9f2020-07-16 15:39:59 -0500332 auto pelFFDC = convertToPelFFDC(ffdc);
333 AdditionalData ad{additionalData};
Matt Spinler1d4c74a2019-12-16 14:40:21 -0600334 std::string msg;
Matt Spinler67456c22019-10-21 12:22:49 -0500335
Matt Spinler30ddc9f2020-07-16 15:39:59 -0500336 if (!entry)
Matt Spinler67456c22019-10-21 12:22:49 -0500337 {
Matt Spinler30ddc9f2020-07-16 15:39:59 -0500338 // Instead, get the default entry that means there is no
339 // other matching entry. This error will still use the
340 // AdditionalData values of the original error, and this
341 // code will add the error message value that wasn't found
342 // to this AD. This way, there will at least be a PEL,
343 // possibly with callouts, to allow users to debug the
344 // issue that caused the error even without its own PEL.
Matt Spinler1d4c74a2019-12-16 14:40:21 -0600345 msg = "Event not found in PEL message registry: " + message;
346 log<level::INFO>(msg.c_str());
Matt Spinler30ddc9f2020-07-16 15:39:59 -0500347
348 entry = _registry.lookup(defaultLogMessage, rg::LookupType::name);
349 if (!entry)
350 {
351 log<level::ERR>("Default event not found in PEL message registry");
352 return;
353 }
354
355 ad.add(additional_data::error, message);
356 }
357
358 auto pel = std::make_unique<openpower::pels::PEL>(
359 *entry, obmcLogID, timestamp, severity, ad, pelFFDC, *_dataIface);
360
361 _repo.add(pel);
362
363 if (_repo.sizeWarning())
364 {
365 scheduleRepoPrune();
366 }
367
368 auto src = pel->primarySRC();
369 if (src)
370 {
Matt Spinler22421b92020-07-17 09:41:08 -0500371 auto msg =
372 fmt::format("Created PEL {:#x} (BMC ID {}) with SRC {}", pel->id(),
373 pel->obmcLogID(), (*src)->asciiString());
Matt Spinler30ddc9f2020-07-16 15:39:59 -0500374 while (msg.back() == ' ')
375 {
376 msg.pop_back();
377 }
378 log<level::INFO>(msg.c_str());
Matt Spinler1d4c74a2019-12-16 14:40:21 -0600379 }
Matt Spinler1962e082020-08-05 13:44:53 -0500380
381 // Activate any resulting service indicators if necessary
382 auto policy = service_indicators::getPolicy(*_dataIface);
383 policy->activate(*pel);
Andrew Geissler44fc3162020-07-09 09:21:31 -0500384
385 // Check if firmware should quiesce system due to error
386 checkPelAndQuiesce(pel);
Vijay Lobod354a392021-06-01 16:21:02 -0500387 updateEventId(pel);
Vijay Lobo593a4c62021-06-16 14:25:26 -0500388 updateResolution(pel);
Matt Spinler4e8078c2019-07-09 13:22:32 -0500389}
390
Matt Spinlera34ab722019-12-16 10:39:32 -0600391sdbusplus::message::unix_fd Manager::getPEL(uint32_t pelID)
392{
393 Repository::LogID id{Repository::LogID::Pel(pelID)};
394 std::optional<int> fd;
395
Matt Spinler5f5352e2020-03-05 16:23:27 -0600396 log<level::DEBUG>("getPEL", entry("PEL_ID=0x%X", pelID));
397
Matt Spinlera34ab722019-12-16 10:39:32 -0600398 try
399 {
400 fd = _repo.getPELFD(id);
401 }
402 catch (std::exception& e)
403 {
404 throw common_error::InternalFailure();
405 }
406
407 if (!fd)
408 {
409 throw common_error::InvalidArgument();
410 }
411
Matt Spinler6b1a5c82020-01-07 08:48:53 -0600412 scheduleFDClose(*fd);
413
Matt Spinlera34ab722019-12-16 10:39:32 -0600414 return *fd;
415}
416
Matt Spinler6b1a5c82020-01-07 08:48:53 -0600417void Manager::scheduleFDClose(int fd)
418{
419 _fdCloserEventSource = std::make_unique<sdeventplus::source::Defer>(
Matt Spinlerff9cec22020-07-15 13:06:35 -0500420 _event, std::bind(std::mem_fn(&Manager::closeFD), this, fd,
421 std::placeholders::_1));
Matt Spinler6b1a5c82020-01-07 08:48:53 -0600422}
423
Patrick Williamsd26fa3e2021-04-21 15:22:23 -0500424void Manager::closeFD(int fd, sdeventplus::source::EventBase& /*source*/)
Matt Spinler6b1a5c82020-01-07 08:48:53 -0600425{
426 close(fd);
427 _fdCloserEventSource.reset();
428}
429
Matt Spinlera34ab722019-12-16 10:39:32 -0600430std::vector<uint8_t> Manager::getPELFromOBMCID(uint32_t obmcLogID)
431{
432 Repository::LogID id{Repository::LogID::Obmc(obmcLogID)};
433 std::optional<std::vector<uint8_t>> data;
434
Matt Spinler5f5352e2020-03-05 16:23:27 -0600435 log<level::DEBUG>("getPELFromOBMCID", entry("OBMC_LOG_ID=%d", obmcLogID));
436
Matt Spinlera34ab722019-12-16 10:39:32 -0600437 try
438 {
439 data = _repo.getPELData(id);
440 }
441 catch (std::exception& e)
442 {
443 throw common_error::InternalFailure();
444 }
445
446 if (!data)
447 {
448 throw common_error::InvalidArgument();
449 }
450
451 return *data;
452}
453
454void Manager::hostAck(uint32_t pelID)
455{
456 Repository::LogID id{Repository::LogID::Pel(pelID)};
457
Matt Spinler5f5352e2020-03-05 16:23:27 -0600458 log<level::DEBUG>("HostAck", entry("PEL_ID=0x%X", pelID));
459
Matt Spinlera34ab722019-12-16 10:39:32 -0600460 if (!_repo.hasPEL(id))
461 {
462 throw common_error::InvalidArgument();
463 }
464
465 if (_hostNotifier)
466 {
467 _hostNotifier->ackPEL(pelID);
468 }
469}
470
471void Manager::hostReject(uint32_t pelID, RejectionReason reason)
472{
473 Repository::LogID id{Repository::LogID::Pel(pelID)};
474
Matt Spinler5f5352e2020-03-05 16:23:27 -0600475 log<level::DEBUG>("HostReject", entry("PEL_ID=0x%X", pelID),
476 entry("REASON=%d", static_cast<int>(reason)));
477
Matt Spinlera34ab722019-12-16 10:39:32 -0600478 if (!_repo.hasPEL(id))
479 {
480 throw common_error::InvalidArgument();
481 }
482
Matt Spinler05c2c6c2019-12-18 14:02:09 -0600483 if (reason == RejectionReason::BadPEL)
Matt Spinlera34ab722019-12-16 10:39:32 -0600484 {
Matt Spinler05c2c6c2019-12-18 14:02:09 -0600485 AdditionalData data;
486 data.add("BAD_ID", getNumberString("0x%08X", pelID));
487 _eventLogger.log("org.open_power.Logging.Error.SentBadPELToHost",
488 Entry::Level::Informational, data);
489 if (_hostNotifier)
Matt Spinlera34ab722019-12-16 10:39:32 -0600490 {
491 _hostNotifier->setBadPEL(pelID);
492 }
Matt Spinler05c2c6c2019-12-18 14:02:09 -0600493 }
494 else if ((reason == RejectionReason::HostFull) && _hostNotifier)
495 {
496 _hostNotifier->setHostFull(pelID);
Matt Spinlera34ab722019-12-16 10:39:32 -0600497 }
498}
499
Matt Spinler7e727a32020-07-07 15:00:17 -0500500void Manager::scheduleRepoPrune()
501{
Matt Spinler7e727a32020-07-07 15:00:17 -0500502 _repoPrunerEventSource = std::make_unique<sdeventplus::source::Defer>(
Matt Spinlerff9cec22020-07-15 13:06:35 -0500503 _event, std::bind(std::mem_fn(&Manager::pruneRepo), this,
504 std::placeholders::_1));
Matt Spinler7e727a32020-07-07 15:00:17 -0500505}
506
Patrick Williamsd26fa3e2021-04-21 15:22:23 -0500507void Manager::pruneRepo(sdeventplus::source::EventBase& /*source*/)
Matt Spinler7e727a32020-07-07 15:00:17 -0500508{
509 auto idsToDelete = _repo.prune();
510
511 // Remove the OpenBMC event logs for the PELs that were just removed.
512 std::for_each(idsToDelete.begin(), idsToDelete.end(),
513 [this](auto id) { this->_logManager.erase(id); });
514
515 _repoPrunerEventSource.reset();
516}
517
Matt Spinlerff9cec22020-07-15 13:06:35 -0500518void Manager::setupPELDeleteWatch()
519{
520 _pelFileDeleteFD = inotify_init1(IN_NONBLOCK);
521 if (-1 == _pelFileDeleteFD)
522 {
523 auto e = errno;
524 std::string msg =
525 "inotify_init1 failed with errno " + std::to_string(e);
526 log<level::ERR>(msg.c_str());
527 abort();
528 }
529
530 _pelFileDeleteWatchFD = inotify_add_watch(
531 _pelFileDeleteFD, _repo.repoPath().c_str(), IN_DELETE);
532 if (-1 == _pelFileDeleteWatchFD)
533 {
534 auto e = errno;
535 std::string msg =
536 "inotify_add_watch failed with error " + std::to_string(e);
537 log<level::ERR>(msg.c_str());
538 abort();
539 }
540
541 _pelFileDeleteEventSource = std::make_unique<sdeventplus::source::IO>(
542 _event, _pelFileDeleteFD, EPOLLIN,
543 std::bind(std::mem_fn(&Manager::pelFileDeleted), this,
544 std::placeholders::_1, std::placeholders::_2,
545 std::placeholders::_3));
546}
547
Patrick Williamsd26fa3e2021-04-21 15:22:23 -0500548void Manager::pelFileDeleted(sdeventplus::source::IO& /*io*/, int /*fd*/,
Matt Spinlerff9cec22020-07-15 13:06:35 -0500549 uint32_t revents)
550{
551 if (!(revents & EPOLLIN))
552 {
553 return;
554 }
555
556 // An event for 1 PEL uses 48B. When all PELs are deleted at once,
557 // as many events as there is room for can be handled in one callback.
558 // A size of 2000 will allow 41 to be processed, with additional
559 // callbacks being needed to process the remaining ones.
Matt Spinler9d59d582021-05-19 07:57:10 -0600560 std::array<uint8_t, 2000> data{};
Matt Spinlerff9cec22020-07-15 13:06:35 -0500561 auto bytesRead = read(_pelFileDeleteFD, data.data(), data.size());
562 if (bytesRead < 0)
563 {
564 auto e = errno;
565 std::string msg = "Failed reading data from inotify event, errno = " +
566 std::to_string(e);
567 log<level::ERR>(msg.c_str());
568 abort();
569 }
570
571 auto offset = 0;
572 while (offset < bytesRead)
573 {
574 auto event = reinterpret_cast<inotify_event*>(&data[offset]);
575 if (event->mask & IN_DELETE)
576 {
577 std::string filename{event->name};
578
579 // Get the PEL ID from the filename and tell the
580 // repo it's been removed, and then delete the BMC
581 // event log if it's there.
582 auto pos = filename.find_first_of('_');
583 if (pos != std::string::npos)
584 {
585 try
586 {
587 auto idString = filename.substr(pos + 1);
588 auto pelID = std::stoul(idString, nullptr, 16);
589
590 Repository::LogID id{Repository::LogID::Pel(pelID)};
591 auto removedLogID = _repo.remove(id);
592 if (removedLogID)
593 {
594 _logManager.erase(removedLogID->obmcID.id);
595 }
596 }
597 catch (const std::exception& e)
598 {
599 log<level::INFO>("Could not find PEL ID from its filename",
600 entry("FILENAME=%s", filename.c_str()));
601 }
602 }
603 }
604
605 offset += offsetof(inotify_event, name) + event->len;
606 }
607}
Matt Spinler9cc30072020-09-16 15:39:34 -0500608
609std::tuple<uint32_t, uint32_t> Manager::createPELWithFFDCFiles(
610 std::string message, Entry::Level severity,
611 std::map<std::string, std::string> additionalData,
612 std::vector<std::tuple<
613 sdbusplus::xyz::openbmc_project::Logging::server::Create::FFDCFormat,
614 uint8_t, uint8_t, sdbusplus::message::unix_fd>>
615 fFDC)
616{
Matt Spinler44893cc2020-08-26 11:34:17 -0500617 _logManager.createWithFFDC(message, severity, additionalData, fFDC);
618
619 return {_logManager.lastEntryID(), _repo.lastPelID()};
Matt Spinler9cc30072020-09-16 15:39:34 -0500620}
621
Andrew Geissler44fc3162020-07-09 09:21:31 -0500622void Manager::checkPelAndQuiesce(std::unique_ptr<openpower::pels::PEL>& pel)
623{
Matt Spinlerb2abc042021-05-17 15:32:50 -0600624 if ((pel->userHeader().severity() ==
625 static_cast<uint8_t>(SeverityType::nonError)) ||
626 (pel->userHeader().severity() ==
627 static_cast<uint8_t>(SeverityType::recovered)))
Andrew Geissler44fc3162020-07-09 09:21:31 -0500628 {
Matt Spinlerb2abc042021-05-17 15:32:50 -0600629 log<level::DEBUG>(
630 "PEL severity informational or recovered. no quiesce needed");
Andrew Geissler44fc3162020-07-09 09:21:31 -0500631 return;
632 }
633 if (!_logManager.isQuiesceOnErrorEnabled())
634 {
635 log<level::DEBUG>("QuiesceOnHwError not enabled, no quiesce needed");
636 return;
637 }
638
639 // Now check if it has any type of callout
640 if (pel->isCalloutPresent())
641 {
Matt Spinlerb2abc042021-05-17 15:32:50 -0600642 log<level::INFO>(
643 "QuiesceOnHwError enabled, PEL severity not nonError or recovered, "
644 "and callout is present");
Andrew Geissler44fc3162020-07-09 09:21:31 -0500645
646 _logManager.quiesceOnError(pel->obmcLogID());
647 }
648}
649
Vijay Lobod354a392021-06-01 16:21:02 -0500650std::string Manager::getEventId(const openpower::pels::PEL& pel) const
651{
652 std::string str;
653 auto src = pel.primarySRC();
654 if (src)
655 {
656 const auto& hexwords = (*src)->hexwordData();
657
658 std::string refcode = (*src)->asciiString();
659 size_t pos = refcode.find_last_not_of(0x20);
660 if (pos != std::string::npos)
661 {
662 refcode.erase(pos + 1);
663 }
664 str = refcode;
665
666 for (auto& value : hexwords)
667 {
668 str += " ";
669 str += getNumberString("%08X", value);
670 }
671 }
672 return str;
673}
674
675void Manager::updateEventId(std::unique_ptr<openpower::pels::PEL>& pel)
676{
677 std::string eventIdStr = getEventId(*pel);
678
679 auto entryN = _logManager.entries.find(pel->obmcLogID());
680 if (entryN != _logManager.entries.end())
681 {
682 entryN->second->eventId(eventIdStr);
683 }
684}
685
Vijay Lobo593a4c62021-06-16 14:25:26 -0500686std::string Manager::getResolution(const openpower::pels::PEL& pel) const
687{
688 std::string str;
689 std::string resolution;
690 auto src = pel.primarySRC();
691 if (src)
692 {
693 // First extract the callout pointer and then go through
694 const auto& callouts = (*src)->callouts();
695 namespace pv = openpower::pels::pel_values;
696 // All PELs dont have callout, check before parsing callout data
697 if (callouts)
698 {
699 const auto& entries = callouts->callouts();
700 // Entry starts with index 1
701 uint8_t index = 1;
702 for (auto& entry : entries)
703 {
704 resolution += std::to_string(index) + ". ";
705 // Adding Location code to resolution
706 if (!entry->locationCode().empty())
707 resolution +=
708 "Location Code: " + entry->locationCode() + ", ";
709 if (entry->fruIdentity())
710 {
711 // Get priority and set the resolution string
712 str = pv::getValue(entry->priority(),
713 pel_values::calloutPriorityValues,
714 pel_values::registryNamePos);
715 str[0] = toupper(str[0]);
716 resolution += "Priority: " + str + ", ";
717 if (entry->fruIdentity()->getPN().has_value())
718 {
719 resolution +=
720 "PN: " + entry->fruIdentity()->getPN().value() +
721 ", ";
722 }
723 if (entry->fruIdentity()->getSN().has_value())
724 {
725 resolution +=
726 "SN: " + entry->fruIdentity()->getSN().value() +
727 ", ";
728 }
729 if (entry->fruIdentity()->getCCIN().has_value())
730 {
731 resolution +=
732 "CCIN: " + entry->fruIdentity()->getCCIN().value() +
733 ", ";
734 }
735 // Add the maintenance procedure
736 if (entry->fruIdentity()->getMaintProc().has_value())
737 {
738 resolution +=
739 "Procedure: " +
740 entry->fruIdentity()->getMaintProc().value() + ", ";
741 }
742 }
743 resolution.resize(resolution.size() - 2);
744 resolution += "\n";
745 index++;
746 }
747 }
748 }
749 return resolution;
750}
751
752void Manager::updateResolution(std::unique_ptr<openpower::pels::PEL>& pel)
753{
754 std::string callouts = getResolution(*pel);
755 auto entryN = _logManager.entries.find(pel->obmcLogID());
756 if (entryN != _logManager.entries.end())
757 {
758 entryN->second->resolution(callouts);
759 }
760}
761
Adriana Kobylake7d271a2020-12-07 14:32:44 -0600762void Manager::setEntryPath(uint32_t obmcLogID)
763{
764 Repository::LogID id{Repository::LogID::Obmc(obmcLogID)};
765 if (auto attributes = _repo.getPELAttributes(id); attributes)
766 {
767 auto& attr = attributes.value().get();
768 auto entry = _logManager.entries.find(obmcLogID);
769 if (entry != _logManager.entries.end())
770 {
771 entry->second->path(attr.path);
772 }
773 }
774}
775
Vijay Lobocbc93a42021-05-20 19:04:07 -0500776void Manager::setServiceProviderNotifyFlag(uint32_t obmcLogID)
777{
778 Repository::LogID id{Repository::LogID::Obmc(obmcLogID)};
779 if (auto attributes = _repo.getPELAttributes(id); attributes)
780 {
781 auto& attr = attributes.value().get();
782 auto entry = _logManager.entries.find(obmcLogID);
783 if (entry != _logManager.entries.end())
784 {
785 if (attr.actionFlags.test(callHomeFlagBit))
786 {
787 entry->second->serviceProviderNotify(true);
788 }
789 else
790 {
791 entry->second->serviceProviderNotify(false);
792 }
793 }
794 }
795}
796
Ramesh Iyyarf4203c42021-06-24 06:09:23 -0500797uint32_t Manager::getPELIdFromBMCLogId(uint32_t bmcLogId)
798{
799 Repository::LogID id{Repository::LogID::Obmc(bmcLogId)};
800 if (auto logId = _repo.getLogID(id); !logId.has_value())
801 {
802 throw common_error::InvalidArgument();
803 }
804 else
805 {
806 return logId->pelID.id;
807 }
808}
809
Ramesh Iyyar530efbf2021-06-24 06:22:22 -0500810uint32_t Manager::getBMCLogIdFromPELId(uint32_t pelId)
811{
812 Repository::LogID id{Repository::LogID::Pel(pelId)};
813 if (auto logId = _repo.getLogID(id); !logId.has_value())
814 {
815 throw common_error::InvalidArgument();
816 }
817 else
818 {
819 return logId->obmcID.id;
820 }
821}
822
Matt Spinler4e8078c2019-07-09 13:22:32 -0500823} // namespace pels
824} // namespace openpower