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 2009 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 sbd_error_t *sep; 238 } sbdp_ref_t; 239 240 static int 241 sbdp_check_dip(dev_info_t *dip, void *arg, uint_t ref) 242 { 243 char *dname; 244 sbdp_ref_t *sbrp = (sbdp_ref_t *)arg; 245 246 if (dip == NULL) 247 return (DDI_WALK_CONTINUE); 248 249 ASSERT(sbrp->sep != NULL); 250 ASSERT(sbrp->refcount != NULL); 251 252 if (!sbdp_is_real_device(dip)) 253 return (DDI_WALK_CONTINUE); 254 255 dname = ddi_binding_name(dip); 256 257 if ((strcmp(dname, "pciclass,060940") == 0) || (strcmp(dname, 258 "pciclass,060980") == 0)) { 259 (void) ddi_pathname(dip, sbdp_get_err_buf(sbrp->sep)); 260 sbdp_set_err(sbrp->sep, ESBD_BUSY, NULL); 261 (*sbrp->refcount)++; 262 return (DDI_WALK_TERMINATE); 263 } 264 265 #ifdef DEBUG 266 if (sbdp_bypass_device(dname)) 267 return (DDI_WALK_CONTINUE); 268 #endif 269 270 if (ref) { 271 (*sbrp->refcount)++; 272 SBDP_DBG_QR("\n%s (major# %d) is referenced\n", 273 dname, ddi_name_to_major(dname)); 274 (void) ddi_pathname(dip, sbdp_get_err_buf(sbrp->sep)); 275 sbdp_set_err(sbrp->sep, ESBD_BUSY, NULL); 276 return (DDI_WALK_TERMINATE); 277 } 278 return (DDI_WALK_CONTINUE); 279 } 280 281 void 282 sbdp_check_devices(dev_info_t *dip, int *refcount, sbd_error_t *sep) 283 { 284 sbdp_ref_t sbr; 285 286 sbr.refcount = refcount; 287 sbr.sep = sep; 288 289 ASSERT(e_ddi_branch_held(dip)); 290 291 (void) e_ddi_branch_referenced(dip, sbdp_check_dip, &sbr); 292 } 293 294 /* 295 * Starting from the root node suspend all devices in the device tree. 296 * Assumes that all devices have already been marked busy. 297 */ 298 static int 299 sbdp_suspend_devices_(dev_info_t *dip, sbdp_sr_handle_t *srh) 300 { 301 major_t major; 302 char *dname; 303 304 for (; dip != NULL; dip = ddi_get_next_sibling(dip)) { 305 char d_name[40], d_alias[40], *d_info; 306 307 if (sbdp_suspend_devices_(ddi_get_child(dip), srh)) { 308 return (ENXIO); 309 } 310 311 if (!sbdp_is_real_device(dip)) 312 continue; 313 314 major = (major_t)-1; 315 if ((dname = DEVI(dip)->devi_binding_name) != NULL) 316 major = ddi_name_to_major(dname); 317 318 #ifdef DEBUG 319 if (sbdp_bypass_device(dname)) { 320 SBDP_DBG_QR("bypassed suspend of %s (major# %d)\n", 321 dname, major); 322 continue; 323 } 324 #endif 325 326 if ((d_info = ddi_get_name_addr(dip)) == NULL) 327 d_info = "<null>"; 328 329 d_name[0] = 0; 330 if (sbdp_resolve_devname(dip, d_name, d_alias) == 0) { 331 if (d_alias[0] != 0) { 332 SBDP_DBG_QR("\tsuspending %s@%s (aka %s)\n", 333 d_name, d_info, d_alias); 334 } else { 335 SBDP_DBG_QR("\tsuspending %s@%s\n", 336 d_name, d_info); 337 } 338 } else { 339 SBDP_DBG_QR("\tsuspending %s@%s\n", dname, d_info); 340 } 341 342 if (devi_detach(dip, DDI_SUSPEND) != DDI_SUCCESS) { 343 (void) sprintf(sbdp_get_err_buf(&srh->sep), 344 "%d", major); 345 346 sbdp_set_err(&srh->sep, ESGT_SUSPEND, NULL); 347 ndi_hold_devi(dip); 348 SR_FAILED_DIP(srh) = dip; 349 return (DDI_FAILURE); 350 } 351 } 352 353 return (DDI_SUCCESS); 354 } 355 356 /*ARGSUSED*/ 357 static int 358 sbdp_suspend_devices_enter(dev_info_t *dip, void *arg) 359 { 360 struct dev_info *devi = DEVI(dip); 361 ndi_devi_enter(dip, &devi->devi_circular); 362 return (DDI_WALK_CONTINUE); 363 } 364 365 /*ARGSUSED*/ 366 static int 367 sbdp_suspend_devices_exit(dev_info_t *dip, void *arg) 368 { 369 struct dev_info *devi = DEVI(dip); 370 ndi_devi_exit(dip, devi->devi_circular); 371 return (DDI_WALK_CONTINUE); 372 } 373 374 /* 375 * Before suspending devices first mark all device nodes busy. This 376 * avoids a deadlock situation when another thread holds a device busy 377 * and accesses an already suspended device. 378 */ 379 static int 380 sbdp_suspend_devices(dev_info_t *dip, sbdp_sr_handle_t *srh) 381 { 382 int rv; 383 384 /* assumes dip is ddi_root_node so no ndi_devi_enter required */ 385 ASSERT(dip == ddi_root_node()); 386 ddi_walk_devs(dip, sbdp_suspend_devices_enter, NULL); 387 rv = sbdp_suspend_devices_(dip, srh); 388 ddi_walk_devs(dip, sbdp_suspend_devices_exit, NULL); 389 return (rv); 390 } 391 392 static void 393 sbdp_resume_devices(dev_info_t *start, sbdp_sr_handle_t *srh) 394 { 395 int circ; 396 dev_info_t *dip, *next, *last = NULL; 397 char *bn; 398 sbd_error_t *sep; 399 400 sep = &srh->sep; 401 402 /* attach in reverse device tree order */ 403 while (last != start) { 404 dip = start; 405 next = ddi_get_next_sibling(dip); 406 while (next != last && dip != SR_FAILED_DIP(srh)) { 407 dip = next; 408 next = ddi_get_next_sibling(dip); 409 } 410 if (dip == SR_FAILED_DIP(srh)) { 411 /* Release hold acquired in sbdp_suspend_devices() */ 412 ndi_rele_devi(dip); 413 SR_FAILED_DIP(srh) = NULL; 414 } else if (sbdp_is_real_device(dip) && 415 SR_FAILED_DIP(srh) == NULL) { 416 417 if (DEVI(dip)->devi_binding_name != NULL) { 418 bn = ddi_binding_name(dip); 419 } 420 #ifdef DEBUG 421 if (!sbdp_bypass_device(bn)) { 422 #else 423 { 424 #endif 425 char d_name[40], d_alias[40], *d_info; 426 427 d_name[0] = 0; 428 d_info = ddi_get_name_addr(dip); 429 if (d_info == NULL) 430 d_info = "<null>"; 431 432 if (!sbdp_resolve_devname(dip, d_name, 433 d_alias)) { 434 if (d_alias[0] != 0) { 435 SBDP_DBG_QR("\tresuming " 436 "%s@%s (aka %s)\n", 437 d_name, d_info, 438 d_alias); 439 } else { 440 SBDP_DBG_QR("\tresuming " 441 "%s@%s\n", 442 d_name, d_info); 443 } 444 } else { 445 SBDP_DBG_QR("\tresuming %s@%s\n", 446 bn, d_info); 447 } 448 449 if (devi_attach(dip, DDI_RESUME) != 450 DDI_SUCCESS) { 451 /* 452 * Print a console warning, 453 * set an errno of ESGT_RESUME, 454 * and save the driver major 455 * number in the e_str. 456 */ 457 458 (void) sprintf(sbdp_get_err_buf(sep), 459 "%s@%s", 460 d_name[0] ? d_name : bn, d_info); 461 SBDP_DBG_QR("\tFAILED to resume " 462 "%s\n", sbdp_get_err_buf(sep)); 463 sbdp_set_err(sep, 464 ESGT_RESUME, NULL); 465 } 466 } 467 } 468 ndi_devi_enter(dip, &circ); 469 sbdp_resume_devices(ddi_get_child(dip), srh); 470 ndi_devi_exit(dip, circ); 471 last = dip; 472 } 473 } 474 475 /* 476 * True if thread is virtually stopped. Similar to CPR_VSTOPPED 477 * but from DR point of view. These user threads are waiting in 478 * the kernel. Once they return from kernel, they will process 479 * the stop signal and stop. 480 */ 481 #define SBDP_VSTOPPED(t) \ 482 ((t)->t_state == TS_SLEEP && \ 483 (t)->t_wchan != NULL && \ 484 (t)->t_astflag && \ 485 ((t)->t_proc_flag & TP_CHKPT)) 486 487 488 static int 489 sbdp_stop_user_threads(sbdp_sr_handle_t *srh) 490 { 491 int count; 492 char cache_psargs[PSARGSZ]; 493 kthread_id_t cache_tp; 494 uint_t cache_t_state; 495 int bailout; 496 sbd_error_t *sep; 497 kthread_id_t tp; 498 499 extern void add_one_utstop(); 500 extern void utstop_timedwait(clock_t); 501 extern void utstop_init(void); 502 503 #define SBDP_UTSTOP_RETRY 4 504 #define SBDP_UTSTOP_WAIT hz 505 506 if (sbdp_skip_user_threads) 507 return (DDI_SUCCESS); 508 509 sep = &srh->sep; 510 ASSERT(sep); 511 512 utstop_init(); 513 514 /* we need to try a few times to get past fork, etc. */ 515 for (count = 0; count < SBDP_UTSTOP_RETRY; count++) { 516 /* walk the entire threadlist */ 517 mutex_enter(&pidlock); 518 for (tp = curthread->t_next; tp != curthread; tp = tp->t_next) { 519 proc_t *p = ttoproc(tp); 520 521 /* handle kernel threads separately */ 522 if (p->p_as == &kas || p->p_stat == SZOMB) 523 continue; 524 525 mutex_enter(&p->p_lock); 526 thread_lock(tp); 527 528 if (tp->t_state == TS_STOPPED) { 529 /* add another reason to stop this thread */ 530 tp->t_schedflag &= ~TS_RESUME; 531 } else { 532 tp->t_proc_flag |= TP_CHKPT; 533 534 thread_unlock(tp); 535 mutex_exit(&p->p_lock); 536 add_one_utstop(); 537 mutex_enter(&p->p_lock); 538 thread_lock(tp); 539 540 aston(tp); 541 542 if (ISWAKEABLE(tp) || ISWAITING(tp)) { 543 setrun_locked(tp); 544 } 545 } 546 547 /* grab thread if needed */ 548 if (tp->t_state == TS_ONPROC && tp->t_cpu != CPU) 549 poke_cpu(tp->t_cpu->cpu_id); 550 551 552 thread_unlock(tp); 553 mutex_exit(&p->p_lock); 554 } 555 mutex_exit(&pidlock); 556 557 558 /* let everything catch up */ 559 utstop_timedwait(count * count * SBDP_UTSTOP_WAIT); 560 561 562 /* now, walk the threadlist again to see if we are done */ 563 mutex_enter(&pidlock); 564 for (tp = curthread->t_next, bailout = 0; 565 tp != curthread; tp = tp->t_next) { 566 proc_t *p = ttoproc(tp); 567 568 /* handle kernel threads separately */ 569 if (p->p_as == &kas || p->p_stat == SZOMB) 570 continue; 571 572 /* 573 * If this thread didn't stop, and we don't allow 574 * unstopped blocked threads, bail. 575 */ 576 thread_lock(tp); 577 if (!CPR_ISTOPPED(tp) && 578 !(sbdp_allow_blocked_threads && 579 SBDP_VSTOPPED(tp))) { 580 581 /* nope, cache the details for later */ 582 bcopy(p->p_user.u_psargs, cache_psargs, 583 sizeof (cache_psargs)); 584 cache_tp = tp; 585 cache_t_state = tp->t_state; 586 bailout = 1; 587 } 588 thread_unlock(tp); 589 } 590 mutex_exit(&pidlock); 591 592 /* were all the threads stopped? */ 593 if (!bailout) 594 break; 595 } 596 597 /* were we unable to stop all threads after a few tries? */ 598 if (bailout) { 599 cmn_err(CE_NOTE, "process: %s id: %p state: %x\n", 600 cache_psargs, (void *)cache_tp, cache_t_state); 601 602 (void) sprintf(sbdp_get_err_buf(sep), "%s", cache_psargs); 603 sbdp_set_err(sep, ESGT_UTHREAD, NULL); 604 return (ESRCH); 605 } 606 607 return (DDI_SUCCESS); 608 } 609 610 static void 611 sbdp_start_user_threads(void) 612 { 613 kthread_id_t tp; 614 615 mutex_enter(&pidlock); 616 617 /* walk all threads and release them */ 618 for (tp = curthread->t_next; tp != curthread; tp = tp->t_next) { 619 proc_t *p = ttoproc(tp); 620 621 /* skip kernel threads */ 622 if (ttoproc(tp)->p_as == &kas) 623 continue; 624 625 mutex_enter(&p->p_lock); 626 tp->t_proc_flag &= ~TP_CHKPT; 627 mutex_exit(&p->p_lock); 628 629 thread_lock(tp); 630 if (CPR_ISTOPPED(tp)) { 631 /* back on the runq */ 632 tp->t_schedflag |= TS_RESUME; 633 setrun_locked(tp); 634 } 635 thread_unlock(tp); 636 } 637 638 mutex_exit(&pidlock); 639 } 640 641 static void 642 sbdp_signal_user(int sig) 643 { 644 struct proc *p; 645 646 mutex_enter(&pidlock); 647 648 for (p = practive; p != NULL; p = p->p_next) { 649 /* only user threads */ 650 if (p->p_exec == NULL || p->p_stat == SZOMB || 651 p == proc_init || p == ttoproc(curthread)) 652 continue; 653 654 mutex_enter(&p->p_lock); 655 sigtoproc(p, NULL, sig); 656 mutex_exit(&p->p_lock); 657 } 658 659 mutex_exit(&pidlock); 660 661 /* add a bit of delay */ 662 delay(hz); 663 } 664 665 static uint_t saved_watchdog_seconds; 666 667 void 668 sbdp_resume(sbdp_sr_handle_t *srh) 669 { 670 /* 671 * update the signature block 672 */ 673 CPU_SIGNATURE(OS_SIG, SIGST_RESUME_INPROGRESS, SIGSUBST_NULL, 674 CPU->cpu_id); 675 676 switch (SR_STATE(srh)) { 677 case SBDP_SRSTATE_FULL: 678 679 ASSERT(MUTEX_HELD(&cpu_lock)); 680 681 /* 682 * Prevent false alarm in tod_validate() due to tod 683 * value change between suspend and resume 684 */ 685 mutex_enter(&tod_lock); 686 tod_fault_reset(); 687 mutex_exit(&tod_lock); 688 689 sbdp_enable_intr(); /* enable intr & clock */ 690 691 /* 692 * release all the other cpus 693 * using start_cpus() vice sbdp_release_cpus() 694 */ 695 start_cpus(); 696 mutex_exit(&cpu_lock); 697 698 /* 699 * If we suspended hw watchdog at suspend, 700 * re-enable it now. 701 */ 702 if (SR_CHECK_FLAG(srh, SR_FLAG_WATCHDOG)) { 703 mutex_enter(&tod_lock); 704 tod_ops.tod_set_watchdog_timer( 705 saved_watchdog_seconds); 706 mutex_exit(&tod_lock); 707 } 708 709 /* FALLTHROUGH */ 710 711 case SBDP_SRSTATE_DRIVER: 712 /* 713 * resume devices: root node doesn't have to 714 * be held in any way. 715 */ 716 sbdp_resume_devices(ddi_root_node(), srh); 717 718 /* 719 * resume the lock manager 720 */ 721 lm_cprresume(); 722 723 /* FALLTHROUGH */ 724 725 case SBDP_SRSTATE_USER: 726 /* 727 * finally, resume user threads 728 */ 729 if (!sbdp_skip_user_threads) { 730 SBDP_DBG_QR("DR: resuming user threads...\n"); 731 sbdp_start_user_threads(); 732 } 733 /* FALLTHROUGH */ 734 735 case SBDP_SRSTATE_BEGIN: 736 default: 737 /* 738 * let those who care know that we've just resumed 739 */ 740 SBDP_DBG_QR("sending SIGTHAW...\n"); 741 sbdp_signal_user(SIGTHAW); 742 break; 743 } 744 745 /* 746 * update the signature block 747 */ 748 CPU_SIGNATURE(OS_SIG, SIGST_RUN, SIGSUBST_NULL, CPU->cpu_id); 749 750 SBDP_DBG_QR("DR: resume COMPLETED\n"); 751 } 752 753 int 754 sbdp_suspend(sbdp_sr_handle_t *srh) 755 { 756 int force; 757 int rc = DDI_SUCCESS; 758 759 force = (srh && (srh->sr_flags & SBDP_IOCTL_FLAG_FORCE)); 760 761 /* 762 * if no force flag, check for unsafe drivers 763 */ 764 if (force) { 765 SBDP_DBG_QR("\nsbdp_suspend invoked with force flag"); 766 } 767 768 /* 769 * update the signature block 770 */ 771 CPU_SIGNATURE(OS_SIG, SIGST_QUIESCE_INPROGRESS, SIGSUBST_NULL, 772 CPU->cpu_id); 773 774 /* 775 * first, stop all user threads 776 */ 777 SBDP_DBG_QR("SBDP: suspending user threads...\n"); 778 SR_SET_STATE(srh, SBDP_SRSTATE_USER); 779 if (((rc = sbdp_stop_user_threads(srh)) != DDI_SUCCESS) && 780 sbdp_check_user_stop_result) { 781 sbdp_resume(srh); 782 return (rc); 783 } 784 785 #ifndef SKIP_SYNC 786 /* 787 * This sync swap out all user pages 788 */ 789 vfs_sync(SYNC_ALL); 790 #endif 791 792 /* 793 * special treatment for lock manager 794 */ 795 lm_cprsuspend(); 796 797 #ifndef SKIP_SYNC 798 /* 799 * sync the file system in case we never make it back 800 */ 801 sync(); 802 803 #endif 804 /* 805 * now suspend drivers 806 */ 807 SBDP_DBG_QR("SBDP: suspending drivers...\n"); 808 SR_SET_STATE(srh, SBDP_SRSTATE_DRIVER); 809 810 /* 811 * Root node doesn't have to be held in any way. 812 */ 813 if ((rc = sbdp_suspend_devices(ddi_root_node(), srh)) != DDI_SUCCESS) { 814 sbdp_resume(srh); 815 return (rc); 816 } 817 818 /* 819 * finally, grab all cpus 820 */ 821 SR_SET_STATE(srh, SBDP_SRSTATE_FULL); 822 823 /* 824 * if watchdog was activated, disable it 825 */ 826 if (watchdog_activated) { 827 mutex_enter(&tod_lock); 828 saved_watchdog_seconds = tod_ops.tod_clear_watchdog_timer(); 829 mutex_exit(&tod_lock); 830 SR_SET_FLAG(srh, SR_FLAG_WATCHDOG); 831 } else { 832 SR_CLEAR_FLAG(srh, SR_FLAG_WATCHDOG); 833 } 834 835 mutex_enter(&cpu_lock); 836 pause_cpus(NULL); 837 sbdp_stop_intr(); 838 839 /* 840 * update the signature block 841 */ 842 CPU_SIGNATURE(OS_SIG, SIGST_QUIESCED, SIGSUBST_NULL, CPU->cpu_id); 843 844 return (rc); 845 } 846 847 /*ARGSUSED*/ 848 int 849 sbdp_test_suspend(sbdp_handle_t *hp) 850 { 851 sbdp_sr_handle_t *srh; 852 int err; 853 854 SBDP_DBG_QR("%s...\n", "sbdp_test_suspend"); 855 856 srh = sbdp_get_sr_handle(); 857 858 srh->sr_flags = hp->h_flags; 859 860 if ((err = sbdp_suspend(srh)) == DDI_SUCCESS) { 861 sbdp_resume(srh); 862 } else { 863 SBDP_DBG_MISC("sbdp_suspend() failed, err = 0x%x\n", err); 864 } 865 sbdp_release_sr_handle(srh); 866 867 return (0); 868 } 869 870 #ifdef DEBUG 871 int 872 sbdp_passthru_test_quiesce(sbdp_handle_t *hp, void *arg) 873 { 874 _NOTE(ARGUNUSED(arg)) 875 876 return (sbdp_test_suspend(hp)); 877 } 878 #endif 879