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 14 #include <algorithm> 15 #include <cstdlib> 16 #include <cstring> 17 #include <format> 18 #include <iomanip> 19 #include <list> 20 #include <map> 21 #include <sstream> 22 #include <string> 23 24 namespace openpower 25 { 26 namespace pels 27 { 28 namespace phal 29 { 30 31 using namespace phosphor::logging; 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 log<level::ERR>(std::format("getLocationCode({}): Exception({})", 124 pdbg_target_path(target), e.what()) 125 .c_str()); 126 } 127 128 if (DT_GET_PROP(ATTR_PHYS_DEV_PATH, target, targetInfo->physDevPath)) 129 { 130 log<level::ERR>( 131 std::format("Could not read({}) PHYS_DEV_PATH attribute", 132 pdbg_target_path(target)) 133 .c_str()); 134 } 135 136 if (DT_GET_PROP(ATTR_MRU_ID, target, targetInfo->mruId)) 137 { 138 log<level::ERR>(std::format("Could not read({}) ATTR_MRU_ID attribute", 139 pdbg_target_path(target)) 140 .c_str()); 141 } 142 143 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 */ 160 bool 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 { 170 std::string fmt; 171 for (auto value : targetInfo.physBinPath) 172 { 173 fmt += std::format("{:02X} ", value); 174 } 175 176 log<level::ERR>(std::format("Given ATTR_PHYS_BIN_PATH value {} " 177 "not found in phal device tree", 178 fmt) 179 .c_str()); 180 return false; 181 } 182 else if (ret == requireAttrNotFound) 183 { 184 return false; 185 } 186 187 return true; 188 } 189 190 /** 191 * @brief GET PEL priority from pHAL priority 192 * 193 * The pHAL callout priority is in different format than PEL format 194 * so, this api is used to return current phal supported priority into 195 * PEL expected format. 196 * 197 * @param[in] phalPriority used to pass phal priority format string 198 * 199 * @return pel priority format string else empty if failure 200 * 201 * @note For "NONE" returning "L" (LOW) 202 */ 203 static std::string getPelPriority(const std::string& phalPriority) 204 { 205 const std::map<std::string, std::string> priorityMap = { 206 {"HIGH", "H"}, {"MEDIUM", "M"}, {"LOW", "L"}, {"NONE", "L"}}; 207 208 auto it = priorityMap.find(phalPriority); 209 if (it == priorityMap.end()) 210 { 211 log<level::ERR>(std::format("Unsupported phal priority({}) is given " 212 "to get pel priority format", 213 phalPriority) 214 .c_str()); 215 return "H"; 216 } 217 218 return it->second; 219 } 220 221 /** 222 * @brief addPlanarCallout 223 * 224 * This function will add a json for planar callout in the input json list. 225 * The caller can pass this json list into createErrorPEL to apply the callout. 226 * 227 * @param[in,out] jsonCalloutDataList - json list where callout json will be 228 * emplaced 229 * @param[in] priority - string indicating priority. 230 */ 231 static void addPlanarCallout(json& jsonCalloutDataList, 232 const std::string& priority) 233 { 234 json jsonCalloutData; 235 236 // Inventory path for planar 237 jsonCalloutData["InventoryPath"] = 238 "/xyz/openbmc_project/inventory/system/chassis/motherboard"; 239 jsonCalloutData["Deconfigured"] = false; 240 jsonCalloutData["Guarded"] = false; 241 jsonCalloutData["Priority"] = priority; 242 243 jsonCalloutDataList.emplace_back(jsonCalloutData); 244 } 245 246 /** 247 * @brief processClockInfoErrorHelper 248 * 249 * Creates informational PEL for spare clock failure 250 * 251 * @param[in] ffdc FFDC data capturd by the HWP 252 * @param[out] pelJSONFmtCalloutDataList used to store collected callout 253 * data into pel expected format 254 * @param[out] ffdcUserData used to store additional ffdc user data to 255 * provided by the SBE FFDC packet. 256 * 257 * @return NULL 258 * 259 **/ 260 void processClockInfoErrorHelper(const FFDC& ffdc, 261 json& pelJSONFmtCalloutDataList, 262 FFDCData& ffdcUserData) 263 { 264 log<level::INFO>( 265 std::format("processClockInfoErrorHelper: FFDC Message[{}]", 266 ffdc.message) 267 .c_str()); 268 269 // Adding hardware procedures return code details 270 ffdcUserData.emplace_back("HWP_RC", ffdc.hwp_errorinfo.rc); 271 ffdcUserData.emplace_back("HWP_RC_DESC", ffdc.hwp_errorinfo.rc_desc); 272 273 // Adding hardware procedures required ffdc data for debug 274 for_each(ffdc.hwp_errorinfo.ffdcs_data.cbegin(), 275 ffdc.hwp_errorinfo.ffdcs_data.cend(), 276 [&ffdcUserData]( 277 const std::pair<std::string, std::string>& ele) -> void { 278 std::string keyWithPrefix("HWP_FFDC_"); 279 keyWithPrefix.append(ele.first); 280 281 ffdcUserData.emplace_back(keyWithPrefix, ele.second); 282 }); 283 // get clock position information 284 auto clk_pos = 0xFF; // Invalid position. 285 for (auto& hwCallout : ffdc.hwp_errorinfo.hwcallouts) 286 { 287 if ((hwCallout.hwid == "PROC_REF_CLOCK") || 288 (hwCallout.hwid == "PCI_REF_CLOCK")) 289 { 290 clk_pos = hwCallout.clkPos; 291 break; 292 } 293 } 294 // Adding CDG (Only deconfigure) targets details 295 for_each(ffdc.hwp_errorinfo.cdg_targets.begin(), 296 ffdc.hwp_errorinfo.cdg_targets.end(), 297 [&ffdcUserData, &pelJSONFmtCalloutDataList, 298 clk_pos](const CDG_Target& cdg_tgt) -> void { 299 json jsonCalloutData; 300 std::string pelPriority = "H"; 301 jsonCalloutData["Priority"] = pelPriority; // Not used 302 jsonCalloutData["SymbolicFRU"] = "REFCLK" + std::to_string(clk_pos); 303 jsonCalloutData["Deconfigured"] = cdg_tgt.deconfigure; 304 jsonCalloutData["EntityPath"] = cdg_tgt.target_entity_path; 305 pelJSONFmtCalloutDataList.emplace_back(jsonCalloutData); 306 }); 307 } 308 309 void convertFAPItoPELformat(FFDC& ffdc, json& pelJSONFmtCalloutDataList, 310 FFDCData& ffdcUserData) 311 { 312 if (ffdc.ffdc_type == FFDC_TYPE_SPARE_CLOCK_INFO) 313 { 314 processClockInfoErrorHelper(ffdc, pelJSONFmtCalloutDataList, 315 ffdcUserData); 316 return; 317 } 318 319 if (ffdc.ffdc_type == FFDC_TYPE_HWP) 320 { 321 // Adding hardware procedures return code details 322 ffdcUserData.emplace_back("HWP_RC", ffdc.hwp_errorinfo.rc); 323 ffdcUserData.emplace_back("HWP_RC_DESC", ffdc.hwp_errorinfo.rc_desc); 324 325 // Adding hardware procedures required ffdc data for debug 326 for_each( 327 ffdc.hwp_errorinfo.ffdcs_data.begin(), 328 ffdc.hwp_errorinfo.ffdcs_data.end(), 329 [&ffdcUserData](std::pair<std::string, std::string>& ele) -> void { 330 std::string keyWithPrefix("HWP_FFDC_"); 331 keyWithPrefix.append(ele.first); 332 333 ffdcUserData.emplace_back(keyWithPrefix, ele.second); 334 }); 335 336 // Adding hardware callout details 337 int calloutCount = 0; 338 for_each(ffdc.hwp_errorinfo.hwcallouts.begin(), 339 ffdc.hwp_errorinfo.hwcallouts.end(), 340 [&ffdcUserData, &calloutCount, &pelJSONFmtCalloutDataList]( 341 const HWCallout& hwCallout) -> void { 342 calloutCount++; 343 std::stringstream keyPrefix; 344 keyPrefix << "HWP_HW_CO_" << std::setfill('0') << std::setw(2) 345 << calloutCount << "_"; 346 347 ffdcUserData.emplace_back( 348 std::string(keyPrefix.str()).append("HW_ID"), hwCallout.hwid); 349 350 ffdcUserData.emplace_back( 351 std::string(keyPrefix.str()).append("PRIORITY"), 352 hwCallout.callout_priority); 353 354 phal::TargetInfo targetInfo; 355 phal::getTgtReqAttrsVal(hwCallout.target_entity_path, targetInfo); 356 357 std::string locationCode = std::string(targetInfo.locationCode); 358 ffdcUserData.emplace_back( 359 std::string(keyPrefix.str()).append("LOC_CODE"), locationCode); 360 361 std::string physPath = std::string(targetInfo.physDevPath); 362 ffdcUserData.emplace_back( 363 std::string(keyPrefix.str()).append("PHYS_PATH"), physPath); 364 365 ffdcUserData.emplace_back( 366 std::string(keyPrefix.str()).append("CLK_POS"), 367 std::to_string(hwCallout.clkPos)); 368 369 ffdcUserData.emplace_back( 370 std::string(keyPrefix.str()).append("CALLOUT_PLANAR"), 371 (hwCallout.isPlanarCallout == true ? "true" : "false")); 372 373 std::string pelPriority = 374 getPelPriority(hwCallout.callout_priority); 375 376 if (hwCallout.isPlanarCallout) 377 { 378 addPlanarCallout(pelJSONFmtCalloutDataList, pelPriority); 379 } 380 }); 381 382 // Adding CDG (callout, deconfigure and guard) targets details 383 calloutCount = 0; 384 for_each(ffdc.hwp_errorinfo.cdg_targets.begin(), 385 ffdc.hwp_errorinfo.cdg_targets.end(), 386 [&ffdcUserData, &calloutCount, &pelJSONFmtCalloutDataList]( 387 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"), locationCode); 401 std::string physPath = std::string(targetInfo.physDevPath); 402 ffdcUserData.emplace_back( 403 std::string(keyPrefix.str()).append("PHYS_PATH"), physPath); 404 405 ffdcUserData.emplace_back( 406 std::string(keyPrefix.str()).append("CO_REQ"), 407 (cdg_tgt.callout == true ? "true" : "false")); 408 409 ffdcUserData.emplace_back( 410 std::string(keyPrefix.str()).append("CO_PRIORITY"), 411 cdg_tgt.callout_priority); 412 413 ffdcUserData.emplace_back( 414 std::string(keyPrefix.str()).append("DECONF_REQ"), 415 (cdg_tgt.deconfigure == true ? "true" : "false")); 416 417 ffdcUserData.emplace_back( 418 std::string(keyPrefix.str()).append("GUARD_REQ"), 419 (cdg_tgt.guard == true ? "true" : "false")); 420 421 ffdcUserData.emplace_back( 422 std::string(keyPrefix.str()).append("GUARD_TYPE"), 423 cdg_tgt.guard_type); 424 425 json jsonCalloutData; 426 jsonCalloutData["LocationCode"] = locationCode; 427 std::string pelPriority = getPelPriority(cdg_tgt.callout_priority); 428 jsonCalloutData["Priority"] = pelPriority; 429 430 if (targetInfo.mruId != 0) 431 { 432 jsonCalloutData["MRUs"] = json::array({ 433 {{"ID", targetInfo.mruId}, {"Priority", pelPriority}}, 434 }); 435 } 436 jsonCalloutData["Deconfigured"] = cdg_tgt.deconfigure; 437 jsonCalloutData["Guarded"] = cdg_tgt.guard; 438 jsonCalloutData["GuardType"] = cdg_tgt.guard_type; 439 jsonCalloutData["EntityPath"] = cdg_tgt.target_entity_path; 440 441 pelJSONFmtCalloutDataList.emplace_back(jsonCalloutData); 442 }); 443 444 // Adding procedure callout 445 calloutCount = 0; 446 for_each(ffdc.hwp_errorinfo.procedures_callout.begin(), 447 ffdc.hwp_errorinfo.procedures_callout.end(), 448 [&ffdcUserData, &calloutCount, &pelJSONFmtCalloutDataList]( 449 const ProcedureCallout& procCallout) -> void { 450 calloutCount++; 451 std::stringstream keyPrefix; 452 keyPrefix << "HWP_PROC_CO_" << std::setfill('0') << std::setw(2) 453 << calloutCount << "_"; 454 ffdcUserData.emplace_back( 455 std::string(keyPrefix.str()).append("PRIORITY"), 456 procCallout.callout_priority); 457 ffdcUserData.emplace_back( 458 std::string(keyPrefix.str()).append("MAINT_PROCEDURE"), 459 procCallout.proc_callout); 460 json jsonCalloutData; 461 jsonCalloutData["Procedure"] = procCallout.proc_callout; 462 std::string pelPriority = 463 getPelPriority(procCallout.callout_priority); 464 jsonCalloutData["Priority"] = pelPriority; 465 pelJSONFmtCalloutDataList.emplace_back(jsonCalloutData); 466 }); 467 } 468 else if ((ffdc.ffdc_type != FFDC_TYPE_NONE) && 469 (ffdc.ffdc_type != FFDC_TYPE_UNSUPPORTED)) 470 { 471 log<level::ERR>(std::format("Unsupported phal FFDC type to create PEL. " 472 "MSG: {}", 473 ffdc.message) 474 .c_str()); 475 } 476 } 477 478 } // namespace phal 479 } // namespace pels 480 } // namespace openpower 481