xref: /openbmc/openpower-debug-collector/watchdog/watchdog_handler.cpp (revision 90bb9ad27c9d4d595a9459a24864e569d82912ba)
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  */
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  */
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 
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