blob: f24f63c1bb52aba8f1b6bd9dccaadacaae4d1133 [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);
Vijay Loboafb1b462021-07-21 23:29:13 -0500191 createPELEntry(obmcLogID);
Matt Spinler19e72902020-01-24 11:05:20 -0600192 }
193 else
194 {
195 log<level::ERR>("Invalid PEL received from the host",
196 entry("OBMCLOGID=%d", obmcLogID));
197
198 AdditionalData ad;
199 ad.add("PLID", getNumberString("0x%08X", pel->plid()));
200 ad.add("OBMC_LOG_ID", std::to_string(obmcLogID));
201 ad.add("PEL_SIZE", std::to_string(pelData.size()));
202
203 std::string asciiString;
204 auto src = pel->primarySRC();
205 if (src)
206 {
207 asciiString = (*src)->asciiString();
208 }
209
210 ad.add("SRC", asciiString);
211
212 _eventLogger.log("org.open_power.Logging.Error.BadHostPEL",
213 Entry::Level::Error, ad);
Matt Spinlerfe721892020-04-02 10:28:08 -0500214
215 // Save it to a file for debug in the lab. Just keep the latest.
216 // Not adding it to the PEL because it could already be max size
217 // and don't want to truncate an already invalid PEL.
218 std::ofstream pelFile{getPELRepoPath() / "badPEL"};
219 pelFile.write(reinterpret_cast<const char*>(pelData.data()),
220 pelData.size());
Matt Spinler19e72902020-01-24 11:05:20 -0600221 }
222}
223
224void Manager::addESELPEL(const std::string& esel, uint32_t obmcLogID)
225{
226 std::vector<uint8_t> data;
227
Matt Spinler5f5352e2020-03-05 16:23:27 -0600228 log<level::DEBUG>("Adding PEL from ESEL",
229 entry("OBMC_LOG_ID=%d", obmcLogID));
230
Matt Spinler19e72902020-01-24 11:05:20 -0600231 try
232 {
233 data = std::move(eselToRawData(esel));
234 }
235 catch (std::exception& e)
236 {
237 // Try to add it below anyway, so it follows the usual bad data path.
238 log<level::ERR>("Problems converting ESEL string to a byte vector");
239 }
240
241 addPEL(data, obmcLogID);
242}
243
244std::vector<uint8_t> Manager::eselToRawData(const std::string& esel)
245{
246 std::vector<uint8_t> data;
247 std::string byteString;
248
249 // As the eSEL string looks like: "50 48 00 ab ..." there are 3
250 // characters per raw byte, and since the actual PEL data starts
251 // at the 16th byte, the code will grab the PEL data starting at
252 // offset 48 in the string.
253 static constexpr size_t pelStart = 16 * 3;
254
255 if (esel.size() <= pelStart)
256 {
257 log<level::ERR>("ESEL data too short",
258 entry("ESEL_SIZE=%d", esel.size()));
259
260 throw std::length_error("ESEL data too short");
261 }
262
263 for (size_t i = pelStart; i < esel.size(); i += 3)
264 {
265 if (i + 1 < esel.size())
266 {
267 byteString = esel.substr(i, 2);
268 data.push_back(std::stoi(byteString, nullptr, 16));
269 }
270 else
271 {
272 log<level::ERR>("ESEL data too short",
273 entry("ESEL_SIZE=%d", esel.size()));
274 throw std::length_error("ESEL data too short");
275 }
276 }
277
278 return data;
279}
280
Matt Spinler4e8078c2019-07-09 13:22:32 -0500281void Manager::erase(uint32_t obmcLogID)
282{
Matt Spinler475e5742019-07-18 16:09:49 -0500283 Repository::LogID id{Repository::LogID::Obmc(obmcLogID)};
284
Vijay Loboafb1b462021-07-21 23:29:13 -0500285 auto path = std::string(OBJ_ENTRY) + '/' + std::to_string(obmcLogID);
286 _pelEntries.erase(path);
Matt Spinler475e5742019-07-18 16:09:49 -0500287 _repo.remove(id);
Matt Spinler4e8078c2019-07-09 13:22:32 -0500288}
289
Patrick Williamsd26fa3e2021-04-21 15:22:23 -0500290bool Manager::isDeleteProhibited(uint32_t /*obmcLogID*/)
Matt Spinler4e8078c2019-07-09 13:22:32 -0500291{
292 return false;
293}
294
Matt Spinler56ad2a02020-03-26 14:00:52 -0500295PelFFDC Manager::convertToPelFFDC(const FFDCEntries& ffdc)
296{
297 PelFFDC pelFFDC;
298
299 std::for_each(ffdc.begin(), ffdc.end(), [&pelFFDC](const auto& f) {
300 PelFFDCfile pf;
301 pf.subType = std::get<ffdcSubtypePos>(f);
302 pf.version = std::get<ffdcVersionPos>(f);
303 pf.fd = std::get<ffdcFDPos>(f);
304
305 switch (std::get<ffdcFormatPos>(f))
306 {
307 case Create::FFDCFormat::JSON:
308 pf.format = UserDataFormat::json;
309 break;
310 case Create::FFDCFormat::CBOR:
311 pf.format = UserDataFormat::cbor;
312 break;
313 case Create::FFDCFormat::Text:
314 pf.format = UserDataFormat::text;
315 break;
316 case Create::FFDCFormat::Custom:
317 pf.format = UserDataFormat::custom;
318 break;
319 }
320
321 pelFFDC.push_back(pf);
322 });
323
324 return pelFFDC;
325}
326
Matt Spinler4e8078c2019-07-09 13:22:32 -0500327void Manager::createPEL(const std::string& message, uint32_t obmcLogID,
328 uint64_t timestamp,
329 phosphor::logging::Entry::Level severity,
330 const std::vector<std::string>& additionalData,
Patrick Williamsd26fa3e2021-04-21 15:22:23 -0500331 const std::vector<std::string>& /*associations*/,
Matt Spinler56ad2a02020-03-26 14:00:52 -0500332 const FFDCEntries& ffdc)
Matt Spinler4e8078c2019-07-09 13:22:32 -0500333{
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800334 auto entry = _registry.lookup(message, rg::LookupType::name);
Matt Spinler30ddc9f2020-07-16 15:39:59 -0500335 auto pelFFDC = convertToPelFFDC(ffdc);
336 AdditionalData ad{additionalData};
Matt Spinler1d4c74a2019-12-16 14:40:21 -0600337 std::string msg;
Matt Spinler67456c22019-10-21 12:22:49 -0500338
Matt Spinler30ddc9f2020-07-16 15:39:59 -0500339 if (!entry)
Matt Spinler67456c22019-10-21 12:22:49 -0500340 {
Matt Spinler30ddc9f2020-07-16 15:39:59 -0500341 // Instead, get the default entry that means there is no
342 // other matching entry. This error will still use the
343 // AdditionalData values of the original error, and this
344 // code will add the error message value that wasn't found
345 // to this AD. This way, there will at least be a PEL,
346 // possibly with callouts, to allow users to debug the
347 // issue that caused the error even without its own PEL.
Matt Spinler1d4c74a2019-12-16 14:40:21 -0600348 msg = "Event not found in PEL message registry: " + message;
349 log<level::INFO>(msg.c_str());
Matt Spinler30ddc9f2020-07-16 15:39:59 -0500350
351 entry = _registry.lookup(defaultLogMessage, rg::LookupType::name);
352 if (!entry)
353 {
354 log<level::ERR>("Default event not found in PEL message registry");
355 return;
356 }
357
358 ad.add(additional_data::error, message);
359 }
360
361 auto pel = std::make_unique<openpower::pels::PEL>(
362 *entry, obmcLogID, timestamp, severity, ad, pelFFDC, *_dataIface);
363
364 _repo.add(pel);
365
366 if (_repo.sizeWarning())
367 {
368 scheduleRepoPrune();
369 }
370
371 auto src = pel->primarySRC();
372 if (src)
373 {
Matt Spinler22421b92020-07-17 09:41:08 -0500374 auto msg =
375 fmt::format("Created PEL {:#x} (BMC ID {}) with SRC {}", pel->id(),
376 pel->obmcLogID(), (*src)->asciiString());
Matt Spinler30ddc9f2020-07-16 15:39:59 -0500377 while (msg.back() == ' ')
378 {
379 msg.pop_back();
380 }
381 log<level::INFO>(msg.c_str());
Matt Spinler1d4c74a2019-12-16 14:40:21 -0600382 }
Matt Spinler1962e082020-08-05 13:44:53 -0500383
384 // Activate any resulting service indicators if necessary
385 auto policy = service_indicators::getPolicy(*_dataIface);
386 policy->activate(*pel);
Andrew Geissler44fc3162020-07-09 09:21:31 -0500387
388 // Check if firmware should quiesce system due to error
389 checkPelAndQuiesce(pel);
Vijay Lobod354a392021-06-01 16:21:02 -0500390 updateEventId(pel);
Vijay Lobo593a4c62021-06-16 14:25:26 -0500391 updateResolution(pel);
Vijay Loboafb1b462021-07-21 23:29:13 -0500392 createPELEntry(obmcLogID);
Matt Spinler4e8078c2019-07-09 13:22:32 -0500393}
394
Matt Spinlera34ab722019-12-16 10:39:32 -0600395sdbusplus::message::unix_fd Manager::getPEL(uint32_t pelID)
396{
397 Repository::LogID id{Repository::LogID::Pel(pelID)};
398 std::optional<int> fd;
399
Matt Spinler5f5352e2020-03-05 16:23:27 -0600400 log<level::DEBUG>("getPEL", entry("PEL_ID=0x%X", pelID));
401
Matt Spinlera34ab722019-12-16 10:39:32 -0600402 try
403 {
404 fd = _repo.getPELFD(id);
405 }
406 catch (std::exception& e)
407 {
408 throw common_error::InternalFailure();
409 }
410
411 if (!fd)
412 {
413 throw common_error::InvalidArgument();
414 }
415
Matt Spinler6b1a5c82020-01-07 08:48:53 -0600416 scheduleFDClose(*fd);
417
Matt Spinlera34ab722019-12-16 10:39:32 -0600418 return *fd;
419}
420
Matt Spinler6b1a5c82020-01-07 08:48:53 -0600421void Manager::scheduleFDClose(int fd)
422{
423 _fdCloserEventSource = std::make_unique<sdeventplus::source::Defer>(
Matt Spinlerff9cec22020-07-15 13:06:35 -0500424 _event, std::bind(std::mem_fn(&Manager::closeFD), this, fd,
425 std::placeholders::_1));
Matt Spinler6b1a5c82020-01-07 08:48:53 -0600426}
427
Patrick Williamsd26fa3e2021-04-21 15:22:23 -0500428void Manager::closeFD(int fd, sdeventplus::source::EventBase& /*source*/)
Matt Spinler6b1a5c82020-01-07 08:48:53 -0600429{
430 close(fd);
431 _fdCloserEventSource.reset();
432}
433
Matt Spinlera34ab722019-12-16 10:39:32 -0600434std::vector<uint8_t> Manager::getPELFromOBMCID(uint32_t obmcLogID)
435{
436 Repository::LogID id{Repository::LogID::Obmc(obmcLogID)};
437 std::optional<std::vector<uint8_t>> data;
438
Matt Spinler5f5352e2020-03-05 16:23:27 -0600439 log<level::DEBUG>("getPELFromOBMCID", entry("OBMC_LOG_ID=%d", obmcLogID));
440
Matt Spinlera34ab722019-12-16 10:39:32 -0600441 try
442 {
443 data = _repo.getPELData(id);
444 }
445 catch (std::exception& e)
446 {
447 throw common_error::InternalFailure();
448 }
449
450 if (!data)
451 {
452 throw common_error::InvalidArgument();
453 }
454
455 return *data;
456}
457
458void Manager::hostAck(uint32_t pelID)
459{
460 Repository::LogID id{Repository::LogID::Pel(pelID)};
461
Matt Spinler5f5352e2020-03-05 16:23:27 -0600462 log<level::DEBUG>("HostAck", entry("PEL_ID=0x%X", pelID));
463
Matt Spinlera34ab722019-12-16 10:39:32 -0600464 if (!_repo.hasPEL(id))
465 {
466 throw common_error::InvalidArgument();
467 }
468
469 if (_hostNotifier)
470 {
471 _hostNotifier->ackPEL(pelID);
472 }
473}
474
475void Manager::hostReject(uint32_t pelID, RejectionReason reason)
476{
477 Repository::LogID id{Repository::LogID::Pel(pelID)};
478
Matt Spinler5f5352e2020-03-05 16:23:27 -0600479 log<level::DEBUG>("HostReject", entry("PEL_ID=0x%X", pelID),
480 entry("REASON=%d", static_cast<int>(reason)));
481
Matt Spinlera34ab722019-12-16 10:39:32 -0600482 if (!_repo.hasPEL(id))
483 {
484 throw common_error::InvalidArgument();
485 }
486
Matt Spinler05c2c6c2019-12-18 14:02:09 -0600487 if (reason == RejectionReason::BadPEL)
Matt Spinlera34ab722019-12-16 10:39:32 -0600488 {
Matt Spinler05c2c6c2019-12-18 14:02:09 -0600489 AdditionalData data;
490 data.add("BAD_ID", getNumberString("0x%08X", pelID));
491 _eventLogger.log("org.open_power.Logging.Error.SentBadPELToHost",
492 Entry::Level::Informational, data);
493 if (_hostNotifier)
Matt Spinlera34ab722019-12-16 10:39:32 -0600494 {
495 _hostNotifier->setBadPEL(pelID);
496 }
Matt Spinler05c2c6c2019-12-18 14:02:09 -0600497 }
498 else if ((reason == RejectionReason::HostFull) && _hostNotifier)
499 {
500 _hostNotifier->setHostFull(pelID);
Matt Spinlera34ab722019-12-16 10:39:32 -0600501 }
502}
503
Matt Spinler7e727a32020-07-07 15:00:17 -0500504void Manager::scheduleRepoPrune()
505{
Matt Spinler7e727a32020-07-07 15:00:17 -0500506 _repoPrunerEventSource = std::make_unique<sdeventplus::source::Defer>(
Matt Spinlerff9cec22020-07-15 13:06:35 -0500507 _event, std::bind(std::mem_fn(&Manager::pruneRepo), this,
508 std::placeholders::_1));
Matt Spinler7e727a32020-07-07 15:00:17 -0500509}
510
Patrick Williamsd26fa3e2021-04-21 15:22:23 -0500511void Manager::pruneRepo(sdeventplus::source::EventBase& /*source*/)
Matt Spinler7e727a32020-07-07 15:00:17 -0500512{
513 auto idsToDelete = _repo.prune();
514
515 // Remove the OpenBMC event logs for the PELs that were just removed.
516 std::for_each(idsToDelete.begin(), idsToDelete.end(),
517 [this](auto id) { this->_logManager.erase(id); });
518
519 _repoPrunerEventSource.reset();
520}
521
Matt Spinlerff9cec22020-07-15 13:06:35 -0500522void Manager::setupPELDeleteWatch()
523{
524 _pelFileDeleteFD = inotify_init1(IN_NONBLOCK);
525 if (-1 == _pelFileDeleteFD)
526 {
527 auto e = errno;
528 std::string msg =
529 "inotify_init1 failed with errno " + std::to_string(e);
530 log<level::ERR>(msg.c_str());
531 abort();
532 }
533
534 _pelFileDeleteWatchFD = inotify_add_watch(
535 _pelFileDeleteFD, _repo.repoPath().c_str(), IN_DELETE);
536 if (-1 == _pelFileDeleteWatchFD)
537 {
538 auto e = errno;
539 std::string msg =
540 "inotify_add_watch failed with error " + std::to_string(e);
541 log<level::ERR>(msg.c_str());
542 abort();
543 }
544
545 _pelFileDeleteEventSource = std::make_unique<sdeventplus::source::IO>(
546 _event, _pelFileDeleteFD, EPOLLIN,
547 std::bind(std::mem_fn(&Manager::pelFileDeleted), this,
548 std::placeholders::_1, std::placeholders::_2,
549 std::placeholders::_3));
550}
551
Patrick Williamsd26fa3e2021-04-21 15:22:23 -0500552void Manager::pelFileDeleted(sdeventplus::source::IO& /*io*/, int /*fd*/,
Matt Spinlerff9cec22020-07-15 13:06:35 -0500553 uint32_t revents)
554{
555 if (!(revents & EPOLLIN))
556 {
557 return;
558 }
559
560 // An event for 1 PEL uses 48B. When all PELs are deleted at once,
561 // as many events as there is room for can be handled in one callback.
562 // A size of 2000 will allow 41 to be processed, with additional
563 // callbacks being needed to process the remaining ones.
Matt Spinler9d59d582021-05-19 07:57:10 -0600564 std::array<uint8_t, 2000> data{};
Matt Spinlerff9cec22020-07-15 13:06:35 -0500565 auto bytesRead = read(_pelFileDeleteFD, data.data(), data.size());
566 if (bytesRead < 0)
567 {
568 auto e = errno;
569 std::string msg = "Failed reading data from inotify event, errno = " +
570 std::to_string(e);
571 log<level::ERR>(msg.c_str());
572 abort();
573 }
574
575 auto offset = 0;
576 while (offset < bytesRead)
577 {
578 auto event = reinterpret_cast<inotify_event*>(&data[offset]);
579 if (event->mask & IN_DELETE)
580 {
581 std::string filename{event->name};
582
583 // Get the PEL ID from the filename and tell the
584 // repo it's been removed, and then delete the BMC
585 // event log if it's there.
586 auto pos = filename.find_first_of('_');
587 if (pos != std::string::npos)
588 {
589 try
590 {
591 auto idString = filename.substr(pos + 1);
592 auto pelID = std::stoul(idString, nullptr, 16);
593
594 Repository::LogID id{Repository::LogID::Pel(pelID)};
595 auto removedLogID = _repo.remove(id);
596 if (removedLogID)
597 {
598 _logManager.erase(removedLogID->obmcID.id);
599 }
600 }
601 catch (const std::exception& e)
602 {
603 log<level::INFO>("Could not find PEL ID from its filename",
604 entry("FILENAME=%s", filename.c_str()));
605 }
606 }
607 }
608
609 offset += offsetof(inotify_event, name) + event->len;
610 }
611}
Matt Spinler9cc30072020-09-16 15:39:34 -0500612
613std::tuple<uint32_t, uint32_t> Manager::createPELWithFFDCFiles(
614 std::string message, Entry::Level severity,
615 std::map<std::string, std::string> additionalData,
616 std::vector<std::tuple<
617 sdbusplus::xyz::openbmc_project::Logging::server::Create::FFDCFormat,
618 uint8_t, uint8_t, sdbusplus::message::unix_fd>>
619 fFDC)
620{
Matt Spinler44893cc2020-08-26 11:34:17 -0500621 _logManager.createWithFFDC(message, severity, additionalData, fFDC);
622
623 return {_logManager.lastEntryID(), _repo.lastPelID()};
Matt Spinler9cc30072020-09-16 15:39:34 -0500624}
625
Andrew Geissler44fc3162020-07-09 09:21:31 -0500626void Manager::checkPelAndQuiesce(std::unique_ptr<openpower::pels::PEL>& pel)
627{
Matt Spinlerb2abc042021-05-17 15:32:50 -0600628 if ((pel->userHeader().severity() ==
629 static_cast<uint8_t>(SeverityType::nonError)) ||
630 (pel->userHeader().severity() ==
631 static_cast<uint8_t>(SeverityType::recovered)))
Andrew Geissler44fc3162020-07-09 09:21:31 -0500632 {
Matt Spinlerb2abc042021-05-17 15:32:50 -0600633 log<level::DEBUG>(
634 "PEL severity informational or recovered. no quiesce needed");
Andrew Geissler44fc3162020-07-09 09:21:31 -0500635 return;
636 }
637 if (!_logManager.isQuiesceOnErrorEnabled())
638 {
639 log<level::DEBUG>("QuiesceOnHwError not enabled, no quiesce needed");
640 return;
641 }
642
643 // Now check if it has any type of callout
644 if (pel->isCalloutPresent())
645 {
Matt Spinlerb2abc042021-05-17 15:32:50 -0600646 log<level::INFO>(
647 "QuiesceOnHwError enabled, PEL severity not nonError or recovered, "
648 "and callout is present");
Andrew Geissler44fc3162020-07-09 09:21:31 -0500649
650 _logManager.quiesceOnError(pel->obmcLogID());
651 }
652}
653
Vijay Lobod354a392021-06-01 16:21:02 -0500654std::string Manager::getEventId(const openpower::pels::PEL& pel) const
655{
656 std::string str;
657 auto src = pel.primarySRC();
658 if (src)
659 {
660 const auto& hexwords = (*src)->hexwordData();
661
662 std::string refcode = (*src)->asciiString();
663 size_t pos = refcode.find_last_not_of(0x20);
664 if (pos != std::string::npos)
665 {
666 refcode.erase(pos + 1);
667 }
668 str = refcode;
669
670 for (auto& value : hexwords)
671 {
672 str += " ";
673 str += getNumberString("%08X", value);
674 }
675 }
676 return str;
677}
678
679void Manager::updateEventId(std::unique_ptr<openpower::pels::PEL>& pel)
680{
681 std::string eventIdStr = getEventId(*pel);
682
683 auto entryN = _logManager.entries.find(pel->obmcLogID());
684 if (entryN != _logManager.entries.end())
685 {
686 entryN->second->eventId(eventIdStr);
687 }
688}
689
Vijay Lobo593a4c62021-06-16 14:25:26 -0500690std::string Manager::getResolution(const openpower::pels::PEL& pel) const
691{
692 std::string str;
693 std::string resolution;
694 auto src = pel.primarySRC();
695 if (src)
696 {
697 // First extract the callout pointer and then go through
698 const auto& callouts = (*src)->callouts();
699 namespace pv = openpower::pels::pel_values;
700 // All PELs dont have callout, check before parsing callout data
701 if (callouts)
702 {
703 const auto& entries = callouts->callouts();
704 // Entry starts with index 1
705 uint8_t index = 1;
706 for (auto& entry : entries)
707 {
708 resolution += std::to_string(index) + ". ";
709 // Adding Location code to resolution
710 if (!entry->locationCode().empty())
711 resolution +=
712 "Location Code: " + entry->locationCode() + ", ";
713 if (entry->fruIdentity())
714 {
715 // Get priority and set the resolution string
716 str = pv::getValue(entry->priority(),
717 pel_values::calloutPriorityValues,
718 pel_values::registryNamePos);
719 str[0] = toupper(str[0]);
720 resolution += "Priority: " + str + ", ";
721 if (entry->fruIdentity()->getPN().has_value())
722 {
723 resolution +=
724 "PN: " + entry->fruIdentity()->getPN().value() +
725 ", ";
726 }
727 if (entry->fruIdentity()->getSN().has_value())
728 {
729 resolution +=
730 "SN: " + entry->fruIdentity()->getSN().value() +
731 ", ";
732 }
733 if (entry->fruIdentity()->getCCIN().has_value())
734 {
735 resolution +=
736 "CCIN: " + entry->fruIdentity()->getCCIN().value() +
737 ", ";
738 }
739 // Add the maintenance procedure
740 if (entry->fruIdentity()->getMaintProc().has_value())
741 {
742 resolution +=
743 "Procedure: " +
744 entry->fruIdentity()->getMaintProc().value() + ", ";
745 }
746 }
747 resolution.resize(resolution.size() - 2);
748 resolution += "\n";
749 index++;
750 }
751 }
752 }
753 return resolution;
754}
755
756void Manager::updateResolution(std::unique_ptr<openpower::pels::PEL>& pel)
757{
758 std::string callouts = getResolution(*pel);
759 auto entryN = _logManager.entries.find(pel->obmcLogID());
760 if (entryN != _logManager.entries.end())
761 {
762 entryN->second->resolution(callouts);
763 }
764}
765
Adriana Kobylake7d271a2020-12-07 14:32:44 -0600766void Manager::setEntryPath(uint32_t obmcLogID)
767{
768 Repository::LogID id{Repository::LogID::Obmc(obmcLogID)};
769 if (auto attributes = _repo.getPELAttributes(id); attributes)
770 {
771 auto& attr = attributes.value().get();
772 auto entry = _logManager.entries.find(obmcLogID);
773 if (entry != _logManager.entries.end())
774 {
775 entry->second->path(attr.path);
776 }
777 }
778}
779
Vijay Lobocbc93a42021-05-20 19:04:07 -0500780void Manager::setServiceProviderNotifyFlag(uint32_t obmcLogID)
781{
782 Repository::LogID id{Repository::LogID::Obmc(obmcLogID)};
783 if (auto attributes = _repo.getPELAttributes(id); attributes)
784 {
785 auto& attr = attributes.value().get();
786 auto entry = _logManager.entries.find(obmcLogID);
787 if (entry != _logManager.entries.end())
788 {
Vijay Loboafb1b462021-07-21 23:29:13 -0500789 entry->second->serviceProviderNotify(
790 attr.actionFlags.test(callHomeFlagBit));
Vijay Lobocbc93a42021-05-20 19:04:07 -0500791 }
792 }
793}
794
Vijay Loboafb1b462021-07-21 23:29:13 -0500795void Manager::createPELEntry(uint32_t obmcLogID)
796{
797 std::map<std::string, PropertiesVariant> varData;
798 Repository::LogID id{Repository::LogID::Obmc(obmcLogID)};
799 if (auto attributes = _repo.getPELAttributes(id); attributes)
800 {
801 namespace pv = openpower::pels::pel_values;
802 auto& attr = attributes.value().get();
803 varData.emplace(std::string("Hidden"),
804 attr.actionFlags.test(hiddenFlagBit));
805 varData.emplace(
806 std::string("Subsystem"),
807 pv::getValue(attr.subsystem, pel_values::subsystemValues));
808 // Path to create PELEntry Interface is same as PEL
809 auto path = std::string(OBJ_ENTRY) + '/' + std::to_string(obmcLogID);
810 // Create Interface for PELEntry and set properties
811 auto pelEntry = std::make_unique<PELEntry>(_logManager.getBus(),
812 path.c_str(), varData);
813 _pelEntries.emplace(std::move(path), std::move(pelEntry));
814 }
815}
816
Ramesh Iyyarf4203c42021-06-24 06:09:23 -0500817uint32_t Manager::getPELIdFromBMCLogId(uint32_t bmcLogId)
818{
819 Repository::LogID id{Repository::LogID::Obmc(bmcLogId)};
820 if (auto logId = _repo.getLogID(id); !logId.has_value())
821 {
822 throw common_error::InvalidArgument();
823 }
824 else
825 {
826 return logId->pelID.id;
827 }
828}
829
Ramesh Iyyar530efbf2021-06-24 06:22:22 -0500830uint32_t Manager::getBMCLogIdFromPELId(uint32_t pelId)
831{
832 Repository::LogID id{Repository::LogID::Pel(pelId)};
833 if (auto logId = _repo.getLogID(id); !logId.has_value())
834 {
835 throw common_error::InvalidArgument();
836 }
837 else
838 {
839 return logId->obmcID.id;
840 }
841}
842
Matt Spinler4e8078c2019-07-09 13:22:32 -0500843} // namespace pels
844} // namespace openpower