blob: f9869a38d73e38d20c805b2f00e29f2871f7982a [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;
Jayanth Othayothfe2abd12022-10-28 00:22:10 -0500390 std::string pelPriority = "L";
Jayanth Othayothd8be1eb2022-06-28 07:33:06 -0500391 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;
deepakala-k9f351b02022-10-05 09:03:57 -0500446 case IPL_ERR_GUARD_PARTITION_ACCESS:
447 processGuardPartitionAccessError();
448 break;
Marri Devender Rao381c3e32021-12-01 06:27:55 -0600449 default:
450 createPEL("org.open_power.PHAL.Error.Boot");
451 // reset trace log and exit
452 reset();
453 break;
Jayanth Othayothfaaef2a2021-10-08 06:49:36 -0500454 }
Jayanth Othayoth2b211702021-09-06 05:14:23 -0500455}
456
rajerpp1db924722021-11-30 11:00:05 -0600457/**
458 * @brief addPlanarCallout
459 *
460 * This function will add a json for planar callout in the input json list.
461 * The caller can pass this json list into createErrorPEL to apply the callout.
462 *
463 * @param[in,out] jsonCalloutDataList - json list where callout json will be
464 * emplaced
465 * @param[in] priority - string indicating priority.
466 */
467static void addPlanarCallout(json& jsonCalloutDataList,
468 const std::string& priority)
469{
470 json jsonCalloutData;
471
472 // Inventory path for planar
473 jsonCalloutData["InventoryPath"] =
474 "/xyz/openbmc_project/inventory/system/chassis/motherboard";
475 jsonCalloutData["Deconfigured"] = false;
476 jsonCalloutData["Guarded"] = false;
477 jsonCalloutData["Priority"] = priority;
478
479 jsonCalloutDataList.emplace_back(jsonCalloutData);
480}
481
Marri Devender Rao4d5b5bf2022-05-23 09:23:31 -0500482/**
483 * @brief processPoweroffError
484 *
485 * Creates informational PEL for the PLAT/HWP error occured during poweroff
486 *
487 * Not adding callouts from FFDC as the hardware errors in the poweroff path
488 * should be non-visible. so that we don't throw out extraneous callouts for
489 * power errors or because the CEC is just not in an expected state.
490 *
491 * @param[in] ffdc - FFDC data capturd by the HWP
492 * @param[in] ffdc_prefix - prefix string for logging the data.
493 */
494
495void processPoweroffError(FFDC* ffdc, const std::string& ffdc_prefix)
496{
497 try
498 {
499 log<level::INFO>(
500 fmt::format("processPoweroffError: Message[{}]", ffdc->message)
501 .c_str());
502
503 // To store phal trace and other additional data about ffdc.
504 FFDCData pelAdditionalData;
505
506 if (ffdc->ffdc_type == FFDC_TYPE_HWP)
507 {
508 std::string keyWithPrefix(ffdc_prefix + "RC");
509 // Adding hardware procedures return code details
510 pelAdditionalData.emplace_back(keyWithPrefix,
511 ffdc->hwp_errorinfo.rc);
512 keyWithPrefix = ffdc_prefix + "RC_DESC";
513 pelAdditionalData.emplace_back(keyWithPrefix,
514 ffdc->hwp_errorinfo.rc_desc);
515 }
516 else if ((ffdc->ffdc_type != FFDC_TYPE_NONE) &&
517 (ffdc->ffdc_type != FFDC_TYPE_UNSUPPORTED))
518 {
519 log<level::ERR>(
520 fmt::format("Unsupported phal FFDC type to create PEL. "
521 "MSG: {}",
522 ffdc->message)
523 .c_str());
524 }
525
526 // Adding collected phal logs into PEL additional data
527 for_each(traceLog.begin(), traceLog.end(),
528 [&pelAdditionalData](
529 std::pair<std::string, std::string>& ele) -> void {
530 pelAdditionalData.emplace_back(ele.first, ele.second);
531 });
532
533 openpower::pel::createErrorPEL("org.open_power.PHAL.Error.Boot", {},
534 pelAdditionalData,
535 Severity::Informational);
536 }
537 catch (const std::exception& ex)
538 {
539 reset();
540 throw ex;
541 }
542 reset();
543}
544
rajerpp1db924722021-11-30 11:00:05 -0600545void processBootErrorHelper(FFDC* ffdc, const std::string& ffdc_prefix)
Jayanth Othayoth2b211702021-09-06 05:14:23 -0500546{
Marri Devender Rao381c3e32021-12-01 06:27:55 -0600547 log<level::INFO>("processBootErrorHelper ");
Brad Bishopf6783cd2020-10-27 19:25:09 -0400548 try
549 {
Ramesh Iyyar3af83eb2020-11-19 23:11:38 -0600550 log<level::INFO>(
Marri Devender Rao381c3e32021-12-01 06:27:55 -0600551 fmt::format("PHAL FFDC: Return Message[{}]", ffdc->message)
552 .c_str());
Brad Bishopf6783cd2020-10-27 19:25:09 -0400553
Jayanth Othayothd8be1eb2022-06-28 07:33:06 -0500554 // Special handling for spare clock related errors.
555 if (ffdc->ffdc_type == FFDC_TYPE_SPARE_CLOCK_INFO)
556 {
557 processClockInfoErrorHelper(ffdc, ffdc_prefix);
558 return;
559 }
Brad Bishopf6783cd2020-10-27 19:25:09 -0400560 // To store callouts details in json format as per pel expectation.
561 json jsonCalloutDataList;
562 jsonCalloutDataList = json::array();
563
564 // To store phal trace and other additional data about ffdc.
565 FFDCData pelAdditionalData;
566
Marri Devender Rao381c3e32021-12-01 06:27:55 -0600567 if (ffdc->ffdc_type == FFDC_TYPE_HWP)
Brad Bishopf6783cd2020-10-27 19:25:09 -0400568 {
rajerpp1db924722021-11-30 11:00:05 -0600569 std::string keyWithPrefix(ffdc_prefix + "RC");
Brad Bishopf6783cd2020-10-27 19:25:09 -0400570 // Adding hardware procedures return code details
rajerpp1db924722021-11-30 11:00:05 -0600571 pelAdditionalData.emplace_back(keyWithPrefix,
572 ffdc->hwp_errorinfo.rc);
573 keyWithPrefix = ffdc_prefix + "RC_DESC";
574 pelAdditionalData.emplace_back(keyWithPrefix,
Marri Devender Rao381c3e32021-12-01 06:27:55 -0600575 ffdc->hwp_errorinfo.rc_desc);
Brad Bishopf6783cd2020-10-27 19:25:09 -0400576
577 // Adding hardware procedures required ffdc data for debug
Marri Devender Rao381c3e32021-12-01 06:27:55 -0600578 for_each(ffdc->hwp_errorinfo.ffdcs_data.begin(),
579 ffdc->hwp_errorinfo.ffdcs_data.end(),
rajerpp1db924722021-11-30 11:00:05 -0600580 [&pelAdditionalData, &ffdc_prefix](
Brad Bishopf6783cd2020-10-27 19:25:09 -0400581 std::pair<std::string, std::string>& ele) -> void {
rajerpp1db924722021-11-30 11:00:05 -0600582 std::string keyWithPrefix(ffdc_prefix + "FFDC_");
Brad Bishopf6783cd2020-10-27 19:25:09 -0400583 keyWithPrefix.append(ele.first);
584
585 pelAdditionalData.emplace_back(keyWithPrefix,
586 ele.second);
587 });
588
589 // Adding hardware callout details
590 int calloutCount = 0;
rajerpp1db924722021-11-30 11:00:05 -0600591 for_each(
592 ffdc->hwp_errorinfo.hwcallouts.begin(),
593 ffdc->hwp_errorinfo.hwcallouts.end(),
594 [&pelAdditionalData, &calloutCount, &jsonCalloutDataList,
595 &ffdc_prefix](const HWCallout& hwCallout) -> void {
596 calloutCount++;
597 std::stringstream keyPrefix;
598 keyPrefix << ffdc_prefix << "HW_CO_" << std::setfill('0')
599 << std::setw(2) << calloutCount << "_";
Brad Bishopf6783cd2020-10-27 19:25:09 -0400600
rajerpp1db924722021-11-30 11:00:05 -0600601 pelAdditionalData.emplace_back(
602 std::string(keyPrefix.str()).append("HW_ID"),
603 hwCallout.hwid);
Brad Bishopf6783cd2020-10-27 19:25:09 -0400604
rajerpp1db924722021-11-30 11:00:05 -0600605 pelAdditionalData.emplace_back(
606 std::string(keyPrefix.str()).append("PRIORITY"),
607 hwCallout.callout_priority);
Brad Bishopf6783cd2020-10-27 19:25:09 -0400608
rajerpp1db924722021-11-30 11:00:05 -0600609 // Log target details only if entity path is
610 // available. For example target entity path will not
611 // be available for non-hwp clock failure.
612 if (!hwCallout.target_entity_path.empty())
613 {
614 phal::TargetInfo targetInfo;
615 phal::getTgtReqAttrsVal(hwCallout.target_entity_path,
616 targetInfo);
Brad Bishopf6783cd2020-10-27 19:25:09 -0400617
rajerpp1db924722021-11-30 11:00:05 -0600618 std::string locationCode =
619 std::string(targetInfo.locationCode);
620 pelAdditionalData.emplace_back(
621 std::string(keyPrefix.str()).append("LOC_CODE"),
622 locationCode);
Brad Bishopf6783cd2020-10-27 19:25:09 -0400623
rajerpp1db924722021-11-30 11:00:05 -0600624 std::string physPath =
625 std::string(targetInfo.physDevPath);
626 pelAdditionalData.emplace_back(
627 std::string(keyPrefix.str()).append("PHYS_PATH"),
628 physPath);
629 }
Brad Bishopf6783cd2020-10-27 19:25:09 -0400630
rajerpp1db924722021-11-30 11:00:05 -0600631 pelAdditionalData.emplace_back(
632 std::string(keyPrefix.str()).append("CLK_POS"),
633 std::to_string(hwCallout.clkPos));
634
635 pelAdditionalData.emplace_back(
636 std::string(keyPrefix.str()).append("CALLOUT_PLANAR"),
637 (hwCallout.isPlanarCallout == true ? "true" : "false"));
638
639 std::string pelPriority =
640 getPelPriority(hwCallout.callout_priority);
641
642 if (hwCallout.isPlanarCallout)
643 {
644 addPlanarCallout(jsonCalloutDataList, pelPriority);
645 }
646 });
Brad Bishopf6783cd2020-10-27 19:25:09 -0400647
648 // Adding CDG (callout, deconfigure and guard) targets details
649 calloutCount = 0;
rajerpp1db924722021-11-30 11:00:05 -0600650 for_each(
651 ffdc->hwp_errorinfo.cdg_targets.begin(),
652 ffdc->hwp_errorinfo.cdg_targets.end(),
653 [&pelAdditionalData, &calloutCount, &jsonCalloutDataList,
654 &ffdc_prefix](const CDG_Target& cdg_tgt) -> void {
655 calloutCount++;
656 std::stringstream keyPrefix;
657 keyPrefix << ffdc_prefix << "CDG_TGT_" << std::setfill('0')
658 << std::setw(2) << calloutCount << "_";
Brad Bishopf6783cd2020-10-27 19:25:09 -0400659
rajerpp1db924722021-11-30 11:00:05 -0600660 phal::TargetInfo targetInfo;
661 targetInfo.deconfigure = cdg_tgt.deconfigure;
Brad Bishopf6783cd2020-10-27 19:25:09 -0400662
rajerpp1db924722021-11-30 11:00:05 -0600663 phal::getTgtReqAttrsVal(cdg_tgt.target_entity_path,
664 targetInfo);
Brad Bishopf6783cd2020-10-27 19:25:09 -0400665
rajerpp1db924722021-11-30 11:00:05 -0600666 std::string locationCode =
667 std::string(targetInfo.locationCode);
668 pelAdditionalData.emplace_back(
669 std::string(keyPrefix.str()).append("LOC_CODE"),
670 locationCode);
671 std::string physPath = std::string(targetInfo.physDevPath);
672 pelAdditionalData.emplace_back(
673 std::string(keyPrefix.str()).append("PHYS_PATH"),
674 physPath);
Brad Bishopf6783cd2020-10-27 19:25:09 -0400675
rajerpp1db924722021-11-30 11:00:05 -0600676 pelAdditionalData.emplace_back(
677 std::string(keyPrefix.str()).append("CO_REQ"),
678 (cdg_tgt.callout == true ? "true" : "false"));
Brad Bishopf6783cd2020-10-27 19:25:09 -0400679
rajerpp1db924722021-11-30 11:00:05 -0600680 pelAdditionalData.emplace_back(
681 std::string(keyPrefix.str()).append("CO_PRIORITY"),
682 cdg_tgt.callout_priority);
Brad Bishopf6783cd2020-10-27 19:25:09 -0400683
rajerpp1db924722021-11-30 11:00:05 -0600684 pelAdditionalData.emplace_back(
685 std::string(keyPrefix.str()).append("DECONF_REQ"),
686 (cdg_tgt.deconfigure == true ? "true" : "false"));
Brad Bishopf6783cd2020-10-27 19:25:09 -0400687
rajerpp1db924722021-11-30 11:00:05 -0600688 pelAdditionalData.emplace_back(
689 std::string(keyPrefix.str()).append("GUARD_REQ"),
690 (cdg_tgt.guard == true ? "true" : "false"));
Brad Bishopf6783cd2020-10-27 19:25:09 -0400691
rajerpp1db924722021-11-30 11:00:05 -0600692 pelAdditionalData.emplace_back(
693 std::string(keyPrefix.str()).append("GUARD_TYPE"),
694 cdg_tgt.guard_type);
Brad Bishopf6783cd2020-10-27 19:25:09 -0400695
rajerpp1db924722021-11-30 11:00:05 -0600696 json jsonCalloutData;
697 jsonCalloutData["LocationCode"] = locationCode;
698 std::string pelPriority =
699 getPelPriority(cdg_tgt.callout_priority);
700 jsonCalloutData["Priority"] = pelPriority;
Brad Bishopf6783cd2020-10-27 19:25:09 -0400701
rajerpp1db924722021-11-30 11:00:05 -0600702 if (targetInfo.mruId != 0)
703 {
704 jsonCalloutData["MRUs"] = json::array({
705 {{"ID", targetInfo.mruId},
706 {"Priority", pelPriority}},
707 });
708 }
709 jsonCalloutData["Deconfigured"] = cdg_tgt.deconfigure;
710 jsonCalloutData["Guarded"] = cdg_tgt.guard;
711 jsonCalloutData["GuardType"] = cdg_tgt.guard_type;
712 jsonCalloutData["EntityPath"] = cdg_tgt.target_entity_path;
Brad Bishopf6783cd2020-10-27 19:25:09 -0400713
rajerpp1db924722021-11-30 11:00:05 -0600714 jsonCalloutDataList.emplace_back(jsonCalloutData);
715 });
Jayanth Othayoth0ac7c382021-11-15 05:43:24 -0600716 // Adding procedure callout
717 calloutCount = 0;
718 for_each(
Marri Devender Rao381c3e32021-12-01 06:27:55 -0600719 ffdc->hwp_errorinfo.procedures_callout.begin(),
720 ffdc->hwp_errorinfo.procedures_callout.end(),
rajerpp1db924722021-11-30 11:00:05 -0600721 [&pelAdditionalData, &calloutCount, &jsonCalloutDataList,
722 &ffdc_prefix](const ProcedureCallout& procCallout) -> void {
Jayanth Othayoth0ac7c382021-11-15 05:43:24 -0600723 calloutCount++;
724 std::stringstream keyPrefix;
rajerpp1db924722021-11-30 11:00:05 -0600725 keyPrefix << ffdc_prefix << "PROC_CO_" << std::setfill('0')
Jayanth Othayoth0ac7c382021-11-15 05:43:24 -0600726 << std::setw(2) << calloutCount << "_";
727
728 pelAdditionalData.emplace_back(
729 std::string(keyPrefix.str()).append("PRIORITY"),
730 procCallout.callout_priority);
731
732 pelAdditionalData.emplace_back(
733 std::string(keyPrefix.str()).append("MAINT_PROCEDURE"),
734 procCallout.proc_callout);
735
736 json jsonCalloutData;
737 jsonCalloutData["Procedure"] = procCallout.proc_callout;
738 std::string pelPriority =
739 getPelPriority(procCallout.callout_priority);
740 jsonCalloutData["Priority"] = pelPriority;
741 jsonCalloutDataList.emplace_back(jsonCalloutData);
742 });
Brad Bishopf6783cd2020-10-27 19:25:09 -0400743 }
Marri Devender Rao381c3e32021-12-01 06:27:55 -0600744 else if ((ffdc->ffdc_type != FFDC_TYPE_NONE) &&
745 (ffdc->ffdc_type != FFDC_TYPE_UNSUPPORTED))
Brad Bishopf6783cd2020-10-27 19:25:09 -0400746 {
747 log<level::ERR>(
748 fmt::format("Unsupported phal FFDC type to create PEL. "
749 "MSG: {}",
Marri Devender Rao381c3e32021-12-01 06:27:55 -0600750 ffdc->message)
Brad Bishopf6783cd2020-10-27 19:25:09 -0400751 .c_str());
752 }
753
754 // Adding collected phal logs into PEL additional data
755 for_each(traceLog.begin(), traceLog.end(),
756 [&pelAdditionalData](
757 std::pair<std::string, std::string>& ele) -> void {
758 pelAdditionalData.emplace_back(ele.first, ele.second);
759 });
760
761 // TODO: #ibm-openbmc/dev/issues/2595 : Once enabled this support,
762 // callout details is not required to sort in H,M and L orders which
763 // are expected by pel because, pel will take care for sorting callouts
764 // based on priority so, now adding support to send callout in order
765 // i.e High -> Medium -> Low.
766 std::sort(
767 jsonCalloutDataList.begin(), jsonCalloutDataList.end(),
768 [](const json& aEle, const json& bEle) -> bool {
769 // Considering b element having higher priority than a element
770 // or Both element will be same priorty (to keep same order
771 // which are given by phal when two callouts are having same
772 // priority)
773 if (((aEle["Priority"] == "M") && (bEle["Priority"] == "H")) ||
774 ((aEle["Priority"] == "L") &&
775 ((bEle["Priority"] == "H") ||
776 (bEle["Priority"] == "M"))) ||
777 (aEle["Priority"] == bEle["Priority"]))
778 {
779 return false;
780 }
781
782 // Considering a element having higher priority than b element
783 return true;
784 });
Jayanth Othayoth8fe9ff92021-11-14 09:15:59 -0600785 openpower::pel::createErrorPEL("org.open_power.PHAL.Error.Boot",
Marri Devender Rao4d5b5bf2022-05-23 09:23:31 -0500786 jsonCalloutDataList, pelAdditionalData,
787 Severity::Error);
Brad Bishopf6783cd2020-10-27 19:25:09 -0400788 }
Patrick Williams1a9a5a62021-10-06 13:05:06 -0500789 catch (const std::exception& ex)
Brad Bishopf6783cd2020-10-27 19:25:09 -0400790 {
791 reset();
792 throw ex;
793 }
794 reset();
795}
796
Marri Devender Rao381c3e32021-12-01 06:27:55 -0600797void processPlatBootError(const ipl_error_info& errInfo)
798{
799 log<level::INFO>("processPlatBootError ");
800
801 // Collecting ffdc details from phal
802 FFDC* ffdc = reinterpret_cast<FFDC*>(errInfo.private_data);
803 try
804 {
Marri Devender Rao4d5b5bf2022-05-23 09:23:31 -0500805 if (util::isHostPoweringOff())
806 {
807 processPoweroffError(ffdc, "PLAT_");
808 }
809 else
810 {
811 processBootErrorHelper(ffdc, "PLAT_");
812 }
Marri Devender Rao381c3e32021-12-01 06:27:55 -0600813 }
814 catch (const std::exception& ex)
815 {
816 log<level::ERR>(
817 fmt::format("processPlatBootError: exception({})", ex.what())
818 .c_str());
819 throw ex;
820 }
821}
822
823void processBootError(bool status)
824{
825 log<level::INFO>(
826 fmt::format("processBootError: status({})", status).c_str());
827
828 try
829 {
830 // return If no failure during hwp execution
831 if (status)
832 return;
Marri Devender Rao381c3e32021-12-01 06:27:55 -0600833 // Collecting ffdc details from phal
834 FFDC ffdc;
835 libekb_get_ffdc(ffdc);
836
Marri Devender Rao4d5b5bf2022-05-23 09:23:31 -0500837 if (util::isHostPoweringOff())
838 {
839 processPoweroffError(&ffdc, "HWP_");
840 }
841 else
842 {
843 processBootErrorHelper(&ffdc, "HWP_");
844 }
Marri Devender Rao381c3e32021-12-01 06:27:55 -0600845 }
846 catch (const std::exception& ex)
847 {
848 log<level::ERR>(
849 fmt::format("processBootError: exception({})", ex.what()).c_str());
850 throw ex;
851 }
852}
853
Jayanth Othayoth4079f092021-09-20 07:36:54 -0500854void processSbeBootError()
855{
856 log<level::INFO>("processSbeBootError : Entered ");
857
858 using namespace openpower::phal::sbe;
Jayanth Othayoth4079f092021-09-20 07:36:54 -0500859
860 // To store phal trace and other additional data about ffdc.
861 FFDCData pelAdditionalData;
862
863 // Adding collected phal logs into PEL additional data
864 for_each(
865 traceLog.begin(), traceLog.end(),
866 [&pelAdditionalData](std::pair<std::string, std::string>& ele) -> void {
867 pelAdditionalData.emplace_back(ele.first, ele.second);
868 });
869
870 // reset the trace log and counter
871 reset();
872
873 // get primary processor to collect FFDC/Dump information.
874 struct pdbg_target* procTarget;
875 pdbg_for_each_class_target("proc", procTarget)
876 {
877 if (openpower::phal::isPrimaryProc(procTarget))
878 break;
879 procTarget = nullptr;
880 }
881 // check valid primary processor is available
882 if (procTarget == nullptr)
883 {
884 log<level::ERR>("processSbeBootError: fail to get primary processor");
Jayanth Othayoth0a516de2021-11-14 09:59:06 -0600885 // Add BMC code callout and create PEL
886 json jsonCalloutDataList;
887 jsonCalloutDataList = json::array();
888 json jsonCalloutData;
889 jsonCalloutData["Procedure"] = "BMC0001";
890 jsonCalloutData["Priority"] = "H";
891 jsonCalloutDataList.emplace_back(jsonCalloutData);
892 openpower::pel::createErrorPEL(
893 "org.open_power.Processor.Error.SbeBootFailure",
Marri Devender Rao4d5b5bf2022-05-23 09:23:31 -0500894 jsonCalloutDataList, {}, Severity::Error);
Jayanth Othayoth4079f092021-09-20 07:36:54 -0500895 return;
896 }
897 // SBE error object.
898 sbeError_t sbeError;
899 bool dumpIsRequired = false;
900
901 try
902 {
903 // Capture FFDC information on primary processor
904 sbeError = captureFFDC(procTarget);
905 }
Jayanth Othayothfaaef2a2021-10-08 06:49:36 -0500906 catch (const phalError_t& phalError)
Jayanth Othayoth4079f092021-09-20 07:36:54 -0500907 {
908 // Fail to collect FFDC information , trigger Dump
909 log<level::ERR>(
Jayanth Othayothfaaef2a2021-10-08 06:49:36 -0500910 fmt::format("captureFFDC: Exception({})", phalError.what())
911 .c_str());
Jayanth Othayoth4079f092021-09-20 07:36:54 -0500912 dumpIsRequired = true;
913 }
914
Jayanth Othayoth006641e2021-10-07 06:56:24 -0500915 std::string event;
916
Jayanth Othayoth4079f092021-09-20 07:36:54 -0500917 if ((sbeError.errType() == SBE_FFDC_NO_DATA) ||
918 (sbeError.errType() == SBE_CMD_TIMEOUT) || (dumpIsRequired))
919 {
Jayanth Othayoth006641e2021-10-07 06:56:24 -0500920 event = "org.open_power.Processor.Error.SbeBootTimeout";
921 dumpIsRequired = true;
922 }
923 else
924 {
925 event = "org.open_power.Processor.Error.SbeBootFailure";
Jayanth Othayoth4079f092021-09-20 07:36:54 -0500926 }
927 // SRC6 : [0:15] chip position
Jayanth Othayoth006641e2021-10-07 06:56:24 -0500928 uint32_t index = pdbg_target_index(procTarget);
929 pelAdditionalData.emplace_back("SRC6", std::to_string(index << 16));
Jayanth Othayoth4079f092021-09-20 07:36:54 -0500930 // Create SBE Error with FFDC data.
Jayanth Othayothe5ba5fd2022-01-27 09:29:01 -0600931 auto logId =
932 createSbeErrorPEL(event, sbeError, pelAdditionalData, procTarget);
Jayanth Othayoth006641e2021-10-07 06:56:24 -0500933
934 if (dumpIsRequired)
935 {
936 using namespace openpower::phal::dump;
937 DumpParameters dumpParameters = {logId, index, SBE_DUMP_TIMEOUT,
938 DumpType::SBE};
939 try
940 {
941 requestDump(dumpParameters);
942 }
943 catch (const std::runtime_error& e)
944 {
945 // Allowing call back to handle the error gracefully.
946 log<level::ERR>("Dump collection failed");
947 // TODO revist error handling.
948 }
949 }
Jayanth Othayoth4079f092021-09-20 07:36:54 -0500950}
951
deepakala-k9f351b02022-10-05 09:03:57 -0500952void processGuardPartitionAccessError()
953{
954 // Adding collected phal logs into PEL additional data
955 FFDCData pelAdditionalData;
956
957 for_each(
958 traceLog.begin(), traceLog.end(),
959 [&pelAdditionalData](std::pair<std::string, std::string>& ele) -> void {
960 pelAdditionalData.emplace_back(ele.first, ele.second);
961 });
962
963 openpower::pel::createPEL("org.open_power.PHAL.Error.GuardPartitionAccess",
964 pelAdditionalData);
965}
966
Brad Bishopf6783cd2020-10-27 19:25:09 -0400967void reset()
968{
969 // reset the trace log and counter
970 traceLog.clear();
971 counter = 0;
972}
973
Brad Bishop63508a72020-10-27 18:55:01 -0400974void pDBGLogTraceCallbackHelper(int, const char* fmt, va_list ap)
Brad Bishopf6783cd2020-10-27 19:25:09 -0400975{
976 processLogTraceCallback(NULL, fmt, ap);
977}
978} // namespace detail
979
980static inline uint8_t getLogLevelFromEnv(const char* env, const uint8_t dValue)
981{
982 auto logLevel = dValue;
983 try
984 {
985 if (const char* env_p = std::getenv(env))
986 {
987 logLevel = std::stoi(env_p);
988 }
989 }
Patrick Williams1a9a5a62021-10-06 13:05:06 -0500990 catch (const std::exception& e)
Brad Bishopf6783cd2020-10-27 19:25:09 -0400991 {
992 log<level::ERR>(("Conversion Failure"), entry("ENVIRONMENT=%s", env),
993 entry("EXCEPTION=%s", e.what()));
994 }
995 return logLevel;
996}
997
998void addBootErrorCallbacks()
999{
1000 // Get individual phal repos log level from environment variable
1001 // and update the log level.
1002 pdbg_set_loglevel(getLogLevelFromEnv("PDBG_LOG", PDBG_INFO));
1003 libekb_set_loglevel(getLogLevelFromEnv("LIBEKB_LOG", LIBEKB_LOG_IMP));
1004 ipl_set_loglevel(getLogLevelFromEnv("IPL_LOG", IPL_INFO));
1005
1006 // add callback for debug traces
1007 pdbg_set_logfunc(detail::pDBGLogTraceCallbackHelper);
1008 libekb_set_logfunc(detail::processLogTraceCallback, NULL);
1009 ipl_set_logfunc(detail::processLogTraceCallback, NULL);
1010
1011 // add callback for ipl failures
Jayanth Othayoth2b211702021-09-06 05:14:23 -05001012 ipl_set_error_callback_func(detail::processIplErrorCallback);
Brad Bishopf6783cd2020-10-27 19:25:09 -04001013}
1014
1015} // namespace pel
1016} // namespace openpower