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 /* 23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * A CPR derivative specifically for sbd 29 */ 30 31 #include <sys/types.h> 32 #include <sys/systm.h> 33 #include <sys/machparam.h> 34 #include <sys/machsystm.h> 35 #include <sys/ddi.h> 36 #define SUNDDI_IMPL 37 #include <sys/sunddi.h> 38 #include <sys/sunndi.h> 39 #include <sys/devctl.h> 40 #include <sys/time.h> 41 #include <sys/kmem.h> 42 #include <nfs/lm.h> 43 #include <sys/ddi_impldefs.h> 44 #include <sys/ndi_impldefs.h> 45 #include <sys/obpdefs.h> 46 #include <sys/cmn_err.h> 47 #include <sys/debug.h> 48 #include <sys/errno.h> 49 #include <sys/callb.h> 50 #include <sys/clock.h> 51 #include <sys/x_call.h> 52 #include <sys/cpuvar.h> 53 #include <sys/epm.h> 54 #include <sys/vfs.h> 55 56 #ifdef DEBUG 57 #include <sys/note.h> 58 #endif 59 60 #include <sys/promif.h> 61 #include <sys/conf.h> 62 #include <sys/cyclic.h> 63 64 #include <sys/sbd_ioctl.h> 65 #include <sys/sbd.h> 66 #include <sys/sbdp_priv.h> 67 #include <sys/cpu_sgnblk_defs.h> 68 69 static char * 70 sbdp_get_err_buf(sbd_error_t *ep) 71 { 72 return (ep->e_rsc); 73 } 74 75 extern void e_ddi_enter_driver_list(struct devnames *dnp, int *listcnt); 76 extern void e_ddi_exit_driver_list(struct devnames *dnp, int listcnt); 77 extern int is_pseudo_device(dev_info_t *dip); 78 79 extern kmutex_t cpu_lock; 80 81 static int sbdp_is_real_device(dev_info_t *dip); 82 #ifdef DEBUG 83 static int sbdp_bypass_device(char *dname); 84 #endif 85 static int sbdp_check_dip(dev_info_t *dip, void *arg, uint_t ref); 86 87 static int sbdp_resolve_devname(dev_info_t *dip, char *buffer, 88 char *alias); 89 90 int sbdp_test_suspend(sbdp_handle_t *hp); 91 92 #define SR_STATE(srh) ((srh)->sr_suspend_state) 93 #define SR_SET_STATE(srh, state) (SR_STATE((srh)) = (state)) 94 #define SR_FAILED_DIP(srh) ((srh)->sr_failed_dip) 95 96 #define SR_FLAG_WATCHDOG 0x1 97 #define SR_CHECK_FLAG(srh, flag) ((srh)->sr_flags & (flag)) 98 #define SR_SET_FLAG(srh, flag) ((srh)->sr_flags |= (flag)) 99 #define SR_CLEAR_FLAG(srh, flag) ((srh)->sr_flags &= ~(flag)) 100 101 #ifdef DEBUG 102 /* 103 * Just for testing. List of drivers to bypass when performing a suspend. 104 */ 105 static char *sbdp_bypass_list[] = { 106 /* "sgsbbc", this is an example when needed */ 107 "" 108 }; 109 #endif 110 111 #define SKIP_SYNC /* bypass sync ops in sbdp_suspend */ 112 113 /* 114 * sbdp_skip_user_threads is used to control if user threads should 115 * be suspended. If sbdp_skip_user_threads is true, the rest of the 116 * flags are not used; if it is false, sbdp_check_user_stop_result 117 * will be used to control whether or not we need to check suspend 118 * result, and sbdp_allow_blocked_threads will be used to control 119 * whether or not we allow suspend to continue if there are blocked 120 * threads. We allow all combinations of sbdp_check_user_stop_result 121 * and sbdp_allow_block_threads, even though it might not make much 122 * sense to not allow block threads when we don't even check stop 123 * result. 124 */ 125 static int sbdp_skip_user_threads = 0; /* default to FALSE */ 126 static int sbdp_check_user_stop_result = 1; /* default to TRUE */ 127 static int sbdp_allow_blocked_threads = 1; /* default to TRUE */ 128 129 130 static void 131 sbdp_stop_intr(void) 132 { 133 kpreempt_disable(); 134 cyclic_suspend(); 135 } 136 137 static void 138 sbdp_enable_intr(void) 139 { 140 cyclic_resume(); 141 kpreempt_enable(); 142 } 143 144 sbdp_sr_handle_t * 145 sbdp_get_sr_handle(void) 146 { 147 sbdp_sr_handle_t *srh; 148 srh = kmem_zalloc(sizeof (sbdp_sr_handle_t), KM_SLEEP); 149 150 return (srh); 151 } 152 153 void 154 sbdp_release_sr_handle(sbdp_sr_handle_t *srh) 155 { 156 ASSERT(SR_FAILED_DIP(srh) == NULL); 157 kmem_free((caddr_t)srh, sizeof (sbdp_sr_handle_t)); 158 } 159 160 static int 161 sbdp_is_real_device(dev_info_t *dip) 162 { 163 struct regspec *regbuf = NULL; 164 int length = 0; 165 int rc; 166 167 if (ddi_get_driver(dip) == NULL) 168 return (0); 169 170 if (DEVI(dip)->devi_pm_flags & (PMC_NEEDS_SR|PMC_PARENTAL_SR)) 171 return (1); 172 if (DEVI(dip)->devi_pm_flags & PMC_NO_SR) 173 return (0); 174 175 /* 176 * now the general case 177 */ 178 rc = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg", 179 (caddr_t)®buf, &length); 180 ASSERT(rc != DDI_PROP_NO_MEMORY); 181 if (rc != DDI_PROP_SUCCESS) { 182 return (0); 183 } else { 184 if ((length > 0) && (regbuf != NULL)) 185 kmem_free(regbuf, length); 186 return (1); 187 } 188 } 189 190 #ifdef DEBUG 191 static int 192 sbdp_bypass_device(char *dname) 193 { 194 int i; 195 char **lname; 196 /* check the bypass list */ 197 for (i = 0, lname = &sbdp_bypass_list[i]; **lname != '\0'; lname++) { 198 SBDP_DBG_QR("Checking %s\n", *lname); 199 if (strcmp(dname, sbdp_bypass_list[i++]) == 0) 200 return (1); 201 } 202 return (0); 203 } 204 #endif 205 206 static int 207 sbdp_resolve_devname(dev_info_t *dip, char *buffer, char *alias) 208 { 209 major_t devmajor; 210 char *aka, *name; 211 212 *buffer = *alias = 0; 213 214 if (dip == NULL) 215 return (-1); 216 217 if ((name = ddi_get_name(dip)) == NULL) 218 name = "<null name>"; 219 220 aka = name; 221 222 if ((devmajor = ddi_name_to_major(aka)) != -1) 223 aka = ddi_major_to_name(devmajor); 224 225 (void) strcpy(buffer, name); 226 227 if (strcmp(name, aka)) 228 (void) strcpy(alias, aka); 229 else 230 *alias = 0; 231 232 return (0); 233 } 234 235 typedef struct sbdp_ref { 236 int *refcount; 237 int *refcount_non_gldv3; 238 sbd_error_t *sep; 239 } sbdp_ref_t; 240 241 static int 242 sbdp_check_dip(dev_info_t *dip, void *arg, uint_t ref) 243 { 244 char *dname; 245 sbdp_ref_t *sbrp = (sbdp_ref_t *)arg; 246 247 if (dip == NULL) 248 return (DDI_WALK_CONTINUE); 249 250 ASSERT(sbrp->sep != NULL); 251 ASSERT(sbrp->refcount != NULL); 252 253 if (!sbdp_is_real_device(dip)) 254 return (DDI_WALK_CONTINUE); 255 256 dname = ddi_binding_name(dip); 257 258 if ((strcmp(dname, "pciclass,060940") == 0) || (strcmp(dname, 259 "pciclass,060980") == 0)) { 260 (void) ddi_pathname(dip, sbdp_get_err_buf(sbrp->sep)); 261 sbdp_set_err(sbrp->sep, ESBD_BUSY, NULL); 262 (*sbrp->refcount)++; 263 return (DDI_WALK_TERMINATE); 264 } 265 266 #ifdef DEBUG 267 if (sbdp_bypass_device(dname)) 268 return (DDI_WALK_CONTINUE); 269 #endif 270 271 if (ref) { 272 major_t major; 273 274 (*sbrp->refcount)++; 275 SBDP_DBG_QR("\n%s (major# %d) is referenced\n", 276 dname, ddi_name_to_major(dname)); 277 (void) ddi_pathname(dip, sbdp_get_err_buf(sbrp->sep)); 278 major = ddi_driver_major(dip); 279 if (sbrp->refcount_non_gldv3 && NETWORK_PHYSDRV(major) && 280 !GLDV3_DRV(major)) { 281 (*sbrp->refcount_non_gldv3)++; 282 return (DDI_WALK_CONTINUE); 283 } 284 sbdp_set_err(sbrp->sep, ESBD_BUSY, NULL); 285 return (DDI_WALK_TERMINATE); 286 } 287 return (DDI_WALK_CONTINUE); 288 } 289 290 void 291 sbdp_check_devices(dev_info_t *dip, int *refcount, sbd_error_t *sep, 292 int *refcount_non_gldv3) 293 { 294 sbdp_ref_t sbr; 295 296 sbr.refcount = refcount; 297 sbr.refcount_non_gldv3 = refcount_non_gldv3; 298 sbr.sep = sep; 299 300 ASSERT(e_ddi_branch_held(dip)); 301 302 (void) e_ddi_branch_referenced(dip, sbdp_check_dip, &sbr); 303 } 304 305 /* 306 * Starting from the root node suspend all devices in the device tree. 307 * Assumes that all devices have already been marked busy. 308 */ 309 static int 310 sbdp_suspend_devices_(dev_info_t *dip, sbdp_sr_handle_t *srh) 311 { 312 major_t major; 313 char *dname; 314 315 for (; dip != NULL; dip = ddi_get_next_sibling(dip)) { 316 char d_name[40], d_alias[40], *d_info; 317 318 if (sbdp_suspend_devices_(ddi_get_child(dip), srh)) { 319 return (ENXIO); 320 } 321 322 if (!sbdp_is_real_device(dip)) 323 continue; 324 325 major = (major_t)-1; 326 if ((dname = DEVI(dip)->devi_binding_name) != NULL) 327 major = ddi_name_to_major(dname); 328 329 #ifdef DEBUG 330 if (sbdp_bypass_device(dname)) { 331 SBDP_DBG_QR("bypassed suspend of %s (major# %d)\n", 332 dname, major); 333 continue; 334 } 335 #endif 336 337 if ((d_info = ddi_get_name_addr(dip)) == NULL) 338 d_info = "<null>"; 339 340 d_name[0] = 0; 341 if (sbdp_resolve_devname(dip, d_name, d_alias) == 0) { 342 if (d_alias[0] != 0) { 343 SBDP_DBG_QR("\tsuspending %s@%s (aka %s)\n", 344 d_name, d_info, d_alias); 345 } else { 346 SBDP_DBG_QR("\tsuspending %s@%s\n", 347 d_name, d_info); 348 } 349 } else { 350 SBDP_DBG_QR("\tsuspending %s@%s\n", dname, d_info); 351 } 352 353 if (devi_detach(dip, DDI_SUSPEND) != DDI_SUCCESS) { 354 (void) sprintf(sbdp_get_err_buf(&srh->sep), 355 "%d", major); 356 357 sbdp_set_err(&srh->sep, ESGT_SUSPEND, NULL); 358 ndi_hold_devi(dip); 359 SR_FAILED_DIP(srh) = dip; 360 return (DDI_FAILURE); 361 } 362 } 363 364 return (DDI_SUCCESS); 365 } 366 367 /*ARGSUSED*/ 368 static int 369 sbdp_suspend_devices_enter(dev_info_t *dip, void *arg) 370 { 371 struct dev_info *devi = DEVI(dip); 372 ndi_devi_enter(dip, &devi->devi_circular); 373 return (DDI_WALK_CONTINUE); 374 } 375 376 /*ARGSUSED*/ 377 static int 378 sbdp_suspend_devices_exit(dev_info_t *dip, void *arg) 379 { 380 struct dev_info *devi = DEVI(dip); 381 ndi_devi_exit(dip, devi->devi_circular); 382 return (DDI_WALK_CONTINUE); 383 } 384 385 /* 386 * Before suspending devices first mark all device nodes busy. This 387 * avoids a deadlock situation when another thread holds a device busy 388 * and accesses an already suspended device. 389 */ 390 static int 391 sbdp_suspend_devices(dev_info_t *dip, sbdp_sr_handle_t *srh) 392 { 393 int rv; 394 395 /* assumes dip is ddi_root_node so no ndi_devi_enter required */ 396 ASSERT(dip == ddi_root_node()); 397 ddi_walk_devs(dip, sbdp_suspend_devices_enter, NULL); 398 rv = sbdp_suspend_devices_(dip, srh); 399 ddi_walk_devs(dip, sbdp_suspend_devices_exit, NULL); 400 return (rv); 401 } 402 403 static void 404 sbdp_resume_devices(dev_info_t *start, sbdp_sr_handle_t *srh) 405 { 406 int circ; 407 dev_info_t *dip, *next, *last = NULL; 408 char *bn; 409 sbd_error_t *sep; 410 411 sep = &srh->sep; 412 413 /* attach in reverse device tree order */ 414 while (last != start) { 415 dip = start; 416 next = ddi_get_next_sibling(dip); 417 while (next != last && dip != SR_FAILED_DIP(srh)) { 418 dip = next; 419 next = ddi_get_next_sibling(dip); 420 } 421 if (dip == SR_FAILED_DIP(srh)) { 422 /* Release hold acquired in sbdp_suspend_devices() */ 423 ndi_rele_devi(dip); 424 SR_FAILED_DIP(srh) = NULL; 425 } else if (sbdp_is_real_device(dip) && 426 SR_FAILED_DIP(srh) == NULL) { 427 428 if (DEVI(dip)->devi_binding_name != NULL) { 429 bn = ddi_binding_name(dip); 430 } 431 #ifdef DEBUG 432 if (!sbdp_bypass_device(bn)) { 433 #else 434 { 435 #endif 436 char d_name[40], d_alias[40], *d_info; 437 438 d_name[0] = 0; 439 d_info = ddi_get_name_addr(dip); 440 if (d_info == NULL) 441 d_info = "<null>"; 442 443 if (!sbdp_resolve_devname(dip, d_name, 444 d_alias)) { 445 if (d_alias[0] != 0) { 446 SBDP_DBG_QR("\tresuming " 447 "%s@%s (aka %s)\n", 448 d_name, d_info, 449 d_alias); 450 } else { 451 SBDP_DBG_QR("\tresuming " 452 "%s@%s\n", 453 d_name, d_info); 454 } 455 } else { 456 SBDP_DBG_QR("\tresuming %s@%s\n", 457 bn, d_info); 458 } 459 460 if (devi_attach(dip, DDI_RESUME) != 461 DDI_SUCCESS) { 462 /* 463 * Print a console warning, 464 * set an errno of ESGT_RESUME, 465 * and save the driver major 466 * number in the e_str. 467 */ 468 469 (void) sprintf(sbdp_get_err_buf(sep), 470 "%s@%s", 471 d_name[0] ? d_name : bn, d_info); 472 SBDP_DBG_QR("\tFAILED to resume " 473 "%s\n", sbdp_get_err_buf(sep)); 474 sbdp_set_err(sep, 475 ESGT_RESUME, NULL); 476 } 477 } 478 } 479 ndi_devi_enter(dip, &circ); 480 sbdp_resume_devices(ddi_get_child(dip), srh); 481 ndi_devi_exit(dip, circ); 482 last = dip; 483 } 484 } 485 486 /* 487 * True if thread is virtually stopped. Similar to CPR_VSTOPPED 488 * but from DR point of view. These user threads are waiting in 489 * the kernel. Once they return from kernel, they will process 490 * the stop signal and stop. 491 */ 492 #define SBDP_VSTOPPED(t) \ 493 ((t)->t_state == TS_SLEEP && \ 494 (t)->t_wchan != NULL && \ 495 (t)->t_astflag && \ 496 ((t)->t_proc_flag & TP_CHKPT)) 497 498 499 static int 500 sbdp_stop_user_threads(sbdp_sr_handle_t *srh) 501 { 502 int count; 503 char cache_psargs[PSARGSZ]; 504 kthread_id_t cache_tp; 505 uint_t cache_t_state; 506 int bailout; 507 sbd_error_t *sep; 508 kthread_id_t tp; 509 510 extern void add_one_utstop(); 511 extern void utstop_timedwait(clock_t); 512 extern void utstop_init(void); 513 514 #define SBDP_UTSTOP_RETRY 4 515 #define SBDP_UTSTOP_WAIT hz 516 517 if (sbdp_skip_user_threads) 518 return (DDI_SUCCESS); 519 520 sep = &srh->sep; 521 ASSERT(sep); 522 523 utstop_init(); 524 525 /* we need to try a few times to get past fork, etc. */ 526 for (count = 0; count < SBDP_UTSTOP_RETRY; count++) { 527 /* walk the entire threadlist */ 528 mutex_enter(&pidlock); 529 for (tp = curthread->t_next; tp != curthread; tp = tp->t_next) { 530 proc_t *p = ttoproc(tp); 531 532 /* handle kernel threads separately */ 533 if (p->p_as == &kas || p->p_stat == SZOMB) 534 continue; 535 536 mutex_enter(&p->p_lock); 537 thread_lock(tp); 538 539 if (tp->t_state == TS_STOPPED) { 540 /* add another reason to stop this thread */ 541 tp->t_schedflag &= ~TS_RESUME; 542 } else { 543 tp->t_proc_flag |= TP_CHKPT; 544 545 thread_unlock(tp); 546 mutex_exit(&p->p_lock); 547 add_one_utstop(); 548 mutex_enter(&p->p_lock); 549 thread_lock(tp); 550 551 aston(tp); 552 553 if (ISWAKEABLE(tp) || ISWAITING(tp)) { 554 setrun_locked(tp); 555 } 556 } 557 558 /* grab thread if needed */ 559 if (tp->t_state == TS_ONPROC && tp->t_cpu != CPU) 560 poke_cpu(tp->t_cpu->cpu_id); 561 562 563 thread_unlock(tp); 564 mutex_exit(&p->p_lock); 565 } 566 mutex_exit(&pidlock); 567 568 569 /* let everything catch up */ 570 utstop_timedwait(count * count * SBDP_UTSTOP_WAIT); 571 572 573 /* now, walk the threadlist again to see if we are done */ 574 mutex_enter(&pidlock); 575 for (tp = curthread->t_next, bailout = 0; 576 tp != curthread; tp = tp->t_next) { 577 proc_t *p = ttoproc(tp); 578 579 /* handle kernel threads separately */ 580 if (p->p_as == &kas || p->p_stat == SZOMB) 581 continue; 582 583 /* 584 * If this thread didn't stop, and we don't allow 585 * unstopped blocked threads, bail. 586 */ 587 thread_lock(tp); 588 if (!CPR_ISTOPPED(tp) && 589 !(sbdp_allow_blocked_threads && 590 SBDP_VSTOPPED(tp))) { 591 592 /* nope, cache the details for later */ 593 bcopy(p->p_user.u_psargs, cache_psargs, 594 sizeof (cache_psargs)); 595 cache_tp = tp; 596 cache_t_state = tp->t_state; 597 bailout = 1; 598 } 599 thread_unlock(tp); 600 } 601 mutex_exit(&pidlock); 602 603 /* were all the threads stopped? */ 604 if (!bailout) 605 break; 606 } 607 608 /* were we unable to stop all threads after a few tries? */ 609 if (bailout) { 610 cmn_err(CE_NOTE, "process: %s id: %p state: %x\n", 611 cache_psargs, (void *)cache_tp, cache_t_state); 612 613 (void) sprintf(sbdp_get_err_buf(sep), "%s", cache_psargs); 614 sbdp_set_err(sep, ESGT_UTHREAD, NULL); 615 return (ESRCH); 616 } 617 618 return (DDI_SUCCESS); 619 } 620 621 static void 622 sbdp_start_user_threads(void) 623 { 624 kthread_id_t tp; 625 626 mutex_enter(&pidlock); 627 628 /* walk all threads and release them */ 629 for (tp = curthread->t_next; tp != curthread; tp = tp->t_next) { 630 proc_t *p = ttoproc(tp); 631 632 /* skip kernel threads */ 633 if (ttoproc(tp)->p_as == &kas) 634 continue; 635 636 mutex_enter(&p->p_lock); 637 tp->t_proc_flag &= ~TP_CHKPT; 638 mutex_exit(&p->p_lock); 639 640 thread_lock(tp); 641 if (CPR_ISTOPPED(tp)) { 642 /* back on the runq */ 643 tp->t_schedflag |= TS_RESUME; 644 setrun_locked(tp); 645 } 646 thread_unlock(tp); 647 } 648 649 mutex_exit(&pidlock); 650 } 651 652 static void 653 sbdp_signal_user(int sig) 654 { 655 struct proc *p; 656 657 mutex_enter(&pidlock); 658 659 for (p = practive; p != NULL; p = p->p_next) { 660 /* only user threads */ 661 if (p->p_exec == NULL || p->p_stat == SZOMB || 662 p == proc_init || p == ttoproc(curthread)) 663 continue; 664 665 mutex_enter(&p->p_lock); 666 sigtoproc(p, NULL, sig); 667 mutex_exit(&p->p_lock); 668 } 669 670 mutex_exit(&pidlock); 671 672 /* add a bit of delay */ 673 delay(hz); 674 } 675 676 static uint_t saved_watchdog_seconds; 677 678 void 679 sbdp_resume(sbdp_sr_handle_t *srh) 680 { 681 /* 682 * update the signature block 683 */ 684 CPU_SIGNATURE(OS_SIG, SIGST_RESUME_INPROGRESS, SIGSUBST_NULL, 685 CPU->cpu_id); 686 687 switch (SR_STATE(srh)) { 688 case SBDP_SRSTATE_FULL: 689 690 ASSERT(MUTEX_HELD(&cpu_lock)); 691 692 /* 693 * Prevent false alarm in tod_validate() due to tod 694 * value change between suspend and resume 695 */ 696 mutex_enter(&tod_lock); 697 tod_status_set(TOD_DR_RESUME_DONE); 698 mutex_exit(&tod_lock); 699 700 sbdp_enable_intr(); /* enable intr & clock */ 701 702 /* 703 * release all the other cpus 704 * using start_cpus() vice sbdp_release_cpus() 705 */ 706 start_cpus(); 707 mutex_exit(&cpu_lock); 708 709 /* 710 * If we suspended hw watchdog at suspend, 711 * re-enable it now. 712 */ 713 if (SR_CHECK_FLAG(srh, SR_FLAG_WATCHDOG)) { 714 mutex_enter(&tod_lock); 715 tod_ops.tod_set_watchdog_timer( 716 saved_watchdog_seconds); 717 mutex_exit(&tod_lock); 718 } 719 720 /* FALLTHROUGH */ 721 722 case SBDP_SRSTATE_DRIVER: 723 /* 724 * resume devices: root node doesn't have to 725 * be held in any way. 726 */ 727 sbdp_resume_devices(ddi_root_node(), srh); 728 729 /* 730 * resume the lock manager 731 */ 732 lm_cprresume(); 733 734 /* FALLTHROUGH */ 735 736 case SBDP_SRSTATE_USER: 737 /* 738 * finally, resume user threads 739 */ 740 if (!sbdp_skip_user_threads) { 741 SBDP_DBG_QR("DR: resuming user threads...\n"); 742 sbdp_start_user_threads(); 743 } 744 /* FALLTHROUGH */ 745 746 case SBDP_SRSTATE_BEGIN: 747 default: 748 /* 749 * let those who care know that we've just resumed 750 */ 751 SBDP_DBG_QR("sending SIGTHAW...\n"); 752 sbdp_signal_user(SIGTHAW); 753 break; 754 } 755 756 /* 757 * update the signature block 758 */ 759 CPU_SIGNATURE(OS_SIG, SIGST_RUN, SIGSUBST_NULL, CPU->cpu_id); 760 761 SBDP_DBG_QR("DR: resume COMPLETED\n"); 762 } 763 764 int 765 sbdp_suspend(sbdp_sr_handle_t *srh) 766 { 767 int force; 768 int rc = DDI_SUCCESS; 769 770 force = (srh && (srh->sr_flags & SBDP_IOCTL_FLAG_FORCE)); 771 772 /* 773 * if no force flag, check for unsafe drivers 774 */ 775 if (force) { 776 SBDP_DBG_QR("\nsbdp_suspend invoked with force flag"); 777 } 778 779 /* 780 * update the signature block 781 */ 782 CPU_SIGNATURE(OS_SIG, SIGST_QUIESCE_INPROGRESS, SIGSUBST_NULL, 783 CPU->cpu_id); 784 785 /* 786 * first, stop all user threads 787 */ 788 SBDP_DBG_QR("SBDP: suspending user threads...\n"); 789 SR_SET_STATE(srh, SBDP_SRSTATE_USER); 790 if (((rc = sbdp_stop_user_threads(srh)) != DDI_SUCCESS) && 791 sbdp_check_user_stop_result) { 792 sbdp_resume(srh); 793 return (rc); 794 } 795 796 #ifndef SKIP_SYNC 797 /* 798 * This sync swap out all user pages 799 */ 800 vfs_sync(SYNC_ALL); 801 #endif 802 803 /* 804 * special treatment for lock manager 805 */ 806 lm_cprsuspend(); 807 808 #ifndef SKIP_SYNC 809 /* 810 * sync the file system in case we never make it back 811 */ 812 sync(); 813 814 #endif 815 /* 816 * now suspend drivers 817 */ 818 SBDP_DBG_QR("SBDP: suspending drivers...\n"); 819 SR_SET_STATE(srh, SBDP_SRSTATE_DRIVER); 820 821 /* 822 * Root node doesn't have to be held in any way. 823 */ 824 if ((rc = sbdp_suspend_devices(ddi_root_node(), srh)) != DDI_SUCCESS) { 825 sbdp_resume(srh); 826 return (rc); 827 } 828 829 /* 830 * finally, grab all cpus 831 */ 832 SR_SET_STATE(srh, SBDP_SRSTATE_FULL); 833 834 /* 835 * if watchdog was activated, disable it 836 */ 837 if (watchdog_activated) { 838 mutex_enter(&tod_lock); 839 saved_watchdog_seconds = tod_ops.tod_clear_watchdog_timer(); 840 mutex_exit(&tod_lock); 841 SR_SET_FLAG(srh, SR_FLAG_WATCHDOG); 842 } else { 843 SR_CLEAR_FLAG(srh, SR_FLAG_WATCHDOG); 844 } 845 846 mutex_enter(&cpu_lock); 847 pause_cpus(NULL, NULL); 848 sbdp_stop_intr(); 849 850 /* 851 * update the signature block 852 */ 853 CPU_SIGNATURE(OS_SIG, SIGST_QUIESCED, SIGSUBST_NULL, CPU->cpu_id); 854 855 return (rc); 856 } 857 858 /*ARGSUSED*/ 859 int 860 sbdp_test_suspend(sbdp_handle_t *hp) 861 { 862 sbdp_sr_handle_t *srh; 863 int err; 864 865 SBDP_DBG_QR("%s...\n", "sbdp_test_suspend"); 866 867 srh = sbdp_get_sr_handle(); 868 869 srh->sr_flags = hp->h_flags; 870 871 if ((err = sbdp_suspend(srh)) == DDI_SUCCESS) { 872 sbdp_resume(srh); 873 } else { 874 SBDP_DBG_MISC("sbdp_suspend() failed, err = 0x%x\n", err); 875 } 876 sbdp_release_sr_handle(srh); 877 878 return (0); 879 } 880 881 #ifdef DEBUG 882 int 883 sbdp_passthru_test_quiesce(sbdp_handle_t *hp, void *arg) 884 { 885 _NOTE(ARGUNUSED(arg)) 886 887 return (sbdp_test_suspend(hp)); 888 } 889 #endif