extern "C" { #include } #include "fapi_data_process.hpp" #include #include #include #include #include #include #include #include #include #include #include namespace openpower { namespace pels { namespace phal { using namespace phosphor::logging; /** * Used to pass buffer to pdbg callback api to get required target * data (attributes) based on given data (attribute). */ struct TargetInfo { ATTR_PHYS_BIN_PATH_Type physBinPath; ATTR_LOCATION_CODE_Type locationCode; ATTR_PHYS_DEV_PATH_Type physDevPath; ATTR_MRU_ID_Type mruId; bool deconfigure; TargetInfo() { memset(&physBinPath, '\0', sizeof(physBinPath)); memset(&locationCode, '\0', sizeof(locationCode)); memset(&physDevPath, '\0', sizeof(physDevPath)); mruId = 0; deconfigure = false; } }; /** * Used to return in callback function which are used to get * physical path value and it binary format value. * * The value for constexpr defined based on pdbg_target_traverse function usage. */ constexpr int continueTgtTraversal = 0; constexpr int requireAttrFound = 1; constexpr int requireAttrNotFound = 2; /** * @brief Used to get target location code from phal device tree * * @param[in] target current device tree target * @param[out] appPrivData used for accessing|storing from|to application * * @return 0 to continue traverse, non-zero to stop traverse */ int pdbgCallbackToGetTgtReqAttrsVal(struct pdbg_target* target, void* appPrivData) { TargetInfo* targetInfo = static_cast(appPrivData); ATTR_PHYS_BIN_PATH_Type physBinPath; /** * TODO: Issue: phal/pdata#16 * Should not use direct pdbg api to read attribute. Need to use DT_GET_PROP * macro for bmc app's and this will call libdt-api api but, it will print * "pdbg_target_get_attribute failed" trace if attribute is not found and * this callback will call recursively by using pdbg_target_traverse() until * find expected attribute based on return code from this callback. Because, * need to do target iteration to get actual attribute (ATTR_PHYS_BIN_PATH) * value when device tree target info doesn't know to read attribute from * device tree. So, Due to this error trace user will get confusion while * looking traces. Hence using pdbg api to avoid trace until libdt-api * provides log level setup. */ if (!pdbg_target_get_attribute( target, "ATTR_PHYS_BIN_PATH", std::stoi(dtAttr::fapi2::ATTR_PHYS_BIN_PATH_Spec), dtAttr::fapi2::ATTR_PHYS_BIN_PATH_ElementCount, physBinPath)) { return continueTgtTraversal; } if (std::memcmp(physBinPath, targetInfo->physBinPath, sizeof(physBinPath)) != 0) { return continueTgtTraversal; } if (DT_GET_PROP(ATTR_LOCATION_CODE, target, targetInfo->locationCode)) { log("Could not read LOCATION_CODE attribute"); return requireAttrNotFound; } if (DT_GET_PROP(ATTR_PHYS_DEV_PATH, target, targetInfo->physDevPath)) { log("Could not read PHYS_DEV_PATH attribute"); return requireAttrNotFound; } if (DT_GET_PROP(ATTR_MRU_ID, target, targetInfo->mruId)) { log("Could not read MRU_ID attribute"); return requireAttrNotFound; } if (targetInfo->deconfigure) { ATTR_HWAS_STATE_Type hwasState; if (DT_GET_PROP(ATTR_HWAS_STATE, target, hwasState)) { log("Could not read HWAS_STATE attribute"); return requireAttrNotFound; } log(fmt::format("Marking target({}) as Non-Functional", targetInfo->physDevPath) .c_str()); hwasState.functional = 0; if (DT_SET_PROP(ATTR_HWAS_STATE, target, hwasState)) { log("Could not write HWAS_STATE attribute"); return requireAttrNotFound; } } return requireAttrFound; } /** * @brief Used to get target info (attributes data) * * To get target required attributes value using another attribute value * ("PHYS_BIN_PATH" which is present in same target attributes list) by using * "ipdbg_target_traverse" api because, here we have attribute value only and * doesn't have respective device tree target info to get required attributes * values from it attributes list. * * @param[in] physBinPath to pass PHYS_BIN_PATH value * @param[out] targetInfo to pas buufer to fill with required attributes * * @return true on success otherwise false */ bool getTgtReqAttrsVal(const std::vector& physBinPath, TargetInfo& targetInfo) { std::memcpy(&targetInfo.physBinPath, physBinPath.data(), sizeof(targetInfo.physBinPath)); int ret = pdbg_target_traverse(NULL, pdbgCallbackToGetTgtReqAttrsVal, &targetInfo); if (ret == 0) { log(fmt::format("Given ATTR_PHYS_BIN_PATH value({}) " "not found in phal device tree", targetInfo.physBinPath) .c_str()); return false; } else if (ret == requireAttrNotFound) { return false; } return true; } /** * @brief GET PEL priority from pHAL priority * * The pHAL callout priority is in different format than PEL format * so, this api is used to return current phal supported priority into * PEL expected format. * * @param[in] phalPriority used to pass phal priority format string * * @return pel priority format string else empty if failure * * @note For "NONE" returning "L" (LOW) */ static std::string getPelPriority(const std::string& phalPriority) { const std::map priorityMap = { {"HIGH", "H"}, {"MEDIUM", "M"}, {"LOW", "L"}, {"NONE", "L"}}; auto it = priorityMap.find(phalPriority); if (it == priorityMap.end()) { log(fmt::format("Unsupported phal priority({}) is given " "to get pel priority format", phalPriority) .c_str()); return "H"; } return it->second; } void convertFAPItoPELformat(FFDC& ffdc, json& pelJSONFmtCalloutDataList, FFDCData& ffdcUserData) { if (ffdc.ffdc_type == FFDC_TYPE_HWP) { // Adding hardware procedures return code details ffdcUserData.emplace_back("HWP_RC", ffdc.hwp_errorinfo.rc); ffdcUserData.emplace_back("HWP_RC_DESC", ffdc.hwp_errorinfo.rc_desc); // Adding hardware procedures required ffdc data for debug for_each( ffdc.hwp_errorinfo.ffdcs_data.begin(), ffdc.hwp_errorinfo.ffdcs_data.end(), [&ffdcUserData](std::pair& ele) -> void { std::string keyWithPrefix("HWP_FFDC_"); keyWithPrefix.append(ele.first); ffdcUserData.emplace_back(keyWithPrefix, ele.second); }); // Adding hardware callout details int calloutCount = 0; for_each( ffdc.hwp_errorinfo.hwcallouts.begin(), ffdc.hwp_errorinfo.hwcallouts.end(), [&ffdcUserData, &calloutCount, &pelJSONFmtCalloutDataList](const HWCallout& hwCallout) -> void { calloutCount++; std::stringstream keyPrefix; keyPrefix << "HWP_HW_CO_" << std::setfill('0') << std::setw(2) << calloutCount << "_"; ffdcUserData.emplace_back( std::string(keyPrefix.str()).append("HW_ID"), hwCallout.hwid); ffdcUserData.emplace_back( std::string(keyPrefix.str()).append("PRIORITY"), hwCallout.callout_priority); phal::TargetInfo targetInfo; phal::getTgtReqAttrsVal(hwCallout.target_entity_path, targetInfo); std::string locationCode = std::string(targetInfo.locationCode); ffdcUserData.emplace_back( std::string(keyPrefix.str()).append("LOC_CODE"), locationCode); std::string physPath = std::string(targetInfo.physDevPath); ffdcUserData.emplace_back( std::string(keyPrefix.str()).append("PHYS_PATH"), physPath); ffdcUserData.emplace_back( std::string(keyPrefix.str()).append("CLK_POS"), std::to_string(hwCallout.clkPos)); json jsonCalloutData; jsonCalloutData["LocationCode"] = locationCode; std::string pelPriority = getPelPriority(hwCallout.callout_priority); jsonCalloutData["Priority"] = pelPriority; if (targetInfo.mruId != 0) { jsonCalloutData["MRUs"] = json::array({ {{"ID", targetInfo.mruId}, {"Priority", pelPriority}}, }); } pelJSONFmtCalloutDataList.emplace_back(jsonCalloutData); }); // Adding CDG (callout, deconfigure and guard) targets details calloutCount = 0; for_each( ffdc.hwp_errorinfo.cdg_targets.begin(), ffdc.hwp_errorinfo.cdg_targets.end(), [&ffdcUserData, &calloutCount, &pelJSONFmtCalloutDataList](const CDG_Target& cdg_tgt) -> void { calloutCount++; std::stringstream keyPrefix; keyPrefix << "HWP_CDG_TGT_" << std::setfill('0') << std::setw(2) << calloutCount << "_"; phal::TargetInfo targetInfo; targetInfo.deconfigure = cdg_tgt.deconfigure; phal::getTgtReqAttrsVal(cdg_tgt.target_entity_path, targetInfo); std::string locationCode = std::string(targetInfo.locationCode); ffdcUserData.emplace_back( std::string(keyPrefix.str()).append("LOC_CODE"), locationCode); std::string physPath = std::string(targetInfo.physDevPath); ffdcUserData.emplace_back( std::string(keyPrefix.str()).append("PHYS_PATH"), physPath); ffdcUserData.emplace_back( std::string(keyPrefix.str()).append("CO_REQ"), (cdg_tgt.callout == true ? "true" : "false")); ffdcUserData.emplace_back( std::string(keyPrefix.str()).append("CO_PRIORITY"), cdg_tgt.callout_priority); ffdcUserData.emplace_back( std::string(keyPrefix.str()).append("DECONF_REQ"), (cdg_tgt.deconfigure == true ? "true" : "false")); ffdcUserData.emplace_back( std::string(keyPrefix.str()).append("GUARD_REQ"), (cdg_tgt.guard == true ? "true" : "false")); ffdcUserData.emplace_back( std::string(keyPrefix.str()).append("GUARD_TYPE"), cdg_tgt.guard_type); json jsonCalloutData; jsonCalloutData["LocationCode"] = locationCode; std::string pelPriority = getPelPriority(cdg_tgt.callout_priority); jsonCalloutData["Priority"] = pelPriority; if (targetInfo.mruId != 0) { jsonCalloutData["MRUs"] = json::array({ {{"ID", targetInfo.mruId}, {"Priority", pelPriority}}, }); } jsonCalloutData["Deconfigured"] = cdg_tgt.deconfigure; jsonCalloutData["Guarded"] = cdg_tgt.guard; pelJSONFmtCalloutDataList.emplace_back(jsonCalloutData); }); } else if ((ffdc.ffdc_type != FFDC_TYPE_NONE) && (ffdc.ffdc_type != FFDC_TYPE_UNSUPPORTED)) { log(fmt::format("Unsupported phal FFDC type to create PEL. " "MSG: {}", ffdc.message) .c_str()); } } } // namespace phal } // namespace pels } // namespace openpower