blob: 88c869ee1d9881de431176012f40761cdda79a2f [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 Othayoth4d779b22021-06-03 05:45:13 -0500238void convertFAPItoPELformat(FFDC& ffdc, json& pelJSONFmtCalloutDataList,
239 FFDCData& ffdcUserData)
240{
241 if (ffdc.ffdc_type == FFDC_TYPE_HWP)
242 {
243 // Adding hardware procedures return code details
244 ffdcUserData.emplace_back("HWP_RC", ffdc.hwp_errorinfo.rc);
245 ffdcUserData.emplace_back("HWP_RC_DESC", ffdc.hwp_errorinfo.rc_desc);
246
247 // Adding hardware procedures required ffdc data for debug
248 for_each(
249 ffdc.hwp_errorinfo.ffdcs_data.begin(),
250 ffdc.hwp_errorinfo.ffdcs_data.end(),
251 [&ffdcUserData](std::pair<std::string, std::string>& ele) -> void {
252 std::string keyWithPrefix("HWP_FFDC_");
253 keyWithPrefix.append(ele.first);
254
255 ffdcUserData.emplace_back(keyWithPrefix, ele.second);
256 });
257
258 // Adding hardware callout details
259 int calloutCount = 0;
260 for_each(
261 ffdc.hwp_errorinfo.hwcallouts.begin(),
262 ffdc.hwp_errorinfo.hwcallouts.end(),
263 [&ffdcUserData, &calloutCount,
264 &pelJSONFmtCalloutDataList](const HWCallout& hwCallout) -> void {
265 calloutCount++;
266 std::stringstream keyPrefix;
267 keyPrefix << "HWP_HW_CO_" << std::setfill('0') << std::setw(2)
268 << calloutCount << "_";
269
270 ffdcUserData.emplace_back(
271 std::string(keyPrefix.str()).append("HW_ID"),
272 hwCallout.hwid);
273
274 ffdcUserData.emplace_back(
275 std::string(keyPrefix.str()).append("PRIORITY"),
276 hwCallout.callout_priority);
277
278 phal::TargetInfo targetInfo;
279 phal::getTgtReqAttrsVal(hwCallout.target_entity_path,
280 targetInfo);
281
282 std::string locationCode = std::string(targetInfo.locationCode);
283 ffdcUserData.emplace_back(
284 std::string(keyPrefix.str()).append("LOC_CODE"),
285 locationCode);
286
287 std::string physPath = std::string(targetInfo.physDevPath);
288 ffdcUserData.emplace_back(
289 std::string(keyPrefix.str()).append("PHYS_PATH"), physPath);
290
291 ffdcUserData.emplace_back(
292 std::string(keyPrefix.str()).append("CLK_POS"),
293 std::to_string(hwCallout.clkPos));
rajerpp1f928c4a2021-11-27 05:55:21 -0600294
295 ffdcUserData.emplace_back(
296 std::string(keyPrefix.str()).append("CALLOUT_PLANAR"),
297 (hwCallout.isPlanarCallout == true ? "true" : "false"));
298
299 std::string pelPriority =
300 getPelPriority(hwCallout.callout_priority);
301
302 if (hwCallout.isPlanarCallout)
303 {
304 addPlanarCallout(pelJSONFmtCalloutDataList, pelPriority);
305 }
Jayanth Othayoth4d779b22021-06-03 05:45:13 -0500306 });
307
308 // Adding CDG (callout, deconfigure and guard) targets details
309 calloutCount = 0;
310 for_each(
311 ffdc.hwp_errorinfo.cdg_targets.begin(),
312 ffdc.hwp_errorinfo.cdg_targets.end(),
313 [&ffdcUserData, &calloutCount,
314 &pelJSONFmtCalloutDataList](const CDG_Target& cdg_tgt) -> void {
315 calloutCount++;
316 std::stringstream keyPrefix;
317 keyPrefix << "HWP_CDG_TGT_" << std::setfill('0') << std::setw(2)
318 << calloutCount << "_";
319
320 phal::TargetInfo targetInfo;
321 targetInfo.deconfigure = cdg_tgt.deconfigure;
322
323 phal::getTgtReqAttrsVal(cdg_tgt.target_entity_path, targetInfo);
324
325 std::string locationCode = std::string(targetInfo.locationCode);
326 ffdcUserData.emplace_back(
327 std::string(keyPrefix.str()).append("LOC_CODE"),
328 locationCode);
329 std::string physPath = std::string(targetInfo.physDevPath);
330 ffdcUserData.emplace_back(
331 std::string(keyPrefix.str()).append("PHYS_PATH"), physPath);
332
333 ffdcUserData.emplace_back(
334 std::string(keyPrefix.str()).append("CO_REQ"),
335 (cdg_tgt.callout == true ? "true" : "false"));
336
337 ffdcUserData.emplace_back(
338 std::string(keyPrefix.str()).append("CO_PRIORITY"),
339 cdg_tgt.callout_priority);
340
341 ffdcUserData.emplace_back(
342 std::string(keyPrefix.str()).append("DECONF_REQ"),
343 (cdg_tgt.deconfigure == true ? "true" : "false"));
344
345 ffdcUserData.emplace_back(
346 std::string(keyPrefix.str()).append("GUARD_REQ"),
347 (cdg_tgt.guard == true ? "true" : "false"));
348
349 ffdcUserData.emplace_back(
350 std::string(keyPrefix.str()).append("GUARD_TYPE"),
351 cdg_tgt.guard_type);
352
353 json jsonCalloutData;
354 jsonCalloutData["LocationCode"] = locationCode;
355 std::string pelPriority =
356 getPelPriority(cdg_tgt.callout_priority);
357 jsonCalloutData["Priority"] = pelPriority;
358
359 if (targetInfo.mruId != 0)
360 {
361 jsonCalloutData["MRUs"] = json::array({
362 {{"ID", targetInfo.mruId}, {"Priority", pelPriority}},
363 });
364 }
365 jsonCalloutData["Deconfigured"] = cdg_tgt.deconfigure;
366 jsonCalloutData["Guarded"] = cdg_tgt.guard;
Jayanth Othayoth95205eb2021-11-08 06:21:30 -0600367 jsonCalloutData["GuardType"] = cdg_tgt.guard_type;
368 jsonCalloutData["EntityPath"] = cdg_tgt.target_entity_path;
Jayanth Othayoth4d779b22021-06-03 05:45:13 -0500369
370 pelJSONFmtCalloutDataList.emplace_back(jsonCalloutData);
371 });
Jayanth Othayoth9368b712021-11-17 01:03:42 -0600372
373 // Adding procedure callout
374 calloutCount = 0;
375 for_each(ffdc.hwp_errorinfo.procedures_callout.begin(),
376 ffdc.hwp_errorinfo.procedures_callout.end(),
377 [&ffdcUserData, &calloutCount, &pelJSONFmtCalloutDataList](
378 const ProcedureCallout& procCallout) -> void {
379 calloutCount++;
380 std::stringstream keyPrefix;
381 keyPrefix << "HWP_PROC_CO_" << std::setfill('0')
382 << std::setw(2) << calloutCount << "_";
383 ffdcUserData.emplace_back(
384 std::string(keyPrefix.str()).append("PRIORITY"),
385 procCallout.callout_priority);
386 ffdcUserData.emplace_back(
387 std::string(keyPrefix.str()).append("MAINT_PROCEDURE"),
388 procCallout.proc_callout);
389 json jsonCalloutData;
390 jsonCalloutData["Procedure"] = procCallout.proc_callout;
391 std::string pelPriority =
392 getPelPriority(procCallout.callout_priority);
393 jsonCalloutData["Priority"] = pelPriority;
394 pelJSONFmtCalloutDataList.emplace_back(jsonCalloutData);
395 });
Jayanth Othayoth4d779b22021-06-03 05:45:13 -0500396 }
397 else if ((ffdc.ffdc_type != FFDC_TYPE_NONE) &&
398 (ffdc.ffdc_type != FFDC_TYPE_UNSUPPORTED))
399 {
400 log<level::ERR>(fmt::format("Unsupported phal FFDC type to create PEL. "
401 "MSG: {}",
402 ffdc.message)
403 .c_str());
404 }
405}
406
407} // namespace phal
408} // namespace pels
409} // namespace openpower