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 */ 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 */ 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 */ 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 */ 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