1 #include <format> 2 extern "C" 3 { 4 #include <libpdbg.h> 5 #include <libpdbg_sbe.h> 6 } 7 8 #include <libphal.H> 9 10 #include <phosphor-logging/lg2.hpp> 11 #include <watchdog_common.hpp> 12 #include <watchdog_dbus.hpp> 13 #include <watchdog_handler.hpp> 14 #include <watchdog_logging.hpp> 15 16 namespace watchdog 17 { 18 namespace dump 19 { 20 21 void triggerHostbootDump(const uint32_t timeout) 22 { 23 constexpr auto HOST_STATE_DIAGNOSTIC_MODE = 24 "obmc-host-diagnostic-mode@0.target"; 25 constexpr auto HOST_STATE_QUIESCE_TGT = "obmc-host-quiesce@0.target"; 26 27 // Put system into diagnostic mode 28 transitionHost(HOST_STATE_DIAGNOSTIC_MODE); 29 30 eventWatchdogTimeout(timeout); 31 32 // Put system into quiesce state 33 transitionHost(HOST_STATE_QUIESCE_TGT); 34 } 35 36 /** 37 * @brief get SBE special callout information 38 * 39 * @details This function adds the special sbe callout in the user provided 40 * json callout list. includes BMC0002 procedure callout with high priority 41 * and processor callout with medium priority. 42 * 43 * @param[in] procTarget - pdbg processor target 44 * @param[out] jsonCalloutDataList - reference to json callout list 45 */ 46 static void getSBECallout(struct pdbg_target* procTarget, 47 json& jsonCalloutDataList) 48 { 49 using namespace openpower::phal::pdbg; 50 json jsonProcedCallout; 51 52 // Add procedure callout 53 jsonProcedCallout["Procedure"] = "BMC0002"; 54 jsonProcedCallout["Priority"] = "H"; 55 jsonCalloutDataList.emplace_back(jsonProcedCallout); 56 try 57 { 58 ATTR_LOCATION_CODE_Type locationCode; 59 // Initialize with default data. 60 memset(&locationCode, '\0', sizeof(locationCode)); 61 // Get location code information 62 openpower::phal::pdbg::getLocationCode(procTarget, locationCode); 63 json jsonProcCallout; 64 jsonProcCallout["LocationCode"] = locationCode; 65 jsonProcCallout["Deconfigured"] = false; 66 jsonProcCallout["Guarded"] = false; 67 jsonProcCallout["Priority"] = "M"; 68 jsonCalloutDataList.emplace_back(jsonProcCallout); 69 } 70 catch (const std::exception& e) 71 { 72 lg2::error("getLocationCode({LOCATION}): Exception({ERROR})", 73 "LOCATION", pdbg_target_path(procTarget), "ERROR", e); 74 } 75 } 76 77 void handleSbeBootError(struct pdbg_target* procTarget, const uint32_t timeout) 78 { 79 using namespace openpower::phal; 80 81 sbeError_t sbeError; 82 bool dumpIsRequired = false; 83 84 try 85 { 86 // Capture FFDC information on primary processor 87 sbeError = sbe::captureFFDC(procTarget); 88 } 89 catch (const std::exception& e) 90 { 91 // Failed to collect FFDC information 92 lg2::error("captureFFDC: Exception{ERROR}", "ERROR", e); 93 dumpIsRequired = true; 94 } 95 96 // event type 97 std::string event; 98 if ((sbeError.errType() == exception::SBE_FFDC_NO_DATA) || 99 (sbeError.errType() == exception::SBE_CMD_TIMEOUT) || (dumpIsRequired)) 100 { 101 lg2::info("No FFDC data"); 102 event = "org.open_power.Processor.Error.SbeBootTimeout"; 103 dumpIsRequired = true; 104 } 105 else 106 { 107 lg2::error("SBE Boot failure"); 108 event = "org.open_power.Processor.Error.SbeBootFailure"; 109 } 110 111 // Additional data 112 std::map<std::string, std::string> additionalData; 113 114 // SRC6 : [0:15] chip position 115 uint32_t index = pdbg_target_index(procTarget); 116 additionalData.emplace("SRC6", std::to_string(index << 16)); 117 additionalData.emplace("SBE_ERR_MSG", sbeError.what()); 118 119 // FFDC 120 auto ffdc = std::vector<FFDCTuple>{}; 121 // get SBE ffdc file descriptor 122 auto fd = sbeError.getFd(); 123 124 // Log error with additional ffdc if fd is valid 125 if (fd > 0) 126 { 127 ffdc.push_back( 128 std::make_tuple(sdbusplus::xyz::openbmc_project::Logging::server:: 129 Create::FFDCFormat::Custom, 130 static_cast<uint8_t>(0xCB), 131 static_cast<uint8_t>(0x01), sbeError.getFd())); 132 } 133 134 std::unique_ptr<FFDCFile> ffdcFilePtr; 135 try 136 { 137 if (dumpIsRequired) 138 { 139 // Additional callout is required for SBE timeout case 140 // In this case no SBE FFDC information available and 141 // required to add default callouts. 142 json jsonCalloutDataList; 143 jsonCalloutDataList = json::array(); 144 getSBECallout(procTarget, jsonCalloutDataList); 145 ffdcFilePtr = std::make_unique<FFDCFile>(jsonCalloutDataList); 146 ffdc.push_back(std::make_tuple( 147 sdbusplus::xyz::openbmc_project::Logging::server::Create:: 148 FFDCFormat::JSON, 149 static_cast<uint8_t>(0xCA), static_cast<uint8_t>(0x01), 150 ffdcFilePtr->getFileDescriptor())); 151 } 152 } 153 catch (const std::exception& e) 154 { 155 lg2::error("Skipping SBE special callout due to Exception({ERROR})", 156 "ERROR", e); 157 } 158 auto pelId = createPel(event, additionalData, ffdc); 159 160 if (dumpIsRequired) 161 { 162 try 163 { 164 using namespace openpower::phal; 165 166 // Check SBE dump collection allowed 167 bool dumpAllowed = sbe::isDumpAllowed(procTarget); 168 if (!dumpAllowed) 169 { 170 // Possibly another collection in progress, skip dump collection 171 lg2::error("Another collection is in progress, skipping " 172 "dump collection"); 173 return; 174 } 175 } 176 catch (const std::exception& e) 177 { 178 lg2::error("Exception {ERROR} occurred", "ERROR", e); 179 return; 180 } 181 182 DumpParameters dumpParameters; 183 dumpParameters.logId = pelId; 184 dumpParameters.unitId = index; 185 dumpParameters.timeout = timeout; 186 dumpParameters.dumpType = DumpType::SBE; 187 188 // will not return until dump is complete or timeout 189 requestDump(dumpParameters); 190 } 191 } 192 193 } // namespace dump 194 } // namespace watchdog 195