1 #include "config.h"
2
3 #include <attn/attn_dbus.hpp>
4 #include <attn/attn_dump.hpp>
5 #include <attn/attn_logging.hpp>
6 #include <sdbusplus/bus.hpp>
7 #include <sdbusplus/exception.hpp>
8 #include <util/dbus.hpp>
9 #include <util/trace.hpp>
10
11 constexpr uint64_t dumpTimeout = 3600000000; // microseconds
12
13 constexpr auto operationStatusInProgress =
14 "xyz.openbmc_project.Common.Progress.OperationStatus.InProgress";
15
16 namespace attn
17 {
18
19 /**
20 * Callback for dump request properties change signal monitor
21 *
22 * @param[in] i_msg Dbus message from the dbus match infrastructure
23 * @param[out] o_dumpStatus Dump status dbus response string
24 * @return Always non-zero indicating no error, no cascading callbacks
25 */
dumpStatusChanged(sdbusplus::message_t & i_msg,std::string & o_dumpStatus)26 uint dumpStatusChanged(sdbusplus::message_t& i_msg, std::string& o_dumpStatus)
27 {
28 // reply (msg) will be a property change message
29 std::string interface;
30 std::map<std::string, std::variant<std::string, uint8_t>> property;
31 i_msg.read(interface, property);
32
33 // looking for property Status changes
34 std::string propertyType = "Status";
35 auto dumpStatus = property.find(propertyType);
36
37 if (dumpStatus != property.end())
38 {
39 const std::string* status =
40 std::get_if<std::string>(&(dumpStatus->second));
41
42 if (nullptr != status)
43 {
44 o_dumpStatus = *status;
45 }
46 }
47
48 return 1; // non-negative return code for successful callback
49 }
50
51 /**
52 * Register a callback for dump progress status changes
53 *
54 * @param[in] i_path The object path of the dump to monitor
55 */
monitorDump(const std::string & i_path)56 void monitorDump(const std::string& i_path)
57 {
58 // setup the signal match rules and callback
59 std::string matchInterface = "xyz.openbmc_project.Common.Progress";
60 auto bus = sdbusplus::bus::new_system();
61
62 // monitor dump status change property, will update dumpStatus
63 std::string dumpStatus = "requested";
64 std::unique_ptr<sdbusplus::bus::match_t> match =
65 std::make_unique<sdbusplus::bus::match_t>(
66 bus,
67 sdbusplus::bus::match::rules::propertiesChanged(
68 i_path.c_str(), matchInterface.c_str()),
69 [&](auto& msg) { return dumpStatusChanged(msg, dumpStatus); });
70
71 // wait for dump status to be completed (complete == true)
72 trace::inf("dump requested %s", i_path.c_str());
73
74 // wait for dump status not InProgress or timeout
75 uint64_t timeRemaining = dumpTimeout;
76
77 std::chrono::steady_clock::time_point begin =
78 std::chrono::steady_clock::now();
79
80 while (("requested" == dumpStatus ||
81 operationStatusInProgress == dumpStatus) &&
82 0 != timeRemaining)
83 {
84 bus.wait(timeRemaining);
85 uint64_t timeElapsed =
86 std::chrono::duration_cast<std::chrono::microseconds>(
87 std::chrono::steady_clock::now() - begin)
88 .count();
89
90 timeRemaining =
91 timeElapsed > timeRemaining ? 0 : timeRemaining - timeElapsed;
92
93 bus.process_discard();
94 }
95
96 if (0 == timeRemaining)
97 {
98 trace::err("dump request timed out after %" PRIu64 " microseconds",
99 dumpTimeout);
100 }
101
102 trace::inf("dump status: %s", dumpStatus.c_str());
103 }
104
105 /** Api used to enable or disable watchdog dbus property */
enableWatchdog(bool enable)106 void enableWatchdog(bool enable)
107 {
108 constexpr auto service = "xyz.openbmc_project.Watchdog";
109 constexpr auto object = "/xyz/openbmc_project/watchdog/host0";
110 constexpr auto interface = "xyz.openbmc_project.State.Watchdog";
111 constexpr auto property = "Enabled";
112 util::dbus::setProperty<bool>(service, object, interface, property, enable);
113 }
114
115 /** Request a dump from the dump manager */
requestDump(uint32_t i_logId,const DumpParameters & i_dumpParameters)116 void requestDump(uint32_t i_logId, const DumpParameters& i_dumpParameters)
117 {
118 constexpr auto interface = "xyz.openbmc_project.Dump.Create";
119 constexpr auto function = "CreateDump";
120
121 sdbusplus::message_t method;
122 bool watchdogDisabled = false;
123
124 if (0 == dbusMethod(OP_DUMP_OBJ_PATH, interface, function, method))
125 {
126 try
127 {
128 // During a checkstop attention, the system is not functioning
129 // normally. So a hardware or hostboot dump is collected and it
130 // could take a while to get completed. So disable the watchdog when
131 // the dump collection is in progress.
132 if (DumpType::Hostboot == i_dumpParameters.dumpType ||
133 DumpType::Hardware == i_dumpParameters.dumpType)
134 {
135 watchdogDisabled = true;
136 enableWatchdog(false);
137 }
138 // dbus call arguments
139 std::map<std::string, std::variant<std::string, uint64_t>>
140 createParams;
141 createParams["com.ibm.Dump.Create.CreateParameters.ErrorLogId"] =
142 uint64_t(i_logId);
143 if (DumpType::Hostboot == i_dumpParameters.dumpType)
144 {
145 createParams["com.ibm.Dump.Create.CreateParameters.DumpType"] =
146 "com.ibm.Dump.Create.DumpType.Hostboot";
147 }
148 else if (DumpType::Hardware == i_dumpParameters.dumpType)
149 {
150 createParams["com.ibm.Dump.Create.CreateParameters.DumpType"] =
151 "com.ibm.Dump.Create.DumpType.Hardware";
152 createParams
153 ["com.ibm.Dump.Create.CreateParameters.FailingUnitId"] =
154 i_dumpParameters.unitId;
155 }
156 else if (DumpType::SBE == i_dumpParameters.dumpType)
157 {
158 createParams["com.ibm.Dump.Create.CreateParameters.DumpType"] =
159 "com.ibm.Dump.Create.DumpType.SBE";
160 createParams
161 ["com.ibm.Dump.Create.CreateParameters.FailingUnitId"] =
162 i_dumpParameters.unitId;
163 }
164 method.append(createParams);
165
166 // using system dbus
167 auto bus = sdbusplus::bus::new_system();
168 auto response = bus.call(method);
169
170 // reply will be type dbus::ObjectPath
171 sdbusplus::message::object_path reply;
172 response.read(reply);
173
174 // monitor dump progress
175 monitorDump(reply);
176 }
177 catch (const sdbusplus::exception::SdBusError& e)
178 {
179 trace::err("requestDump exception");
180 trace::err(e.what());
181 }
182
183 if (watchdogDisabled)
184 {
185 // Dump collection is over, enable the watchdog
186 enableWatchdog(true);
187 }
188 }
189 }
190
191 } // namespace attn
192