1 #include <attn/attn_dbus.hpp>
2 #include <attn/attn_dump.hpp>
3 #include <attn/attn_logging.hpp>
4 #include <sdbusplus/bus.hpp>
5 #include <sdbusplus/exception.hpp>
6 #include <util/dbus.hpp>
7 #include <util/trace.hpp>
8 
9 constexpr uint64_t dumpTimeout = 3600000000; // microseconds
10 
11 constexpr auto operationStatusInProgress =
12     "xyz.openbmc_project.Common.Progress.OperationStatus.InProgress";
13 
14 namespace attn
15 {
16 
17 /**
18  *  Callback for dump request properties change signal monitor
19  *
20  * @param[in] i_msg         Dbus message from the dbus match infrastructure
21  * @param[out] o_dumpStatus Dump status dbus response string
22  * @return Always non-zero indicating no error, no cascading callbacks
23  */
24 uint dumpStatusChanged(sdbusplus::message_t& i_msg, std::string& o_dumpStatus)
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     i_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)
41         {
42             o_dumpStatus = *status;
43         }
44     }
45 
46     return 1; // non-negative return code for successful callback
47 }
48 
49 /**
50  * Register a callback for dump progress status changes
51  *
52  * @param[in] i_path The object path of the dump to monitor
53  */
54 void monitorDump(const std::string& i_path)
55 {
56     // setup the signal match rules and callback
57     std::string matchInterface = "xyz.openbmc_project.Common.Progress";
58     auto bus = sdbusplus::bus::new_system();
59 
60     // monitor dump status change property, will update dumpStatus
61     std::string dumpStatus = "requested";
62     std::unique_ptr<sdbusplus::bus::match_t> match =
63         std::make_unique<sdbusplus::bus::match_t>(
64             bus,
65             sdbusplus::bus::match::rules::propertiesChanged(
66                 i_path.c_str(), matchInterface.c_str()),
67             [&](auto& msg) { return dumpStatusChanged(msg, dumpStatus); });
68 
69     // wait for dump status to be completed (complete == true)
70     trace::inf("dump requested %s", i_path.c_str());
71 
72     // wait for dump status not InProgress or timeout
73     uint64_t timeRemaining = dumpTimeout;
74 
75     std::chrono::steady_clock::time_point begin =
76         std::chrono::steady_clock::now();
77 
78     while (("requested" == dumpStatus ||
79             operationStatusInProgress == dumpStatus) &&
80            0 != timeRemaining)
81     {
82         bus.wait(timeRemaining);
83         uint64_t timeElapsed =
84             std::chrono::duration_cast<std::chrono::microseconds>(
85                 std::chrono::steady_clock::now() - begin)
86                 .count();
87 
88         timeRemaining =
89             timeElapsed > timeRemaining ? 0 : timeRemaining - timeElapsed;
90 
91         bus.process_discard();
92     }
93 
94     if (0 == timeRemaining)
95     {
96         trace::err("dump request timed out after %" PRIu64 " microseconds",
97                    dumpTimeout);
98     }
99 
100     trace::inf("dump status: %s", dumpStatus.c_str());
101 }
102 
103 /** Api used to enable or disable watchdog dbus property */
104 void enableWatchdog(bool enable)
105 {
106     constexpr auto service = "xyz.openbmc_project.Watchdog";
107     constexpr auto object = "/xyz/openbmc_project/watchdog/host0";
108     constexpr auto interface = "xyz.openbmc_project.State.Watchdog";
109     constexpr auto property = "Enabled";
110     util::dbus::setProperty<bool>(service, object, interface, property, enable);
111 }
112 
113 /** Request a dump from the dump manager */
114 void requestDump(uint32_t i_logId, const DumpParameters& i_dumpParameters)
115 {
116     constexpr auto path = "/org/openpower/dump";
117     constexpr auto interface = "xyz.openbmc_project.Dump.Create";
118     constexpr auto function = "CreateDump";
119 
120     sdbusplus::message_t method;
121     bool watchdogDisabled = false;
122 
123     if (0 == dbusMethod(path, interface, function, method))
124     {
125         try
126         {
127             // During a checkstop attention, the system is not functioning
128             // normally. So a hardware or hostboot dump is collected and it
129             // could take a while to get completed. So disable the watchdog when
130             // the dump collection is in progress.
131             if (DumpType::Hostboot == i_dumpParameters.dumpType ||
132                 DumpType::Hardware == i_dumpParameters.dumpType)
133             {
134                 watchdogDisabled = true;
135                 enableWatchdog(false);
136             }
137             // dbus call arguments
138             std::map<std::string, std::variant<std::string, uint64_t>>
139                 createParams;
140             createParams["com.ibm.Dump.Create.CreateParameters.ErrorLogId"] =
141                 uint64_t(i_logId);
142             if (DumpType::Hostboot == i_dumpParameters.dumpType)
143             {
144                 createParams["com.ibm.Dump.Create.CreateParameters.DumpType"] =
145                     "com.ibm.Dump.Create.DumpType.Hostboot";
146             }
147             else if (DumpType::Hardware == i_dumpParameters.dumpType)
148             {
149                 createParams["com.ibm.Dump.Create.CreateParameters.DumpType"] =
150                     "com.ibm.Dump.Create.DumpType.Hardware";
151                 createParams
152                     ["com.ibm.Dump.Create.CreateParameters.FailingUnitId"] =
153                         i_dumpParameters.unitId;
154             }
155             else if (DumpType::SBE == i_dumpParameters.dumpType)
156             {
157                 createParams["com.ibm.Dump.Create.CreateParameters.DumpType"] =
158                     "com.ibm.Dump.Create.DumpType.SBE";
159                 createParams
160                     ["com.ibm.Dump.Create.CreateParameters.FailingUnitId"] =
161                         i_dumpParameters.unitId;
162             }
163             method.append(createParams);
164 
165             // using system dbus
166             auto bus = sdbusplus::bus::new_system();
167             auto response = bus.call(method);
168 
169             // reply will be type dbus::ObjectPath
170             sdbusplus::message::object_path reply;
171             response.read(reply);
172 
173             // monitor dump progress
174             monitorDump(reply);
175         }
176         catch (const sdbusplus::exception::SdBusError& e)
177         {
178             trace::err("requestDump exception");
179             trace::err(e.what());
180         }
181 
182         if (watchdogDisabled)
183         {
184             // Dump collection is over, enable the watchdog
185             enableWatchdog(true);
186         }
187     }
188 }
189 
190 } // namespace attn
191