1 #include "watchdog_handler.hpp"
2
3 #include "watchdog_dbus.hpp"
4 #include "watchdog_logging.hpp"
5
6 #include <phosphor-logging/lg2.hpp>
7 #include <sdbusplus/bus.hpp>
8 #include <sdbusplus/bus/match.hpp>
9
10 namespace watchdog
11 {
12 namespace dump
13 {
14
15 /**
16 * @brief Callback for dump request properties change signal monitor
17 *
18 * @param msg - dbus message from the dbus match infrastructure
19 * @param path - the object path we are monitoring
20 * @param progressStatus - dump progress status
21 * @return Always non-zero indicating no error, no cascading callbacks
22 */
dumpStatusChanged(sdbusplus::message_t & msg,std::string path,DumpProgressStatus & progressStatus)23 uint dumpStatusChanged(sdbusplus::message_t& msg, std::string path,
24 DumpProgressStatus& progressStatus)
25 {
26 // reply (msg) will be a property change message
27 std::string interface;
28 std::map<std::string, std::variant<std::string, uint8_t>> property;
29 msg.read(interface, property);
30
31 // looking for property Status changes
32 std::string propertyType = "Status";
33 auto dumpStatus = property.find(propertyType);
34
35 if (dumpStatus != property.end())
36 {
37 const std::string* status =
38 std::get_if<std::string>(&(dumpStatus->second));
39
40 if ((nullptr != status) && ("xyz.openbmc_project.Common.Progress."
41 "OperationStatus.InProgress" != *status))
42 {
43 // dump is not in InProgress state, trace some info and change in
44 // progress status
45 lg2::info("{PATH}", "PATH", path);
46 lg2::info("{STATUS}", "STATUS", *status);
47
48 if ("xyz.openbmc_project.Common.Progress.OperationStatus."
49 "Completed" == *status)
50 {
51 // Dump completed successfully
52 progressStatus = DumpProgressStatus::Completed;
53 }
54 else
55 {
56 // Dump Failed
57 progressStatus = DumpProgressStatus::Failed;
58 }
59 }
60 }
61
62 return 1; // non-negative return code for successful callback
63 }
64
65 /**
66 * @brief Register a callback for dump progress status changes
67 *
68 * @param path - the object path of the dump to monitor
69 * @param timeout - timeout - timeout interval in seconds
70 */
monitorDump(const std::string & path,const uint32_t timeout)71 void monitorDump(const std::string& path, const uint32_t timeout)
72 {
73 // callback will update progressStatus
74 DumpProgressStatus progressStatus = DumpProgressStatus::InProgress;
75
76 // setup the signal match rules and callback
77 std::string matchInterface = "xyz.openbmc_project.Common.Progress";
78 auto bus = sdbusplus::bus::new_system();
79
80 std::unique_ptr<sdbusplus::bus::match_t> match =
81 std::make_unique<sdbusplus::bus::match_t>(
82 bus,
83 sdbusplus::bus::match::rules::propertiesChanged(
84 path.c_str(), matchInterface.c_str()),
85 [&](auto& msg) {
86 return dumpStatusChanged(msg, path, progressStatus);
87 });
88
89 // wait for dump status to be completed (complete == true)
90 // or until timeout interval
91
92 bool timedOut = false;
93 uint32_t secondsCount = 0;
94 while ((DumpProgressStatus::InProgress == progressStatus) && !timedOut)
95 {
96 bus.wait(std::chrono::seconds(1));
97 bus.process_discard();
98
99 if (++secondsCount == timeout)
100 {
101 timedOut = true;
102 }
103 }
104
105 if (timedOut)
106 {
107 lg2::error("Dump progress status did not change to "
108 "complete within the timeout interval, exiting...");
109 }
110 else if (DumpProgressStatus::Completed == progressStatus)
111 {
112 lg2::info("dump collection completed");
113 }
114 else
115 {
116 lg2::info("dump collection failed");
117 }
118 }
119
requestDump(const DumpParameters & dumpParameters)120 void requestDump(const DumpParameters& dumpParameters)
121 {
122 constexpr auto path = "/xyz/openbmc_project/dump/system";
123 constexpr auto interface = "xyz.openbmc_project.Dump.Create";
124 constexpr auto function = "CreateDump";
125
126 sdbusplus::message_t method;
127
128 if (0 == dbusMethod(path, interface, function, method))
129 {
130 try
131 {
132 // dbus call arguments
133 std::map<std::string, std::variant<std::string, uint64_t>>
134 createParams;
135 createParams["com.ibm.Dump.Create.CreateParameters.ErrorLogId"] =
136 uint64_t(dumpParameters.logId);
137 if (DumpType::Hostboot == dumpParameters.dumpType)
138 {
139 lg2::info("hostboot dump requested");
140 createParams["com.ibm.Dump.Create.CreateParameters.DumpType"] =
141 "com.ibm.Dump.Create.DumpType.Hostboot";
142 }
143 else if (DumpType::SBE == dumpParameters.dumpType)
144 {
145 lg2::info("SBE dump requested");
146 createParams["com.ibm.Dump.Create.CreateParameters.DumpType"] =
147 "com.ibm.Dump.Create.DumpType.SBE";
148 createParams
149 ["com.ibm.Dump.Create.CreateParameters.FailingUnitId"] =
150 dumpParameters.unitId;
151 }
152
153 method.append(createParams);
154
155 // using system dbus
156 auto bus = sdbusplus::bus::new_system();
157 auto response = bus.call(method);
158
159 // reply will be type dbus::ObjectPath
160 sdbusplus::message::object_path reply;
161 response.read(reply);
162
163 // monitor dump progress
164 monitorDump(reply, dumpParameters.timeout);
165 }
166 catch (const sdbusplus::exception_t& e)
167 {
168 constexpr auto ERROR_DUMP_DISABLED =
169 "xyz.openbmc_project.Dump.Create.Error.Disabled";
170 if (e.name() == ERROR_DUMP_DISABLED)
171 {
172 // Dump is disabled, Skip the dump collection.
173 lg2::info("Dump is disabled on({UNIT}), "
174 "skipping dump collection",
175 "UNIT", dumpParameters.unitId);
176 }
177 else
178 {
179 lg2::error("D-Bus call createDump exception OBJPATH={OBJPATH}, "
180 "INTERFACE={INTERFACE}, EXCEPTION={ERROR}",
181 "OBJPATH", path, "INTERFACE", interface, "ERROR", e);
182 }
183 }
184 }
185 }
186
187 } // namespace dump
188 } // namespace watchdog
189