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