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/log.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 log<level::ERR>( 50 "WatchdogService: Method error resetting time remaining", 51 entry("ENABLE_WATCHDOG=%d", !!enableWatchdog), 52 entry("ERROR=%s", e.what())); 53 elog<InternalFailure>(); 54 } 55 } 56 57 WatchdogService::Properties WatchdogService::getProperties() 58 { 59 bool wasValid = wd_service.isValid(bus); 60 auto request = wd_service.newMethodCall(bus, prop_intf, "GetAll"); 61 request.append(wd_intf); 62 63 std::map<std::string, std::variant<bool, uint64_t, std::string>> properties; 64 try 65 { 66 auto response = bus.call(request); 67 response.read(properties); 68 } 69 catch (const std::exception& e) 70 { 71 wd_service.invalidate(); 72 if (wasValid) 73 { 74 // Retry the request once in case the cached service was stale 75 return getProperties(); 76 } 77 log<level::ERR>("WatchdogService: Method error getting properties", 78 entry("ERROR=%s", e.what())); 79 elog<InternalFailure>(); 80 } 81 82 try 83 { 84 Properties wd_prop; 85 wd_prop.initialized = std::get<bool>(properties.at("Initialized")); 86 wd_prop.enabled = std::get<bool>(properties.at("Enabled")); 87 wd_prop.expireAction = Watchdog::convertActionFromString( 88 std::get<std::string>(properties.at("ExpireAction"))); 89 wd_prop.timerUse = Watchdog::convertTimerUseFromString( 90 std::get<std::string>(properties.at("CurrentTimerUse"))); 91 wd_prop.expiredTimerUse = Watchdog::convertTimerUseFromString( 92 std::get<std::string>(properties.at("ExpiredTimerUse"))); 93 94 wd_prop.interval = std::get<uint64_t>(properties.at("Interval")); 95 wd_prop.timeRemaining = 96 std::get<uint64_t>(properties.at("TimeRemaining")); 97 return wd_prop; 98 } 99 catch (const std::exception& e) 100 { 101 log<level::ERR>("WatchdogService: Decode error in get properties", 102 entry("ERROR=%s", e.what())); 103 elog<InternalFailure>(); 104 } 105 106 // Needed instead of elog<InternalFailure>() since the compiler can't 107 // deduce the that elog<>() always throws 108 throw std::runtime_error( 109 "WatchdogService: Should not reach end of getProperties"); 110 } 111 112 template <typename T> 113 T WatchdogService::getProperty(const std::string& key) 114 { 115 bool wasValid = wd_service.isValid(bus); 116 auto request = wd_service.newMethodCall(bus, prop_intf, "Get"); 117 request.append(wd_intf, key); 118 try 119 { 120 auto response = bus.call(request); 121 std::variant<T> value; 122 response.read(value); 123 return std::get<T>(value); 124 } 125 catch (const std::exception& e) 126 { 127 wd_service.invalidate(); 128 if (wasValid) 129 { 130 // Retry the request once in case the cached service was stale 131 return getProperty<T>(key); 132 } 133 log<level::ERR>("WatchdogService: Method error getting property", 134 entry("PROPERTY=%s", key.c_str()), 135 entry("ERROR=%s", e.what())); 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 try 152 { 153 auto response = bus.call(request); 154 } 155 catch (const std::exception& e) 156 { 157 wd_service.invalidate(); 158 if (wasValid) 159 { 160 // Retry the request once in case the cached service was stale 161 setProperty(key, val); 162 return; 163 } 164 log<level::ERR>("WatchdogService: Method error setting property", 165 entry("PROPERTY=%s", key.c_str()), 166 entry("ERROR=%s", e.what())); 167 elog<InternalFailure>(); 168 } 169 } 170 171 bool WatchdogService::getInitialized() 172 { 173 return getProperty<bool>("Initialized"); 174 } 175 176 void WatchdogService::setInitialized(bool initialized) 177 { 178 setProperty("Initialized", initialized); 179 } 180 181 void WatchdogService::setEnabled(bool enabled) 182 { 183 setProperty("Enabled", enabled); 184 } 185 186 void WatchdogService::setLogTimeout(bool LogTimeout) 187 { 188 setProperty("LogTimeout", LogTimeout); 189 } 190 191 void WatchdogService::setExpireAction(Action expireAction) 192 { 193 setProperty("ExpireAction", convertForMessage(expireAction)); 194 } 195 196 void WatchdogService::setTimerUse(TimerUse timerUse) 197 { 198 setProperty("CurrentTimerUse", convertForMessage(timerUse)); 199 } 200 201 void WatchdogService::setExpiredTimerUse(TimerUse timerUse) 202 { 203 setProperty("ExpiredTimerUse", convertForMessage(timerUse)); 204 } 205 206 void WatchdogService::setInterval(uint64_t interval) 207 { 208 setProperty("Interval", interval); 209 } 210