1 #include <fmt/format.h> 2 3 #include <phosphor-logging/log.hpp> 4 #include <sdbusplus/bus.hpp> 5 #include <sdbusplus/bus/match.hpp> 6 #include <watchdog_dbus.hpp> 7 #include <watchdog_handler.hpp> 8 #include <watchdog_logging.hpp> 9 10 namespace watchdog 11 { 12 namespace dump 13 { 14 15 using namespace phosphor::logging; 16 17 /** 18 * @brief Callback for dump request properties change signal monitor 19 * 20 * @param msg - dbus message from the dbus match infrastructure 21 * @param path - the object path we are monitoring 22 * @param progressStatus - dump progress status 23 * @return Always non-zero indicating no error, no cascading callbacks 24 */ 25 uint dumpStatusChanged(sdbusplus::message_t& msg, std::string path, 26 DumpProgressStatus& progressStatus) 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 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) && ("xyz.openbmc_project.Common.Progress." 43 "OperationStatus.InProgress" != *status)) 44 { 45 // dump is not in InProgress state, trace some info and change in 46 // progress status 47 log<level::INFO>(path.c_str()); 48 log<level::INFO>((*status).c_str()); 49 50 if ("xyz.openbmc_project.Common.Progress.OperationStatus." 51 "Completed" == *status) 52 { 53 // Dump completed successfully 54 progressStatus = DumpProgressStatus::Completed; 55 } 56 else 57 { 58 // Dump Failed 59 progressStatus = DumpProgressStatus::Failed; 60 } 61 } 62 } 63 64 return 1; // non-negative return code for successful callback 65 } 66 67 /** 68 * @brief Register a callback for dump progress status changes 69 * 70 * @param path - the object path of the dump to monitor 71 * @param timeout - timeout - timeout interval in seconds 72 */ 73 void monitorDump(const std::string& path, const uint32_t timeout) 74 { 75 // callback will update progressStatus 76 DumpProgressStatus progressStatus = DumpProgressStatus::InProgress; 77 78 // setup the signal match rules and callback 79 std::string matchInterface = "xyz.openbmc_project.Common.Progress"; 80 auto bus = sdbusplus::bus::new_system(); 81 82 std::unique_ptr<sdbusplus::bus::match_t> match = 83 std::make_unique<sdbusplus::bus::match_t>( 84 bus, 85 sdbusplus::bus::match::rules::propertiesChanged( 86 path.c_str(), matchInterface.c_str()), 87 [&](auto& msg) { 88 return dumpStatusChanged(msg, path, progressStatus); 89 }); 90 91 // wait for dump status to be completed (complete == true) 92 // or until timeout interval 93 94 bool timedOut = false; 95 uint32_t secondsCount = 0; 96 while ((DumpProgressStatus::InProgress == progressStatus) && !timedOut) 97 { 98 bus.wait(std::chrono::seconds(1)); 99 bus.process_discard(); 100 101 if (++secondsCount == timeout) 102 { 103 timedOut = true; 104 } 105 } 106 107 if (timedOut) 108 { 109 log<level::ERR>("Dump progress status did not change to " 110 "complete within the timeout interval, exiting..."); 111 } 112 else if (DumpProgressStatus::Completed == progressStatus) 113 { 114 log<level::INFO>("dump collection completed"); 115 } 116 else 117 { 118 log<level::INFO>("dump collection failed"); 119 } 120 } 121 122 void requestDump(const DumpParameters& dumpParameters) 123 { 124 constexpr auto path = "/org/openpower/dump"; 125 constexpr auto interface = "xyz.openbmc_project.Dump.Create"; 126 constexpr auto function = "CreateDump"; 127 128 sdbusplus::message_t method; 129 130 if (0 == dbusMethod(path, interface, function, method)) 131 { 132 try 133 { 134 // dbus call arguments 135 std::map<std::string, std::variant<std::string, uint64_t>> 136 createParams; 137 createParams["com.ibm.Dump.Create.CreateParameters.ErrorLogId"] = 138 uint64_t(dumpParameters.logId); 139 if (DumpType::Hostboot == dumpParameters.dumpType) 140 { 141 log<level::INFO>("hostboot dump requested"); 142 createParams["com.ibm.Dump.Create.CreateParameters.DumpType"] = 143 "com.ibm.Dump.Create.DumpType.Hostboot"; 144 } 145 else if (DumpType::SBE == dumpParameters.dumpType) 146 { 147 log<level::INFO>("SBE dump requested"); 148 createParams["com.ibm.Dump.Create.CreateParameters.DumpType"] = 149 "com.ibm.Dump.Create.DumpType.SBE"; 150 createParams 151 ["com.ibm.Dump.Create.CreateParameters.FailingUnitId"] = 152 dumpParameters.unitId; 153 } 154 155 method.append(createParams); 156 157 // using system dbus 158 auto bus = sdbusplus::bus::new_system(); 159 auto response = bus.call(method); 160 161 // reply will be type dbus::ObjectPath 162 sdbusplus::message::object_path reply; 163 response.read(reply); 164 165 // monitor dump progress 166 monitorDump(reply, dumpParameters.timeout); 167 } 168 catch (const sdbusplus::exception_t& e) 169 { 170 constexpr auto ERROR_DUMP_DISABLED = 171 "xyz.openbmc_project.Dump.Create.Error.Disabled"; 172 if (e.name() == ERROR_DUMP_DISABLED) 173 { 174 // Dump is disabled, Skip the dump collection. 175 log<level::INFO>( 176 fmt::format( 177 "Dump is disabled on({}), skipping dump collection", 178 dumpParameters.unitId) 179 .c_str()); 180 } 181 else 182 { 183 log<level::ERR>( 184 fmt::format("D-Bus call createDump exception ", 185 "OBJPATH={}, INTERFACE={}, EXCEPTION={}", path, 186 interface, e.what()) 187 .c_str()); 188 } 189 } 190 } 191 } 192 193 } // namespace dump 194 } // namespace watchdog 195