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
triggerHostbootDump(const uint32_t timeout)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 */
getSBECallout(struct pdbg_target * procTarget,json & jsonCalloutDataList)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
handleSbeBootError(struct pdbg_target * procTarget,const uint32_t timeout)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