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