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