blob: b97565663e2e8e010744e7e76d3f87362cb68008 [file] [log] [blame]
Jayanth Othayoth4d779b22021-06-03 05:45:13 -05001extern "C" {
2#include <libpdbg.h>
3}
4
5#include "fapi_data_process.hpp"
6
7#include <attributes_info.H>
8#include <fmt/format.h>
Jayanth Othayoth417b88e2021-11-17 00:28:09 -06009#include <libphal.H>
10#include <phal_exception.H>
Jayanth Othayoth4d779b22021-06-03 05:45:13 -050011
12#include <algorithm>
13#include <cstdlib>
14#include <cstring>
15#include <iomanip>
16#include <list>
17#include <map>
18#include <phosphor-logging/elog.hpp>
19#include <sstream>
20#include <string>
21
22namespace openpower
23{
24namespace pels
25{
26namespace phal
27{
28
29using namespace phosphor::logging;
Jayanth Othayoth417b88e2021-11-17 00:28:09 -060030using namespace openpower::phal::exception;
Jayanth Othayoth4d779b22021-06-03 05:45:13 -050031
32/**
33 * Used to pass buffer to pdbg callback api to get required target
34 * data (attributes) based on given data (attribute).
35 */
36struct TargetInfo
37{
38 ATTR_PHYS_BIN_PATH_Type physBinPath;
39 ATTR_LOCATION_CODE_Type locationCode;
40 ATTR_PHYS_DEV_PATH_Type physDevPath;
41 ATTR_MRU_ID_Type mruId;
42
43 bool deconfigure;
44
45 TargetInfo()
46 {
47 memset(&physBinPath, '\0', sizeof(physBinPath));
48 memset(&locationCode, '\0', sizeof(locationCode));
49 memset(&physDevPath, '\0', sizeof(physDevPath));
50 mruId = 0;
51 deconfigure = false;
52 }
53};
54
55/**
56 * Used to return in callback function which are used to get
57 * physical path value and it binary format value.
58 *
59 * The value for constexpr defined based on pdbg_target_traverse function usage.
60 */
61constexpr int continueTgtTraversal = 0;
62constexpr int requireAttrFound = 1;
63constexpr int requireAttrNotFound = 2;
64
65/**
66 * @brief Used to get target location code from phal device tree
67 *
68 * @param[in] target current device tree target
69 * @param[out] appPrivData used for accessing|storing from|to application
70 *
71 * @return 0 to continue traverse, non-zero to stop traverse
72 */
73int pdbgCallbackToGetTgtReqAttrsVal(struct pdbg_target* target,
74 void* appPrivData)
75{
Jayanth Othayoth417b88e2021-11-17 00:28:09 -060076 using namespace openpower::phal::pdbg;
77
Jayanth Othayoth4d779b22021-06-03 05:45:13 -050078 TargetInfo* targetInfo = static_cast<TargetInfo*>(appPrivData);
79
80 ATTR_PHYS_BIN_PATH_Type physBinPath;
81 /**
82 * TODO: Issue: phal/pdata#16
83 * Should not use direct pdbg api to read attribute. Need to use DT_GET_PROP
84 * macro for bmc app's and this will call libdt-api api but, it will print
85 * "pdbg_target_get_attribute failed" trace if attribute is not found and
86 * this callback will call recursively by using pdbg_target_traverse() until
87 * find expected attribute based on return code from this callback. Because,
88 * need to do target iteration to get actual attribute (ATTR_PHYS_BIN_PATH)
89 * value when device tree target info doesn't know to read attribute from
90 * device tree. So, Due to this error trace user will get confusion while
91 * looking traces. Hence using pdbg api to avoid trace until libdt-api
92 * provides log level setup.
93 */
94 if (!pdbg_target_get_attribute(
95 target, "ATTR_PHYS_BIN_PATH",
96 std::stoi(dtAttr::fapi2::ATTR_PHYS_BIN_PATH_Spec),
97 dtAttr::fapi2::ATTR_PHYS_BIN_PATH_ElementCount, physBinPath))
98 {
99 return continueTgtTraversal;
100 }
101
102 if (std::memcmp(physBinPath, targetInfo->physBinPath,
103 sizeof(physBinPath)) != 0)
104 {
105 return continueTgtTraversal;
106 }
107
Jayanth Othayoth363ac762021-11-17 00:38:24 -0600108 // Found Target, now collect the required attributes associated to the
109 // target. Incase of any attribute read failure, initialize the data with
110 // default value.
111
Jayanth Othayoth417b88e2021-11-17 00:28:09 -0600112 try
Jayanth Othayoth4d779b22021-06-03 05:45:13 -0500113 {
Jayanth Othayoth417b88e2021-11-17 00:28:09 -0600114 // Get location code information
115 openpower::phal::pdbg::getLocationCode(target,
116 targetInfo->locationCode);
117 }
118 catch (const std::exception& e)
119 {
120 // log message and continue with default data
121 log<level::ERR>(fmt::format("getLocationCode({}): Exception({})",
122 pdbg_target_path(target), e.what())
123 .c_str());
Jayanth Othayoth4d779b22021-06-03 05:45:13 -0500124 }
125
126 if (DT_GET_PROP(ATTR_PHYS_DEV_PATH, target, targetInfo->physDevPath))
127 {
Jayanth Othayoth363ac762021-11-17 00:38:24 -0600128 log<level::ERR>(
129 fmt::format("Could not read({}) PHYS_DEV_PATH attribute",
130 pdbg_target_path(target))
131 .c_str());
Jayanth Othayoth4d779b22021-06-03 05:45:13 -0500132 }
133
134 if (DT_GET_PROP(ATTR_MRU_ID, target, targetInfo->mruId))
135 {
Jayanth Othayoth363ac762021-11-17 00:38:24 -0600136 log<level::ERR>(fmt::format("Could not read({}) ATTR_MRU_ID attribute",
137 pdbg_target_path(target))
138 .c_str());
Jayanth Othayoth4d779b22021-06-03 05:45:13 -0500139 }
140
Jayanth Othayoth4d779b22021-06-03 05:45:13 -0500141 return requireAttrFound;
142}
143
144/**
145 * @brief Used to get target info (attributes data)
146 *
147 * To get target required attributes value using another attribute value
148 * ("PHYS_BIN_PATH" which is present in same target attributes list) by using
149 * "ipdbg_target_traverse" api because, here we have attribute value only and
150 * doesn't have respective device tree target info to get required attributes
151 * values from it attributes list.
152 *
153 * @param[in] physBinPath to pass PHYS_BIN_PATH value
154 * @param[out] targetInfo to pas buufer to fill with required attributes
155 *
156 * @return true on success otherwise false
157 */
158bool getTgtReqAttrsVal(const std::vector<uint8_t>& physBinPath,
159 TargetInfo& targetInfo)
160{
161 std::memcpy(&targetInfo.physBinPath, physBinPath.data(),
162 sizeof(targetInfo.physBinPath));
163
164 int ret = pdbg_target_traverse(NULL, pdbgCallbackToGetTgtReqAttrsVal,
165 &targetInfo);
166 if (ret == 0)
167 {
168 log<level::ERR>(fmt::format("Given ATTR_PHYS_BIN_PATH value({}) "
169 "not found in phal device tree",
170 targetInfo.physBinPath)
171 .c_str());
172 return false;
173 }
174 else if (ret == requireAttrNotFound)
175 {
176 return false;
177 }
178
179 return true;
180}
181
182/**
183 * @brief GET PEL priority from pHAL priority
184 *
185 * The pHAL callout priority is in different format than PEL format
186 * so, this api is used to return current phal supported priority into
187 * PEL expected format.
188 *
189 * @param[in] phalPriority used to pass phal priority format string
190 *
191 * @return pel priority format string else empty if failure
192 *
193 * @note For "NONE" returning "L" (LOW)
194 */
195static std::string getPelPriority(const std::string& phalPriority)
196{
197 const std::map<std::string, std::string> priorityMap = {
198 {"HIGH", "H"}, {"MEDIUM", "M"}, {"LOW", "L"}, {"NONE", "L"}};
199
200 auto it = priorityMap.find(phalPriority);
201 if (it == priorityMap.end())
202 {
203 log<level::ERR>(fmt::format("Unsupported phal priority({}) is given "
204 "to get pel priority format",
205 phalPriority)
206 .c_str());
207 return "H";
208 }
209
210 return it->second;
211}
212
rajerpp1f928c4a2021-11-27 05:55:21 -0600213/**
214 * @brief addPlanarCallout
215 *
216 * This function will add a json for planar callout in the input json list.
217 * The caller can pass this json list into createErrorPEL to apply the callout.
218 *
219 * @param[in,out] jsonCalloutDataList - json list where callout json will be
220 * emplaced
221 * @param[in] priority - string indicating priority.
222 */
223static void addPlanarCallout(json& jsonCalloutDataList,
224 const std::string& priority)
225{
226 json jsonCalloutData;
227
228 // Inventory path for planar
229 jsonCalloutData["InventoryPath"] =
230 "/xyz/openbmc_project/inventory/system/chassis/motherboard";
231 jsonCalloutData["Deconfigured"] = false;
232 jsonCalloutData["Guarded"] = false;
233 jsonCalloutData["Priority"] = priority;
234
235 jsonCalloutDataList.emplace_back(jsonCalloutData);
236}
237
Jayanth Othayothe98777d2022-06-30 04:11:07 -0500238/**
239 * @brief processClockInfoErrorHelper
240 *
241 * Creates informational PEL for spare clock failure
242 *
243 * @param[in] ffdc FFDC data capturd by the HWP
244 * @param[out] pelJSONFmtCalloutDataList used to store collected callout
245 * data into pel expected format
246 * @param[out] ffdcUserData used to store additional ffdc user data to
247 * provided by the SBE FFDC packet.
248 *
249 * @return NULL
250 *
251 **/
252void processClockInfoErrorHelper(const FFDC& ffdc,
253 json& pelJSONFmtCalloutDataList,
254 FFDCData& ffdcUserData)
255{
256 log<level::INFO>(
257 fmt::format("processClockInfoErrorHelper: FFDC Message[{}]",
258 ffdc.message)
259 .c_str());
260
261 // Adding hardware procedures return code details
262 ffdcUserData.emplace_back("HWP_RC", ffdc.hwp_errorinfo.rc);
263 ffdcUserData.emplace_back("HWP_RC_DESC", ffdc.hwp_errorinfo.rc_desc);
264
265 // Adding hardware procedures required ffdc data for debug
266 for_each(ffdc.hwp_errorinfo.ffdcs_data.cbegin(),
267 ffdc.hwp_errorinfo.ffdcs_data.cend(),
268 [&ffdcUserData](
269 const std::pair<std::string, std::string>& ele) -> void {
270 std::string keyWithPrefix("HWP_FFDC_");
271 keyWithPrefix.append(ele.first);
272
273 ffdcUserData.emplace_back(keyWithPrefix, ele.second);
274 });
275 // get clock position information
276 auto clk_pos = 0xFF; // Invalid position.
277 for (auto& hwCallout : ffdc.hwp_errorinfo.hwcallouts)
278 {
279 if ((hwCallout.hwid == "PROC_REF_CLOCK") ||
280 (hwCallout.hwid == "PCI_REF_CLOCK"))
281 {
282 clk_pos = hwCallout.clkPos;
283 break;
284 }
285 }
286 // Adding CDG (Only deconfigure) targets details
287 for_each(ffdc.hwp_errorinfo.cdg_targets.begin(),
288 ffdc.hwp_errorinfo.cdg_targets.end(),
289 [&ffdcUserData, &pelJSONFmtCalloutDataList,
290 clk_pos](const CDG_Target& cdg_tgt) -> void {
291 json jsonCalloutData;
292 std::string pelPriority = "H";
293 jsonCalloutData["Priority"] = pelPriority; // Not used
294 jsonCalloutData["SymbolicFRU"] =
295 "REFCLK" + std::to_string(clk_pos);
296 jsonCalloutData["Deconfigured"] = cdg_tgt.deconfigure;
297 jsonCalloutData["EntityPath"] = cdg_tgt.target_entity_path;
298 pelJSONFmtCalloutDataList.emplace_back(jsonCalloutData);
299 });
300}
301
Jayanth Othayoth4d779b22021-06-03 05:45:13 -0500302void convertFAPItoPELformat(FFDC& ffdc, json& pelJSONFmtCalloutDataList,
303 FFDCData& ffdcUserData)
304{
Jayanth Othayothe98777d2022-06-30 04:11:07 -0500305 if (ffdc.ffdc_type == FFDC_TYPE_SPARE_CLOCK_INFO)
306 {
307 processClockInfoErrorHelper(ffdc, pelJSONFmtCalloutDataList,
308 ffdcUserData);
309 return;
310 }
311
Jayanth Othayoth4d779b22021-06-03 05:45:13 -0500312 if (ffdc.ffdc_type == FFDC_TYPE_HWP)
313 {
314 // Adding hardware procedures return code details
315 ffdcUserData.emplace_back("HWP_RC", ffdc.hwp_errorinfo.rc);
316 ffdcUserData.emplace_back("HWP_RC_DESC", ffdc.hwp_errorinfo.rc_desc);
317
318 // Adding hardware procedures required ffdc data for debug
319 for_each(
320 ffdc.hwp_errorinfo.ffdcs_data.begin(),
321 ffdc.hwp_errorinfo.ffdcs_data.end(),
322 [&ffdcUserData](std::pair<std::string, std::string>& ele) -> void {
323 std::string keyWithPrefix("HWP_FFDC_");
324 keyWithPrefix.append(ele.first);
325
326 ffdcUserData.emplace_back(keyWithPrefix, ele.second);
327 });
328
329 // Adding hardware callout details
330 int calloutCount = 0;
331 for_each(
332 ffdc.hwp_errorinfo.hwcallouts.begin(),
333 ffdc.hwp_errorinfo.hwcallouts.end(),
334 [&ffdcUserData, &calloutCount,
335 &pelJSONFmtCalloutDataList](const HWCallout& hwCallout) -> void {
336 calloutCount++;
337 std::stringstream keyPrefix;
338 keyPrefix << "HWP_HW_CO_" << std::setfill('0') << std::setw(2)
339 << calloutCount << "_";
340
341 ffdcUserData.emplace_back(
342 std::string(keyPrefix.str()).append("HW_ID"),
343 hwCallout.hwid);
344
345 ffdcUserData.emplace_back(
346 std::string(keyPrefix.str()).append("PRIORITY"),
347 hwCallout.callout_priority);
348
349 phal::TargetInfo targetInfo;
350 phal::getTgtReqAttrsVal(hwCallout.target_entity_path,
351 targetInfo);
352
353 std::string locationCode = std::string(targetInfo.locationCode);
354 ffdcUserData.emplace_back(
355 std::string(keyPrefix.str()).append("LOC_CODE"),
356 locationCode);
357
358 std::string physPath = std::string(targetInfo.physDevPath);
359 ffdcUserData.emplace_back(
360 std::string(keyPrefix.str()).append("PHYS_PATH"), physPath);
361
362 ffdcUserData.emplace_back(
363 std::string(keyPrefix.str()).append("CLK_POS"),
364 std::to_string(hwCallout.clkPos));
rajerpp1f928c4a2021-11-27 05:55:21 -0600365
366 ffdcUserData.emplace_back(
367 std::string(keyPrefix.str()).append("CALLOUT_PLANAR"),
368 (hwCallout.isPlanarCallout == true ? "true" : "false"));
369
370 std::string pelPriority =
371 getPelPriority(hwCallout.callout_priority);
372
373 if (hwCallout.isPlanarCallout)
374 {
375 addPlanarCallout(pelJSONFmtCalloutDataList, pelPriority);
376 }
Jayanth Othayoth4d779b22021-06-03 05:45:13 -0500377 });
378
379 // Adding CDG (callout, deconfigure and guard) targets details
380 calloutCount = 0;
381 for_each(
382 ffdc.hwp_errorinfo.cdg_targets.begin(),
383 ffdc.hwp_errorinfo.cdg_targets.end(),
384 [&ffdcUserData, &calloutCount,
385 &pelJSONFmtCalloutDataList](const CDG_Target& cdg_tgt) -> void {
386 calloutCount++;
387 std::stringstream keyPrefix;
388 keyPrefix << "HWP_CDG_TGT_" << std::setfill('0') << std::setw(2)
389 << calloutCount << "_";
390
391 phal::TargetInfo targetInfo;
392 targetInfo.deconfigure = cdg_tgt.deconfigure;
393
394 phal::getTgtReqAttrsVal(cdg_tgt.target_entity_path, targetInfo);
395
396 std::string locationCode = std::string(targetInfo.locationCode);
397 ffdcUserData.emplace_back(
398 std::string(keyPrefix.str()).append("LOC_CODE"),
399 locationCode);
400 std::string physPath = std::string(targetInfo.physDevPath);
401 ffdcUserData.emplace_back(
402 std::string(keyPrefix.str()).append("PHYS_PATH"), physPath);
403
404 ffdcUserData.emplace_back(
405 std::string(keyPrefix.str()).append("CO_REQ"),
406 (cdg_tgt.callout == true ? "true" : "false"));
407
408 ffdcUserData.emplace_back(
409 std::string(keyPrefix.str()).append("CO_PRIORITY"),
410 cdg_tgt.callout_priority);
411
412 ffdcUserData.emplace_back(
413 std::string(keyPrefix.str()).append("DECONF_REQ"),
414 (cdg_tgt.deconfigure == true ? "true" : "false"));
415
416 ffdcUserData.emplace_back(
417 std::string(keyPrefix.str()).append("GUARD_REQ"),
418 (cdg_tgt.guard == true ? "true" : "false"));
419
420 ffdcUserData.emplace_back(
421 std::string(keyPrefix.str()).append("GUARD_TYPE"),
422 cdg_tgt.guard_type);
423
424 json jsonCalloutData;
425 jsonCalloutData["LocationCode"] = locationCode;
426 std::string pelPriority =
427 getPelPriority(cdg_tgt.callout_priority);
428 jsonCalloutData["Priority"] = pelPriority;
429
430 if (targetInfo.mruId != 0)
431 {
432 jsonCalloutData["MRUs"] = json::array({
433 {{"ID", targetInfo.mruId}, {"Priority", pelPriority}},
434 });
435 }
436 jsonCalloutData["Deconfigured"] = cdg_tgt.deconfigure;
437 jsonCalloutData["Guarded"] = cdg_tgt.guard;
Jayanth Othayoth95205eb2021-11-08 06:21:30 -0600438 jsonCalloutData["GuardType"] = cdg_tgt.guard_type;
439 jsonCalloutData["EntityPath"] = cdg_tgt.target_entity_path;
Jayanth Othayoth4d779b22021-06-03 05:45:13 -0500440
441 pelJSONFmtCalloutDataList.emplace_back(jsonCalloutData);
442 });
Jayanth Othayoth9368b712021-11-17 01:03:42 -0600443
444 // Adding procedure callout
445 calloutCount = 0;
446 for_each(ffdc.hwp_errorinfo.procedures_callout.begin(),
447 ffdc.hwp_errorinfo.procedures_callout.end(),
448 [&ffdcUserData, &calloutCount, &pelJSONFmtCalloutDataList](
449 const ProcedureCallout& procCallout) -> void {
450 calloutCount++;
451 std::stringstream keyPrefix;
452 keyPrefix << "HWP_PROC_CO_" << std::setfill('0')
453 << std::setw(2) << calloutCount << "_";
454 ffdcUserData.emplace_back(
455 std::string(keyPrefix.str()).append("PRIORITY"),
456 procCallout.callout_priority);
457 ffdcUserData.emplace_back(
458 std::string(keyPrefix.str()).append("MAINT_PROCEDURE"),
459 procCallout.proc_callout);
460 json jsonCalloutData;
461 jsonCalloutData["Procedure"] = procCallout.proc_callout;
462 std::string pelPriority =
463 getPelPriority(procCallout.callout_priority);
464 jsonCalloutData["Priority"] = pelPriority;
465 pelJSONFmtCalloutDataList.emplace_back(jsonCalloutData);
466 });
Jayanth Othayoth4d779b22021-06-03 05:45:13 -0500467 }
468 else if ((ffdc.ffdc_type != FFDC_TYPE_NONE) &&
469 (ffdc.ffdc_type != FFDC_TYPE_UNSUPPORTED))
470 {
471 log<level::ERR>(fmt::format("Unsupported phal FFDC type to create PEL. "
472 "MSG: {}",
473 ffdc.message)
474 .c_str());
475 }
476}
477
478} // namespace phal
479} // namespace pels
480} // namespace openpower