1 #include "watchdog_service.hpp" 2 3 #include <ipmid/api.hpp> 4 #include <phosphor-logging/elog-errors.hpp> 5 #include <phosphor-logging/elog.hpp> 6 #include <phosphor-logging/lg2.hpp> 7 #include <sdbusplus/bus.hpp> 8 #include <sdbusplus/message.hpp> 9 #include <xyz/openbmc_project/Common/error.hpp> 10 #include <xyz/openbmc_project/State/Watchdog/server.hpp> 11 12 #include <exception> 13 #include <stdexcept> 14 #include <string> 15 16 using phosphor::logging::elog; 17 using phosphor::logging::entry; 18 using phosphor::logging::level; 19 using phosphor::logging::log; 20 using sdbusplus::common::xyz::openbmc_project::state::convertForMessage; 21 using sdbusplus::error::xyz::openbmc_project::common::InternalFailure; 22 using sdbusplus::server::xyz::openbmc_project::state::Watchdog; 23 24 static constexpr char wd_path[] = "/xyz/openbmc_project/watchdog/host0"; 25 static constexpr char wd_intf[] = "xyz.openbmc_project.State.Watchdog"; 26 static constexpr char prop_intf[] = "org.freedesktop.DBus.Properties"; 27 28 ipmi::ServiceCache WatchdogService::wd_service(wd_intf, wd_path); 29 30 WatchdogService::WatchdogService() : bus(ipmid_get_sd_bus_connection()) {} 31 32 void WatchdogService::resetTimeRemaining(bool enableWatchdog) 33 { 34 bool wasValid = wd_service.isValid(bus); 35 auto request = wd_service.newMethodCall(bus, wd_intf, "ResetTimeRemaining"); 36 request.append(enableWatchdog); 37 try 38 { 39 auto response = bus.call(request); 40 } 41 catch (const std::exception& e) 42 { 43 wd_service.invalidate(); 44 if (wasValid) 45 { 46 // Retry the request once in case the cached service was stale 47 return resetTimeRemaining(enableWatchdog); 48 } 49 lg2::error("WatchdogService: Method error resetting time remaining, " 50 "ENABLE_WATCHDOG: {ENABLE_WATCHDOG}, ERROR: {ERROR}", 51 "ENABLE_WATCHDOG", enableWatchdog, "ERROR", e); 52 elog<InternalFailure>(); 53 } 54 } 55 56 WatchdogService::Properties WatchdogService::getProperties() 57 { 58 bool wasValid = wd_service.isValid(bus); 59 auto request = wd_service.newMethodCall(bus, prop_intf, "GetAll"); 60 request.append(wd_intf); 61 62 std::map<std::string, std::variant<bool, uint64_t, std::string>> properties; 63 try 64 { 65 auto response = bus.call(request); 66 response.read(properties); 67 } 68 catch (const std::exception& e) 69 { 70 wd_service.invalidate(); 71 if (wasValid) 72 { 73 // Retry the request once in case the cached service was stale 74 return getProperties(); 75 } 76 lg2::error("WatchdogService: Method error getting properties: {ERROR}", 77 "ERROR", e); 78 elog<InternalFailure>(); 79 } 80 81 try 82 { 83 Properties wd_prop; 84 wd_prop.initialized = std::get<bool>(properties.at("Initialized")); 85 wd_prop.enabled = std::get<bool>(properties.at("Enabled")); 86 wd_prop.expireAction = Watchdog::convertActionFromString( 87 std::get<std::string>(properties.at("ExpireAction"))); 88 wd_prop.timerUse = Watchdog::convertTimerUseFromString( 89 std::get<std::string>(properties.at("CurrentTimerUse"))); 90 wd_prop.expiredTimerUse = Watchdog::convertTimerUseFromString( 91 std::get<std::string>(properties.at("ExpiredTimerUse"))); 92 93 wd_prop.interval = std::get<uint64_t>(properties.at("Interval")); 94 wd_prop.timeRemaining = 95 std::get<uint64_t>(properties.at("TimeRemaining")); 96 return wd_prop; 97 } 98 catch (const std::exception& e) 99 { 100 lg2::error("WatchdogService: Decode error in get properties: {ERROR}", 101 "ERROR", e); 102 elog<InternalFailure>(); 103 } 104 105 // Needed instead of elog<InternalFailure>() since the compiler can't 106 // deduce the that elog<>() always throws 107 throw std::runtime_error( 108 "WatchdogService: Should not reach end of getProperties"); 109 } 110 111 template <typename T> 112 T WatchdogService::getProperty(const std::string& key) 113 { 114 bool wasValid = wd_service.isValid(bus); 115 auto request = wd_service.newMethodCall(bus, prop_intf, "Get"); 116 request.append(wd_intf, key); 117 try 118 { 119 auto response = bus.call(request); 120 std::variant<T> value; 121 response.read(value); 122 return std::get<T>(value); 123 } 124 catch (const std::exception& e) 125 { 126 wd_service.invalidate(); 127 if (wasValid) 128 { 129 // Retry the request once in case the cached service was stale 130 return getProperty<T>(key); 131 } 132 lg2::error("WatchdogService: Method error getting {PROPERTY}: {ERROR}", 133 "PROPERTY", key, "ERROR", e); 134 elog<InternalFailure>(); 135 } 136 137 // Needed instead of elog<InternalFailure>() since the compiler can't 138 // deduce the that elog<>() always throws 139 throw std::runtime_error( 140 "WatchdogService: Should not reach end of getProperty"); 141 } 142 143 template <typename T> 144 void WatchdogService::setProperty(const std::string& key, const T& val) 145 { 146 bool wasValid = wd_service.isValid(bus); 147 auto request = wd_service.newMethodCall(bus, prop_intf, "Set"); 148 request.append(wd_intf, key, std::variant<T>(val)); 149 try 150 { 151 auto response = bus.call(request); 152 } 153 catch (const std::exception& e) 154 { 155 wd_service.invalidate(); 156 if (wasValid) 157 { 158 // Retry the request once in case the cached service was stale 159 setProperty(key, val); 160 return; 161 } 162 lg2::error("WatchdogService: Method error setting {PROPERTY}: {ERROR}", 163 "PROPERTY", key, "ERROR", e); 164 elog<InternalFailure>(); 165 } 166 } 167 168 bool WatchdogService::getInitialized() 169 { 170 return getProperty<bool>("Initialized"); 171 } 172 173 void WatchdogService::setInitialized(bool initialized) 174 { 175 setProperty("Initialized", initialized); 176 } 177 178 void WatchdogService::setEnabled(bool enabled) 179 { 180 setProperty("Enabled", enabled); 181 } 182 183 void WatchdogService::setLogTimeout(bool LogTimeout) 184 { 185 setProperty("LogTimeout", LogTimeout); 186 } 187 188 void WatchdogService::setExpireAction(Action expireAction) 189 { 190 setProperty("ExpireAction", convertForMessage(expireAction)); 191 } 192 193 void WatchdogService::setTimerUse(TimerUse timerUse) 194 { 195 setProperty("CurrentTimerUse", convertForMessage(timerUse)); 196 } 197 198 void WatchdogService::setExpiredTimerUse(TimerUse timerUse) 199 { 200 setProperty("ExpiredTimerUse", convertForMessage(timerUse)); 201 } 202 203 void WatchdogService::setInterval(uint64_t interval) 204 { 205 setProperty("Interval", interval); 206 } 207