blob: 68230be252e6f8b08163e5b6d812895fcce5fbf9 [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>
9
10#include <algorithm>
11#include <cstdlib>
12#include <cstring>
13#include <iomanip>
14#include <list>
15#include <map>
16#include <phosphor-logging/elog.hpp>
17#include <sstream>
18#include <string>
19
20namespace openpower
21{
22namespace pels
23{
24namespace phal
25{
26
27using namespace phosphor::logging;
28
29/**
30 * Used to pass buffer to pdbg callback api to get required target
31 * data (attributes) based on given data (attribute).
32 */
33struct TargetInfo
34{
35 ATTR_PHYS_BIN_PATH_Type physBinPath;
36 ATTR_LOCATION_CODE_Type locationCode;
37 ATTR_PHYS_DEV_PATH_Type physDevPath;
38 ATTR_MRU_ID_Type mruId;
39
40 bool deconfigure;
41
42 TargetInfo()
43 {
44 memset(&physBinPath, '\0', sizeof(physBinPath));
45 memset(&locationCode, '\0', sizeof(locationCode));
46 memset(&physDevPath, '\0', sizeof(physDevPath));
47 mruId = 0;
48 deconfigure = false;
49 }
50};
51
52/**
53 * Used to return in callback function which are used to get
54 * physical path value and it binary format value.
55 *
56 * The value for constexpr defined based on pdbg_target_traverse function usage.
57 */
58constexpr int continueTgtTraversal = 0;
59constexpr int requireAttrFound = 1;
60constexpr int requireAttrNotFound = 2;
61
62/**
63 * @brief Used to get target location code from phal device tree
64 *
65 * @param[in] target current device tree target
66 * @param[out] appPrivData used for accessing|storing from|to application
67 *
68 * @return 0 to continue traverse, non-zero to stop traverse
69 */
70int pdbgCallbackToGetTgtReqAttrsVal(struct pdbg_target* target,
71 void* appPrivData)
72{
73 TargetInfo* targetInfo = static_cast<TargetInfo*>(appPrivData);
74
75 ATTR_PHYS_BIN_PATH_Type physBinPath;
76 /**
77 * TODO: Issue: phal/pdata#16
78 * Should not use direct pdbg api to read attribute. Need to use DT_GET_PROP
79 * macro for bmc app's and this will call libdt-api api but, it will print
80 * "pdbg_target_get_attribute failed" trace if attribute is not found and
81 * this callback will call recursively by using pdbg_target_traverse() until
82 * find expected attribute based on return code from this callback. Because,
83 * need to do target iteration to get actual attribute (ATTR_PHYS_BIN_PATH)
84 * value when device tree target info doesn't know to read attribute from
85 * device tree. So, Due to this error trace user will get confusion while
86 * looking traces. Hence using pdbg api to avoid trace until libdt-api
87 * provides log level setup.
88 */
89 if (!pdbg_target_get_attribute(
90 target, "ATTR_PHYS_BIN_PATH",
91 std::stoi(dtAttr::fapi2::ATTR_PHYS_BIN_PATH_Spec),
92 dtAttr::fapi2::ATTR_PHYS_BIN_PATH_ElementCount, physBinPath))
93 {
94 return continueTgtTraversal;
95 }
96
97 if (std::memcmp(physBinPath, targetInfo->physBinPath,
98 sizeof(physBinPath)) != 0)
99 {
100 return continueTgtTraversal;
101 }
102
103 if (DT_GET_PROP(ATTR_LOCATION_CODE, target, targetInfo->locationCode))
104 {
105 log<level::ERR>("Could not read LOCATION_CODE attribute");
106 return requireAttrNotFound;
107 }
108
109 if (DT_GET_PROP(ATTR_PHYS_DEV_PATH, target, targetInfo->physDevPath))
110 {
111 log<level::ERR>("Could not read PHYS_DEV_PATH attribute");
112 return requireAttrNotFound;
113 }
114
115 if (DT_GET_PROP(ATTR_MRU_ID, target, targetInfo->mruId))
116 {
117 log<level::ERR>("Could not read MRU_ID attribute");
118 return requireAttrNotFound;
119 }
120
121 if (targetInfo->deconfigure)
122 {
123 ATTR_HWAS_STATE_Type hwasState;
124 if (DT_GET_PROP(ATTR_HWAS_STATE, target, hwasState))
125 {
126 log<level::ERR>("Could not read HWAS_STATE attribute");
127 return requireAttrNotFound;
128 }
129
130 log<level::INFO>(fmt::format("Marking target({}) as Non-Functional",
131 targetInfo->physDevPath)
132 .c_str());
133 hwasState.functional = 0;
134
135 if (DT_SET_PROP(ATTR_HWAS_STATE, target, hwasState))
136 {
137 log<level::ERR>("Could not write HWAS_STATE attribute");
138 return requireAttrNotFound;
139 }
140 }
141
142 return requireAttrFound;
143}
144
145/**
146 * @brief Used to get target info (attributes data)
147 *
148 * To get target required attributes value using another attribute value
149 * ("PHYS_BIN_PATH" which is present in same target attributes list) by using
150 * "ipdbg_target_traverse" api because, here we have attribute value only and
151 * doesn't have respective device tree target info to get required attributes
152 * values from it attributes list.
153 *
154 * @param[in] physBinPath to pass PHYS_BIN_PATH value
155 * @param[out] targetInfo to pas buufer to fill with required attributes
156 *
157 * @return true on success otherwise false
158 */
159bool getTgtReqAttrsVal(const std::vector<uint8_t>& physBinPath,
160 TargetInfo& targetInfo)
161{
162 std::memcpy(&targetInfo.physBinPath, physBinPath.data(),
163 sizeof(targetInfo.physBinPath));
164
165 int ret = pdbg_target_traverse(NULL, pdbgCallbackToGetTgtReqAttrsVal,
166 &targetInfo);
167 if (ret == 0)
168 {
169 log<level::ERR>(fmt::format("Given ATTR_PHYS_BIN_PATH value({}) "
170 "not found in phal device tree",
171 targetInfo.physBinPath)
172 .c_str());
173 return false;
174 }
175 else if (ret == requireAttrNotFound)
176 {
177 return false;
178 }
179
180 return true;
181}
182
183/**
184 * @brief GET PEL priority from pHAL priority
185 *
186 * The pHAL callout priority is in different format than PEL format
187 * so, this api is used to return current phal supported priority into
188 * PEL expected format.
189 *
190 * @param[in] phalPriority used to pass phal priority format string
191 *
192 * @return pel priority format string else empty if failure
193 *
194 * @note For "NONE" returning "L" (LOW)
195 */
196static std::string getPelPriority(const std::string& phalPriority)
197{
198 const std::map<std::string, std::string> priorityMap = {
199 {"HIGH", "H"}, {"MEDIUM", "M"}, {"LOW", "L"}, {"NONE", "L"}};
200
201 auto it = priorityMap.find(phalPriority);
202 if (it == priorityMap.end())
203 {
204 log<level::ERR>(fmt::format("Unsupported phal priority({}) is given "
205 "to get pel priority format",
206 phalPriority)
207 .c_str());
208 return "H";
209 }
210
211 return it->second;
212}
213
214void convertFAPItoPELformat(FFDC& ffdc, json& pelJSONFmtCalloutDataList,
215 FFDCData& ffdcUserData)
216{
217 if (ffdc.ffdc_type == FFDC_TYPE_HWP)
218 {
219 // Adding hardware procedures return code details
220 ffdcUserData.emplace_back("HWP_RC", ffdc.hwp_errorinfo.rc);
221 ffdcUserData.emplace_back("HWP_RC_DESC", ffdc.hwp_errorinfo.rc_desc);
222
223 // Adding hardware procedures required ffdc data for debug
224 for_each(
225 ffdc.hwp_errorinfo.ffdcs_data.begin(),
226 ffdc.hwp_errorinfo.ffdcs_data.end(),
227 [&ffdcUserData](std::pair<std::string, std::string>& ele) -> void {
228 std::string keyWithPrefix("HWP_FFDC_");
229 keyWithPrefix.append(ele.first);
230
231 ffdcUserData.emplace_back(keyWithPrefix, ele.second);
232 });
233
234 // Adding hardware callout details
235 int calloutCount = 0;
236 for_each(
237 ffdc.hwp_errorinfo.hwcallouts.begin(),
238 ffdc.hwp_errorinfo.hwcallouts.end(),
239 [&ffdcUserData, &calloutCount,
240 &pelJSONFmtCalloutDataList](const HWCallout& hwCallout) -> void {
241 calloutCount++;
242 std::stringstream keyPrefix;
243 keyPrefix << "HWP_HW_CO_" << std::setfill('0') << std::setw(2)
244 << calloutCount << "_";
245
246 ffdcUserData.emplace_back(
247 std::string(keyPrefix.str()).append("HW_ID"),
248 hwCallout.hwid);
249
250 ffdcUserData.emplace_back(
251 std::string(keyPrefix.str()).append("PRIORITY"),
252 hwCallout.callout_priority);
253
254 phal::TargetInfo targetInfo;
255 phal::getTgtReqAttrsVal(hwCallout.target_entity_path,
256 targetInfo);
257
258 std::string locationCode = std::string(targetInfo.locationCode);
259 ffdcUserData.emplace_back(
260 std::string(keyPrefix.str()).append("LOC_CODE"),
261 locationCode);
262
263 std::string physPath = std::string(targetInfo.physDevPath);
264 ffdcUserData.emplace_back(
265 std::string(keyPrefix.str()).append("PHYS_PATH"), physPath);
266
267 ffdcUserData.emplace_back(
268 std::string(keyPrefix.str()).append("CLK_POS"),
269 std::to_string(hwCallout.clkPos));
270
271 json jsonCalloutData;
272 jsonCalloutData["LocationCode"] = locationCode;
273 std::string pelPriority =
274 getPelPriority(hwCallout.callout_priority);
275 jsonCalloutData["Priority"] = pelPriority;
276
277 if (targetInfo.mruId != 0)
278 {
279 jsonCalloutData["MRUs"] = json::array({
280 {{"ID", targetInfo.mruId}, {"Priority", pelPriority}},
281 });
282 }
283
284 pelJSONFmtCalloutDataList.emplace_back(jsonCalloutData);
285 });
286
287 // Adding CDG (callout, deconfigure and guard) targets details
288 calloutCount = 0;
289 for_each(
290 ffdc.hwp_errorinfo.cdg_targets.begin(),
291 ffdc.hwp_errorinfo.cdg_targets.end(),
292 [&ffdcUserData, &calloutCount,
293 &pelJSONFmtCalloutDataList](const CDG_Target& cdg_tgt) -> void {
294 calloutCount++;
295 std::stringstream keyPrefix;
296 keyPrefix << "HWP_CDG_TGT_" << std::setfill('0') << std::setw(2)
297 << calloutCount << "_";
298
299 phal::TargetInfo targetInfo;
300 targetInfo.deconfigure = cdg_tgt.deconfigure;
301
302 phal::getTgtReqAttrsVal(cdg_tgt.target_entity_path, targetInfo);
303
304 std::string locationCode = std::string(targetInfo.locationCode);
305 ffdcUserData.emplace_back(
306 std::string(keyPrefix.str()).append("LOC_CODE"),
307 locationCode);
308 std::string physPath = std::string(targetInfo.physDevPath);
309 ffdcUserData.emplace_back(
310 std::string(keyPrefix.str()).append("PHYS_PATH"), physPath);
311
312 ffdcUserData.emplace_back(
313 std::string(keyPrefix.str()).append("CO_REQ"),
314 (cdg_tgt.callout == true ? "true" : "false"));
315
316 ffdcUserData.emplace_back(
317 std::string(keyPrefix.str()).append("CO_PRIORITY"),
318 cdg_tgt.callout_priority);
319
320 ffdcUserData.emplace_back(
321 std::string(keyPrefix.str()).append("DECONF_REQ"),
322 (cdg_tgt.deconfigure == true ? "true" : "false"));
323
324 ffdcUserData.emplace_back(
325 std::string(keyPrefix.str()).append("GUARD_REQ"),
326 (cdg_tgt.guard == true ? "true" : "false"));
327
328 ffdcUserData.emplace_back(
329 std::string(keyPrefix.str()).append("GUARD_TYPE"),
330 cdg_tgt.guard_type);
331
332 json jsonCalloutData;
333 jsonCalloutData["LocationCode"] = locationCode;
334 std::string pelPriority =
335 getPelPriority(cdg_tgt.callout_priority);
336 jsonCalloutData["Priority"] = pelPriority;
337
338 if (targetInfo.mruId != 0)
339 {
340 jsonCalloutData["MRUs"] = json::array({
341 {{"ID", targetInfo.mruId}, {"Priority", pelPriority}},
342 });
343 }
344 jsonCalloutData["Deconfigured"] = cdg_tgt.deconfigure;
345 jsonCalloutData["Guarded"] = cdg_tgt.guard;
346
347 pelJSONFmtCalloutDataList.emplace_back(jsonCalloutData);
348 });
349 }
350 else if ((ffdc.ffdc_type != FFDC_TYPE_NONE) &&
351 (ffdc.ffdc_type != FFDC_TYPE_UNSUPPORTED))
352 {
353 log<level::ERR>(fmt::format("Unsupported phal FFDC type to create PEL. "
354 "MSG: {}",
355 ffdc.message)
356 .c_str());
357 }
358}
359
360} // namespace phal
361} // namespace pels
362} // namespace openpower