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