xref: /openbmc/phosphor-logging/extensions/openpower-pels/fapi_data_process.cpp (revision 9ca4d137ad0f0dd03074652c55186a035fba27d1)
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 
47     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  */
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  */
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  */
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  */
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  **/
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 
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