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