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