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