blob: f97c45ba78640a9263fb57d3e1ba19232169f771 [file] [log] [blame]
Patrick Venture5e6ac712017-10-25 12:16:19 -07001#include "watchdog.hpp"
2
Patrick Venture0b02be92018-08-31 11:55:55 -07003#include "watchdog_service.hpp"
4
William A. Kennington III52575252018-02-09 15:54:56 -08005#include <endian.h>
Patrick Venture0b02be92018-08-31 11:55:55 -07006
Yong Lia729bf42019-10-14 12:42:10 +08007#include <bitset>
Patrick Venture0b02be92018-08-31 11:55:55 -07008#include <cstdint>
Vernon Mauerye08fbff2019-04-03 09:19:34 -07009#include <ipmid/api.hpp>
William A. Kennington III021b4c12018-05-10 11:12:51 -070010#include <phosphor-logging/elog-errors.hpp>
Patrick Venture0b02be92018-08-31 11:55:55 -070011#include <phosphor-logging/elog.hpp>
William A. Kennington III52575252018-02-09 15:54:56 -080012#include <phosphor-logging/log.hpp>
13#include <string>
William A. Kennington III021b4c12018-05-10 11:12:51 -070014#include <xyz/openbmc_project/Common/error.hpp>
Patrick Venture894571d2017-11-09 14:46:54 -080015
William A. Kennington IIIbae471c2018-06-15 10:38:01 -070016using phosphor::logging::commit;
William A. Kennington III52575252018-02-09 15:54:56 -080017using phosphor::logging::level;
18using phosphor::logging::log;
William A. Kennington III021b4c12018-05-10 11:12:51 -070019using sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Patrick Venture5e6ac712017-10-25 12:16:19 -070020
William A. Kennington IIIbae471c2018-06-15 10:38:01 -070021static bool lastCallSuccessful = false;
22
23void reportError()
24{
25 // We don't want to fill the SEL with errors if the daemon dies and doesn't
26 // come back but the watchdog keeps on ticking. Instead, we only report the
27 // error if we haven't reported one since the last successful call
28 if (!lastCallSuccessful)
29 {
30 return;
31 }
32 lastCallSuccessful = false;
33
34 // TODO: This slow down the end of the IPMI transaction waiting
35 // for the commit to finish. commit<>() can take at least 5 seconds
36 // to complete. 5s is very slow for an IPMI command and ends up
37 // congesting the IPMI channel needlessly, especially if the watchdog
38 // is ticking fairly quickly and we have some transient issues.
39 commit<InternalFailure>();
40}
41
Vernon Mauery11df4f62019-03-25 14:17:54 -070042ipmi::RspType<> ipmiAppResetWatchdogTimer()
Patrick Venture5e6ac712017-10-25 12:16:19 -070043{
William A. Kennington III52575252018-02-09 15:54:56 -080044 try
45 {
46 WatchdogService wd_service;
William A. Kennington III52575252018-02-09 15:54:56 -080047
William A. Kennington IIIde14a022018-02-09 16:11:18 -080048 // Notify the caller if we haven't initialized our timer yet
49 // so it can configure actions and timeouts
William A. Kennington III2ecf5122018-04-27 14:31:51 -070050 if (!wd_service.getInitialized())
William A. Kennington IIIde14a022018-02-09 16:11:18 -080051 {
William A. Kennington IIIbae471c2018-06-15 10:38:01 -070052 lastCallSuccessful = true;
Vernon Mauery11df4f62019-03-25 14:17:54 -070053
54 constexpr uint8_t ccWatchdogNotInit = 0x80;
55 return ipmi::response(ccWatchdogNotInit);
William A. Kennington IIIde14a022018-02-09 16:11:18 -080056 }
57
William A. Kennington III4b017a92018-04-27 14:31:08 -070058 // The ipmi standard dictates we enable the watchdog during reset
59 wd_service.resetTimeRemaining(true);
William A. Kennington IIIbae471c2018-06-15 10:38:01 -070060 lastCallSuccessful = true;
Vernon Mauery11df4f62019-03-25 14:17:54 -070061 return ipmi::responseSuccess();
Patrick Venture5e6ac712017-10-25 12:16:19 -070062 }
William A. Kennington III021b4c12018-05-10 11:12:51 -070063 catch (const InternalFailure& e)
64 {
William A. Kennington IIIbae471c2018-06-15 10:38:01 -070065 reportError();
Vernon Mauery11df4f62019-03-25 14:17:54 -070066 return ipmi::responseUnspecifiedError();
William A. Kennington III021b4c12018-05-10 11:12:51 -070067 }
William A. Kennington III52575252018-02-09 15:54:56 -080068 catch (const std::exception& e)
69 {
70 const std::string e_str = std::string("wd_reset: ") + e.what();
71 log<level::ERR>(e_str.c_str());
William A. Kennington IIIbae471c2018-06-15 10:38:01 -070072 reportError();
Vernon Mauery11df4f62019-03-25 14:17:54 -070073 return ipmi::responseUnspecifiedError();
William A. Kennington III5325f2c2018-01-08 15:17:09 -080074 }
William A. Kennington III52575252018-02-09 15:54:56 -080075 catch (...)
76 {
77 log<level::ERR>("wd_reset: Unknown Error");
William A. Kennington IIIbae471c2018-06-15 10:38:01 -070078 reportError();
Vernon Mauery11df4f62019-03-25 14:17:54 -070079 return ipmi::responseUnspecifiedError();
William A. Kennington III5325f2c2018-01-08 15:17:09 -080080 }
Patrick Venture5e6ac712017-10-25 12:16:19 -070081}
William A. Kennington III61d5f7b2018-02-09 15:23:53 -080082
William A. Kennington III52575252018-02-09 15:54:56 -080083static constexpr uint8_t wd_dont_stop = 0x1 << 6;
84static constexpr uint8_t wd_timeout_action_mask = 0x3;
85
Deepak Kumar Sahucfae9482019-05-20 14:58:58 +000086static constexpr uint8_t wdTimerUseResTimer1 = 0x0;
87static constexpr uint8_t wdTimerUseResTimer2 = 0x6;
88static constexpr uint8_t wdTimerUseResTimer3 = 0x7;
89
Yong Li4dd71af2019-09-29 14:18:07 +080090static constexpr uint8_t wdTimeoutActionMax = 3;
Deepak Kumar Sahucfae9482019-05-20 14:58:58 +000091static constexpr uint8_t wdTimeoutInterruptTimer = 0x04;
Yong Li118907e2019-01-11 17:36:17 +080092
Patrick Venture0b02be92018-08-31 11:55:55 -070093enum class IpmiAction : uint8_t
94{
William A. Kennington III52575252018-02-09 15:54:56 -080095 None = 0x0,
96 HardReset = 0x1,
97 PowerOff = 0x2,
98 PowerCycle = 0x3,
99};
100
William A. Kennington IIIb638de22018-02-09 16:12:53 -0800101/** @brief Converts an IPMI Watchdog Action to DBUS defined action
102 * @param[in] ipmi_action The IPMI Watchdog Action
103 * @return The Watchdog Action that the ipmi_action maps to
104 */
105WatchdogService::Action ipmiActionToWdAction(IpmiAction ipmi_action)
106{
Patrick Venture0b02be92018-08-31 11:55:55 -0700107 switch (ipmi_action)
William A. Kennington IIIb638de22018-02-09 16:12:53 -0800108 {
109 case IpmiAction::None:
110 {
111 return WatchdogService::Action::None;
112 }
113 case IpmiAction::HardReset:
114 {
115 return WatchdogService::Action::HardReset;
116 }
117 case IpmiAction::PowerOff:
118 {
119 return WatchdogService::Action::PowerOff;
120 }
121 case IpmiAction::PowerCycle:
122 {
123 return WatchdogService::Action::PowerCycle;
124 }
125 default:
126 {
127 throw std::domain_error("IPMI Action is invalid");
128 }
129 }
130}
131
Yong Li118907e2019-01-11 17:36:17 +0800132enum class IpmiTimerUse : uint8_t
133{
134 Reserved = 0x0,
135 BIOSFRB2 = 0x1,
136 BIOSPOST = 0x2,
137 OSLoad = 0x3,
138 SMSOS = 0x4,
139 OEM = 0x5,
140};
141
142WatchdogService::TimerUse ipmiTimerUseToWdTimerUse(IpmiTimerUse ipmiTimerUse)
143{
144 switch (ipmiTimerUse)
145 {
146 case IpmiTimerUse::Reserved:
147 {
148 return WatchdogService::TimerUse::Reserved;
149 }
150 case IpmiTimerUse::BIOSFRB2:
151 {
152 return WatchdogService::TimerUse::BIOSFRB2;
153 }
154 case IpmiTimerUse::BIOSPOST:
155 {
156 return WatchdogService::TimerUse::BIOSPOST;
157 }
158 case IpmiTimerUse::OSLoad:
159 {
160 return WatchdogService::TimerUse::OSLoad;
161 }
162 case IpmiTimerUse::SMSOS:
163 {
164 return WatchdogService::TimerUse::SMSOS;
165 }
166 case IpmiTimerUse::OEM:
167 {
168 return WatchdogService::TimerUse::OEM;
169 }
170 default:
171 {
172 return WatchdogService::TimerUse::Reserved;
173 }
174 }
175}
176
Yong Li4dd71af2019-09-29 14:18:07 +0800177static bool timerNotLogFlags = false;
Yong Lia729bf42019-10-14 12:42:10 +0800178static std::bitset<8> timerUseExpirationFlags = 0;
Yong Li4dd71af2019-09-29 14:18:07 +0800179static uint3_t timerPreTimeoutInterrupt = 0;
Yong Lia729bf42019-10-14 12:42:10 +0800180static constexpr uint8_t wdExpirationFlagReservedBit0 = 0x0;
181static constexpr uint8_t wdExpirationFlagReservedBit6 = 0x6;
182static constexpr uint8_t wdExpirationFlagReservedBit7 = 0x7;
William A. Kennington III52575252018-02-09 15:54:56 -0800183
Deepak Kumar Sahucfae9482019-05-20 14:58:58 +0000184/**@brief The Set Watchdog Timer ipmi command.
185 *
186 * @param
187 * - timerUse
188 * - dontStopTimer
189 * - dontLog
190 * - timerAction
191 * - pretimeout
192 * - expireFlags
193 * - initialCountdown
194 *
195 * @return completion code on success.
196 **/
Yong Lia729bf42019-10-14 12:42:10 +0800197ipmi::RspType<>
198 ipmiSetWatchdogTimer(uint3_t timerUse, uint3_t reserved, bool dontStopTimer,
199 bool dontLog, uint3_t timeoutAction, uint1_t reserved1,
200 uint3_t preTimeoutInterrupt, uint1_t reserved2,
201 uint8_t preTimeoutInterval,
202 std::bitset<8> expFlagValue, uint16_t initialCountdown)
William A. Kennington III61d5f7b2018-02-09 15:23:53 -0800203{
Deepak Kumar Sahucfae9482019-05-20 14:58:58 +0000204 if ((timerUse == wdTimerUseResTimer1) ||
205 (timerUse == wdTimerUseResTimer2) ||
206 (timerUse == wdTimerUseResTimer3) ||
Yong Li4dd71af2019-09-29 14:18:07 +0800207 (timeoutAction > wdTimeoutActionMax) ||
Deepak Kumar Sahucfae9482019-05-20 14:58:58 +0000208 (preTimeoutInterrupt == wdTimeoutInterruptTimer) ||
Yong Lia729bf42019-10-14 12:42:10 +0800209 (reserved | reserved1 | reserved2 |
210 expFlagValue.test(wdExpirationFlagReservedBit0) |
211 expFlagValue.test(wdExpirationFlagReservedBit6) |
212 expFlagValue.test(wdExpirationFlagReservedBit7)))
William A. Kennington III52575252018-02-09 15:54:56 -0800213 {
Deepak Kumar Sahucfae9482019-05-20 14:58:58 +0000214 return ipmi::responseInvalidFieldRequest();
William A. Kennington III52575252018-02-09 15:54:56 -0800215 }
Deepak Kumar Sahucfae9482019-05-20 14:58:58 +0000216
217 if (preTimeoutInterval > (initialCountdown / 10))
218 {
219 return ipmi::responseInvalidFieldRequest();
220 }
221
Yong Li4dd71af2019-09-29 14:18:07 +0800222 timerNotLogFlags = dontLog;
223 timerPreTimeoutInterrupt = preTimeoutInterrupt;
William A. Kennington III61d5f7b2018-02-09 15:23:53 -0800224
William A. Kennington III52575252018-02-09 15:54:56 -0800225 try
William A. Kennington III61d5f7b2018-02-09 15:23:53 -0800226 {
William A. Kennington III52575252018-02-09 15:54:56 -0800227 WatchdogService wd_service;
228 // Stop the timer if the don't stop bit is not set
Deepak Kumar Sahucfae9482019-05-20 14:58:58 +0000229 if (!(dontStopTimer))
William A. Kennington III52575252018-02-09 15:54:56 -0800230 {
231 wd_service.setEnabled(false);
William A. Kennington III61d5f7b2018-02-09 15:23:53 -0800232 }
233
William A. Kennington III52575252018-02-09 15:54:56 -0800234 // Set the action based on the request
Deepak Kumar Sahucfae9482019-05-20 14:58:58 +0000235 const auto ipmi_action = static_cast<IpmiAction>(
236 static_cast<uint8_t>(timeoutAction) & wd_timeout_action_mask);
William A. Kennington IIIb638de22018-02-09 16:12:53 -0800237 wd_service.setExpireAction(ipmiActionToWdAction(ipmi_action));
William A. Kennington III52575252018-02-09 15:54:56 -0800238
Yong Li118907e2019-01-11 17:36:17 +0800239 const auto ipmiTimerUse =
Deepak Kumar Sahucfae9482019-05-20 14:58:58 +0000240 static_cast<IpmiTimerUse>(static_cast<uint8_t>(timerUse));
Yong Li118907e2019-01-11 17:36:17 +0800241 wd_service.setTimerUse(ipmiTimerUseToWdTimerUse(ipmiTimerUse));
242
Deepak Kumar Sahucfae9482019-05-20 14:58:58 +0000243 wd_service.setExpiredTimerUse(WatchdogService::TimerUse::Reserved);
244
Yong Lia729bf42019-10-14 12:42:10 +0800245 timerUseExpirationFlags &= ~expFlagValue;
Deepak Kumar Sahucfae9482019-05-20 14:58:58 +0000246
William A. Kennington III52575252018-02-09 15:54:56 -0800247 // Set the new interval and the time remaining deci -> mill seconds
Deepak Kumar Sahucfae9482019-05-20 14:58:58 +0000248 const uint64_t interval = initialCountdown * 100;
William A. Kennington III52575252018-02-09 15:54:56 -0800249 wd_service.setInterval(interval);
250 wd_service.setTimeRemaining(interval);
251
William A. Kennington IIIde14a022018-02-09 16:11:18 -0800252 // Mark as initialized so that future resets behave correctly
253 wd_service.setInitialized(true);
254
William A. Kennington IIIbae471c2018-06-15 10:38:01 -0700255 lastCallSuccessful = true;
Deepak Kumar Sahucfae9482019-05-20 14:58:58 +0000256 return ipmi::responseSuccess();
William A. Kennington III61d5f7b2018-02-09 15:23:53 -0800257 }
Patrick Venture0b02be92018-08-31 11:55:55 -0700258 catch (const std::domain_error&)
William A. Kennington III52575252018-02-09 15:54:56 -0800259 {
Deepak Kumar Sahucfae9482019-05-20 14:58:58 +0000260 return ipmi::responseInvalidFieldRequest();
William A. Kennington III52575252018-02-09 15:54:56 -0800261 }
William A. Kennington III021b4c12018-05-10 11:12:51 -0700262 catch (const InternalFailure& e)
263 {
William A. Kennington IIIbae471c2018-06-15 10:38:01 -0700264 reportError();
Deepak Kumar Sahucfae9482019-05-20 14:58:58 +0000265 return ipmi::responseUnspecifiedError();
William A. Kennington III021b4c12018-05-10 11:12:51 -0700266 }
William A. Kennington III52575252018-02-09 15:54:56 -0800267 catch (const std::exception& e)
268 {
269 const std::string e_str = std::string("wd_set: ") + e.what();
270 log<level::ERR>(e_str.c_str());
William A. Kennington IIIbae471c2018-06-15 10:38:01 -0700271 reportError();
Deepak Kumar Sahucfae9482019-05-20 14:58:58 +0000272 return ipmi::responseUnspecifiedError();
William A. Kennington III52575252018-02-09 15:54:56 -0800273 }
274 catch (...)
275 {
276 log<level::ERR>("wd_set: Unknown Error");
William A. Kennington IIIbae471c2018-06-15 10:38:01 -0700277 reportError();
Deepak Kumar Sahucfae9482019-05-20 14:58:58 +0000278 return ipmi::responseUnspecifiedError();
William A. Kennington III52575252018-02-09 15:54:56 -0800279 }
William A. Kennington III61d5f7b2018-02-09 15:23:53 -0800280}
William A. Kennington III73f44512018-02-09 15:28:46 -0800281
282/** @brief Converts a DBUS Watchdog Action to IPMI defined action
283 * @param[in] wd_action The DBUS Watchdog Action
284 * @return The IpmiAction that the wd_action maps to
285 */
286IpmiAction wdActionToIpmiAction(WatchdogService::Action wd_action)
287{
Patrick Venture0b02be92018-08-31 11:55:55 -0700288 switch (wd_action)
William A. Kennington III73f44512018-02-09 15:28:46 -0800289 {
290 case WatchdogService::Action::None:
291 {
292 return IpmiAction::None;
293 }
294 case WatchdogService::Action::HardReset:
295 {
296 return IpmiAction::HardReset;
297 }
298 case WatchdogService::Action::PowerOff:
299 {
300 return IpmiAction::PowerOff;
301 }
302 case WatchdogService::Action::PowerCycle:
303 {
304 return IpmiAction::PowerCycle;
305 }
306 default:
307 {
308 // We have no method via IPMI to signal that the action is unknown
309 // or unmappable in some way.
310 // Just ignore the error and return NONE so the host can reconcile.
311 return IpmiAction::None;
312 }
313 }
314}
315
Yong Li118907e2019-01-11 17:36:17 +0800316IpmiTimerUse wdTimerUseToIpmiTimerUse(WatchdogService::TimerUse wdTimerUse)
317{
318 switch (wdTimerUse)
319 {
320 case WatchdogService::TimerUse::Reserved:
321 {
322 return IpmiTimerUse::Reserved;
323 }
324 case WatchdogService::TimerUse::BIOSFRB2:
325 {
326 return IpmiTimerUse::BIOSFRB2;
327 }
328 case WatchdogService::TimerUse::BIOSPOST:
329 {
330 return IpmiTimerUse::BIOSPOST;
331 }
332 case WatchdogService::TimerUse::OSLoad:
333 {
334 return IpmiTimerUse::OSLoad;
335 }
336
337 case WatchdogService::TimerUse::SMSOS:
338 {
339 return IpmiTimerUse::SMSOS;
340 }
341 case WatchdogService::TimerUse::OEM:
342 {
343 return IpmiTimerUse::OEM;
344 }
345 default:
346 {
347 return IpmiTimerUse::Reserved;
348 }
349 }
350}
351
William A. Kennington III73f44512018-02-09 15:28:46 -0800352static constexpr uint8_t wd_running = 0x1 << 6;
353
Deepak Kumar Sahucfae9482019-05-20 14:58:58 +0000354/**@brief The getWatchdogTimer ipmi command.
355 *
356 * @return Completion code plus timer details.
357 * - timerUse
358 * - timerAction
359 * - pretimeout
360 * - expireFlags
361 * - initialCountdown
362 * - presentCountdown
363 **/
Yong Li4dd71af2019-09-29 14:18:07 +0800364ipmi::RspType<uint3_t, // timerUse - timer use
365 uint3_t, // timerUse - reserved
366 bool, // timerUse - timer is started
367 bool, // timerUse - don't log
368
369 uint3_t, // timerAction - timeout action
370 uint1_t, // timerAction - reserved
371 uint3_t, // timerAction - pre-timeout interrupt
372 uint1_t, // timerAction - reserved
373
Yong Lia729bf42019-10-14 12:42:10 +0800374 uint8_t, // pretimeout
375 std::bitset<8>, // expireFlags
376 uint16_t, // initial Countdown - Little Endian (deciseconds)
377 uint16_t // present Countdown - Little Endian (deciseconds)
Deepak Kumar Sahucfae9482019-05-20 14:58:58 +0000378 >
379 ipmiGetWatchdogTimer()
William A. Kennington III73f44512018-02-09 15:28:46 -0800380{
Deepak Kumar Sahucfae9482019-05-20 14:58:58 +0000381 uint16_t presentCountdown = 0;
382 uint8_t pretimeout = 0;
William A. Kennington III73f44512018-02-09 15:28:46 -0800383
384 try
385 {
386 WatchdogService wd_service;
387 WatchdogService::Properties wd_prop = wd_service.getProperties();
388
389 // Build and return the response
Yong Lif7c9db02019-01-15 13:45:33 +0800390 // Interval and timeRemaining need converted from milli -> deci seconds
Deepak Kumar Sahucfae9482019-05-20 14:58:58 +0000391 uint16_t initialCountdown = htole16(wd_prop.interval / 100);
392
393 if (wd_prop.expiredTimerUse != WatchdogService::TimerUse::Reserved)
394 {
Yong Lia729bf42019-10-14 12:42:10 +0800395 timerUseExpirationFlags.set(static_cast<uint8_t>(
396 wdTimerUseToIpmiTimerUse(wd_prop.expiredTimerUse)));
Deepak Kumar Sahucfae9482019-05-20 14:58:58 +0000397 }
398
William A. Kennington III73f44512018-02-09 15:28:46 -0800399 if (wd_prop.enabled)
400 {
Deepak Kumar Sahucfae9482019-05-20 14:58:58 +0000401 presentCountdown = htole16(wd_prop.timeRemaining / 100);
Yong Lif7c9db02019-01-15 13:45:33 +0800402 }
403 else
404 {
Deepak Kumar Sahucfae9482019-05-20 14:58:58 +0000405 if (wd_prop.expiredTimerUse == WatchdogService::TimerUse::Reserved)
406 {
407 presentCountdown = initialCountdown;
Deepak Kumar Sahucfae9482019-05-20 14:58:58 +0000408 }
409 else
410 {
411 presentCountdown = 0;
Yong Li4dd71af2019-09-29 14:18:07 +0800412 // Automatically clear it whenever a timer expiration occurs.
413 timerNotLogFlags = false;
Deepak Kumar Sahucfae9482019-05-20 14:58:58 +0000414 }
William A. Kennington III73f44512018-02-09 15:28:46 -0800415 }
Yong Li118907e2019-01-11 17:36:17 +0800416
William A. Kennington III73f44512018-02-09 15:28:46 -0800417 // TODO: Do something about having pretimeout support
Deepak Kumar Sahucfae9482019-05-20 14:58:58 +0000418 pretimeout = 0;
419
William A. Kennington IIIbae471c2018-06-15 10:38:01 -0700420 lastCallSuccessful = true;
Yong Li4dd71af2019-09-29 14:18:07 +0800421 return ipmi::responseSuccess(
422 static_cast<uint3_t>(wdTimerUseToIpmiTimerUse(wd_prop.timerUse)), 0,
423 wd_prop.enabled, timerNotLogFlags,
424 static_cast<uint3_t>(wdActionToIpmiAction(wd_prop.expireAction)), 0,
Yong Lia729bf42019-10-14 12:42:10 +0800425 timerPreTimeoutInterrupt, 0, pretimeout, timerUseExpirationFlags,
Yong Li4dd71af2019-09-29 14:18:07 +0800426 initialCountdown, presentCountdown);
William A. Kennington III73f44512018-02-09 15:28:46 -0800427 }
William A. Kennington III021b4c12018-05-10 11:12:51 -0700428 catch (const InternalFailure& e)
429 {
William A. Kennington IIIbae471c2018-06-15 10:38:01 -0700430 reportError();
Deepak Kumar Sahucfae9482019-05-20 14:58:58 +0000431 return ipmi::responseUnspecifiedError();
William A. Kennington III021b4c12018-05-10 11:12:51 -0700432 }
William A. Kennington III73f44512018-02-09 15:28:46 -0800433 catch (const std::exception& e)
434 {
435 const std::string e_str = std::string("wd_get: ") + e.what();
436 log<level::ERR>(e_str.c_str());
William A. Kennington IIIbae471c2018-06-15 10:38:01 -0700437 reportError();
Deepak Kumar Sahucfae9482019-05-20 14:58:58 +0000438 return ipmi::responseUnspecifiedError();
William A. Kennington III73f44512018-02-09 15:28:46 -0800439 }
440 catch (...)
441 {
442 log<level::ERR>("wd_get: Unknown Error");
William A. Kennington IIIbae471c2018-06-15 10:38:01 -0700443 reportError();
Deepak Kumar Sahucfae9482019-05-20 14:58:58 +0000444 return ipmi::responseUnspecifiedError();
William A. Kennington III73f44512018-02-09 15:28:46 -0800445 }
446}