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 static void 82 pow2ns_to_ts(int pow2ns, struct timespec *ts) 83 { 84 uint64_t ns; 85 86 ns = 1ULL << pow2ns; 87 ts->tv_sec = ns / 1000000000ULL; 88 ts->tv_nsec = ns % 1000000000ULL; 89 } 90 91 static int 92 pow2ns_to_ticks(int pow2ns) 93 { 94 struct timeval tv; 95 struct timespec ts; 96 97 pow2ns_to_ts(pow2ns, &ts); 98 TIMESPEC_TO_TIMEVAL(&tv, &ts); 99 return (tvtohz(&tv)); 100 } 101 102 static int 103 seconds_to_pow2ns(int seconds) 104 { 105 uint64_t power; 106 uint64_t ns; 107 uint64_t shifted; 108 109 ns = ((uint64_t)seconds) * 1000000000ULL; 110 power = flsll(ns); 111 shifted = 1ULL << power; 112 if (shifted <= ns) { 113 power++; 114 } 115 return (power); 116 } 117 118 119 int 120 wdog_kern_pat(u_int utim) 121 { 122 int error; 123 124 if ((utim & WD_LASTVAL) != 0 && (utim & WD_INTERVAL) > 0) 125 return (EINVAL); 126 127 if ((utim & WD_LASTVAL) != 0) { 128 /* 129 * if WD_LASTVAL is set, fill in the bits for timeout 130 * from the saved value in wd_last_u. 131 */ 132 MPASS((wd_last_u & ~WD_INTERVAL) == 0); 133 utim &= ~WD_LASTVAL; 134 utim |= wd_last_u; 135 } else { 136 /* 137 * Otherwise save the new interval. 138 * This can be zero (to disable the watchdog) 139 */ 140 wd_last_u = (utim & WD_INTERVAL); 141 wd_last_u_sysctl = wd_last_u; 142 wd_last_u_sysctl_secs = pow2ns_to_ticks(wd_last_u) / hz; 143 } 144 if ((utim & WD_INTERVAL) == WD_TO_NEVER) { 145 utim = 0; 146 147 /* Assume all is well; watchdog signals failure. */ 148 error = 0; 149 } else { 150 /* Assume no watchdog available; watchdog flags success */ 151 error = EOPNOTSUPP; 152 } 153 if (wd_softtimer) { 154 if (utim == 0) { 155 callout_stop(&wd_softtimeo_handle); 156 } else { 157 (void) callout_reset(&wd_softtimeo_handle, 158 pow2ns_to_ticks(utim), wd_timeout_cb, "soft"); 159 } 160 error = 0; 161 } else { 162 EVENTHANDLER_INVOKE(watchdog_list, utim, &error); 163 } 164 wd_set_pretimeout(wd_pretimeout, true); 165 /* 166 * If we were able to arm/strobe the watchdog, then 167 * update the last time it was strobed for WDIOC_GETTIMELEFT 168 */ 169 if (!error) { 170 struct timespec ts; 171 172 error = kern_clock_gettime(curthread /* XXX */, 173 CLOCK_MONOTONIC_FAST, &ts); 174 if (!error) { 175 wd_lastpat = ts.tv_sec; 176 wd_lastpat_valid = 1; 177 } 178 } 179 return (error); 180 } 181 182 static int 183 wd_valid_act(int act) 184 { 185 186 if ((act & ~(WD_SOFT_MASK)) != 0) 187 return false; 188 return true; 189 } 190 191 static int 192 wd_ioctl_patpat(caddr_t data) 193 { 194 u_int u; 195 196 u = *(u_int *)data; 197 if (u & ~(WD_ACTIVE | WD_PASSIVE | WD_LASTVAL | WD_INTERVAL)) 198 return (EINVAL); 199 if ((u & (WD_ACTIVE | WD_PASSIVE)) == (WD_ACTIVE | WD_PASSIVE)) 200 return (EINVAL); 201 if ((u & (WD_ACTIVE | WD_PASSIVE)) == 0 && ((u & WD_INTERVAL) > 0 || 202 (u & WD_LASTVAL) != 0)) 203 return (EINVAL); 204 if (u & WD_PASSIVE) 205 return (ENOSYS); /* XXX Not implemented yet */ 206 u &= ~(WD_ACTIVE | WD_PASSIVE); 207 208 return (wdog_kern_pat(u)); 209 } 210 211 static int 212 wd_get_time_left(struct thread *td, time_t *remainp) 213 { 214 struct timespec ts; 215 int error; 216 217 error = kern_clock_gettime(td, CLOCK_MONOTONIC_FAST, &ts); 218 if (error) 219 return (error); 220 if (!wd_lastpat_valid) 221 return (ENOENT); 222 *remainp = ts.tv_sec - wd_lastpat; 223 return (0); 224 } 225 226 static void 227 wd_timeout_cb(void *arg) 228 { 229 const char *type = arg; 230 231 #ifdef DDB 232 if ((wd_pretimeout_act & WD_SOFT_DDB)) { 233 char kdb_why[80]; 234 snprintf(kdb_why, sizeof(kdb_why), "watchdog %s-timeout", type); 235 kdb_backtrace(); 236 kdb_enter(KDB_WHY_WATCHDOG, kdb_why); 237 } 238 #endif 239 if ((wd_pretimeout_act & WD_SOFT_LOG)) 240 log(LOG_EMERG, "watchdog %s-timeout, WD_SOFT_LOG\n", type); 241 if ((wd_pretimeout_act & WD_SOFT_PRINTF)) 242 printf("watchdog %s-timeout, WD_SOFT_PRINTF\n", type); 243 if ((wd_pretimeout_act & WD_SOFT_PANIC)) 244 panic("watchdog %s-timeout, WD_SOFT_PANIC set", type); 245 } 246 247 /* 248 * Called to manage timeouts. 249 * newtimeout needs to be in the range of 0 to actual watchdog timeout. 250 * if 0, we disable the pre-timeout. 251 * otherwise we set the pre-timeout provided it's not greater than the 252 * current actual watchdog timeout. 253 */ 254 static int 255 wd_set_pretimeout(int newtimeout, int disableiftoolong) 256 { 257 u_int utime; 258 struct timespec utime_ts; 259 int timeout_ticks; 260 261 utime = wdog_kern_last_timeout(); 262 pow2ns_to_ts(utime, &utime_ts); 263 /* do not permit a pre-timeout >= than the timeout. */ 264 if (newtimeout >= utime_ts.tv_sec) { 265 /* 266 * If 'disableiftoolong' then just fall through 267 * so as to disable the pre-watchdog 268 */ 269 if (disableiftoolong) 270 newtimeout = 0; 271 else 272 return EINVAL; 273 } 274 275 /* disable the pre-timeout */ 276 if (newtimeout == 0) { 277 wd_pretimeout = 0; 278 callout_stop(&wd_pretimeo_handle); 279 return 0; 280 } 281 282 timeout_ticks = pow2ns_to_ticks(utime) - (hz*newtimeout); 283 #if 0 284 printf("wd_set_pretimeout: " 285 "newtimeout: %d, " 286 "utime: %d -> utime_ticks: %d, " 287 "hz*newtimeout: %d, " 288 "timeout_ticks: %d -> sec: %d\n", 289 newtimeout, 290 utime, pow2ns_to_ticks(utime), 291 hz*newtimeout, 292 timeout_ticks, timeout_ticks / hz); 293 #endif 294 295 /* We determined the value is sane, so reset the callout */ 296 (void) callout_reset(&wd_pretimeo_handle, 297 timeout_ticks, wd_timeout_cb, "pre"); 298 wd_pretimeout = newtimeout; 299 return 0; 300 } 301 302 static int 303 wd_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t data, 304 int flags __unused, struct thread *td) 305 { 306 u_int u; 307 time_t timeleft; 308 int error; 309 310 error = 0; 311 312 switch (cmd) { 313 case WDIOC_SETSOFT: 314 u = *(int *)data; 315 /* do nothing? */ 316 if (u == wd_softtimer) 317 break; 318 /* If there is a pending timeout disallow this ioctl */ 319 if (wd_last_u != 0) { 320 error = EINVAL; 321 break; 322 } 323 wd_softtimer = u; 324 break; 325 case WDIOC_SETSOFTTIMEOUTACT: 326 u = *(int *)data; 327 if (wd_valid_act(u)) { 328 wd_softtimeout_act = u; 329 } else { 330 error = EINVAL; 331 } 332 break; 333 case WDIOC_SETPRETIMEOUTACT: 334 u = *(int *)data; 335 if (wd_valid_act(u)) { 336 wd_pretimeout_act = u; 337 } else { 338 error = EINVAL; 339 } 340 break; 341 case WDIOC_GETPRETIMEOUT: 342 *(int *)data = (int)wd_pretimeout; 343 break; 344 case WDIOC_SETPRETIMEOUT: 345 error = wd_set_pretimeout(*(int *)data, false); 346 break; 347 case WDIOC_GETTIMELEFT: 348 error = wd_get_time_left(td, &timeleft); 349 if (error) 350 break; 351 *(int *)data = (int)timeleft; 352 break; 353 case WDIOC_SETTIMEOUT: 354 u = *(u_int *)data; 355 error = wdog_kern_pat(seconds_to_pow2ns(u)); 356 break; 357 case WDIOC_GETTIMEOUT: 358 u = wdog_kern_last_timeout(); 359 *(u_int *)data = u; 360 break; 361 case WDIOCPATPAT: 362 error = wd_ioctl_patpat(data); 363 break; 364 default: 365 error = ENOIOCTL; 366 break; 367 } 368 return (error); 369 } 370 371 /* 372 * Return the last timeout set, this is NOT the seconds from NOW until timeout, 373 * rather it is the amount of seconds passed to WDIOCPATPAT/WDIOC_SETTIMEOUT. 374 */ 375 u_int 376 wdog_kern_last_timeout(void) 377 { 378 379 return (wd_last_u); 380 } 381 382 static struct cdevsw wd_cdevsw = { 383 .d_version = D_VERSION, 384 .d_ioctl = wd_ioctl, 385 .d_name = "watchdog", 386 }; 387 388 static int 389 watchdog_modevent(module_t mod __unused, int type, void *data __unused) 390 { 391 switch(type) { 392 case MOD_LOAD: 393 callout_init(&wd_pretimeo_handle, 1); 394 callout_init(&wd_softtimeo_handle, 1); 395 wd_dev = make_dev(&wd_cdevsw, 0, 396 UID_ROOT, GID_WHEEL, 0600, _PATH_WATCHDOG); 397 return 0; 398 case MOD_UNLOAD: 399 callout_stop(&wd_pretimeo_handle); 400 callout_stop(&wd_softtimeo_handle); 401 callout_drain(&wd_pretimeo_handle); 402 callout_drain(&wd_softtimeo_handle); 403 destroy_dev(wd_dev); 404 return 0; 405 case MOD_SHUTDOWN: 406 return 0; 407 default: 408 return EOPNOTSUPP; 409 } 410 } 411 412 DEV_MODULE(watchdog, watchdog_modevent, NULL); 413