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 json jsonCalloutDataList; 142 jsonCalloutDataList = json::array(); 143 getSBECallout(procTarget, jsonCalloutDataList); 144 ffdcFilePtr = std::make_unique<FFDCFile>(jsonCalloutDataList); 145 ffdc.push_back(std::make_tuple( 146 sdbusplus::xyz::openbmc_project::Logging::server::Create:: 147 FFDCFormat::JSON, 148 static_cast<uint8_t>(0xCA), static_cast<uint8_t>(0x01), 149 ffdcFilePtr->getFileDescriptor())); 150 } 151 catch (const std::exception& e) 152 { 153 log<level::ERR>( 154 fmt::format("Skipping SBE special callout due to Exception({})", 155 e.what()) 156 .c_str()); 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 log<level::INFO>("Another collection is in progress, skipping " 172 "dump collection"); 173 return; 174 } 175 } 176 catch (const std::exception& e) 177 { 178 log<level::ERR>( 179 fmt::format("Exception {} occurred", e.what()).c_str()); 180 return; 181 } 182 183 DumpParameters dumpParameters; 184 dumpParameters.logId = pelId; 185 dumpParameters.unitId = index; 186 dumpParameters.timeout = timeout; 187 dumpParameters.dumpType = DumpType::SBE; 188 189 // will not return until dump is complete or timeout 190 requestDump(dumpParameters); 191 } 192 } 193 194 } // namespace dump 195 } // namespace watchdog 196