1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 27 /* 28 * sun4v application watchdog driver 29 */ 30 31 #include <sys/types.h> 32 #include <sys/file.h> 33 #include <sys/errno.h> 34 #include <sys/open.h> 35 #include <sys/callb.h> 36 #include <sys/cred.h> 37 #include <sys/cyclic.h> 38 #include <sys/uio.h> 39 #include <sys/stat.h> 40 #include <sys/ksynch.h> 41 #include <sys/modctl.h> 42 #include <sys/conf.h> 43 #include <sys/devops.h> 44 #include <sys/debug.h> 45 #include <sys/cmn_err.h> 46 #include <sys/ddi.h> 47 #include <sys/reboot.h> 48 #include <sys/sunddi.h> 49 #include <sys/signal.h> 50 #include <sys/ntwdt.h> 51 #include <sys/note.h> 52 53 /* 54 * tunables 55 */ 56 int ntwdt_disable_timeout_action = 0; 57 58 #ifdef DEBUG 59 60 int ntwdt_debug = 0; /* ntwdt debug flag, dbg all for now. */ 61 62 /* 63 * Flags to set in ntwdt_debug. 64 */ 65 #define NTWDT_DBG_ENTRY 0x00000001 /* drv entry points */ 66 #define NTWDT_DBG_IOCTL 0x00000002 /* ioctl's */ 67 #define NTWDT_DBG_NTWDT 0x00000004 /* other ntwdt debug */ 68 69 #define NTWDT_DBG(flag, msg) \ 70 { if ((ntwdt_debug) & (flag)) (void) printf msg; } 71 #else /* DEBUG */ 72 #define NTWDT_DBG(flag, msg) 73 #endif /* DEBUG */ 74 75 #define NTWDT_MINOR_NODE "awdt" 76 #define getstate(minor) \ 77 ((ntwdt_state_t *)ddi_get_soft_state(ntwdt_statep, (minor))) 78 79 /* 80 * The ntwdt cyclic interval in nanosecond unit as cyclic subsystem supports 81 * nanosecond resolution. 82 */ 83 #define NTWDT_CYCLIC_INTERVAL NANOSEC /* 1 seconds */ 84 85 /* 86 * The ntwdt decrement interval in 1 second resolution. 87 */ 88 #define NTWDT_DECREMENT_INTERVAL 1 /* 1 second */ 89 90 /* 91 * ntwdt_watchdog_flags and macros to set/clear one bit in it. 92 */ 93 #define NTWDT_FLAG_SKIP_CYCLIC 0x1 /* skip next cyclic */ 94 95 #define NTWDT_MAX_TIMEOUT (3 * 60 * 60) /* 3 hours */ 96 97 #define WDT_MIN_COREAPI_MAJOR 1 98 #define WDT_MIN_COREAPI_MINOR 1 99 100 /* 101 * Application watchdog state. 102 */ 103 typedef struct ntwdt_runstate { 104 kmutex_t ntwdt_runstate_mutex; 105 ddi_iblock_cookie_t ntwdt_runstate_mtx_cookie; 106 int ntwdt_watchdog_enabled; /* wdog enabled ? */ 107 int ntwdt_reset_enabled; /* reset enabled ? */ 108 int ntwdt_timer_running; /* wdog running ? */ 109 int ntwdt_watchdog_expired; /* wdog expired ? */ 110 uint32_t ntwdt_time_remaining; /* expiration timer */ 111 uint32_t ntwdt_watchdog_timeout; /* timeout in seconds */ 112 hrtime_t ntwdt_cyclic_interval; /* cyclic interval */ 113 cyc_handler_t ntwdt_cycl_hdlr; 114 cyc_time_t ntwdt_cycl_time; 115 uint32_t ntwdt_watchdog_flags; 116 } ntwdt_runstate_t; 117 118 /* 119 * softstate of NTWDT 120 */ 121 typedef struct { 122 kmutex_t ntwdt_mutex; 123 dev_info_t *ntwdt_dip; /* dip */ 124 int ntwdt_open_flag; /* file open ? */ 125 ntwdt_runstate_t *ntwdt_run_state; /* wdog state */ 126 cyclic_id_t ntwdt_cycl_id; 127 } ntwdt_state_t; 128 129 static void *ntwdt_statep; /* softstate */ 130 static dev_info_t *ntwdt_dip; 131 132 static ddi_softintr_t ntwdt_cyclic_softint_id; 133 134 static int ntwdt_info(dev_info_t *, ddi_info_cmd_t, void *, void **); 135 static int ntwdt_attach(dev_info_t *, ddi_attach_cmd_t); 136 static int ntwdt_detach(dev_info_t *, ddi_detach_cmd_t); 137 static int ntwdt_open(dev_t *, int, int, cred_t *); 138 static int ntwdt_close(dev_t, int, int, cred_t *); 139 static int ntwdt_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 140 141 static int ntwdt_chk_watchdog_support(); 142 static void ntwdt_arm_watchdog(ntwdt_runstate_t *ntwdt_state); 143 static void ntwdt_cyclic_pat(void); 144 static uint_t ntwdt_cyclic_softint(caddr_t arg); 145 static void ntwdt_start_timer(ntwdt_state_t *ntwdt_ptr); 146 static void ntwdt_stop_timer_lock(void *arg); 147 static void ntwdt_stop_timer(void *arg); 148 static void ntwdt_enforce_timeout(); 149 150 static struct cb_ops ntwdt_cb_ops = { 151 ntwdt_open, /* cb_open */ 152 ntwdt_close, /* cb_close */ 153 nodev, /* cb_strategy */ 154 nodev, /* cb_print */ 155 nodev, /* cb_dump */ 156 nodev, /* cb_read */ 157 nodev, /* cb_write */ 158 ntwdt_ioctl, /* cb_ioctl */ 159 nodev, /* cb_devmap */ 160 nodev, /* cb_mmap */ 161 nodev, /* cb_segmap */ 162 nochpoll, /* cb_chpoll */ 163 ddi_prop_op, /* cb_prop_op */ 164 NULL, /* cb_str */ 165 D_NEW | D_MP /* cb_flag */ 166 }; 167 168 static struct dev_ops ntwdt_dev_ops = { 169 DEVO_REV, /* devo_rev */ 170 0, /* devo_refcnt */ 171 ntwdt_info, /* devo_info */ 172 nulldev, /* devo_identify */ 173 nulldev, /* devo_probe */ 174 ntwdt_attach, /* devo_attach */ 175 ntwdt_detach, /* devo_detach */ 176 nodev, /* devo_reset */ 177 &ntwdt_cb_ops, /* devo_cb_ops */ 178 NULL, /* devo_bus_ops */ 179 nulldev, /* devo_power */ 180 ddi_quiesce_not_supported, /* devo_quiesce */ 181 }; 182 183 static struct modldrv modldrv = { 184 &mod_driverops, 185 "Application Watchdog Driver", 186 &ntwdt_dev_ops 187 }; 188 189 static struct modlinkage modlinkage = { 190 MODREV_1, 191 (void *)&modldrv, 192 NULL 193 }; 194 195 int 196 _init(void) 197 { 198 int error = 0; 199 200 NTWDT_DBG(NTWDT_DBG_ENTRY, ("_init")); 201 202 /* Initialize the soft state structures */ 203 if ((error = ddi_soft_state_init(&ntwdt_statep, 204 sizeof (ntwdt_state_t), 1)) != 0) { 205 return (error); 206 } 207 208 /* Install the loadable module */ 209 if ((error = mod_install(&modlinkage)) != 0) { 210 ddi_soft_state_fini(&ntwdt_statep); 211 } 212 return (error); 213 } 214 215 int 216 _info(struct modinfo *modinfop) 217 { 218 NTWDT_DBG(NTWDT_DBG_ENTRY, ("_info")); 219 220 return (mod_info(&modlinkage, modinfop)); 221 } 222 223 int 224 _fini(void) 225 { 226 int retval; 227 228 NTWDT_DBG(NTWDT_DBG_ENTRY, ("_fini")); 229 230 if ((retval = mod_remove(&modlinkage)) == 0) { 231 ddi_soft_state_fini(&ntwdt_statep); 232 } 233 234 return (retval); 235 } 236 237 static int 238 ntwdt_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 239 { 240 int instance; 241 ntwdt_state_t *ntwdt_ptr = NULL; /* pointer to ntwdt_runstatep */ 242 ntwdt_runstate_t *ntwdt_runstatep = NULL; 243 cyc_handler_t *hdlr = NULL; 244 245 switch (cmd) { 246 case DDI_ATTACH: 247 break; 248 249 case DDI_RESUME: 250 return (DDI_SUCCESS); 251 252 default: 253 return (DDI_FAILURE); 254 } 255 256 if (ntwdt_chk_watchdog_support() != 0) { 257 return (DDI_FAILURE); 258 } 259 260 instance = ddi_get_instance(dip); 261 ASSERT(instance == 0); 262 263 if (ddi_soft_state_zalloc(ntwdt_statep, instance) != DDI_SUCCESS) { 264 return (DDI_FAILURE); 265 } 266 ntwdt_ptr = ddi_get_soft_state(ntwdt_statep, instance); 267 ASSERT(ntwdt_ptr != NULL); 268 269 ntwdt_dip = dip; 270 271 ntwdt_ptr->ntwdt_dip = dip; 272 ntwdt_ptr->ntwdt_cycl_id = CYCLIC_NONE; 273 mutex_init(&ntwdt_ptr->ntwdt_mutex, NULL, 274 MUTEX_DRIVER, NULL); 275 276 /* 277 * Initialize the watchdog structure 278 */ 279 ntwdt_ptr->ntwdt_run_state = 280 kmem_zalloc(sizeof (ntwdt_runstate_t), KM_SLEEP); 281 ntwdt_runstatep = ntwdt_ptr->ntwdt_run_state; 282 283 if (ddi_get_soft_iblock_cookie(dip, DDI_SOFTINT_LOW, 284 &ntwdt_runstatep->ntwdt_runstate_mtx_cookie) != DDI_SUCCESS) { 285 cmn_err(CE_WARN, "init of iblock cookie failed " 286 "for ntwdt_runstate_mutex"); 287 goto err1; 288 } else { 289 mutex_init(&ntwdt_runstatep->ntwdt_runstate_mutex, 290 NULL, 291 MUTEX_DRIVER, 292 (void *)ntwdt_runstatep->ntwdt_runstate_mtx_cookie); 293 } 294 295 /* Cyclic fires once per second: */ 296 ntwdt_runstatep->ntwdt_cyclic_interval = NTWDT_CYCLIC_INTERVAL; 297 298 /* init the Cyclic that drives the NTWDT */ 299 hdlr = &ntwdt_runstatep->ntwdt_cycl_hdlr; 300 hdlr->cyh_level = CY_LOCK_LEVEL; 301 hdlr->cyh_func = (cyc_func_t)ntwdt_cyclic_pat; 302 hdlr->cyh_arg = NULL; 303 304 /* Softint that will be triggered by Cyclic that drives NTWDT */ 305 if (ddi_add_softintr(dip, DDI_SOFTINT_LOW, &ntwdt_cyclic_softint_id, 306 NULL, NULL, ntwdt_cyclic_softint, (caddr_t)ntwdt_ptr) 307 != DDI_SUCCESS) { 308 cmn_err(CE_WARN, "failed to add cyclic softintr"); 309 goto err2; 310 } 311 312 /* 313 * Create Minor Node as last activity. This prevents 314 * application from accessing our implementation until it 315 * is initialized. 316 */ 317 if (ddi_create_minor_node(dip, NTWDT_MINOR_NODE, S_IFCHR, 0, 318 DDI_PSEUDO, NULL) == DDI_FAILURE) { 319 cmn_err(CE_WARN, "failed to create Minor Node: %s", 320 NTWDT_MINOR_NODE); 321 goto err3; 322 } 323 324 /* Display our driver info in the banner */ 325 ddi_report_dev(dip); 326 327 return (DDI_SUCCESS); 328 329 err3: 330 ddi_remove_softintr(ntwdt_cyclic_softint_id); 331 err2: 332 mutex_destroy(&ntwdt_runstatep->ntwdt_runstate_mutex); 333 err1: 334 /* clean up the driver stuff here */ 335 kmem_free(ntwdt_runstatep, sizeof (ntwdt_runstate_t)); 336 ntwdt_ptr->ntwdt_run_state = NULL; 337 mutex_destroy(&ntwdt_ptr->ntwdt_mutex); 338 ddi_soft_state_free(ntwdt_statep, instance); 339 ntwdt_dip = NULL; 340 341 return (DDI_FAILURE); 342 } 343 344 /*ARGSUSED*/ 345 static int 346 ntwdt_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 347 { 348 dev_t dev; 349 int instance; 350 int error = DDI_SUCCESS; 351 352 switch (infocmd) { 353 case DDI_INFO_DEVT2DEVINFO: 354 dev = (dev_t)arg; 355 if (getminor(dev) == 0) { 356 *result = (void *)ntwdt_dip; 357 } else { 358 error = DDI_FAILURE; 359 } 360 break; 361 362 case DDI_INFO_DEVT2INSTANCE: 363 dev = (dev_t)arg; 364 instance = getminor(dev); 365 *result = (void *)(uintptr_t)instance; 366 break; 367 368 default: 369 error = DDI_FAILURE; 370 371 } 372 373 return (error); 374 } 375 376 /*ARGSUSED*/ 377 static int 378 ntwdt_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 379 { 380 int instance = ddi_get_instance(dip); 381 ntwdt_state_t *ntwdt_ptr = NULL; 382 383 ntwdt_ptr = ddi_get_soft_state(ntwdt_statep, instance); 384 if (ntwdt_ptr == NULL) { 385 return (DDI_FAILURE); 386 } 387 388 switch (cmd) { 389 case DDI_SUSPEND: 390 return (DDI_SUCCESS); 391 392 case DDI_DETACH: 393 /* 394 * release resources in opposite (LIFO) order as 395 * were allocated in attach. 396 */ 397 ddi_remove_minor_node(dip, NULL); 398 ntwdt_stop_timer_lock((void *)ntwdt_ptr); 399 ddi_remove_softintr(ntwdt_cyclic_softint_id); 400 401 mutex_destroy( 402 &ntwdt_ptr->ntwdt_run_state->ntwdt_runstate_mutex); 403 kmem_free(ntwdt_ptr->ntwdt_run_state, 404 sizeof (ntwdt_runstate_t)); 405 ntwdt_ptr->ntwdt_run_state = NULL; 406 407 mutex_destroy(&ntwdt_ptr->ntwdt_mutex); 408 409 ddi_soft_state_free(ntwdt_statep, instance); 410 411 ntwdt_dip = NULL; 412 return (DDI_SUCCESS); 413 414 default: 415 return (DDI_FAILURE); 416 } 417 } 418 419 /*ARGSUSED*/ 420 static int 421 ntwdt_open(dev_t *devp, int flag, int otyp, cred_t *credp) 422 { 423 int instance = getminor(*devp); 424 int retval = 0; 425 ntwdt_state_t *ntwdt_ptr = getstate(instance); 426 427 if (ntwdt_ptr == NULL) { 428 return (ENXIO); 429 } 430 431 /* 432 * ensure caller is a priviledged process. 433 */ 434 if (drv_priv(credp) != 0) { 435 return (EPERM); 436 } 437 438 mutex_enter(&ntwdt_ptr->ntwdt_mutex); 439 if (ntwdt_ptr->ntwdt_open_flag) { 440 retval = EAGAIN; 441 } else { 442 ntwdt_ptr->ntwdt_open_flag = 1; 443 } 444 mutex_exit(&ntwdt_ptr->ntwdt_mutex); 445 446 return (retval); 447 } 448 449 /*ARGSUSED*/ 450 static int 451 ntwdt_close(dev_t dev, int flag, int otyp, cred_t *credp) 452 { 453 int instance = getminor(dev); 454 ntwdt_state_t *ntwdt_ptr = getstate(instance); 455 456 if (ntwdt_ptr == NULL) { 457 return (ENXIO); 458 } 459 460 mutex_enter(&ntwdt_ptr->ntwdt_mutex); 461 ntwdt_ptr->ntwdt_open_flag = 0; 462 mutex_exit(&ntwdt_ptr->ntwdt_mutex); 463 464 return (0); 465 } 466 467 /*ARGSUSED*/ 468 static int 469 ntwdt_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, 470 int *rvalp) 471 { 472 int instance = getminor(dev); 473 int retval = 0; 474 ntwdt_state_t *ntwdt_ptr = NULL; 475 ntwdt_runstate_t *ntwdt_state; 476 lom_dogstate_t lom_dogstate; 477 lom_dogctl_t lom_dogctl; 478 uint32_t lom_dogtime; 479 480 if ((ntwdt_ptr = getstate(instance)) == NULL) { 481 return (ENXIO); 482 } 483 484 ntwdt_state = ntwdt_ptr->ntwdt_run_state; 485 486 switch (cmd) { 487 case LOMIOCDOGSTATE: 488 mutex_enter(&ntwdt_state->ntwdt_runstate_mutex); 489 lom_dogstate.reset_enable = ntwdt_state->ntwdt_reset_enabled; 490 lom_dogstate.dog_enable = ntwdt_state->ntwdt_watchdog_enabled; 491 lom_dogstate.dog_timeout = ntwdt_state->ntwdt_watchdog_timeout; 492 mutex_exit(&ntwdt_state->ntwdt_runstate_mutex); 493 494 if (ddi_copyout((caddr_t)&lom_dogstate, (caddr_t)arg, 495 sizeof (lom_dogstate_t), mode) != 0) { 496 retval = EFAULT; 497 } 498 break; 499 500 case LOMIOCDOGCTL: 501 if (ddi_copyin((caddr_t)arg, (caddr_t)&lom_dogctl, 502 sizeof (lom_dogctl_t), mode) != 0) { 503 retval = EFAULT; 504 break; 505 } 506 507 NTWDT_DBG(NTWDT_DBG_IOCTL, ("reset_enable: %d, and dog_enable: " 508 "%d, watchdog_timeout %d", lom_dogctl.reset_enable, 509 lom_dogctl.dog_enable, 510 ntwdt_state->ntwdt_watchdog_timeout)); 511 /* 512 * ignore request to enable reset while disabling watchdog. 513 */ 514 if (!lom_dogctl.dog_enable && lom_dogctl.reset_enable) { 515 NTWDT_DBG(NTWDT_DBG_IOCTL, ("invalid combination of " 516 "reset_enable: %d, and dog_enable: %d", 517 lom_dogctl.reset_enable, 518 lom_dogctl.dog_enable)); 519 retval = EINVAL; 520 break; 521 } 522 523 mutex_enter(&ntwdt_state->ntwdt_runstate_mutex); 524 525 if (ntwdt_state->ntwdt_watchdog_timeout == 0) { 526 /* 527 * the LOMIOCDOGTIME has never been used to setup 528 * a valid timeout. 529 */ 530 NTWDT_DBG(NTWDT_DBG_IOCTL, ("timeout has not been set" 531 "watchdog_timeout: %d", 532 ntwdt_state->ntwdt_watchdog_timeout)); 533 retval = EINVAL; 534 goto end; 535 } 536 537 /* 538 * Store the user specified state in the softstate. 539 */ 540 ntwdt_state->ntwdt_reset_enabled = lom_dogctl.reset_enable; 541 ntwdt_state->ntwdt_watchdog_enabled = lom_dogctl.dog_enable; 542 543 if (ntwdt_state->ntwdt_watchdog_enabled != 0) { 544 /* 545 * The user wants to enable the watchdog. 546 * Arm the watchdog and start the cyclic. 547 */ 548 ntwdt_arm_watchdog(ntwdt_state); 549 550 if (ntwdt_state->ntwdt_timer_running == 0) { 551 ntwdt_start_timer(ntwdt_ptr); 552 } 553 554 NTWDT_DBG(NTWDT_DBG_IOCTL, ("AWDT is enabled")); 555 } else { 556 /* 557 * The user wants to disable the watchdog. 558 */ 559 if (ntwdt_state->ntwdt_timer_running != 0) { 560 ntwdt_stop_timer(ntwdt_ptr); 561 } 562 NTWDT_DBG(NTWDT_DBG_IOCTL, ("AWDT is disabled")); 563 } 564 565 mutex_exit(&ntwdt_state->ntwdt_runstate_mutex); 566 break; 567 568 case LOMIOCDOGTIME: 569 if (ddi_copyin((caddr_t)arg, (caddr_t)&lom_dogtime, 570 sizeof (uint32_t), mode) != 0) { 571 retval = EFAULT; 572 break; 573 } 574 575 NTWDT_DBG(NTWDT_DBG_IOCTL, ("user set timeout: %d", 576 lom_dogtime)); 577 578 /* 579 * Ensure specified timeout is valid. 580 */ 581 if ((lom_dogtime == 0) || 582 (lom_dogtime > (uint32_t)NTWDT_MAX_TIMEOUT)) { 583 retval = EINVAL; 584 NTWDT_DBG(NTWDT_DBG_IOCTL, ("user set invalid " 585 "timeout: %d", (int)TICK_TO_MSEC(lom_dogtime))); 586 break; 587 } 588 589 mutex_enter(&ntwdt_state->ntwdt_runstate_mutex); 590 591 ntwdt_state->ntwdt_watchdog_timeout = lom_dogtime; 592 593 /* 594 * If awdt is currently running, re-arm it with the 595 * newly-specified timeout value. 596 */ 597 if (ntwdt_state->ntwdt_timer_running != 0) { 598 ntwdt_arm_watchdog(ntwdt_state); 599 } 600 mutex_exit(&ntwdt_state->ntwdt_runstate_mutex); 601 break; 602 603 case LOMIOCDOGPAT: 604 /* 605 * Allow user to pat the watchdog timer. 606 */ 607 NTWDT_DBG(NTWDT_DBG_IOCTL, ("DOGPAT is invoked")); 608 mutex_enter(&ntwdt_state->ntwdt_runstate_mutex); 609 610 /* 611 * If awdt is not enabled or underlying cyclic is not 612 * running, exit. 613 */ 614 if (!(ntwdt_state->ntwdt_watchdog_enabled && 615 ntwdt_state->ntwdt_timer_running)) { 616 NTWDT_DBG(NTWDT_DBG_IOCTL, ("PAT: AWDT not enabled")); 617 goto end; 618 } 619 620 if (ntwdt_state->ntwdt_watchdog_expired == 0) { 621 /* 622 * re-arm the awdt. 623 */ 624 ntwdt_arm_watchdog(ntwdt_state); 625 NTWDT_DBG(NTWDT_DBG_IOCTL, ("AWDT patted, " 626 "remainning seconds: %d", 627 ntwdt_state->ntwdt_time_remaining)); 628 } 629 630 mutex_exit(&ntwdt_state->ntwdt_runstate_mutex); 631 break; 632 633 default: 634 retval = EINVAL; 635 break; 636 } 637 return (retval); 638 end: 639 mutex_exit(&ntwdt_state->ntwdt_runstate_mutex); 640 return (retval); 641 } 642 643 static void 644 ntwdt_cyclic_pat(void) 645 { 646 ddi_trigger_softintr(ntwdt_cyclic_softint_id); 647 } 648 649 static uint_t 650 ntwdt_cyclic_softint(caddr_t arg) 651 { 652 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 653 ntwdt_state_t *ntwdt_ptr = (ntwdt_state_t *)arg; 654 ntwdt_runstate_t *ntwdt_state; 655 656 ntwdt_state = ntwdt_ptr->ntwdt_run_state; 657 658 mutex_enter(&ntwdt_state->ntwdt_runstate_mutex); 659 660 if ((ntwdt_state->ntwdt_watchdog_flags & NTWDT_FLAG_SKIP_CYCLIC) != 0) { 661 ntwdt_state->ntwdt_watchdog_flags &= ~NTWDT_FLAG_SKIP_CYCLIC; 662 goto end; 663 } 664 665 if ((ntwdt_state->ntwdt_timer_running == 0) || 666 (ntwdt_ptr->ntwdt_cycl_id == CYCLIC_NONE) || 667 (ntwdt_state->ntwdt_watchdog_enabled == 0)) { 668 goto end; 669 } 670 671 NTWDT_DBG(NTWDT_DBG_IOCTL, ("cyclic_softint: %d" 672 "lbolt64: %d\n", ntwdt_state->ntwdt_watchdog_timeout, 673 (int)TICK_TO_MSEC(lbolt64))); 674 675 /* 676 * Decrement the virtual watchdog timer and check if it has expired. 677 */ 678 ntwdt_state->ntwdt_time_remaining -= NTWDT_DECREMENT_INTERVAL; 679 680 if (ntwdt_state->ntwdt_time_remaining == 0) { 681 cmn_err(CE_WARN, "application-watchdog expired"); 682 ntwdt_state->ntwdt_watchdog_expired = 1; 683 684 if (ntwdt_state->ntwdt_reset_enabled != 0) { 685 /* 686 * The user wants to reset the system. 687 */ 688 mutex_exit(&ntwdt_state->ntwdt_runstate_mutex); 689 690 NTWDT_DBG(NTWDT_DBG_NTWDT, ("recovery being done")); 691 ntwdt_enforce_timeout(); 692 } else { 693 NTWDT_DBG(NTWDT_DBG_NTWDT, ("no recovery being done")); 694 ntwdt_state->ntwdt_watchdog_enabled = 0; 695 } 696 697 /* 698 * Schedule Callout to stop the cyclic. 699 */ 700 (void) timeout(ntwdt_stop_timer_lock, ntwdt_ptr, 0); 701 } else { 702 _NOTE(EMPTY) 703 NTWDT_DBG(NTWDT_DBG_NTWDT, ("time remaining in AWDT: %d secs", 704 (int)TICK_TO_MSEC(ntwdt_state->ntwdt_time_remaining))); 705 } 706 707 end: 708 mutex_exit(&ntwdt_state->ntwdt_runstate_mutex); 709 return (DDI_INTR_CLAIMED); 710 } 711 712 static void 713 ntwdt_arm_watchdog(ntwdt_runstate_t *ntwdt_state) 714 { 715 ntwdt_state->ntwdt_time_remaining = ntwdt_state->ntwdt_watchdog_timeout; 716 717 if (ntwdt_state->ntwdt_timer_running != 0) { 718 ntwdt_state->ntwdt_watchdog_flags |= NTWDT_FLAG_SKIP_CYCLIC; 719 } else { 720 ntwdt_state->ntwdt_watchdog_flags &= ~NTWDT_FLAG_SKIP_CYCLIC; 721 } 722 } 723 724 static void 725 ntwdt_start_timer(ntwdt_state_t *ntwdt_ptr) 726 { 727 ntwdt_runstate_t *ntwdt_state = ntwdt_ptr->ntwdt_run_state; 728 cyc_handler_t *hdlr = &ntwdt_state->ntwdt_cycl_hdlr; 729 cyc_time_t *when = &ntwdt_state->ntwdt_cycl_time; 730 731 /* 732 * Init the cyclic. 733 */ 734 when->cyt_interval = ntwdt_state->ntwdt_cyclic_interval; 735 when->cyt_when = gethrtime() + when->cyt_interval; 736 737 ntwdt_state->ntwdt_watchdog_expired = 0; 738 ntwdt_state->ntwdt_timer_running = 1; 739 740 mutex_enter(&cpu_lock); 741 if (ntwdt_ptr->ntwdt_cycl_id == CYCLIC_NONE) { 742 ntwdt_ptr->ntwdt_cycl_id = cyclic_add(hdlr, when); 743 } 744 mutex_exit(&cpu_lock); 745 746 NTWDT_DBG(NTWDT_DBG_NTWDT, ("cyclic-driven timer is started")); 747 } 748 749 static void 750 ntwdt_stop_timer(void *arg) 751 { 752 ntwdt_state_t *ntwdt_ptr = (ntwdt_state_t *)arg; 753 ntwdt_runstate_t *ntwdt_state = ntwdt_ptr->ntwdt_run_state; 754 755 mutex_enter(&cpu_lock); 756 if (ntwdt_ptr->ntwdt_cycl_id != CYCLIC_NONE) { 757 cyclic_remove(ntwdt_ptr->ntwdt_cycl_id); 758 } 759 mutex_exit(&cpu_lock); 760 761 ntwdt_state->ntwdt_watchdog_flags = 0; 762 ntwdt_state->ntwdt_timer_running = 0; 763 ntwdt_ptr->ntwdt_cycl_id = CYCLIC_NONE; 764 765 NTWDT_DBG(NTWDT_DBG_NTWDT, ("cyclic-driven timer is stopped")); 766 } 767 768 /* 769 * This is a wrapper function for ntwdt_stop_timer as some callers 770 * will already have the appropriate mutex locked, and others not. 771 */ 772 static void 773 ntwdt_stop_timer_lock(void *arg) 774 { 775 ntwdt_state_t *ntwdt_ptr = (ntwdt_state_t *)arg; 776 777 mutex_enter(&ntwdt_ptr->ntwdt_run_state->ntwdt_runstate_mutex); 778 ntwdt_stop_timer(arg); 779 mutex_exit(&ntwdt_ptr->ntwdt_run_state->ntwdt_runstate_mutex); 780 } 781 782 static void 783 ntwdt_enforce_timeout() 784 { 785 if (ntwdt_disable_timeout_action != 0) { 786 cmn_err(CE_NOTE, "Appication watchdog timer expired, " 787 "taking no action"); 788 return; 789 } 790 791 NTWDT_DBG(NTWDT_DBG_NTWDT, ("dump cores and rebooting ...")); 792 793 (void) kadmin(A_DUMP, AD_BOOT, NULL, kcred); 794 cmn_err(CE_PANIC, "kadmin(A_DUMP, AD_BOOT) failed"); 795 _NOTE(NOTREACHED); 796 } 797 798 static int 799 ntwdt_chk_watchdog_support() 800 { 801 int retval = 0; 802 803 if ((boothowto & RB_DEBUG) != 0) { 804 cmn_err(CE_WARN, "kernel debugger was booted; " 805 "application watchdog is not available."); 806 retval = ENOTSUP; 807 } 808 return (retval); 809 } 810