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