1 extern "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 #include <libphal.H> 10 #include <phal_exception.H> 11 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 22 namespace openpower 23 { 24 namespace pels 25 { 26 namespace phal 27 { 28 29 using namespace phosphor::logging; 30 using namespace openpower::phal::exception; 31 32 /** 33 * Used to pass buffer to pdbg callback api to get required target 34 * data (attributes) based on given data (attribute). 35 */ 36 struct 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 */ 61 constexpr int continueTgtTraversal = 0; 62 constexpr int requireAttrFound = 1; 63 constexpr 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 */ 73 int pdbgCallbackToGetTgtReqAttrsVal(struct pdbg_target* target, 74 void* appPrivData) 75 { 76 using namespace openpower::phal::pdbg; 77 78 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 108 try 109 { 110 // Get location code information 111 openpower::phal::pdbg::getLocationCode(target, 112 targetInfo->locationCode); 113 } 114 catch (const std::exception& e) 115 { 116 // log message and continue with default data 117 log<level::ERR>(fmt::format("getLocationCode({}): Exception({})", 118 pdbg_target_path(target), e.what()) 119 .c_str()); 120 } 121 122 if (DT_GET_PROP(ATTR_PHYS_DEV_PATH, target, targetInfo->physDevPath)) 123 { 124 log<level::ERR>("Could not read PHYS_DEV_PATH attribute"); 125 return requireAttrNotFound; 126 } 127 128 if (DT_GET_PROP(ATTR_MRU_ID, target, targetInfo->mruId)) 129 { 130 log<level::ERR>("Could not read MRU_ID attribute"); 131 return requireAttrNotFound; 132 } 133 134 return requireAttrFound; 135 } 136 137 /** 138 * @brief Used to get target info (attributes data) 139 * 140 * To get target required attributes value using another attribute value 141 * ("PHYS_BIN_PATH" which is present in same target attributes list) by using 142 * "ipdbg_target_traverse" api because, here we have attribute value only and 143 * doesn't have respective device tree target info to get required attributes 144 * values from it attributes list. 145 * 146 * @param[in] physBinPath to pass PHYS_BIN_PATH value 147 * @param[out] targetInfo to pas buufer to fill with required attributes 148 * 149 * @return true on success otherwise false 150 */ 151 bool getTgtReqAttrsVal(const std::vector<uint8_t>& physBinPath, 152 TargetInfo& targetInfo) 153 { 154 std::memcpy(&targetInfo.physBinPath, physBinPath.data(), 155 sizeof(targetInfo.physBinPath)); 156 157 int ret = pdbg_target_traverse(NULL, pdbgCallbackToGetTgtReqAttrsVal, 158 &targetInfo); 159 if (ret == 0) 160 { 161 log<level::ERR>(fmt::format("Given ATTR_PHYS_BIN_PATH value({}) " 162 "not found in phal device tree", 163 targetInfo.physBinPath) 164 .c_str()); 165 return false; 166 } 167 else if (ret == requireAttrNotFound) 168 { 169 return false; 170 } 171 172 return true; 173 } 174 175 /** 176 * @brief GET PEL priority from pHAL priority 177 * 178 * The pHAL callout priority is in different format than PEL format 179 * so, this api is used to return current phal supported priority into 180 * PEL expected format. 181 * 182 * @param[in] phalPriority used to pass phal priority format string 183 * 184 * @return pel priority format string else empty if failure 185 * 186 * @note For "NONE" returning "L" (LOW) 187 */ 188 static std::string getPelPriority(const std::string& phalPriority) 189 { 190 const std::map<std::string, std::string> priorityMap = { 191 {"HIGH", "H"}, {"MEDIUM", "M"}, {"LOW", "L"}, {"NONE", "L"}}; 192 193 auto it = priorityMap.find(phalPriority); 194 if (it == priorityMap.end()) 195 { 196 log<level::ERR>(fmt::format("Unsupported phal priority({}) is given " 197 "to get pel priority format", 198 phalPriority) 199 .c_str()); 200 return "H"; 201 } 202 203 return it->second; 204 } 205 206 void convertFAPItoPELformat(FFDC& ffdc, json& pelJSONFmtCalloutDataList, 207 FFDCData& ffdcUserData) 208 { 209 if (ffdc.ffdc_type == FFDC_TYPE_HWP) 210 { 211 // Adding hardware procedures return code details 212 ffdcUserData.emplace_back("HWP_RC", ffdc.hwp_errorinfo.rc); 213 ffdcUserData.emplace_back("HWP_RC_DESC", ffdc.hwp_errorinfo.rc_desc); 214 215 // Adding hardware procedures required ffdc data for debug 216 for_each( 217 ffdc.hwp_errorinfo.ffdcs_data.begin(), 218 ffdc.hwp_errorinfo.ffdcs_data.end(), 219 [&ffdcUserData](std::pair<std::string, std::string>& ele) -> void { 220 std::string keyWithPrefix("HWP_FFDC_"); 221 keyWithPrefix.append(ele.first); 222 223 ffdcUserData.emplace_back(keyWithPrefix, ele.second); 224 }); 225 226 // Adding hardware callout details 227 int calloutCount = 0; 228 for_each( 229 ffdc.hwp_errorinfo.hwcallouts.begin(), 230 ffdc.hwp_errorinfo.hwcallouts.end(), 231 [&ffdcUserData, &calloutCount, 232 &pelJSONFmtCalloutDataList](const HWCallout& hwCallout) -> void { 233 calloutCount++; 234 std::stringstream keyPrefix; 235 keyPrefix << "HWP_HW_CO_" << std::setfill('0') << std::setw(2) 236 << calloutCount << "_"; 237 238 ffdcUserData.emplace_back( 239 std::string(keyPrefix.str()).append("HW_ID"), 240 hwCallout.hwid); 241 242 ffdcUserData.emplace_back( 243 std::string(keyPrefix.str()).append("PRIORITY"), 244 hwCallout.callout_priority); 245 246 phal::TargetInfo targetInfo; 247 phal::getTgtReqAttrsVal(hwCallout.target_entity_path, 248 targetInfo); 249 250 std::string locationCode = std::string(targetInfo.locationCode); 251 ffdcUserData.emplace_back( 252 std::string(keyPrefix.str()).append("LOC_CODE"), 253 locationCode); 254 255 std::string physPath = std::string(targetInfo.physDevPath); 256 ffdcUserData.emplace_back( 257 std::string(keyPrefix.str()).append("PHYS_PATH"), physPath); 258 259 ffdcUserData.emplace_back( 260 std::string(keyPrefix.str()).append("CLK_POS"), 261 std::to_string(hwCallout.clkPos)); 262 263 json jsonCalloutData; 264 jsonCalloutData["LocationCode"] = locationCode; 265 std::string pelPriority = 266 getPelPriority(hwCallout.callout_priority); 267 jsonCalloutData["Priority"] = pelPriority; 268 269 if (targetInfo.mruId != 0) 270 { 271 jsonCalloutData["MRUs"] = json::array({ 272 {{"ID", targetInfo.mruId}, {"Priority", pelPriority}}, 273 }); 274 } 275 276 pelJSONFmtCalloutDataList.emplace_back(jsonCalloutData); 277 }); 278 279 // Adding CDG (callout, deconfigure and guard) targets details 280 calloutCount = 0; 281 for_each( 282 ffdc.hwp_errorinfo.cdg_targets.begin(), 283 ffdc.hwp_errorinfo.cdg_targets.end(), 284 [&ffdcUserData, &calloutCount, 285 &pelJSONFmtCalloutDataList](const CDG_Target& cdg_tgt) -> void { 286 calloutCount++; 287 std::stringstream keyPrefix; 288 keyPrefix << "HWP_CDG_TGT_" << std::setfill('0') << std::setw(2) 289 << calloutCount << "_"; 290 291 phal::TargetInfo targetInfo; 292 targetInfo.deconfigure = cdg_tgt.deconfigure; 293 294 phal::getTgtReqAttrsVal(cdg_tgt.target_entity_path, targetInfo); 295 296 std::string locationCode = std::string(targetInfo.locationCode); 297 ffdcUserData.emplace_back( 298 std::string(keyPrefix.str()).append("LOC_CODE"), 299 locationCode); 300 std::string physPath = std::string(targetInfo.physDevPath); 301 ffdcUserData.emplace_back( 302 std::string(keyPrefix.str()).append("PHYS_PATH"), physPath); 303 304 ffdcUserData.emplace_back( 305 std::string(keyPrefix.str()).append("CO_REQ"), 306 (cdg_tgt.callout == true ? "true" : "false")); 307 308 ffdcUserData.emplace_back( 309 std::string(keyPrefix.str()).append("CO_PRIORITY"), 310 cdg_tgt.callout_priority); 311 312 ffdcUserData.emplace_back( 313 std::string(keyPrefix.str()).append("DECONF_REQ"), 314 (cdg_tgt.deconfigure == true ? "true" : "false")); 315 316 ffdcUserData.emplace_back( 317 std::string(keyPrefix.str()).append("GUARD_REQ"), 318 (cdg_tgt.guard == true ? "true" : "false")); 319 320 ffdcUserData.emplace_back( 321 std::string(keyPrefix.str()).append("GUARD_TYPE"), 322 cdg_tgt.guard_type); 323 324 json jsonCalloutData; 325 jsonCalloutData["LocationCode"] = locationCode; 326 std::string pelPriority = 327 getPelPriority(cdg_tgt.callout_priority); 328 jsonCalloutData["Priority"] = pelPriority; 329 330 if (targetInfo.mruId != 0) 331 { 332 jsonCalloutData["MRUs"] = json::array({ 333 {{"ID", targetInfo.mruId}, {"Priority", pelPriority}}, 334 }); 335 } 336 jsonCalloutData["Deconfigured"] = cdg_tgt.deconfigure; 337 jsonCalloutData["Guarded"] = cdg_tgt.guard; 338 jsonCalloutData["GuardType"] = cdg_tgt.guard_type; 339 jsonCalloutData["EntityPath"] = cdg_tgt.target_entity_path; 340 341 pelJSONFmtCalloutDataList.emplace_back(jsonCalloutData); 342 }); 343 } 344 else if ((ffdc.ffdc_type != FFDC_TYPE_NONE) && 345 (ffdc.ffdc_type != FFDC_TYPE_UNSUPPORTED)) 346 { 347 log<level::ERR>(fmt::format("Unsupported phal FFDC type to create PEL. " 348 "MSG: {}", 349 ffdc.message) 350 .c_str()); 351 } 352 } 353 354 } // namespace phal 355 } // namespace pels 356 } // namespace openpower 357