1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2004 Poul-Henning Kamp 5 * Copyright (c) 2013 iXsystems.com, 6 * author: Alfred Perlstein <alfred@freebsd.org> 7 * 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer 15 * in this position and unchanged. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 * 31 */ 32 33 #include "opt_ddb.h" 34 35 #include <sys/cdefs.h> 36 __FBSDID("$FreeBSD$"); 37 38 #include <sys/param.h> 39 #include <sys/types.h> 40 #include <sys/systm.h> 41 #include <sys/conf.h> 42 #include <sys/uio.h> 43 #include <sys/kernel.h> 44 #include <sys/kdb.h> 45 #include <sys/malloc.h> 46 #include <sys/module.h> 47 #include <sys/sysctl.h> 48 #include <sys/syslog.h> 49 #include <sys/watchdog.h> 50 #include <sys/bus.h> 51 #include <machine/bus.h> 52 53 #include <sys/syscallsubr.h> /* kern_clock_gettime() */ 54 55 static int wd_set_pretimeout(int newtimeout, int disableiftoolong); 56 static void wd_timeout_cb(void *arg); 57 58 static struct callout wd_pretimeo_handle; 59 static int wd_pretimeout; 60 static int wd_pretimeout_act = WD_SOFT_LOG; 61 62 static struct callout wd_softtimeo_handle; 63 static int wd_softtimer; /* true = use softtimer instead of hardware 64 watchdog */ 65 static int wd_softtimeout_act = WD_SOFT_LOG; /* action for the software timeout */ 66 67 static struct cdev *wd_dev; 68 static volatile u_int wd_last_u; /* last timeout value set by kern_do_pat */ 69 static u_int wd_last_u_sysctl; /* last timeout value set by kern_do_pat */ 70 static u_int wd_last_u_sysctl_secs; /* wd_last_u in seconds */ 71 72 SYSCTL_NODE(_hw, OID_AUTO, watchdog, CTLFLAG_RD, 0, "Main watchdog device"); 73 SYSCTL_UINT(_hw_watchdog, OID_AUTO, wd_last_u, CTLFLAG_RD, 74 &wd_last_u_sysctl, 0, "Watchdog last update time"); 75 SYSCTL_UINT(_hw_watchdog, OID_AUTO, wd_last_u_secs, CTLFLAG_RD, 76 &wd_last_u_sysctl_secs, 0, "Watchdog last update time"); 77 78 static int wd_lastpat_valid = 0; 79 static time_t wd_lastpat = 0; /* when the watchdog was last patted */ 80 81 /* Hook for external software watchdog to register for use if needed */ 82 void (*wdog_software_attach)(void); 83 84 static void 85 pow2ns_to_ts(int pow2ns, struct timespec *ts) 86 { 87 uint64_t ns; 88 89 ns = 1ULL << pow2ns; 90 ts->tv_sec = ns / 1000000000ULL; 91 ts->tv_nsec = ns % 1000000000ULL; 92 } 93 94 static int 95 pow2ns_to_ticks(int pow2ns) 96 { 97 struct timeval tv; 98 struct timespec ts; 99 100 pow2ns_to_ts(pow2ns, &ts); 101 TIMESPEC_TO_TIMEVAL(&tv, &ts); 102 return (tvtohz(&tv)); 103 } 104 105 static int 106 seconds_to_pow2ns(int seconds) 107 { 108 uint64_t power; 109 uint64_t ns; 110 uint64_t shifted; 111 112 ns = ((uint64_t)seconds) * 1000000000ULL; 113 power = flsll(ns); 114 shifted = 1ULL << power; 115 if (shifted <= ns) { 116 power++; 117 } 118 return (power); 119 } 120 121 122 int 123 wdog_kern_pat(u_int utim) 124 { 125 int error; 126 static int first = 1; 127 128 if ((utim & WD_LASTVAL) != 0 && (utim & WD_INTERVAL) > 0) 129 return (EINVAL); 130 131 if ((utim & WD_LASTVAL) != 0) { 132 /* 133 * if WD_LASTVAL is set, fill in the bits for timeout 134 * from the saved value in wd_last_u. 135 */ 136 MPASS((wd_last_u & ~WD_INTERVAL) == 0); 137 utim &= ~WD_LASTVAL; 138 utim |= wd_last_u; 139 } else { 140 /* 141 * Otherwise save the new interval. 142 * This can be zero (to disable the watchdog) 143 */ 144 wd_last_u = (utim & WD_INTERVAL); 145 wd_last_u_sysctl = wd_last_u; 146 wd_last_u_sysctl_secs = pow2ns_to_ticks(wd_last_u) / hz; 147 } 148 if ((utim & WD_INTERVAL) == WD_TO_NEVER) { 149 utim = 0; 150 151 /* Assume all is well; watchdog signals failure. */ 152 error = 0; 153 } else { 154 /* Assume no watchdog available; watchdog flags success */ 155 error = EOPNOTSUPP; 156 } 157 if (wd_softtimer) { 158 if (utim == 0) { 159 callout_stop(&wd_softtimeo_handle); 160 } else { 161 (void) callout_reset(&wd_softtimeo_handle, 162 pow2ns_to_ticks(utim), wd_timeout_cb, "soft"); 163 } 164 error = 0; 165 } else { 166 EVENTHANDLER_INVOKE(watchdog_list, utim, &error); 167 } 168 /* 169 * If we no hardware watchdog responded, we have not tried to 170 * attach an external software watchdog, and one is available, 171 * attach it now and retry. 172 */ 173 if (error == EOPNOTSUPP && first && *wdog_software_attach != NULL) { 174 (*wdog_software_attach)(); 175 EVENTHANDLER_INVOKE(watchdog_list, utim, &error); 176 } 177 first = 0; 178 179 wd_set_pretimeout(wd_pretimeout, true); 180 /* 181 * If we were able to arm/strobe the watchdog, then 182 * update the last time it was strobed for WDIOC_GETTIMELEFT 183 */ 184 if (!error) { 185 struct timespec ts; 186 187 error = kern_clock_gettime(curthread /* XXX */, 188 CLOCK_MONOTONIC_FAST, &ts); 189 if (!error) { 190 wd_lastpat = ts.tv_sec; 191 wd_lastpat_valid = 1; 192 } 193 } 194 return (error); 195 } 196 197 static int 198 wd_valid_act(int act) 199 { 200 201 if ((act & ~(WD_SOFT_MASK)) != 0) 202 return false; 203 return true; 204 } 205 206 static int 207 wd_ioctl_patpat(caddr_t data) 208 { 209 u_int u; 210 211 u = *(u_int *)data; 212 if (u & ~(WD_ACTIVE | WD_PASSIVE | WD_LASTVAL | WD_INTERVAL)) 213 return (EINVAL); 214 if ((u & (WD_ACTIVE | WD_PASSIVE)) == (WD_ACTIVE | WD_PASSIVE)) 215 return (EINVAL); 216 if ((u & (WD_ACTIVE | WD_PASSIVE)) == 0 && ((u & WD_INTERVAL) > 0 || 217 (u & WD_LASTVAL) != 0)) 218 return (EINVAL); 219 if (u & WD_PASSIVE) 220 return (ENOSYS); /* XXX Not implemented yet */ 221 u &= ~(WD_ACTIVE | WD_PASSIVE); 222 223 return (wdog_kern_pat(u)); 224 } 225 226 static int 227 wd_get_time_left(struct thread *td, time_t *remainp) 228 { 229 struct timespec ts; 230 int error; 231 232 error = kern_clock_gettime(td, CLOCK_MONOTONIC_FAST, &ts); 233 if (error) 234 return (error); 235 if (!wd_lastpat_valid) 236 return (ENOENT); 237 *remainp = ts.tv_sec - wd_lastpat; 238 return (0); 239 } 240 241 static void 242 wd_timeout_cb(void *arg) 243 { 244 const char *type = arg; 245 246 #ifdef DDB 247 if ((wd_pretimeout_act & WD_SOFT_DDB)) { 248 char kdb_why[80]; 249 snprintf(kdb_why, sizeof(kdb_why), "watchdog %s-timeout", type); 250 kdb_backtrace(); 251 kdb_enter(KDB_WHY_WATCHDOG, kdb_why); 252 } 253 #endif 254 if ((wd_pretimeout_act & WD_SOFT_LOG)) 255 log(LOG_EMERG, "watchdog %s-timeout, WD_SOFT_LOG\n", type); 256 if ((wd_pretimeout_act & WD_SOFT_PRINTF)) 257 printf("watchdog %s-timeout, WD_SOFT_PRINTF\n", type); 258 if ((wd_pretimeout_act & WD_SOFT_PANIC)) 259 panic("watchdog %s-timeout, WD_SOFT_PANIC set", type); 260 } 261 262 /* 263 * Called to manage timeouts. 264 * newtimeout needs to be in the range of 0 to actual watchdog timeout. 265 * if 0, we disable the pre-timeout. 266 * otherwise we set the pre-timeout provided it's not greater than the 267 * current actual watchdog timeout. 268 */ 269 static int 270 wd_set_pretimeout(int newtimeout, int disableiftoolong) 271 { 272 u_int utime; 273 struct timespec utime_ts; 274 int timeout_ticks; 275 276 utime = wdog_kern_last_timeout(); 277 pow2ns_to_ts(utime, &utime_ts); 278 /* do not permit a pre-timeout >= than the timeout. */ 279 if (newtimeout >= utime_ts.tv_sec) { 280 /* 281 * If 'disableiftoolong' then just fall through 282 * so as to disable the pre-watchdog 283 */ 284 if (disableiftoolong) 285 newtimeout = 0; 286 else 287 return EINVAL; 288 } 289 290 /* disable the pre-timeout */ 291 if (newtimeout == 0) { 292 wd_pretimeout = 0; 293 callout_stop(&wd_pretimeo_handle); 294 return 0; 295 } 296 297 timeout_ticks = pow2ns_to_ticks(utime) - (hz*newtimeout); 298 #if 0 299 printf("wd_set_pretimeout: " 300 "newtimeout: %d, " 301 "utime: %d -> utime_ticks: %d, " 302 "hz*newtimeout: %d, " 303 "timeout_ticks: %d -> sec: %d\n", 304 newtimeout, 305 utime, pow2ns_to_ticks(utime), 306 hz*newtimeout, 307 timeout_ticks, timeout_ticks / hz); 308 #endif 309 310 /* We determined the value is sane, so reset the callout */ 311 (void) callout_reset(&wd_pretimeo_handle, 312 timeout_ticks, wd_timeout_cb, "pre"); 313 wd_pretimeout = newtimeout; 314 return 0; 315 } 316 317 static int 318 wd_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t data, 319 int flags __unused, struct thread *td) 320 { 321 u_int u; 322 time_t timeleft; 323 int error; 324 325 error = 0; 326 327 switch (cmd) { 328 case WDIOC_SETSOFT: 329 u = *(int *)data; 330 /* do nothing? */ 331 if (u == wd_softtimer) 332 break; 333 /* If there is a pending timeout disallow this ioctl */ 334 if (wd_last_u != 0) { 335 error = EINVAL; 336 break; 337 } 338 wd_softtimer = u; 339 break; 340 case WDIOC_SETSOFTTIMEOUTACT: 341 u = *(int *)data; 342 if (wd_valid_act(u)) { 343 wd_softtimeout_act = u; 344 } else { 345 error = EINVAL; 346 } 347 break; 348 case WDIOC_SETPRETIMEOUTACT: 349 u = *(int *)data; 350 if (wd_valid_act(u)) { 351 wd_pretimeout_act = u; 352 } else { 353 error = EINVAL; 354 } 355 break; 356 case WDIOC_GETPRETIMEOUT: 357 *(int *)data = (int)wd_pretimeout; 358 break; 359 case WDIOC_SETPRETIMEOUT: 360 error = wd_set_pretimeout(*(int *)data, false); 361 break; 362 case WDIOC_GETTIMELEFT: 363 error = wd_get_time_left(td, &timeleft); 364 if (error) 365 break; 366 *(int *)data = (int)timeleft; 367 break; 368 case WDIOC_SETTIMEOUT: 369 u = *(u_int *)data; 370 error = wdog_kern_pat(seconds_to_pow2ns(u)); 371 break; 372 case WDIOC_GETTIMEOUT: 373 u = wdog_kern_last_timeout(); 374 *(u_int *)data = u; 375 break; 376 case WDIOCPATPAT: 377 error = wd_ioctl_patpat(data); 378 break; 379 default: 380 error = ENOIOCTL; 381 break; 382 } 383 return (error); 384 } 385 386 /* 387 * Return the last timeout set, this is NOT the seconds from NOW until timeout, 388 * rather it is the amount of seconds passed to WDIOCPATPAT/WDIOC_SETTIMEOUT. 389 */ 390 u_int 391 wdog_kern_last_timeout(void) 392 { 393 394 return (wd_last_u); 395 } 396 397 static struct cdevsw wd_cdevsw = { 398 .d_version = D_VERSION, 399 .d_ioctl = wd_ioctl, 400 .d_name = "watchdog", 401 }; 402 403 static int 404 watchdog_modevent(module_t mod __unused, int type, void *data __unused) 405 { 406 switch(type) { 407 case MOD_LOAD: 408 callout_init(&wd_pretimeo_handle, 1); 409 callout_init(&wd_softtimeo_handle, 1); 410 wd_dev = make_dev(&wd_cdevsw, 0, 411 UID_ROOT, GID_WHEEL, 0600, _PATH_WATCHDOG); 412 return 0; 413 case MOD_UNLOAD: 414 callout_stop(&wd_pretimeo_handle); 415 callout_stop(&wd_softtimeo_handle); 416 callout_drain(&wd_pretimeo_handle); 417 callout_drain(&wd_softtimeo_handle); 418 destroy_dev(wd_dev); 419 return 0; 420 case MOD_SHUTDOWN: 421 return 0; 422 default: 423 return EOPNOTSUPP; 424 } 425 } 426 427 DEV_MODULE(watchdog, watchdog_modevent, NULL); 428