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