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