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