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