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