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/trace.hpp>
7 
8 constexpr uint64_t dumpTimeout = 3600000000; // microseconds
9 
10 constexpr auto operationStatusInProgress =
11     "xyz.openbmc_project.Common.Progress.OperationStatus.InProgress";
12 
13 namespace attn
14 {
15 
16 /**
17  *  Callback for dump request properties change signal monitor
18  *
19  * @param[in] i_msg         Dbus message from the dbus match infrastructure
20  * @param[out] o_dumpStatus Dump status dbus response string
21  * @return Always non-zero indicating no error, no cascading callbacks
22  */
23 uint dumpStatusChanged(sdbusplus::message_t& i_msg, std::string& o_dumpStatus)
24 {
25     // reply (msg) will be a property change message
26     std::string interface;
27     std::map<std::string, std::variant<std::string, uint8_t>> property;
28     i_msg.read(interface, property);
29 
30     // looking for property Status changes
31     std::string propertyType = "Status";
32     auto dumpStatus          = property.find(propertyType);
33 
34     if (dumpStatus != property.end())
35     {
36         const std::string* status =
37             std::get_if<std::string>(&(dumpStatus->second));
38 
39         if (nullptr != status)
40         {
41             o_dumpStatus = *status;
42         }
43     }
44 
45     return 1; // non-negative return code for successful callback
46 }
47 
48 /**
49  * Register a callback for dump progress status changes
50  *
51  * @param[in] i_path The object path of the dump to monitor
52  */
53 void monitorDump(const std::string& i_path)
54 {
55     // setup the signal match rules and callback
56     std::string matchInterface = "xyz.openbmc_project.Common.Progress";
57     auto bus                   = sdbusplus::bus::new_system();
58 
59     // monitor dump status change property, will update dumpStatus
60     std::string dumpStatus = "requested";
61     std::unique_ptr<sdbusplus::bus::match_t> match =
62         std::make_unique<sdbusplus::bus::match_t>(
63             bus,
64             sdbusplus::bus::match::rules::propertiesChanged(
65                 i_path.c_str(), matchInterface.c_str()),
66             [&](auto& msg) { return dumpStatusChanged(msg, dumpStatus); });
67 
68     // wait for dump status to be completed (complete == true)
69     trace::inf("dump requested %s", i_path.c_str());
70 
71     // wait for dump status not InProgress or timeout
72     uint64_t timeRemaining = dumpTimeout;
73 
74     std::chrono::steady_clock::time_point begin =
75         std::chrono::steady_clock::now();
76 
77     while (("requested" == dumpStatus ||
78             operationStatusInProgress == dumpStatus) &&
79            0 != timeRemaining)
80     {
81         bus.wait(timeRemaining);
82         uint64_t timeElapsed =
83             std::chrono::duration_cast<std::chrono::microseconds>(
84                 std::chrono::steady_clock::now() - begin)
85                 .count();
86 
87         timeRemaining =
88             timeElapsed > timeRemaining ? 0 : timeRemaining - timeElapsed;
89 
90         bus.process_discard();
91     }
92 
93     if (0 == timeRemaining)
94     {
95         trace::err("dump request timed out after %" PRIu64 " microseconds",
96                    dumpTimeout);
97     }
98 
99     trace::inf("dump status: %s", dumpStatus.c_str());
100 }
101 
102 /** Request a dump from the dump manager */
103 void requestDump(uint32_t i_logId, const DumpParameters& i_dumpParameters)
104 {
105     constexpr auto path      = "/org/openpower/dump";
106     constexpr auto interface = "xyz.openbmc_project.Dump.Create";
107     constexpr auto function  = "CreateDump";
108 
109     sdbusplus::message_t method;
110 
111     if (0 == dbusMethod(path, interface, function, method))
112     {
113         try
114         {
115             // dbus call arguments
116             std::map<std::string, std::variant<std::string, uint64_t>>
117                 createParams;
118             createParams["com.ibm.Dump.Create.CreateParameters.ErrorLogId"] =
119                 uint64_t(i_logId);
120             if (DumpType::Hostboot == i_dumpParameters.dumpType)
121             {
122                 createParams["com.ibm.Dump.Create.CreateParameters.DumpType"] =
123                     "com.ibm.Dump.Create.DumpType.Hostboot";
124             }
125             else if (DumpType::Hardware == i_dumpParameters.dumpType)
126             {
127                 createParams["com.ibm.Dump.Create.CreateParameters.DumpType"] =
128                     "com.ibm.Dump.Create.DumpType.Hardware";
129                 createParams
130                     ["com.ibm.Dump.Create.CreateParameters.FailingUnitId"] =
131                         i_dumpParameters.unitId;
132             }
133             else if (DumpType::SBE == i_dumpParameters.dumpType)
134             {
135                 createParams["com.ibm.Dump.Create.CreateParameters.DumpType"] =
136                     "com.ibm.Dump.Create.DumpType.SBE";
137                 createParams
138                     ["com.ibm.Dump.Create.CreateParameters.FailingUnitId"] =
139                         i_dumpParameters.unitId;
140             }
141             method.append(createParams);
142 
143             // using system dbus
144             auto bus      = sdbusplus::bus::new_system();
145             auto response = bus.call(method);
146 
147             // reply will be type dbus::ObjectPath
148             sdbusplus::message::object_path reply;
149             response.read(reply);
150 
151             // monitor dump progress
152             monitorDump(reply);
153         }
154         catch (const sdbusplus::exception::SdBusError& e)
155         {
156             trace::err("requestDump exception");
157             trace::err(e.what());
158         }
159     }
160 }
161 
162 } // namespace attn
163