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