xref: /openbmc/phosphor-logging/extensions/openpower-pels/fapi_data_process.cpp (revision 9368b714f2e4fb2cb3fe4536ffbe4488110d3731)
1 extern "C" {
2 #include <libpdbg.h>
3 }
4 
5 #include "fapi_data_process.hpp"
6 
7 #include <attributes_info.H>
8 #include <fmt/format.h>
9 #include <libphal.H>
10 #include <phal_exception.H>
11 
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 
22 namespace openpower
23 {
24 namespace pels
25 {
26 namespace phal
27 {
28 
29 using namespace phosphor::logging;
30 using namespace openpower::phal::exception;
31 
32 /**
33  * Used to pass buffer to pdbg callback api to get required target
34  * data (attributes) based on given data (attribute).
35  */
36 struct 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  */
61 constexpr int continueTgtTraversal = 0;
62 constexpr int requireAttrFound = 1;
63 constexpr 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  */
73 int pdbgCallbackToGetTgtReqAttrsVal(struct pdbg_target* target,
74                                     void* appPrivData)
75 {
76     using namespace openpower::phal::pdbg;
77 
78     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 
108     // 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 
112     try
113     {
114         // 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());
124     }
125 
126     if (DT_GET_PROP(ATTR_PHYS_DEV_PATH, target, targetInfo->physDevPath))
127     {
128         log<level::ERR>(
129             fmt::format("Could not read({}) PHYS_DEV_PATH attribute",
130                         pdbg_target_path(target))
131                 .c_str());
132     }
133 
134     if (DT_GET_PROP(ATTR_MRU_ID, target, targetInfo->mruId))
135     {
136         log<level::ERR>(fmt::format("Could not read({}) ATTR_MRU_ID attribute",
137                                     pdbg_target_path(target))
138                             .c_str());
139     }
140 
141     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  */
158 bool 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  */
195 static 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 
213 void convertFAPItoPELformat(FFDC& ffdc, json& pelJSONFmtCalloutDataList,
214                             FFDCData& ffdcUserData)
215 {
216     if (ffdc.ffdc_type == FFDC_TYPE_HWP)
217     {
218         // Adding hardware procedures return code details
219         ffdcUserData.emplace_back("HWP_RC", ffdc.hwp_errorinfo.rc);
220         ffdcUserData.emplace_back("HWP_RC_DESC", ffdc.hwp_errorinfo.rc_desc);
221 
222         // Adding hardware procedures required ffdc data for debug
223         for_each(
224             ffdc.hwp_errorinfo.ffdcs_data.begin(),
225             ffdc.hwp_errorinfo.ffdcs_data.end(),
226             [&ffdcUserData](std::pair<std::string, std::string>& ele) -> void {
227                 std::string keyWithPrefix("HWP_FFDC_");
228                 keyWithPrefix.append(ele.first);
229 
230                 ffdcUserData.emplace_back(keyWithPrefix, ele.second);
231             });
232 
233         // Adding hardware callout details
234         int calloutCount = 0;
235         for_each(
236             ffdc.hwp_errorinfo.hwcallouts.begin(),
237             ffdc.hwp_errorinfo.hwcallouts.end(),
238             [&ffdcUserData, &calloutCount,
239              &pelJSONFmtCalloutDataList](const HWCallout& hwCallout) -> void {
240                 calloutCount++;
241                 std::stringstream keyPrefix;
242                 keyPrefix << "HWP_HW_CO_" << std::setfill('0') << std::setw(2)
243                           << calloutCount << "_";
244 
245                 ffdcUserData.emplace_back(
246                     std::string(keyPrefix.str()).append("HW_ID"),
247                     hwCallout.hwid);
248 
249                 ffdcUserData.emplace_back(
250                     std::string(keyPrefix.str()).append("PRIORITY"),
251                     hwCallout.callout_priority);
252 
253                 phal::TargetInfo targetInfo;
254                 phal::getTgtReqAttrsVal(hwCallout.target_entity_path,
255                                         targetInfo);
256 
257                 std::string locationCode = std::string(targetInfo.locationCode);
258                 ffdcUserData.emplace_back(
259                     std::string(keyPrefix.str()).append("LOC_CODE"),
260                     locationCode);
261 
262                 std::string physPath = std::string(targetInfo.physDevPath);
263                 ffdcUserData.emplace_back(
264                     std::string(keyPrefix.str()).append("PHYS_PATH"), physPath);
265 
266                 ffdcUserData.emplace_back(
267                     std::string(keyPrefix.str()).append("CLK_POS"),
268                     std::to_string(hwCallout.clkPos));
269 
270                 json jsonCalloutData;
271                 jsonCalloutData["LocationCode"] = locationCode;
272                 std::string pelPriority =
273                     getPelPriority(hwCallout.callout_priority);
274                 jsonCalloutData["Priority"] = pelPriority;
275 
276                 if (targetInfo.mruId != 0)
277                 {
278                     jsonCalloutData["MRUs"] = json::array({
279                         {{"ID", targetInfo.mruId}, {"Priority", pelPriority}},
280                     });
281                 }
282 
283                 pelJSONFmtCalloutDataList.emplace_back(jsonCalloutData);
284             });
285 
286         // Adding CDG (callout, deconfigure and guard) targets details
287         calloutCount = 0;
288         for_each(
289             ffdc.hwp_errorinfo.cdg_targets.begin(),
290             ffdc.hwp_errorinfo.cdg_targets.end(),
291             [&ffdcUserData, &calloutCount,
292              &pelJSONFmtCalloutDataList](const CDG_Target& cdg_tgt) -> void {
293                 calloutCount++;
294                 std::stringstream keyPrefix;
295                 keyPrefix << "HWP_CDG_TGT_" << std::setfill('0') << std::setw(2)
296                           << calloutCount << "_";
297 
298                 phal::TargetInfo targetInfo;
299                 targetInfo.deconfigure = cdg_tgt.deconfigure;
300 
301                 phal::getTgtReqAttrsVal(cdg_tgt.target_entity_path, targetInfo);
302 
303                 std::string locationCode = std::string(targetInfo.locationCode);
304                 ffdcUserData.emplace_back(
305                     std::string(keyPrefix.str()).append("LOC_CODE"),
306                     locationCode);
307                 std::string physPath = std::string(targetInfo.physDevPath);
308                 ffdcUserData.emplace_back(
309                     std::string(keyPrefix.str()).append("PHYS_PATH"), physPath);
310 
311                 ffdcUserData.emplace_back(
312                     std::string(keyPrefix.str()).append("CO_REQ"),
313                     (cdg_tgt.callout == true ? "true" : "false"));
314 
315                 ffdcUserData.emplace_back(
316                     std::string(keyPrefix.str()).append("CO_PRIORITY"),
317                     cdg_tgt.callout_priority);
318 
319                 ffdcUserData.emplace_back(
320                     std::string(keyPrefix.str()).append("DECONF_REQ"),
321                     (cdg_tgt.deconfigure == true ? "true" : "false"));
322 
323                 ffdcUserData.emplace_back(
324                     std::string(keyPrefix.str()).append("GUARD_REQ"),
325                     (cdg_tgt.guard == true ? "true" : "false"));
326 
327                 ffdcUserData.emplace_back(
328                     std::string(keyPrefix.str()).append("GUARD_TYPE"),
329                     cdg_tgt.guard_type);
330 
331                 json jsonCalloutData;
332                 jsonCalloutData["LocationCode"] = locationCode;
333                 std::string pelPriority =
334                     getPelPriority(cdg_tgt.callout_priority);
335                 jsonCalloutData["Priority"] = pelPriority;
336 
337                 if (targetInfo.mruId != 0)
338                 {
339                     jsonCalloutData["MRUs"] = json::array({
340                         {{"ID", targetInfo.mruId}, {"Priority", pelPriority}},
341                     });
342                 }
343                 jsonCalloutData["Deconfigured"] = cdg_tgt.deconfigure;
344                 jsonCalloutData["Guarded"] = cdg_tgt.guard;
345                 jsonCalloutData["GuardType"] = cdg_tgt.guard_type;
346                 jsonCalloutData["EntityPath"] = cdg_tgt.target_entity_path;
347 
348                 pelJSONFmtCalloutDataList.emplace_back(jsonCalloutData);
349             });
350 
351         // Adding procedure callout
352         calloutCount = 0;
353         for_each(ffdc.hwp_errorinfo.procedures_callout.begin(),
354                  ffdc.hwp_errorinfo.procedures_callout.end(),
355                  [&ffdcUserData, &calloutCount, &pelJSONFmtCalloutDataList](
356                      const ProcedureCallout& procCallout) -> void {
357                      calloutCount++;
358                      std::stringstream keyPrefix;
359                      keyPrefix << "HWP_PROC_CO_" << std::setfill('0')
360                                << std::setw(2) << calloutCount << "_";
361                      ffdcUserData.emplace_back(
362                          std::string(keyPrefix.str()).append("PRIORITY"),
363                          procCallout.callout_priority);
364                      ffdcUserData.emplace_back(
365                          std::string(keyPrefix.str()).append("MAINT_PROCEDURE"),
366                          procCallout.proc_callout);
367                      json jsonCalloutData;
368                      jsonCalloutData["Procedure"] = procCallout.proc_callout;
369                      std::string pelPriority =
370                          getPelPriority(procCallout.callout_priority);
371                      jsonCalloutData["Priority"] = pelPriority;
372                      pelJSONFmtCalloutDataList.emplace_back(jsonCalloutData);
373                  });
374     }
375     else if ((ffdc.ffdc_type != FFDC_TYPE_NONE) &&
376              (ffdc.ffdc_type != FFDC_TYPE_UNSUPPORTED))
377     {
378         log<level::ERR>(fmt::format("Unsupported phal FFDC type to create PEL. "
379                                     "MSG: {}",
380                                     ffdc.message)
381                             .c_str());
382     }
383 }
384 
385 } // namespace phal
386 } // namespace pels
387 } // namespace openpower
388