blob: a658449ee28ff576b776bec05f3413ef840c488a [file] [log] [blame]
Patrick Williams2544b412022-10-04 08:41:06 -05001extern "C"
2{
Jayanth Othayoth4d779b22021-06-03 05:45:13 -05003#include <libpdbg.h>
4}
5
6#include "fapi_data_process.hpp"
7
8#include <attributes_info.H>
9#include <fmt/format.h>
Jayanth Othayoth417b88e2021-11-17 00:28:09 -060010#include <libphal.H>
11#include <phal_exception.H>
Jayanth Othayoth4d779b22021-06-03 05:45:13 -050012
Patrick Williams2544b412022-10-04 08:41:06 -050013#include <phosphor-logging/elog.hpp>
14
Jayanth Othayoth4d779b22021-06-03 05:45:13 -050015#include <algorithm>
16#include <cstdlib>
17#include <cstring>
18#include <iomanip>
19#include <list>
20#include <map>
Jayanth Othayoth4d779b22021-06-03 05:45:13 -050021#include <sstream>
22#include <string>
23
24namespace openpower
25{
26namespace pels
27{
28namespace phal
29{
30
31using namespace phosphor::logging;
Jayanth Othayoth417b88e2021-11-17 00:28:09 -060032using namespace openpower::phal::exception;
Jayanth Othayoth4d779b22021-06-03 05:45:13 -050033
34/**
35 * Used to pass buffer to pdbg callback api to get required target
36 * data (attributes) based on given data (attribute).
37 */
38struct 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 */
63constexpr int continueTgtTraversal = 0;
64constexpr int requireAttrFound = 1;
65constexpr 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 */
75int pdbgCallbackToGetTgtReqAttrsVal(struct pdbg_target* target,
76 void* appPrivData)
77{
Jayanth Othayoth417b88e2021-11-17 00:28:09 -060078 using namespace openpower::phal::pdbg;
79
Jayanth Othayoth4d779b22021-06-03 05:45:13 -050080 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
Jayanth Othayoth363ac762021-11-17 00:38:24 -0600110 // 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
Jayanth Othayoth417b88e2021-11-17 00:28:09 -0600114 try
Jayanth Othayoth4d779b22021-06-03 05:45:13 -0500115 {
Jayanth Othayoth417b88e2021-11-17 00:28:09 -0600116 // 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 log<level::ERR>(fmt::format("getLocationCode({}): Exception({})",
124 pdbg_target_path(target), e.what())
125 .c_str());
Jayanth Othayoth4d779b22021-06-03 05:45:13 -0500126 }
127
128 if (DT_GET_PROP(ATTR_PHYS_DEV_PATH, target, targetInfo->physDevPath))
129 {
Jayanth Othayoth363ac762021-11-17 00:38:24 -0600130 log<level::ERR>(
131 fmt::format("Could not read({}) PHYS_DEV_PATH attribute",
132 pdbg_target_path(target))
133 .c_str());
Jayanth Othayoth4d779b22021-06-03 05:45:13 -0500134 }
135
136 if (DT_GET_PROP(ATTR_MRU_ID, target, targetInfo->mruId))
137 {
Jayanth Othayoth363ac762021-11-17 00:38:24 -0600138 log<level::ERR>(fmt::format("Could not read({}) ATTR_MRU_ID attribute",
139 pdbg_target_path(target))
140 .c_str());
Jayanth Othayoth4d779b22021-06-03 05:45:13 -0500141 }
142
Jayanth Othayoth4d779b22021-06-03 05:45:13 -0500143 return requireAttrFound;
144}
145
146/**
147 * @brief Used to get target info (attributes data)
148 *
149 * To get target required attributes value using another attribute value
150 * ("PHYS_BIN_PATH" which is present in same target attributes list) by using
151 * "ipdbg_target_traverse" api because, here we have attribute value only and
152 * doesn't have respective device tree target info to get required attributes
153 * values from it attributes list.
154 *
155 * @param[in] physBinPath to pass PHYS_BIN_PATH value
156 * @param[out] targetInfo to pas buufer to fill with required attributes
157 *
158 * @return true on success otherwise false
159 */
160bool getTgtReqAttrsVal(const std::vector<uint8_t>& physBinPath,
161 TargetInfo& targetInfo)
162{
163 std::memcpy(&targetInfo.physBinPath, physBinPath.data(),
164 sizeof(targetInfo.physBinPath));
165
166 int ret = pdbg_target_traverse(NULL, pdbgCallbackToGetTgtReqAttrsVal,
167 &targetInfo);
168 if (ret == 0)
169 {
Patrick Williams23cf1fb2022-10-04 09:22:35 -0500170 log<level::ERR>(fmt::format("Given ATTR_PHYS_BIN_PATH value({:02x}) "
Jayanth Othayoth4d779b22021-06-03 05:45:13 -0500171 "not found in phal device tree",
Patrick Williams23cf1fb2022-10-04 09:22:35 -0500172 fmt::join(targetInfo.physBinPath, ""))
Jayanth Othayoth4d779b22021-06-03 05:45:13 -0500173 .c_str());
174 return false;
175 }
176 else if (ret == requireAttrNotFound)
177 {
178 return false;
179 }
180
181 return true;
182}
183
184/**
185 * @brief GET PEL priority from pHAL priority
186 *
187 * The pHAL callout priority is in different format than PEL format
188 * so, this api is used to return current phal supported priority into
189 * PEL expected format.
190 *
191 * @param[in] phalPriority used to pass phal priority format string
192 *
193 * @return pel priority format string else empty if failure
194 *
195 * @note For "NONE" returning "L" (LOW)
196 */
197static std::string getPelPriority(const std::string& phalPriority)
198{
199 const std::map<std::string, std::string> priorityMap = {
200 {"HIGH", "H"}, {"MEDIUM", "M"}, {"LOW", "L"}, {"NONE", "L"}};
201
202 auto it = priorityMap.find(phalPriority);
203 if (it == priorityMap.end())
204 {
205 log<level::ERR>(fmt::format("Unsupported phal priority({}) is given "
206 "to get pel priority format",
207 phalPriority)
208 .c_str());
209 return "H";
210 }
211
212 return it->second;
213}
214
rajerpp1f928c4a2021-11-27 05:55:21 -0600215/**
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 */
225static 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
Jayanth Othayothe98777d2022-06-30 04:11:07 -0500240/**
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 **/
254void processClockInfoErrorHelper(const FFDC& ffdc,
255 json& pelJSONFmtCalloutDataList,
256 FFDCData& ffdcUserData)
257{
258 log<level::INFO>(
259 fmt::format("processClockInfoErrorHelper: FFDC Message[{}]",
260 ffdc.message)
261 .c_str());
262
263 // Adding hardware procedures return code details
264 ffdcUserData.emplace_back("HWP_RC", ffdc.hwp_errorinfo.rc);
265 ffdcUserData.emplace_back("HWP_RC_DESC", ffdc.hwp_errorinfo.rc_desc);
266
267 // Adding hardware procedures required ffdc data for debug
268 for_each(ffdc.hwp_errorinfo.ffdcs_data.cbegin(),
269 ffdc.hwp_errorinfo.ffdcs_data.cend(),
270 [&ffdcUserData](
271 const std::pair<std::string, std::string>& ele) -> void {
272 std::string keyWithPrefix("HWP_FFDC_");
273 keyWithPrefix.append(ele.first);
274
275 ffdcUserData.emplace_back(keyWithPrefix, ele.second);
276 });
277 // get clock position information
278 auto clk_pos = 0xFF; // Invalid position.
279 for (auto& hwCallout : ffdc.hwp_errorinfo.hwcallouts)
280 {
281 if ((hwCallout.hwid == "PROC_REF_CLOCK") ||
282 (hwCallout.hwid == "PCI_REF_CLOCK"))
283 {
284 clk_pos = hwCallout.clkPos;
285 break;
286 }
287 }
288 // Adding CDG (Only deconfigure) targets details
289 for_each(ffdc.hwp_errorinfo.cdg_targets.begin(),
290 ffdc.hwp_errorinfo.cdg_targets.end(),
291 [&ffdcUserData, &pelJSONFmtCalloutDataList,
292 clk_pos](const CDG_Target& cdg_tgt) -> void {
293 json jsonCalloutData;
294 std::string pelPriority = "H";
295 jsonCalloutData["Priority"] = pelPriority; // Not used
Patrick Williams2544b412022-10-04 08:41:06 -0500296 jsonCalloutData["SymbolicFRU"] = "REFCLK" +
297 std::to_string(clk_pos);
Jayanth Othayothe98777d2022-06-30 04:11:07 -0500298 jsonCalloutData["Deconfigured"] = cdg_tgt.deconfigure;
299 jsonCalloutData["EntityPath"] = cdg_tgt.target_entity_path;
300 pelJSONFmtCalloutDataList.emplace_back(jsonCalloutData);
301 });
302}
303
Jayanth Othayoth4d779b22021-06-03 05:45:13 -0500304void convertFAPItoPELformat(FFDC& ffdc, json& pelJSONFmtCalloutDataList,
305 FFDCData& ffdcUserData)
306{
Jayanth Othayothe98777d2022-06-30 04:11:07 -0500307 if (ffdc.ffdc_type == FFDC_TYPE_SPARE_CLOCK_INFO)
308 {
309 processClockInfoErrorHelper(ffdc, pelJSONFmtCalloutDataList,
310 ffdcUserData);
311 return;
312 }
313
Jayanth Othayoth4d779b22021-06-03 05:45:13 -0500314 if (ffdc.ffdc_type == FFDC_TYPE_HWP)
315 {
316 // Adding hardware procedures return code details
317 ffdcUserData.emplace_back("HWP_RC", ffdc.hwp_errorinfo.rc);
318 ffdcUserData.emplace_back("HWP_RC_DESC", ffdc.hwp_errorinfo.rc_desc);
319
320 // Adding hardware procedures required ffdc data for debug
321 for_each(
322 ffdc.hwp_errorinfo.ffdcs_data.begin(),
323 ffdc.hwp_errorinfo.ffdcs_data.end(),
324 [&ffdcUserData](std::pair<std::string, std::string>& ele) -> void {
325 std::string keyWithPrefix("HWP_FFDC_");
326 keyWithPrefix.append(ele.first);
327
328 ffdcUserData.emplace_back(keyWithPrefix, ele.second);
329 });
330
331 // Adding hardware callout details
332 int calloutCount = 0;
333 for_each(
334 ffdc.hwp_errorinfo.hwcallouts.begin(),
335 ffdc.hwp_errorinfo.hwcallouts.end(),
336 [&ffdcUserData, &calloutCount,
337 &pelJSONFmtCalloutDataList](const HWCallout& hwCallout) -> void {
338 calloutCount++;
339 std::stringstream keyPrefix;
340 keyPrefix << "HWP_HW_CO_" << std::setfill('0') << std::setw(2)
341 << calloutCount << "_";
342
343 ffdcUserData.emplace_back(
344 std::string(keyPrefix.str()).append("HW_ID"),
345 hwCallout.hwid);
346
347 ffdcUserData.emplace_back(
348 std::string(keyPrefix.str()).append("PRIORITY"),
349 hwCallout.callout_priority);
350
351 phal::TargetInfo targetInfo;
352 phal::getTgtReqAttrsVal(hwCallout.target_entity_path,
353 targetInfo);
354
355 std::string locationCode = std::string(targetInfo.locationCode);
356 ffdcUserData.emplace_back(
357 std::string(keyPrefix.str()).append("LOC_CODE"),
358 locationCode);
359
360 std::string physPath = std::string(targetInfo.physDevPath);
361 ffdcUserData.emplace_back(
362 std::string(keyPrefix.str()).append("PHYS_PATH"), physPath);
363
364 ffdcUserData.emplace_back(
365 std::string(keyPrefix.str()).append("CLK_POS"),
366 std::to_string(hwCallout.clkPos));
rajerpp1f928c4a2021-11-27 05:55:21 -0600367
368 ffdcUserData.emplace_back(
369 std::string(keyPrefix.str()).append("CALLOUT_PLANAR"),
370 (hwCallout.isPlanarCallout == true ? "true" : "false"));
371
372 std::string pelPriority =
373 getPelPriority(hwCallout.callout_priority);
374
375 if (hwCallout.isPlanarCallout)
376 {
377 addPlanarCallout(pelJSONFmtCalloutDataList, pelPriority);
378 }
Jayanth Othayoth4d779b22021-06-03 05:45:13 -0500379 });
380
381 // Adding CDG (callout, deconfigure and guard) targets details
382 calloutCount = 0;
383 for_each(
384 ffdc.hwp_errorinfo.cdg_targets.begin(),
385 ffdc.hwp_errorinfo.cdg_targets.end(),
386 [&ffdcUserData, &calloutCount,
387 &pelJSONFmtCalloutDataList](const CDG_Target& cdg_tgt) -> void {
388 calloutCount++;
389 std::stringstream keyPrefix;
390 keyPrefix << "HWP_CDG_TGT_" << std::setfill('0') << std::setw(2)
391 << calloutCount << "_";
392
393 phal::TargetInfo targetInfo;
394 targetInfo.deconfigure = cdg_tgt.deconfigure;
395
396 phal::getTgtReqAttrsVal(cdg_tgt.target_entity_path, targetInfo);
397
398 std::string locationCode = std::string(targetInfo.locationCode);
399 ffdcUserData.emplace_back(
400 std::string(keyPrefix.str()).append("LOC_CODE"),
401 locationCode);
402 std::string physPath = std::string(targetInfo.physDevPath);
403 ffdcUserData.emplace_back(
404 std::string(keyPrefix.str()).append("PHYS_PATH"), physPath);
405
406 ffdcUserData.emplace_back(
407 std::string(keyPrefix.str()).append("CO_REQ"),
408 (cdg_tgt.callout == true ? "true" : "false"));
409
410 ffdcUserData.emplace_back(
411 std::string(keyPrefix.str()).append("CO_PRIORITY"),
412 cdg_tgt.callout_priority);
413
414 ffdcUserData.emplace_back(
415 std::string(keyPrefix.str()).append("DECONF_REQ"),
416 (cdg_tgt.deconfigure == true ? "true" : "false"));
417
418 ffdcUserData.emplace_back(
419 std::string(keyPrefix.str()).append("GUARD_REQ"),
420 (cdg_tgt.guard == true ? "true" : "false"));
421
422 ffdcUserData.emplace_back(
423 std::string(keyPrefix.str()).append("GUARD_TYPE"),
424 cdg_tgt.guard_type);
425
426 json jsonCalloutData;
427 jsonCalloutData["LocationCode"] = locationCode;
428 std::string pelPriority =
429 getPelPriority(cdg_tgt.callout_priority);
430 jsonCalloutData["Priority"] = pelPriority;
431
432 if (targetInfo.mruId != 0)
433 {
434 jsonCalloutData["MRUs"] = json::array({
435 {{"ID", targetInfo.mruId}, {"Priority", pelPriority}},
436 });
437 }
438 jsonCalloutData["Deconfigured"] = cdg_tgt.deconfigure;
439 jsonCalloutData["Guarded"] = cdg_tgt.guard;
Jayanth Othayoth95205eb2021-11-08 06:21:30 -0600440 jsonCalloutData["GuardType"] = cdg_tgt.guard_type;
441 jsonCalloutData["EntityPath"] = cdg_tgt.target_entity_path;
Jayanth Othayoth4d779b22021-06-03 05:45:13 -0500442
443 pelJSONFmtCalloutDataList.emplace_back(jsonCalloutData);
444 });
Jayanth Othayoth9368b712021-11-17 01:03:42 -0600445
446 // Adding procedure callout
447 calloutCount = 0;
448 for_each(ffdc.hwp_errorinfo.procedures_callout.begin(),
449 ffdc.hwp_errorinfo.procedures_callout.end(),
450 [&ffdcUserData, &calloutCount, &pelJSONFmtCalloutDataList](
451 const ProcedureCallout& procCallout) -> void {
452 calloutCount++;
453 std::stringstream keyPrefix;
454 keyPrefix << "HWP_PROC_CO_" << std::setfill('0')
455 << std::setw(2) << calloutCount << "_";
456 ffdcUserData.emplace_back(
457 std::string(keyPrefix.str()).append("PRIORITY"),
458 procCallout.callout_priority);
459 ffdcUserData.emplace_back(
460 std::string(keyPrefix.str()).append("MAINT_PROCEDURE"),
461 procCallout.proc_callout);
462 json jsonCalloutData;
463 jsonCalloutData["Procedure"] = procCallout.proc_callout;
464 std::string pelPriority =
465 getPelPriority(procCallout.callout_priority);
466 jsonCalloutData["Priority"] = pelPriority;
467 pelJSONFmtCalloutDataList.emplace_back(jsonCalloutData);
468 });
Jayanth Othayoth4d779b22021-06-03 05:45:13 -0500469 }
470 else if ((ffdc.ffdc_type != FFDC_TYPE_NONE) &&
471 (ffdc.ffdc_type != FFDC_TYPE_UNSUPPORTED))
472 {
473 log<level::ERR>(fmt::format("Unsupported phal FFDC type to create PEL. "
474 "MSG: {}",
475 ffdc.message)
476 .c_str());
477 }
478}
479
480} // namespace phal
481} // namespace pels
482} // namespace openpower