blob: 009b9c00cc843a2e3de0ec4366d085c9b2994340 [file] [log] [blame]
Brad Bishop5e5d4452020-10-27 19:46:13 -04001extern "C"
2{
Brad Bishopf6783cd2020-10-27 19:25:09 -04003#include <libpdbg.h>
4}
5
6#include "create_pel.hpp"
Jayanth Othayoth006641e2021-10-07 06:56:24 -05007#include "dump_utils.hpp"
Jayanth Othayoth4079f092021-09-20 07:36:54 -05008#include "extensions/phal/common_utils.hpp"
Brad Bishopf6783cd2020-10-27 19:25:09 -04009#include "phal_error.hpp"
Marri Devender Rao4d5b5bf2022-05-23 09:23:31 -050010#include "util.hpp"
Brad Bishopf6783cd2020-10-27 19:25:09 -040011
12#include <attributes_info.H>
13#include <fmt/format.h>
14#include <libekb.H>
Jayanth Othayoth4079f092021-09-20 07:36:54 -050015#include <libphal.H>
Brad Bishopf6783cd2020-10-27 19:25:09 -040016
Brad Bishop5e5d4452020-10-27 19:46:13 -040017#include <nlohmann/json.hpp>
18#include <phosphor-logging/elog.hpp>
19
Brad Bishopf6783cd2020-10-27 19:25:09 -040020#include <algorithm>
21#include <cstdlib>
22#include <cstring>
23#include <iomanip>
24#include <list>
25#include <map>
Brad Bishopf6783cd2020-10-27 19:25:09 -040026#include <sstream>
27#include <string>
28
29namespace openpower
30{
31namespace phal
32{
33using namespace phosphor::logging;
Jayanth Othayoth5d5eb312021-11-15 01:54:07 -060034using namespace openpower::phal::exception;
Marri Devender Rao4d5b5bf2022-05-23 09:23:31 -050035using Severity = sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level;
Brad Bishopf6783cd2020-10-27 19:25:09 -040036
37/**
38 * Used to pass buffer to pdbg callback api to get required target
39 * data (attributes) based on given data (attribute).
40 */
41struct TargetInfo
42{
43 ATTR_PHYS_BIN_PATH_Type physBinPath;
44 ATTR_LOCATION_CODE_Type locationCode;
45 ATTR_PHYS_DEV_PATH_Type physDevPath;
46 ATTR_MRU_ID_Type mruId;
47
48 bool deconfigure;
49
50 TargetInfo()
51 {
52 memset(&physBinPath, '\0', sizeof(physBinPath));
53 memset(&locationCode, '\0', sizeof(locationCode));
54 memset(&physDevPath, '\0', sizeof(physDevPath));
55 mruId = 0;
56 deconfigure = false;
57 }
58};
59
60/**
61 * Used to return in callback function which are used to get
62 * physical path value and it binary format value.
63 *
64 * The value for constexpr defined based on pdbg_target_traverse function usage.
65 */
66constexpr int continueTgtTraversal = 0;
67constexpr int requireAttrFound = 1;
68constexpr int requireAttrNotFound = 2;
69
70/**
71 * @brief Used to get target location code from phal device tree
72 *
73 * @param[in] target current device tree target
74 * @param[out] appPrivData used for accessing|storing from|to application
75 *
76 * @return 0 to continue traverse, non-zero to stop traverse
77 */
78int pdbgCallbackToGetTgtReqAttrsVal(struct pdbg_target* target,
79 void* appPrivData)
80{
Jayanth Othayoth5d5eb312021-11-15 01:54:07 -060081 using namespace openpower::phal::pdbg;
82
Brad Bishopf6783cd2020-10-27 19:25:09 -040083 TargetInfo* targetInfo = static_cast<TargetInfo*>(appPrivData);
84
85 ATTR_PHYS_BIN_PATH_Type physBinPath;
86 /**
87 * TODO: Issue: phal/pdata#16
88 * Should not use direct pdbg api to read attribute. Need to use DT_GET_PROP
89 * macro for bmc app's and this will call libdt-api api but, it will print
90 * "pdbg_target_get_attribute failed" trace if attribute is not found and
91 * this callback will call recursively by using pdbg_target_traverse() until
92 * find expected attribute based on return code from this callback. Because,
93 * need to do target iteration to get actual attribute (ATTR_PHYS_BIN_PATH)
94 * value when device tree target info doesn't know to read attribute from
95 * device tree. So, Due to this error trace user will get confusion while
96 * looking traces. Hence using pdbg api to avoid trace until libdt-api
97 * provides log level setup.
98 */
99 if (!pdbg_target_get_attribute(
100 target, "ATTR_PHYS_BIN_PATH",
101 std::stoi(dtAttr::fapi2::ATTR_PHYS_BIN_PATH_Spec),
102 dtAttr::fapi2::ATTR_PHYS_BIN_PATH_ElementCount, physBinPath))
103 {
104 return continueTgtTraversal;
105 }
106
107 if (std::memcmp(physBinPath, targetInfo->physBinPath,
108 sizeof(physBinPath)) != 0)
109 {
110 return continueTgtTraversal;
111 }
112
Jayanth Othayothde909252021-11-15 02:36:45 -0600113 // Found Target, now collect the required attributes associated to the
114 // target. Incase of any attribute read failure, initialize the data with
115 // default value.
Jayanth Othayoth5d5eb312021-11-15 01:54:07 -0600116 try
Brad Bishopf6783cd2020-10-27 19:25:09 -0400117 {
Jayanth Othayoth5d5eb312021-11-15 01:54:07 -0600118 // Get location code information
119 openpower::phal::pdbg::getLocationCode(target,
120 targetInfo->locationCode);
121 }
122 catch (const std::exception& e)
123 {
Jayanth Othayoth5d5eb312021-11-15 01:54:07 -0600124 log<level::ERR>(fmt::format("getLocationCode({}): Exception({})",
125 pdbg_target_path(target), e.what())
126 .c_str());
Brad Bishopf6783cd2020-10-27 19:25:09 -0400127 }
128
129 if (DT_GET_PROP(ATTR_PHYS_DEV_PATH, target, targetInfo->physDevPath))
130 {
Jayanth Othayothde909252021-11-15 02:36:45 -0600131 log<level::ERR>(
132 fmt::format("Could not read({}) PHYS_DEV_PATH attribute",
133 pdbg_target_path(target))
134 .c_str());
Brad Bishopf6783cd2020-10-27 19:25:09 -0400135 }
136
137 if (DT_GET_PROP(ATTR_MRU_ID, target, targetInfo->mruId))
138 {
Jayanth Othayothde909252021-11-15 02:36:45 -0600139 log<level::ERR>(fmt::format("Could not read({}) ATTR_MRU_ID attribute",
140 pdbg_target_path(target))
141 .c_str());
Brad Bishopf6783cd2020-10-27 19:25:09 -0400142 }
143
Brad Bishopf6783cd2020-10-27 19:25:09 -0400144 return requireAttrFound;
145}
146
147/**
148 * @brief Used to get target info (attributes data)
149 *
150 * To get target required attributes value using another attribute value
151 * ("PHYS_BIN_PATH" which is present in same target attributes list) by using
152 * "ipdbg_target_traverse" api because, here we have attribute value only and
153 * doesn't have respective device tree target info to get required attributes
154 * values from it attributes list.
155 *
156 * @param[in] physBinPath to pass PHYS_BIN_PATH value
157 * @param[out] targetInfo to pas buufer to fill with required attributes
158 *
159 * @return true on success otherwise false
160 */
161bool getTgtReqAttrsVal(const std::vector<uint8_t>& physBinPath,
162 TargetInfo& targetInfo)
163{
164 std::memcpy(&targetInfo.physBinPath, physBinPath.data(),
165 sizeof(targetInfo.physBinPath));
166
167 int ret = pdbg_target_traverse(NULL, pdbgCallbackToGetTgtReqAttrsVal,
168 &targetInfo);
169 if (ret == 0)
170 {
171 log<level::ERR>(fmt::format("Given ATTR_PHYS_BIN_PATH value({}) "
172 "not found in phal device tree",
173 targetInfo.physBinPath)
174 .c_str());
175 return false;
176 }
177 else if (ret == requireAttrNotFound)
178 {
179 return false;
180 }
181
182 return true;
183}
184} // namespace phal
185
186namespace pel
187{
188using namespace phosphor::logging;
189
190namespace detail
191{
192using json = nlohmann::json;
193
194// keys need to be unique so using counter value to generate unique key
195static int counter = 0;
196
197// list of debug traces
198static std::vector<std::pair<std::string, std::string>> traceLog;
199
Marri Devender Rao381c3e32021-12-01 06:27:55 -0600200/**
201 * @brief Process platform realted boot failure
202 *
203 * @param[in] errInfo - error details
204 */
205static void processPlatBootError(const ipl_error_info& errInfo);
206
Brad Bishop63508a72020-10-27 18:55:01 -0400207void processLogTraceCallback(void*, const char* fmt, va_list ap)
Brad Bishopf6783cd2020-10-27 19:25:09 -0400208{
209 va_list vap;
210 va_copy(vap, ap);
211 std::vector<char> logData(1 + std::vsnprintf(nullptr, 0, fmt, ap));
212 std::vsnprintf(logData.data(), logData.size(), fmt, vap);
213 va_end(vap);
214 std::string logstr(logData.begin(), logData.end());
215
216 log<level::INFO>(logstr.c_str());
217
218 char timeBuf[80];
219 time_t t = time(0);
220 tm myTm{};
221 gmtime_r(&t, &myTm);
222 strftime(timeBuf, 80, "%Y-%m-%d %H:%M:%S", &myTm);
223
224 // key values need to be unique for PEL
225 // TODO #openbmc/dev/issues/1563
226 // If written to Json no need to worry about unique KEY
227 std::stringstream str;
228 str << std::setfill('0');
229 str << "LOG" << std::setw(3) << counter;
230 str << " " << timeBuf;
231 traceLog.emplace_back(std::make_pair(str.str(), std::move(logstr)));
232 counter++;
233}
234
235/**
236 * @brief GET PEL priority from pHAL priority
237 *
238 * The pHAL callout priority is in different format than PEL format
239 * so, this api is used to return current phal supported priority into
240 * PEL expected format.
241 *
242 * @param[in] phalPriority used to pass phal priority format string
243 *
244 * @return pel priority format string else empty if failure
245 *
246 * @note For "NONE" returning "L" (LOW)
247 */
248static std::string getPelPriority(const std::string& phalPriority)
249{
250 const std::map<std::string, std::string> priorityMap = {
251 {"HIGH", "H"}, {"MEDIUM", "M"}, {"LOW", "L"}, {"NONE", "L"}};
252
253 auto it = priorityMap.find(phalPriority);
254 if (it == priorityMap.end())
255 {
256 log<level::ERR>(fmt::format("Unsupported phal priority({}) is given "
257 "to get pel priority format",
258 phalPriority)
259 .c_str());
260 return "H";
261 }
262
263 return it->second;
264}
265
Jayanth Othayoth69708fb2022-03-22 04:49:01 -0500266/**
267 * @brief Helper function to create PEL for non functional boot
268 * processor related failure.
269 * This function adds the BMC code callout as priority 1 to fix
270 * devtree related software issue. Incase the issue still persist
271 * after reboot recommend to replacing the primary processor.
272 */
273void processNonFunctionalBootProc()
274{
275 json jsonCalloutDataList;
276 json jsonProcedCallout;
277 // Add BMC code callout
278 jsonProcedCallout["Procedure"] = "BMC0001";
279 jsonProcedCallout["Priority"] = "H";
280 jsonCalloutDataList.emplace_back(std::move(jsonProcedCallout));
281
282 // get primary processor
283 struct pdbg_target* procTarget;
284 pdbg_for_each_class_target("proc", procTarget)
285 {
286 if (openpower::phal::isPrimaryProc(procTarget))
287 break;
288 procTarget = nullptr;
289 }
290 // check valid primary processor is available
291 if (procTarget == nullptr)
292 {
293 log<level::ERR>(
294 "processNonFunctionalBootProc: fail to get primary processor");
295 }
296 else
297 {
298 try
299 {
300 ATTR_LOCATION_CODE_Type locationCode = {'\0'};
301 // Get location code information
302 openpower::phal::pdbg::getLocationCode(procTarget, locationCode);
303 json jsonProcCallout;
304 jsonProcCallout["LocationCode"] = locationCode;
305 jsonProcCallout["Deconfigured"] = false;
306 jsonProcCallout["Guarded"] = false;
307 jsonProcCallout["Priority"] = "M";
308 jsonCalloutDataList.emplace_back(std::move(jsonProcCallout));
309 }
310 catch (const std::exception& e)
311 {
312 log<level::ERR>(fmt::format("getLocationCode({}): Exception({})",
313 pdbg_target_path(procTarget), e.what())
314 .c_str());
315 }
316 }
317 // Adding collected phal logs into PEL additional data
318 FFDCData pelAdditionalData;
319 for_each(
320 traceLog.begin(), traceLog.end(),
321 [&pelAdditionalData](std::pair<std::string, std::string>& ele) -> void {
322 pelAdditionalData.emplace_back(ele.first, ele.second);
323 });
324 openpower::pel::createErrorPEL(
325 "org.open_power.PHAL.Error.NonFunctionalBootProc", jsonCalloutDataList,
Marri Devender Rao4d5b5bf2022-05-23 09:23:31 -0500326 pelAdditionalData, Severity::Error);
Jayanth Othayoth69708fb2022-03-22 04:49:01 -0500327 // reset trace log and exit
328 reset();
329}
330
Jayanth Othayothd8be1eb2022-06-28 07:33:06 -0500331/**
332 * @brief processClockInfoErrorHelper
333 *
334 * Creates informational PEL for spare clock failure
335 *
336 * @param[in] ffdc - FFDC data capturd by the HWP
337 * @param[in] ffdc_prefix - prefix string for logging the data.
338 */
339void processClockInfoErrorHelper(FFDC* ffdc, const std::string& ffdc_prefix)
340{
341 try
342 {
343 log<level::INFO>(
344 fmt::format("processClockInfoErrorHelper: FFDC Message[{}]",
345 ffdc->message)
346 .c_str());
347
348 // To store callouts details in json format as per pel expectation.
349 json jsonCalloutDataList;
350 jsonCalloutDataList = json::array();
351
352 // To store phal trace and other additional data about ffdc.
353 FFDCData pelAdditionalData;
354
355 std::string keyWithPrefix(ffdc_prefix + "RC");
356 // Adding hardware procedures return code details
357 pelAdditionalData.emplace_back(keyWithPrefix, ffdc->hwp_errorinfo.rc);
358 keyWithPrefix = ffdc_prefix + "RC_DESC";
359 pelAdditionalData.emplace_back(keyWithPrefix,
360 ffdc->hwp_errorinfo.rc_desc);
361
362 // Adding hardware procedures required ffdc data for debug
363 for_each(ffdc->hwp_errorinfo.ffdcs_data.begin(),
364 ffdc->hwp_errorinfo.ffdcs_data.end(),
365 [&pelAdditionalData, &ffdc_prefix](
366 std::pair<std::string, std::string>& ele) -> void {
367 std::string keyWithPrefix(ffdc_prefix + "FFDC_");
368 keyWithPrefix.append(ele.first);
369
370 pelAdditionalData.emplace_back(keyWithPrefix, ele.second);
371 });
372 // get clock position information
373 auto clk_pos = 0xFF; // Invalid position.
374 for (auto& hwCallout : ffdc->hwp_errorinfo.hwcallouts)
375 {
376 if ((hwCallout.hwid == "PROC_REF_CLOCK") ||
377 (hwCallout.hwid == "PCI_REF_CLOCK"))
378 {
379 clk_pos = hwCallout.clkPos;
380 break;
381 }
382 }
383
384 // Adding CDG (Only deconfigure) targets details
385 for_each(ffdc->hwp_errorinfo.cdg_targets.begin(),
386 ffdc->hwp_errorinfo.cdg_targets.end(),
387 [&pelAdditionalData, &jsonCalloutDataList,
388 clk_pos](const CDG_Target& cdg_tgt) -> void {
389 json jsonCalloutData;
390 std::string pelPriority = "H";
391 jsonCalloutData["Priority"] = pelPriority; // Not used
392 jsonCalloutData["SymbolicFRU"] =
393 "REFCLK" + std::to_string(clk_pos);
394 jsonCalloutData["Deconfigured"] = cdg_tgt.deconfigure;
395 jsonCalloutData["EntityPath"] = cdg_tgt.target_entity_path;
396 jsonCalloutDataList.emplace_back(jsonCalloutData);
397 });
398
399 // Adding collected phal logs into PEL additional data
400 for_each(traceLog.begin(), traceLog.end(),
401 [&pelAdditionalData](
402 std::pair<std::string, std::string>& ele) -> void {
403 pelAdditionalData.emplace_back(ele.first, ele.second);
404 });
405
406 openpower::pel::createErrorPEL("org.open_power.PHAL.Error.SpareClock",
407 jsonCalloutDataList, pelAdditionalData,
408 Severity::Informational);
409 }
410 catch (const std::exception& ex)
411 {
412 reset();
413 throw ex;
414 }
415 reset();
416}
417
Jayanth Othayoth2b211702021-09-06 05:14:23 -0500418void processIplErrorCallback(const ipl_error_info& errInfo)
Brad Bishopf6783cd2020-10-27 19:25:09 -0400419{
Jayanth Othayoth2b211702021-09-06 05:14:23 -0500420 log<level::INFO>(
Jayanth Othayoth4079f092021-09-20 07:36:54 -0500421 fmt::format("processIplErrorCallback: Error type({})", errInfo.type)
Jayanth Othayoth2b211702021-09-06 05:14:23 -0500422 .c_str());
423
Marri Devender Rao381c3e32021-12-01 06:27:55 -0600424 switch (errInfo.type)
Jayanth Othayoth2b211702021-09-06 05:14:23 -0500425 {
Marri Devender Rao381c3e32021-12-01 06:27:55 -0600426 case IPL_ERR_OK:
427 // reset trace log and exit
428 reset();
429 break;
430 case IPL_ERR_SBE_BOOT:
431 case IPL_ERR_SBE_CHIPOP:
432 // handle SBE related failures.
433 processSbeBootError();
434 break;
435 case IPL_ERR_HWP:
436 // Handle hwp failure
437 processBootError(false);
438 break;
439 case IPL_ERR_PLAT:
440 processPlatBootError(errInfo);
441 break;
Jayanth Othayoth69708fb2022-03-22 04:49:01 -0500442 case IPL_ERR_PRI_PROC_NON_FUNC:
443 // Handle non functional boot processor error.
444 processNonFunctionalBootProc();
445 break;
Marri Devender Rao381c3e32021-12-01 06:27:55 -0600446 default:
447 createPEL("org.open_power.PHAL.Error.Boot");
448 // reset trace log and exit
449 reset();
450 break;
Jayanth Othayothfaaef2a2021-10-08 06:49:36 -0500451 }
Jayanth Othayoth2b211702021-09-06 05:14:23 -0500452}
453
rajerpp1db924722021-11-30 11:00:05 -0600454/**
455 * @brief addPlanarCallout
456 *
457 * This function will add a json for planar callout in the input json list.
458 * The caller can pass this json list into createErrorPEL to apply the callout.
459 *
460 * @param[in,out] jsonCalloutDataList - json list where callout json will be
461 * emplaced
462 * @param[in] priority - string indicating priority.
463 */
464static void addPlanarCallout(json& jsonCalloutDataList,
465 const std::string& priority)
466{
467 json jsonCalloutData;
468
469 // Inventory path for planar
470 jsonCalloutData["InventoryPath"] =
471 "/xyz/openbmc_project/inventory/system/chassis/motherboard";
472 jsonCalloutData["Deconfigured"] = false;
473 jsonCalloutData["Guarded"] = false;
474 jsonCalloutData["Priority"] = priority;
475
476 jsonCalloutDataList.emplace_back(jsonCalloutData);
477}
478
Marri Devender Rao4d5b5bf2022-05-23 09:23:31 -0500479/**
480 * @brief processPoweroffError
481 *
482 * Creates informational PEL for the PLAT/HWP error occured during poweroff
483 *
484 * Not adding callouts from FFDC as the hardware errors in the poweroff path
485 * should be non-visible. so that we don't throw out extraneous callouts for
486 * power errors or because the CEC is just not in an expected state.
487 *
488 * @param[in] ffdc - FFDC data capturd by the HWP
489 * @param[in] ffdc_prefix - prefix string for logging the data.
490 */
491
492void processPoweroffError(FFDC* ffdc, const std::string& ffdc_prefix)
493{
494 try
495 {
496 log<level::INFO>(
497 fmt::format("processPoweroffError: Message[{}]", ffdc->message)
498 .c_str());
499
500 // To store phal trace and other additional data about ffdc.
501 FFDCData pelAdditionalData;
502
503 if (ffdc->ffdc_type == FFDC_TYPE_HWP)
504 {
505 std::string keyWithPrefix(ffdc_prefix + "RC");
506 // Adding hardware procedures return code details
507 pelAdditionalData.emplace_back(keyWithPrefix,
508 ffdc->hwp_errorinfo.rc);
509 keyWithPrefix = ffdc_prefix + "RC_DESC";
510 pelAdditionalData.emplace_back(keyWithPrefix,
511 ffdc->hwp_errorinfo.rc_desc);
512 }
513 else if ((ffdc->ffdc_type != FFDC_TYPE_NONE) &&
514 (ffdc->ffdc_type != FFDC_TYPE_UNSUPPORTED))
515 {
516 log<level::ERR>(
517 fmt::format("Unsupported phal FFDC type to create PEL. "
518 "MSG: {}",
519 ffdc->message)
520 .c_str());
521 }
522
523 // Adding collected phal logs into PEL additional data
524 for_each(traceLog.begin(), traceLog.end(),
525 [&pelAdditionalData](
526 std::pair<std::string, std::string>& ele) -> void {
527 pelAdditionalData.emplace_back(ele.first, ele.second);
528 });
529
530 openpower::pel::createErrorPEL("org.open_power.PHAL.Error.Boot", {},
531 pelAdditionalData,
532 Severity::Informational);
533 }
534 catch (const std::exception& ex)
535 {
536 reset();
537 throw ex;
538 }
539 reset();
540}
541
rajerpp1db924722021-11-30 11:00:05 -0600542void processBootErrorHelper(FFDC* ffdc, const std::string& ffdc_prefix)
Jayanth Othayoth2b211702021-09-06 05:14:23 -0500543{
Marri Devender Rao381c3e32021-12-01 06:27:55 -0600544 log<level::INFO>("processBootErrorHelper ");
Brad Bishopf6783cd2020-10-27 19:25:09 -0400545 try
546 {
Ramesh Iyyar3af83eb2020-11-19 23:11:38 -0600547 log<level::INFO>(
Marri Devender Rao381c3e32021-12-01 06:27:55 -0600548 fmt::format("PHAL FFDC: Return Message[{}]", ffdc->message)
549 .c_str());
Brad Bishopf6783cd2020-10-27 19:25:09 -0400550
Jayanth Othayothd8be1eb2022-06-28 07:33:06 -0500551 // Special handling for spare clock related errors.
552 if (ffdc->ffdc_type == FFDC_TYPE_SPARE_CLOCK_INFO)
553 {
554 processClockInfoErrorHelper(ffdc, ffdc_prefix);
555 return;
556 }
Brad Bishopf6783cd2020-10-27 19:25:09 -0400557 // To store callouts details in json format as per pel expectation.
558 json jsonCalloutDataList;
559 jsonCalloutDataList = json::array();
560
561 // To store phal trace and other additional data about ffdc.
562 FFDCData pelAdditionalData;
563
Marri Devender Rao381c3e32021-12-01 06:27:55 -0600564 if (ffdc->ffdc_type == FFDC_TYPE_HWP)
Brad Bishopf6783cd2020-10-27 19:25:09 -0400565 {
rajerpp1db924722021-11-30 11:00:05 -0600566 std::string keyWithPrefix(ffdc_prefix + "RC");
Brad Bishopf6783cd2020-10-27 19:25:09 -0400567 // Adding hardware procedures return code details
rajerpp1db924722021-11-30 11:00:05 -0600568 pelAdditionalData.emplace_back(keyWithPrefix,
569 ffdc->hwp_errorinfo.rc);
570 keyWithPrefix = ffdc_prefix + "RC_DESC";
571 pelAdditionalData.emplace_back(keyWithPrefix,
Marri Devender Rao381c3e32021-12-01 06:27:55 -0600572 ffdc->hwp_errorinfo.rc_desc);
Brad Bishopf6783cd2020-10-27 19:25:09 -0400573
574 // Adding hardware procedures required ffdc data for debug
Marri Devender Rao381c3e32021-12-01 06:27:55 -0600575 for_each(ffdc->hwp_errorinfo.ffdcs_data.begin(),
576 ffdc->hwp_errorinfo.ffdcs_data.end(),
rajerpp1db924722021-11-30 11:00:05 -0600577 [&pelAdditionalData, &ffdc_prefix](
Brad Bishopf6783cd2020-10-27 19:25:09 -0400578 std::pair<std::string, std::string>& ele) -> void {
rajerpp1db924722021-11-30 11:00:05 -0600579 std::string keyWithPrefix(ffdc_prefix + "FFDC_");
Brad Bishopf6783cd2020-10-27 19:25:09 -0400580 keyWithPrefix.append(ele.first);
581
582 pelAdditionalData.emplace_back(keyWithPrefix,
583 ele.second);
584 });
585
586 // Adding hardware callout details
587 int calloutCount = 0;
rajerpp1db924722021-11-30 11:00:05 -0600588 for_each(
589 ffdc->hwp_errorinfo.hwcallouts.begin(),
590 ffdc->hwp_errorinfo.hwcallouts.end(),
591 [&pelAdditionalData, &calloutCount, &jsonCalloutDataList,
592 &ffdc_prefix](const HWCallout& hwCallout) -> void {
593 calloutCount++;
594 std::stringstream keyPrefix;
595 keyPrefix << ffdc_prefix << "HW_CO_" << std::setfill('0')
596 << std::setw(2) << calloutCount << "_";
Brad Bishopf6783cd2020-10-27 19:25:09 -0400597
rajerpp1db924722021-11-30 11:00:05 -0600598 pelAdditionalData.emplace_back(
599 std::string(keyPrefix.str()).append("HW_ID"),
600 hwCallout.hwid);
Brad Bishopf6783cd2020-10-27 19:25:09 -0400601
rajerpp1db924722021-11-30 11:00:05 -0600602 pelAdditionalData.emplace_back(
603 std::string(keyPrefix.str()).append("PRIORITY"),
604 hwCallout.callout_priority);
Brad Bishopf6783cd2020-10-27 19:25:09 -0400605
rajerpp1db924722021-11-30 11:00:05 -0600606 // Log target details only if entity path is
607 // available. For example target entity path will not
608 // be available for non-hwp clock failure.
609 if (!hwCallout.target_entity_path.empty())
610 {
611 phal::TargetInfo targetInfo;
612 phal::getTgtReqAttrsVal(hwCallout.target_entity_path,
613 targetInfo);
Brad Bishopf6783cd2020-10-27 19:25:09 -0400614
rajerpp1db924722021-11-30 11:00:05 -0600615 std::string locationCode =
616 std::string(targetInfo.locationCode);
617 pelAdditionalData.emplace_back(
618 std::string(keyPrefix.str()).append("LOC_CODE"),
619 locationCode);
Brad Bishopf6783cd2020-10-27 19:25:09 -0400620
rajerpp1db924722021-11-30 11:00:05 -0600621 std::string physPath =
622 std::string(targetInfo.physDevPath);
623 pelAdditionalData.emplace_back(
624 std::string(keyPrefix.str()).append("PHYS_PATH"),
625 physPath);
626 }
Brad Bishopf6783cd2020-10-27 19:25:09 -0400627
rajerpp1db924722021-11-30 11:00:05 -0600628 pelAdditionalData.emplace_back(
629 std::string(keyPrefix.str()).append("CLK_POS"),
630 std::to_string(hwCallout.clkPos));
631
632 pelAdditionalData.emplace_back(
633 std::string(keyPrefix.str()).append("CALLOUT_PLANAR"),
634 (hwCallout.isPlanarCallout == true ? "true" : "false"));
635
636 std::string pelPriority =
637 getPelPriority(hwCallout.callout_priority);
638
639 if (hwCallout.isPlanarCallout)
640 {
641 addPlanarCallout(jsonCalloutDataList, pelPriority);
642 }
643 });
Brad Bishopf6783cd2020-10-27 19:25:09 -0400644
645 // Adding CDG (callout, deconfigure and guard) targets details
646 calloutCount = 0;
rajerpp1db924722021-11-30 11:00:05 -0600647 for_each(
648 ffdc->hwp_errorinfo.cdg_targets.begin(),
649 ffdc->hwp_errorinfo.cdg_targets.end(),
650 [&pelAdditionalData, &calloutCount, &jsonCalloutDataList,
651 &ffdc_prefix](const CDG_Target& cdg_tgt) -> void {
652 calloutCount++;
653 std::stringstream keyPrefix;
654 keyPrefix << ffdc_prefix << "CDG_TGT_" << std::setfill('0')
655 << std::setw(2) << calloutCount << "_";
Brad Bishopf6783cd2020-10-27 19:25:09 -0400656
rajerpp1db924722021-11-30 11:00:05 -0600657 phal::TargetInfo targetInfo;
658 targetInfo.deconfigure = cdg_tgt.deconfigure;
Brad Bishopf6783cd2020-10-27 19:25:09 -0400659
rajerpp1db924722021-11-30 11:00:05 -0600660 phal::getTgtReqAttrsVal(cdg_tgt.target_entity_path,
661 targetInfo);
Brad Bishopf6783cd2020-10-27 19:25:09 -0400662
rajerpp1db924722021-11-30 11:00:05 -0600663 std::string locationCode =
664 std::string(targetInfo.locationCode);
665 pelAdditionalData.emplace_back(
666 std::string(keyPrefix.str()).append("LOC_CODE"),
667 locationCode);
668 std::string physPath = std::string(targetInfo.physDevPath);
669 pelAdditionalData.emplace_back(
670 std::string(keyPrefix.str()).append("PHYS_PATH"),
671 physPath);
Brad Bishopf6783cd2020-10-27 19:25:09 -0400672
rajerpp1db924722021-11-30 11:00:05 -0600673 pelAdditionalData.emplace_back(
674 std::string(keyPrefix.str()).append("CO_REQ"),
675 (cdg_tgt.callout == true ? "true" : "false"));
Brad Bishopf6783cd2020-10-27 19:25:09 -0400676
rajerpp1db924722021-11-30 11:00:05 -0600677 pelAdditionalData.emplace_back(
678 std::string(keyPrefix.str()).append("CO_PRIORITY"),
679 cdg_tgt.callout_priority);
Brad Bishopf6783cd2020-10-27 19:25:09 -0400680
rajerpp1db924722021-11-30 11:00:05 -0600681 pelAdditionalData.emplace_back(
682 std::string(keyPrefix.str()).append("DECONF_REQ"),
683 (cdg_tgt.deconfigure == true ? "true" : "false"));
Brad Bishopf6783cd2020-10-27 19:25:09 -0400684
rajerpp1db924722021-11-30 11:00:05 -0600685 pelAdditionalData.emplace_back(
686 std::string(keyPrefix.str()).append("GUARD_REQ"),
687 (cdg_tgt.guard == true ? "true" : "false"));
Brad Bishopf6783cd2020-10-27 19:25:09 -0400688
rajerpp1db924722021-11-30 11:00:05 -0600689 pelAdditionalData.emplace_back(
690 std::string(keyPrefix.str()).append("GUARD_TYPE"),
691 cdg_tgt.guard_type);
Brad Bishopf6783cd2020-10-27 19:25:09 -0400692
rajerpp1db924722021-11-30 11:00:05 -0600693 json jsonCalloutData;
694 jsonCalloutData["LocationCode"] = locationCode;
695 std::string pelPriority =
696 getPelPriority(cdg_tgt.callout_priority);
697 jsonCalloutData["Priority"] = pelPriority;
Brad Bishopf6783cd2020-10-27 19:25:09 -0400698
rajerpp1db924722021-11-30 11:00:05 -0600699 if (targetInfo.mruId != 0)
700 {
701 jsonCalloutData["MRUs"] = json::array({
702 {{"ID", targetInfo.mruId},
703 {"Priority", pelPriority}},
704 });
705 }
706 jsonCalloutData["Deconfigured"] = cdg_tgt.deconfigure;
707 jsonCalloutData["Guarded"] = cdg_tgt.guard;
708 jsonCalloutData["GuardType"] = cdg_tgt.guard_type;
709 jsonCalloutData["EntityPath"] = cdg_tgt.target_entity_path;
Brad Bishopf6783cd2020-10-27 19:25:09 -0400710
rajerpp1db924722021-11-30 11:00:05 -0600711 jsonCalloutDataList.emplace_back(jsonCalloutData);
712 });
Jayanth Othayoth0ac7c382021-11-15 05:43:24 -0600713 // Adding procedure callout
714 calloutCount = 0;
715 for_each(
Marri Devender Rao381c3e32021-12-01 06:27:55 -0600716 ffdc->hwp_errorinfo.procedures_callout.begin(),
717 ffdc->hwp_errorinfo.procedures_callout.end(),
rajerpp1db924722021-11-30 11:00:05 -0600718 [&pelAdditionalData, &calloutCount, &jsonCalloutDataList,
719 &ffdc_prefix](const ProcedureCallout& procCallout) -> void {
Jayanth Othayoth0ac7c382021-11-15 05:43:24 -0600720 calloutCount++;
721 std::stringstream keyPrefix;
rajerpp1db924722021-11-30 11:00:05 -0600722 keyPrefix << ffdc_prefix << "PROC_CO_" << std::setfill('0')
Jayanth Othayoth0ac7c382021-11-15 05:43:24 -0600723 << std::setw(2) << calloutCount << "_";
724
725 pelAdditionalData.emplace_back(
726 std::string(keyPrefix.str()).append("PRIORITY"),
727 procCallout.callout_priority);
728
729 pelAdditionalData.emplace_back(
730 std::string(keyPrefix.str()).append("MAINT_PROCEDURE"),
731 procCallout.proc_callout);
732
733 json jsonCalloutData;
734 jsonCalloutData["Procedure"] = procCallout.proc_callout;
735 std::string pelPriority =
736 getPelPriority(procCallout.callout_priority);
737 jsonCalloutData["Priority"] = pelPriority;
738 jsonCalloutDataList.emplace_back(jsonCalloutData);
739 });
Brad Bishopf6783cd2020-10-27 19:25:09 -0400740 }
Marri Devender Rao381c3e32021-12-01 06:27:55 -0600741 else if ((ffdc->ffdc_type != FFDC_TYPE_NONE) &&
742 (ffdc->ffdc_type != FFDC_TYPE_UNSUPPORTED))
Brad Bishopf6783cd2020-10-27 19:25:09 -0400743 {
744 log<level::ERR>(
745 fmt::format("Unsupported phal FFDC type to create PEL. "
746 "MSG: {}",
Marri Devender Rao381c3e32021-12-01 06:27:55 -0600747 ffdc->message)
Brad Bishopf6783cd2020-10-27 19:25:09 -0400748 .c_str());
749 }
750
751 // Adding collected phal logs into PEL additional data
752 for_each(traceLog.begin(), traceLog.end(),
753 [&pelAdditionalData](
754 std::pair<std::string, std::string>& ele) -> void {
755 pelAdditionalData.emplace_back(ele.first, ele.second);
756 });
757
758 // TODO: #ibm-openbmc/dev/issues/2595 : Once enabled this support,
759 // callout details is not required to sort in H,M and L orders which
760 // are expected by pel because, pel will take care for sorting callouts
761 // based on priority so, now adding support to send callout in order
762 // i.e High -> Medium -> Low.
763 std::sort(
764 jsonCalloutDataList.begin(), jsonCalloutDataList.end(),
765 [](const json& aEle, const json& bEle) -> bool {
766 // Considering b element having higher priority than a element
767 // or Both element will be same priorty (to keep same order
768 // which are given by phal when two callouts are having same
769 // priority)
770 if (((aEle["Priority"] == "M") && (bEle["Priority"] == "H")) ||
771 ((aEle["Priority"] == "L") &&
772 ((bEle["Priority"] == "H") ||
773 (bEle["Priority"] == "M"))) ||
774 (aEle["Priority"] == bEle["Priority"]))
775 {
776 return false;
777 }
778
779 // Considering a element having higher priority than b element
780 return true;
781 });
Jayanth Othayoth8fe9ff92021-11-14 09:15:59 -0600782 openpower::pel::createErrorPEL("org.open_power.PHAL.Error.Boot",
Marri Devender Rao4d5b5bf2022-05-23 09:23:31 -0500783 jsonCalloutDataList, pelAdditionalData,
784 Severity::Error);
Brad Bishopf6783cd2020-10-27 19:25:09 -0400785 }
Patrick Williams1a9a5a62021-10-06 13:05:06 -0500786 catch (const std::exception& ex)
Brad Bishopf6783cd2020-10-27 19:25:09 -0400787 {
788 reset();
789 throw ex;
790 }
791 reset();
792}
793
Marri Devender Rao381c3e32021-12-01 06:27:55 -0600794void processPlatBootError(const ipl_error_info& errInfo)
795{
796 log<level::INFO>("processPlatBootError ");
797
798 // Collecting ffdc details from phal
799 FFDC* ffdc = reinterpret_cast<FFDC*>(errInfo.private_data);
800 try
801 {
Marri Devender Rao4d5b5bf2022-05-23 09:23:31 -0500802 if (util::isHostPoweringOff())
803 {
804 processPoweroffError(ffdc, "PLAT_");
805 }
806 else
807 {
808 processBootErrorHelper(ffdc, "PLAT_");
809 }
Marri Devender Rao381c3e32021-12-01 06:27:55 -0600810 }
811 catch (const std::exception& ex)
812 {
813 log<level::ERR>(
814 fmt::format("processPlatBootError: exception({})", ex.what())
815 .c_str());
816 throw ex;
817 }
818}
819
820void processBootError(bool status)
821{
822 log<level::INFO>(
823 fmt::format("processBootError: status({})", status).c_str());
824
825 try
826 {
827 // return If no failure during hwp execution
828 if (status)
829 return;
Marri Devender Rao381c3e32021-12-01 06:27:55 -0600830 // Collecting ffdc details from phal
831 FFDC ffdc;
832 libekb_get_ffdc(ffdc);
833
Marri Devender Rao4d5b5bf2022-05-23 09:23:31 -0500834 if (util::isHostPoweringOff())
835 {
836 processPoweroffError(&ffdc, "HWP_");
837 }
838 else
839 {
840 processBootErrorHelper(&ffdc, "HWP_");
841 }
Marri Devender Rao381c3e32021-12-01 06:27:55 -0600842 }
843 catch (const std::exception& ex)
844 {
845 log<level::ERR>(
846 fmt::format("processBootError: exception({})", ex.what()).c_str());
847 throw ex;
848 }
849}
850
Jayanth Othayoth4079f092021-09-20 07:36:54 -0500851void processSbeBootError()
852{
853 log<level::INFO>("processSbeBootError : Entered ");
854
855 using namespace openpower::phal::sbe;
Jayanth Othayoth4079f092021-09-20 07:36:54 -0500856
857 // To store phal trace and other additional data about ffdc.
858 FFDCData pelAdditionalData;
859
860 // Adding collected phal logs into PEL additional data
861 for_each(
862 traceLog.begin(), traceLog.end(),
863 [&pelAdditionalData](std::pair<std::string, std::string>& ele) -> void {
864 pelAdditionalData.emplace_back(ele.first, ele.second);
865 });
866
867 // reset the trace log and counter
868 reset();
869
870 // get primary processor to collect FFDC/Dump information.
871 struct pdbg_target* procTarget;
872 pdbg_for_each_class_target("proc", procTarget)
873 {
874 if (openpower::phal::isPrimaryProc(procTarget))
875 break;
876 procTarget = nullptr;
877 }
878 // check valid primary processor is available
879 if (procTarget == nullptr)
880 {
881 log<level::ERR>("processSbeBootError: fail to get primary processor");
Jayanth Othayoth0a516de2021-11-14 09:59:06 -0600882 // Add BMC code callout and create PEL
883 json jsonCalloutDataList;
884 jsonCalloutDataList = json::array();
885 json jsonCalloutData;
886 jsonCalloutData["Procedure"] = "BMC0001";
887 jsonCalloutData["Priority"] = "H";
888 jsonCalloutDataList.emplace_back(jsonCalloutData);
889 openpower::pel::createErrorPEL(
890 "org.open_power.Processor.Error.SbeBootFailure",
Marri Devender Rao4d5b5bf2022-05-23 09:23:31 -0500891 jsonCalloutDataList, {}, Severity::Error);
Jayanth Othayoth4079f092021-09-20 07:36:54 -0500892 return;
893 }
894 // SBE error object.
895 sbeError_t sbeError;
896 bool dumpIsRequired = false;
897
898 try
899 {
900 // Capture FFDC information on primary processor
901 sbeError = captureFFDC(procTarget);
902 }
Jayanth Othayothfaaef2a2021-10-08 06:49:36 -0500903 catch (const phalError_t& phalError)
Jayanth Othayoth4079f092021-09-20 07:36:54 -0500904 {
905 // Fail to collect FFDC information , trigger Dump
906 log<level::ERR>(
Jayanth Othayothfaaef2a2021-10-08 06:49:36 -0500907 fmt::format("captureFFDC: Exception({})", phalError.what())
908 .c_str());
Jayanth Othayoth4079f092021-09-20 07:36:54 -0500909 dumpIsRequired = true;
910 }
911
Jayanth Othayoth006641e2021-10-07 06:56:24 -0500912 std::string event;
913
Jayanth Othayoth4079f092021-09-20 07:36:54 -0500914 if ((sbeError.errType() == SBE_FFDC_NO_DATA) ||
915 (sbeError.errType() == SBE_CMD_TIMEOUT) || (dumpIsRequired))
916 {
Jayanth Othayoth006641e2021-10-07 06:56:24 -0500917 event = "org.open_power.Processor.Error.SbeBootTimeout";
918 dumpIsRequired = true;
919 }
920 else
921 {
922 event = "org.open_power.Processor.Error.SbeBootFailure";
Jayanth Othayoth4079f092021-09-20 07:36:54 -0500923 }
924 // SRC6 : [0:15] chip position
Jayanth Othayoth006641e2021-10-07 06:56:24 -0500925 uint32_t index = pdbg_target_index(procTarget);
926 pelAdditionalData.emplace_back("SRC6", std::to_string(index << 16));
Jayanth Othayoth4079f092021-09-20 07:36:54 -0500927 // Create SBE Error with FFDC data.
Jayanth Othayothe5ba5fd2022-01-27 09:29:01 -0600928 auto logId =
929 createSbeErrorPEL(event, sbeError, pelAdditionalData, procTarget);
Jayanth Othayoth006641e2021-10-07 06:56:24 -0500930
931 if (dumpIsRequired)
932 {
933 using namespace openpower::phal::dump;
934 DumpParameters dumpParameters = {logId, index, SBE_DUMP_TIMEOUT,
935 DumpType::SBE};
936 try
937 {
938 requestDump(dumpParameters);
939 }
940 catch (const std::runtime_error& e)
941 {
942 // Allowing call back to handle the error gracefully.
943 log<level::ERR>("Dump collection failed");
944 // TODO revist error handling.
945 }
946 }
Jayanth Othayoth4079f092021-09-20 07:36:54 -0500947}
948
Brad Bishopf6783cd2020-10-27 19:25:09 -0400949void reset()
950{
951 // reset the trace log and counter
952 traceLog.clear();
953 counter = 0;
954}
955
Brad Bishop63508a72020-10-27 18:55:01 -0400956void pDBGLogTraceCallbackHelper(int, const char* fmt, va_list ap)
Brad Bishopf6783cd2020-10-27 19:25:09 -0400957{
958 processLogTraceCallback(NULL, fmt, ap);
959}
960} // namespace detail
961
962static inline uint8_t getLogLevelFromEnv(const char* env, const uint8_t dValue)
963{
964 auto logLevel = dValue;
965 try
966 {
967 if (const char* env_p = std::getenv(env))
968 {
969 logLevel = std::stoi(env_p);
970 }
971 }
Patrick Williams1a9a5a62021-10-06 13:05:06 -0500972 catch (const std::exception& e)
Brad Bishopf6783cd2020-10-27 19:25:09 -0400973 {
974 log<level::ERR>(("Conversion Failure"), entry("ENVIRONMENT=%s", env),
975 entry("EXCEPTION=%s", e.what()));
976 }
977 return logLevel;
978}
979
980void addBootErrorCallbacks()
981{
982 // Get individual phal repos log level from environment variable
983 // and update the log level.
984 pdbg_set_loglevel(getLogLevelFromEnv("PDBG_LOG", PDBG_INFO));
985 libekb_set_loglevel(getLogLevelFromEnv("LIBEKB_LOG", LIBEKB_LOG_IMP));
986 ipl_set_loglevel(getLogLevelFromEnv("IPL_LOG", IPL_INFO));
987
988 // add callback for debug traces
989 pdbg_set_logfunc(detail::pDBGLogTraceCallbackHelper);
990 libekb_set_logfunc(detail::processLogTraceCallback, NULL);
991 ipl_set_logfunc(detail::processLogTraceCallback, NULL);
992
993 // add callback for ipl failures
Jayanth Othayoth2b211702021-09-06 05:14:23 -0500994 ipl_set_error_callback_func(detail::processIplErrorCallback);
Brad Bishopf6783cd2020-10-27 19:25:09 -0400995}
996
997} // namespace pel
998} // namespace openpower