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
WatchdogService()30 WatchdogService::WatchdogService() : bus(ipmid_get_sd_bus_connection()) {}
31
resetTimeRemaining(bool enableWatchdog)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
getProperties()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>
getProperty(const std::string & key)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>
setProperty(const std::string & key,const T & val)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
getInitialized()168 bool WatchdogService::getInitialized()
169 {
170 return getProperty<bool>("Initialized");
171 }
172
setInitialized(bool initialized)173 void WatchdogService::setInitialized(bool initialized)
174 {
175 setProperty("Initialized", initialized);
176 }
177
setEnabled(bool enabled)178 void WatchdogService::setEnabled(bool enabled)
179 {
180 setProperty("Enabled", enabled);
181 }
182
setLogTimeout(bool LogTimeout)183 void WatchdogService::setLogTimeout(bool LogTimeout)
184 {
185 setProperty("LogTimeout", LogTimeout);
186 }
187
setExpireAction(Action expireAction)188 void WatchdogService::setExpireAction(Action expireAction)
189 {
190 setProperty("ExpireAction", convertForMessage(expireAction));
191 }
192
setTimerUse(TimerUse timerUse)193 void WatchdogService::setTimerUse(TimerUse timerUse)
194 {
195 setProperty("CurrentTimerUse", convertForMessage(timerUse));
196 }
197
setExpiredTimerUse(TimerUse timerUse)198 void WatchdogService::setExpiredTimerUse(TimerUse timerUse)
199 {
200 setProperty("ExpiredTimerUse", convertForMessage(timerUse));
201 }
202
setInterval(uint64_t interval)203 void WatchdogService::setInterval(uint64_t interval)
204 {
205 setProperty("Interval", interval);
206 }
207