1a3114836SGerry Liu /* 2a3114836SGerry Liu * CDDL HEADER START 3a3114836SGerry Liu * 4a3114836SGerry Liu * The contents of this file are subject to the terms of the 5a3114836SGerry Liu * Common Development and Distribution License (the "License"). 6a3114836SGerry Liu * You may not use this file except in compliance with the License. 7a3114836SGerry Liu * 8a3114836SGerry Liu * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9a3114836SGerry Liu * or http://www.opensolaris.org/os/licensing. 10a3114836SGerry Liu * See the License for the specific language governing permissions 11a3114836SGerry Liu * and limitations under the License. 12a3114836SGerry Liu * 13a3114836SGerry Liu * When distributing Covered Code, include this CDDL HEADER in each 14a3114836SGerry Liu * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15a3114836SGerry Liu * If applicable, add the following below this CDDL HEADER, with the 16a3114836SGerry Liu * fields enclosed by brackets "[]" replaced with your own identifying 17a3114836SGerry Liu * information: Portions Copyright [yyyy] [name of copyright owner] 18a3114836SGerry Liu * 19a3114836SGerry Liu * CDDL HEADER END 20a3114836SGerry Liu */ 21a3114836SGerry Liu 22a3114836SGerry Liu /* 23bec42f4bSMary Beale * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 24a3114836SGerry Liu */ 25a3114836SGerry Liu 26a3114836SGerry Liu /* 27a3114836SGerry Liu * A CPR derivative specifically for starfire/starcat 28a3114836SGerry Liu * X86 doesn't make use of the quiesce interfaces, it's kept for simplicity. 29a3114836SGerry Liu */ 30a3114836SGerry Liu 31a3114836SGerry Liu #include <sys/types.h> 32a3114836SGerry Liu #include <sys/systm.h> 33a3114836SGerry Liu #include <sys/machparam.h> 34a3114836SGerry Liu #include <sys/machsystm.h> 35a3114836SGerry Liu #include <sys/ddi.h> 36a3114836SGerry Liu #define SUNDDI_IMPL 37a3114836SGerry Liu #include <sys/sunddi.h> 38a3114836SGerry Liu #include <sys/sunndi.h> 39a3114836SGerry Liu #include <sys/devctl.h> 40a3114836SGerry Liu #include <sys/time.h> 41a3114836SGerry Liu #include <sys/kmem.h> 42a3114836SGerry Liu #include <nfs/lm.h> 43a3114836SGerry Liu #include <sys/ddi_impldefs.h> 44a3114836SGerry Liu #include <sys/ndi_impldefs.h> 45a3114836SGerry Liu #include <sys/obpdefs.h> 46a3114836SGerry Liu #include <sys/cmn_err.h> 47a3114836SGerry Liu #include <sys/debug.h> 48a3114836SGerry Liu #include <sys/errno.h> 49a3114836SGerry Liu #include <sys/callb.h> 50a3114836SGerry Liu #include <sys/clock.h> 51a3114836SGerry Liu #include <sys/x_call.h> 52a3114836SGerry Liu #include <sys/cpuvar.h> 53a3114836SGerry Liu #include <sys/epm.h> 54a3114836SGerry Liu #include <sys/vfs.h> 55a3114836SGerry Liu #include <sys/promif.h> 56a3114836SGerry Liu #include <sys/conf.h> 57a3114836SGerry Liu #include <sys/cyclic.h> 58a3114836SGerry Liu 59a3114836SGerry Liu #include <sys/dr.h> 60a3114836SGerry Liu #include <sys/dr_util.h> 61a3114836SGerry Liu 62a3114836SGerry Liu extern void e_ddi_enter_driver_list(struct devnames *dnp, int *listcnt); 63a3114836SGerry Liu extern void e_ddi_exit_driver_list(struct devnames *dnp, int listcnt); 64a3114836SGerry Liu extern int is_pseudo_device(dev_info_t *dip); 65a3114836SGerry Liu 66a3114836SGerry Liu extern kmutex_t cpu_lock; 67a3114836SGerry Liu extern dr_unsafe_devs_t dr_unsafe_devs; 68a3114836SGerry Liu 69a3114836SGerry Liu static int dr_is_real_device(dev_info_t *dip); 70a3114836SGerry Liu static int dr_is_unsafe_major(major_t major); 71a3114836SGerry Liu static int dr_bypass_device(char *dname); 72a3114836SGerry Liu static int dr_check_dip(dev_info_t *dip, void *arg, uint_t ref); 73a3114836SGerry Liu static int dr_resolve_devname(dev_info_t *dip, char *buffer, 74a3114836SGerry Liu char *alias); 75a3114836SGerry Liu static sbd_error_t *drerr_int(int e_code, uint64_t *arr, int idx, 76a3114836SGerry Liu int majors); 77a3114836SGerry Liu static int dr_add_int(uint64_t *arr, int idx, int len, 78a3114836SGerry Liu uint64_t val); 79a3114836SGerry Liu 80a3114836SGerry Liu int dr_pt_test_suspend(dr_handle_t *hp); 81a3114836SGerry Liu 82a3114836SGerry Liu /* 83a3114836SGerry Liu * dr_quiesce.c interface 84a3114836SGerry Liu * NOTE: states used internally by dr_suspend and dr_resume 85a3114836SGerry Liu */ 86a3114836SGerry Liu typedef enum dr_suspend_state { 87a3114836SGerry Liu DR_SRSTATE_BEGIN = 0, 88a3114836SGerry Liu DR_SRSTATE_USER, 89a3114836SGerry Liu DR_SRSTATE_DRIVER, 90a3114836SGerry Liu DR_SRSTATE_FULL 91a3114836SGerry Liu } suspend_state_t; 92a3114836SGerry Liu 93a3114836SGerry Liu struct dr_sr_handle { 94a3114836SGerry Liu dr_handle_t *sr_dr_handlep; 95a3114836SGerry Liu dev_info_t *sr_failed_dip; 96a3114836SGerry Liu suspend_state_t sr_suspend_state; 97a3114836SGerry Liu uint_t sr_flags; 98a3114836SGerry Liu uint64_t sr_err_ints[DR_MAX_ERR_INT]; 99a3114836SGerry Liu int sr_err_idx; 100a3114836SGerry Liu }; 101a3114836SGerry Liu 102a3114836SGerry Liu #define SR_FLAG_WATCHDOG 0x1 103a3114836SGerry Liu 104a3114836SGerry Liu /* 105a3114836SGerry Liu * XXX 106a3114836SGerry Liu * This hack will go away before RTI. Just for testing. 107a3114836SGerry Liu * List of drivers to bypass when performing a suspend. 108a3114836SGerry Liu */ 109a3114836SGerry Liu static char *dr_bypass_list[] = { 110a3114836SGerry Liu "" 111a3114836SGerry Liu }; 112a3114836SGerry Liu 113a3114836SGerry Liu 114a3114836SGerry Liu #define SKIP_SYNC /* bypass sync ops in dr_suspend */ 115a3114836SGerry Liu 116a3114836SGerry Liu /* 117a3114836SGerry Liu * dr_skip_user_threads is used to control if user threads should 118a3114836SGerry Liu * be suspended. If dr_skip_user_threads is true, the rest of the 119a3114836SGerry Liu * flags are not used; if it is false, dr_check_user_stop_result 120a3114836SGerry Liu * will be used to control whether or not we need to check suspend 121a3114836SGerry Liu * result, and dr_allow_blocked_threads will be used to control 122a3114836SGerry Liu * whether or not we allow suspend to continue if there are blocked 123a3114836SGerry Liu * threads. We allow all combinations of dr_check_user_stop_result 124a3114836SGerry Liu * and dr_allow_block_threads, even though it might not make much 125a3114836SGerry Liu * sense to not allow block threads when we don't even check stop 126a3114836SGerry Liu * result. 127a3114836SGerry Liu */ 128a3114836SGerry Liu static int dr_skip_user_threads = 0; /* default to FALSE */ 129a3114836SGerry Liu static int dr_check_user_stop_result = 1; /* default to TRUE */ 130a3114836SGerry Liu static int dr_allow_blocked_threads = 1; /* default to TRUE */ 131a3114836SGerry Liu 132a3114836SGerry Liu #define DR_CPU_LOOP_MSEC 1000 133a3114836SGerry Liu 134a3114836SGerry Liu static void 135a3114836SGerry Liu dr_stop_intr(void) 136a3114836SGerry Liu { 137a3114836SGerry Liu ASSERT(MUTEX_HELD(&cpu_lock)); 138a3114836SGerry Liu 139a3114836SGerry Liu kpreempt_disable(); 140a3114836SGerry Liu cyclic_suspend(); 141a3114836SGerry Liu } 142a3114836SGerry Liu 143a3114836SGerry Liu static void 144a3114836SGerry Liu dr_enable_intr(void) 145a3114836SGerry Liu { 146a3114836SGerry Liu ASSERT(MUTEX_HELD(&cpu_lock)); 147a3114836SGerry Liu 148a3114836SGerry Liu cyclic_resume(); 149a3114836SGerry Liu kpreempt_enable(); 150a3114836SGerry Liu } 151a3114836SGerry Liu 152a3114836SGerry Liu dr_sr_handle_t * 153a3114836SGerry Liu dr_get_sr_handle(dr_handle_t *hp) 154a3114836SGerry Liu { 155a3114836SGerry Liu dr_sr_handle_t *srh; 156a3114836SGerry Liu 157a3114836SGerry Liu srh = GETSTRUCT(dr_sr_handle_t, 1); 158a3114836SGerry Liu srh->sr_dr_handlep = hp; 159a3114836SGerry Liu 160a3114836SGerry Liu return (srh); 161a3114836SGerry Liu } 162a3114836SGerry Liu 163a3114836SGerry Liu void 164a3114836SGerry Liu dr_release_sr_handle(dr_sr_handle_t *srh) 165a3114836SGerry Liu { 166a3114836SGerry Liu ASSERT(srh->sr_failed_dip == NULL); 167a3114836SGerry Liu FREESTRUCT(srh, dr_sr_handle_t, 1); 168a3114836SGerry Liu } 169a3114836SGerry Liu 170a3114836SGerry Liu static int 171a3114836SGerry Liu dr_is_real_device(dev_info_t *dip) 172a3114836SGerry Liu { 173a3114836SGerry Liu struct regspec *regbuf = NULL; 174a3114836SGerry Liu int length = 0; 175a3114836SGerry Liu int rc; 176a3114836SGerry Liu 177a3114836SGerry Liu if (ddi_get_driver(dip) == NULL) 178a3114836SGerry Liu return (0); 179a3114836SGerry Liu 180a3114836SGerry Liu if (DEVI(dip)->devi_pm_flags & (PMC_NEEDS_SR|PMC_PARENTAL_SR)) 181a3114836SGerry Liu return (1); 182a3114836SGerry Liu if (DEVI(dip)->devi_pm_flags & PMC_NO_SR) 183a3114836SGerry Liu return (0); 184a3114836SGerry Liu 185a3114836SGerry Liu /* 186a3114836SGerry Liu * now the general case 187a3114836SGerry Liu */ 188a3114836SGerry Liu rc = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg", 189a3114836SGerry Liu (caddr_t)®buf, &length); 190a3114836SGerry Liu ASSERT(rc != DDI_PROP_NO_MEMORY); 191a3114836SGerry Liu if (rc != DDI_PROP_SUCCESS) { 192a3114836SGerry Liu return (0); 193a3114836SGerry Liu } else { 194a3114836SGerry Liu if ((length > 0) && (regbuf != NULL)) 195a3114836SGerry Liu kmem_free(regbuf, length); 196a3114836SGerry Liu return (1); 197a3114836SGerry Liu } 198a3114836SGerry Liu } 199a3114836SGerry Liu 200a3114836SGerry Liu static int 201a3114836SGerry Liu dr_is_unsafe_major(major_t major) 202a3114836SGerry Liu { 203a3114836SGerry Liu char *dname, **cpp; 204a3114836SGerry Liu int i, ndevs; 205a3114836SGerry Liu 206a3114836SGerry Liu if ((dname = ddi_major_to_name(major)) == NULL) { 207a3114836SGerry Liu PR_QR("dr_is_unsafe_major: invalid major # %d\n", major); 208a3114836SGerry Liu return (0); 209a3114836SGerry Liu } 210a3114836SGerry Liu 211a3114836SGerry Liu ndevs = dr_unsafe_devs.ndevs; 212a3114836SGerry Liu for (i = 0, cpp = dr_unsafe_devs.devnames; i < ndevs; i++) { 213a3114836SGerry Liu if (strcmp(dname, *cpp++) == 0) 214a3114836SGerry Liu return (1); 215a3114836SGerry Liu } 216a3114836SGerry Liu return (0); 217a3114836SGerry Liu } 218a3114836SGerry Liu 219a3114836SGerry Liu static int 220a3114836SGerry Liu dr_bypass_device(char *dname) 221a3114836SGerry Liu { 222a3114836SGerry Liu int i; 223a3114836SGerry Liu char **lname; 224bec42f4bSMary Beale 225bec42f4bSMary Beale if (dname == NULL) 226bec42f4bSMary Beale return (0); 227bec42f4bSMary Beale 228a3114836SGerry Liu /* check the bypass list */ 229a3114836SGerry Liu for (i = 0, lname = &dr_bypass_list[i]; **lname != '\0'; lname++) { 230a3114836SGerry Liu if (strcmp(dname, dr_bypass_list[i++]) == 0) 231a3114836SGerry Liu return (1); 232a3114836SGerry Liu } 233a3114836SGerry Liu return (0); 234a3114836SGerry Liu } 235a3114836SGerry Liu 236a3114836SGerry Liu static int 237a3114836SGerry Liu dr_resolve_devname(dev_info_t *dip, char *buffer, char *alias) 238a3114836SGerry Liu { 239a3114836SGerry Liu major_t devmajor; 240a3114836SGerry Liu char *aka, *name; 241a3114836SGerry Liu 242a3114836SGerry Liu *buffer = *alias = 0; 243a3114836SGerry Liu 244a3114836SGerry Liu if (dip == NULL) 245a3114836SGerry Liu return (-1); 246a3114836SGerry Liu 247a3114836SGerry Liu if ((name = ddi_get_name(dip)) == NULL) 248a3114836SGerry Liu name = "<null name>"; 249a3114836SGerry Liu 250a3114836SGerry Liu aka = name; 251a3114836SGerry Liu 252a3114836SGerry Liu if ((devmajor = ddi_name_to_major(aka)) != DDI_MAJOR_T_NONE) 253a3114836SGerry Liu aka = ddi_major_to_name(devmajor); 254a3114836SGerry Liu 255a3114836SGerry Liu (void) strcpy(buffer, name); 256a3114836SGerry Liu 257a3114836SGerry Liu if (strcmp(name, aka)) 258a3114836SGerry Liu (void) strcpy(alias, aka); 259a3114836SGerry Liu else 260a3114836SGerry Liu *alias = 0; 261a3114836SGerry Liu 262a3114836SGerry Liu return (0); 263a3114836SGerry Liu } 264a3114836SGerry Liu 265a3114836SGerry Liu struct dr_ref { 266a3114836SGerry Liu int *refcount; 267a3114836SGerry Liu int *refcount_non_gldv3; 268a3114836SGerry Liu uint64_t *arr; 269a3114836SGerry Liu int *idx; 270a3114836SGerry Liu int len; 271a3114836SGerry Liu }; 272a3114836SGerry Liu 273a3114836SGerry Liu /* ARGSUSED */ 274a3114836SGerry Liu static int 275a3114836SGerry Liu dr_check_dip(dev_info_t *dip, void *arg, uint_t ref) 276a3114836SGerry Liu { 277a3114836SGerry Liu major_t major; 278a3114836SGerry Liu char *dname; 279a3114836SGerry Liu struct dr_ref *rp = (struct dr_ref *)arg; 280a3114836SGerry Liu 281a3114836SGerry Liu if (dip == NULL) 282a3114836SGerry Liu return (DDI_WALK_CONTINUE); 283a3114836SGerry Liu 284a3114836SGerry Liu if (!dr_is_real_device(dip)) 285a3114836SGerry Liu return (DDI_WALK_CONTINUE); 286a3114836SGerry Liu 287a3114836SGerry Liu dname = ddi_binding_name(dip); 288a3114836SGerry Liu 289a3114836SGerry Liu if (dr_bypass_device(dname)) 290a3114836SGerry Liu return (DDI_WALK_CONTINUE); 291a3114836SGerry Liu 292a3114836SGerry Liu if (dname && ((major = ddi_name_to_major(dname)) != (major_t)-1)) { 293a3114836SGerry Liu if (ref && rp->refcount) { 294a3114836SGerry Liu *rp->refcount += ref; 295a3114836SGerry Liu PR_QR("\n %s (major# %d) is referenced(%u)\n", dname, 296a3114836SGerry Liu major, ref); 297a3114836SGerry Liu } 298a3114836SGerry Liu if (ref && rp->refcount_non_gldv3) { 299a3114836SGerry Liu if (NETWORK_PHYSDRV(major) && !GLDV3_DRV(major)) 300a3114836SGerry Liu *rp->refcount_non_gldv3 += ref; 301a3114836SGerry Liu } 302a3114836SGerry Liu if (dr_is_unsafe_major(major) && i_ddi_devi_attached(dip)) { 303a3114836SGerry Liu PR_QR("\n %s (major# %d) not hotpluggable\n", dname, 304a3114836SGerry Liu major); 305a3114836SGerry Liu if (rp->arr != NULL && rp->idx != NULL) 306a3114836SGerry Liu *rp->idx = dr_add_int(rp->arr, *rp->idx, 307a3114836SGerry Liu rp->len, (uint64_t)major); 308a3114836SGerry Liu } 309a3114836SGerry Liu } 310a3114836SGerry Liu return (DDI_WALK_CONTINUE); 311a3114836SGerry Liu } 312a3114836SGerry Liu 313a3114836SGerry Liu static int 314a3114836SGerry Liu dr_check_unsafe_major(dev_info_t *dip, void *arg) 315a3114836SGerry Liu { 316a3114836SGerry Liu return (dr_check_dip(dip, arg, 0)); 317a3114836SGerry Liu } 318a3114836SGerry Liu 319a3114836SGerry Liu 320a3114836SGerry Liu /*ARGSUSED*/ 321a3114836SGerry Liu void 322a3114836SGerry Liu dr_check_devices(dev_info_t *dip, int *refcount, dr_handle_t *handle, 323a3114836SGerry Liu uint64_t *arr, int *idx, int len, int *refcount_non_gldv3) 324a3114836SGerry Liu { 325a3114836SGerry Liu struct dr_ref bref = {0}; 326a3114836SGerry Liu 327a3114836SGerry Liu if (dip == NULL) 328a3114836SGerry Liu return; 329a3114836SGerry Liu 330a3114836SGerry Liu bref.refcount = refcount; 331a3114836SGerry Liu bref.refcount_non_gldv3 = refcount_non_gldv3; 332a3114836SGerry Liu bref.arr = arr; 333a3114836SGerry Liu bref.idx = idx; 334a3114836SGerry Liu bref.len = len; 335a3114836SGerry Liu 336a3114836SGerry Liu ASSERT(e_ddi_branch_held(dip)); 337a3114836SGerry Liu (void) e_ddi_branch_referenced(dip, dr_check_dip, &bref); 338a3114836SGerry Liu } 339a3114836SGerry Liu 340a3114836SGerry Liu /* 341a3114836SGerry Liu * The "dip" argument's parent (if it exists) must be held busy. 342a3114836SGerry Liu */ 343a3114836SGerry Liu static int 344a3114836SGerry Liu dr_suspend_devices(dev_info_t *dip, dr_sr_handle_t *srh) 345a3114836SGerry Liu { 346a3114836SGerry Liu dr_handle_t *handle; 347a3114836SGerry Liu major_t major; 348a3114836SGerry Liu char *dname; 349a3114836SGerry Liu int circ; 350a3114836SGerry Liu 351a3114836SGerry Liu /* 352a3114836SGerry Liu * If dip is the root node, it has no siblings and it is 353a3114836SGerry Liu * always held. If dip is not the root node, dr_suspend_devices() 354a3114836SGerry Liu * will be invoked with the parent held busy. 355a3114836SGerry Liu */ 356a3114836SGerry Liu for (; dip != NULL; dip = ddi_get_next_sibling(dip)) { 357a3114836SGerry Liu char d_name[40], d_alias[40], *d_info; 358a3114836SGerry Liu 359a3114836SGerry Liu ndi_devi_enter(dip, &circ); 360a3114836SGerry Liu if (dr_suspend_devices(ddi_get_child(dip), srh)) { 361a3114836SGerry Liu ndi_devi_exit(dip, circ); 362a3114836SGerry Liu return (ENXIO); 363a3114836SGerry Liu } 364a3114836SGerry Liu ndi_devi_exit(dip, circ); 365a3114836SGerry Liu 366a3114836SGerry Liu if (!dr_is_real_device(dip)) 367a3114836SGerry Liu continue; 368a3114836SGerry Liu 369a3114836SGerry Liu major = (major_t)-1; 370a3114836SGerry Liu if ((dname = ddi_binding_name(dip)) != NULL) 371a3114836SGerry Liu major = ddi_name_to_major(dname); 372a3114836SGerry Liu 373a3114836SGerry Liu if (dr_bypass_device(dname)) { 374a3114836SGerry Liu PR_QR(" bypassed suspend of %s (major# %d)\n", dname, 375a3114836SGerry Liu major); 376a3114836SGerry Liu continue; 377a3114836SGerry Liu } 378a3114836SGerry Liu 379a3114836SGerry Liu if (drmach_verify_sr(dip, 1)) { 380a3114836SGerry Liu PR_QR(" bypassed suspend of %s (major# %d)\n", dname, 381a3114836SGerry Liu major); 382a3114836SGerry Liu continue; 383a3114836SGerry Liu } 384a3114836SGerry Liu 385a3114836SGerry Liu if ((d_info = ddi_get_name_addr(dip)) == NULL) 386a3114836SGerry Liu d_info = "<null>"; 387a3114836SGerry Liu 388a3114836SGerry Liu d_name[0] = 0; 389a3114836SGerry Liu if (dr_resolve_devname(dip, d_name, d_alias) == 0) { 390a3114836SGerry Liu if (d_alias[0] != 0) { 391a3114836SGerry Liu prom_printf("\tsuspending %s@%s (aka %s)\n", 392a3114836SGerry Liu d_name, d_info, d_alias); 393a3114836SGerry Liu } else { 394a3114836SGerry Liu prom_printf("\tsuspending %s@%s\n", d_name, 395a3114836SGerry Liu d_info); 396a3114836SGerry Liu } 397a3114836SGerry Liu } else { 398a3114836SGerry Liu prom_printf("\tsuspending %s@%s\n", dname, d_info); 399a3114836SGerry Liu } 400a3114836SGerry Liu 401a3114836SGerry Liu if (devi_detach(dip, DDI_SUSPEND) != DDI_SUCCESS) { 402a3114836SGerry Liu prom_printf("\tFAILED to suspend %s@%s\n", 403a3114836SGerry Liu d_name[0] ? d_name : dname, d_info); 404a3114836SGerry Liu 405a3114836SGerry Liu srh->sr_err_idx = dr_add_int(srh->sr_err_ints, 406a3114836SGerry Liu srh->sr_err_idx, DR_MAX_ERR_INT, (uint64_t)major); 407a3114836SGerry Liu 408a3114836SGerry Liu ndi_hold_devi(dip); 409a3114836SGerry Liu srh->sr_failed_dip = dip; 410a3114836SGerry Liu 411a3114836SGerry Liu handle = srh->sr_dr_handlep; 412a3114836SGerry Liu dr_op_err(CE_IGNORE, handle, ESBD_SUSPEND, "%s@%s", 413a3114836SGerry Liu d_name[0] ? d_name : dname, d_info); 414a3114836SGerry Liu 415a3114836SGerry Liu return (DDI_FAILURE); 416a3114836SGerry Liu } 417a3114836SGerry Liu } 418a3114836SGerry Liu 419a3114836SGerry Liu return (DDI_SUCCESS); 420a3114836SGerry Liu } 421a3114836SGerry Liu 422a3114836SGerry Liu static void 423a3114836SGerry Liu dr_resume_devices(dev_info_t *start, dr_sr_handle_t *srh) 424a3114836SGerry Liu { 425a3114836SGerry Liu dr_handle_t *handle; 426a3114836SGerry Liu dev_info_t *dip, *next, *last = NULL; 427a3114836SGerry Liu major_t major; 428a3114836SGerry Liu char *bn; 429a3114836SGerry Liu int circ; 430a3114836SGerry Liu 431a3114836SGerry Liu major = (major_t)-1; 432a3114836SGerry Liu 433a3114836SGerry Liu /* attach in reverse device tree order */ 434a3114836SGerry Liu while (last != start) { 435a3114836SGerry Liu dip = start; 436a3114836SGerry Liu next = ddi_get_next_sibling(dip); 437a3114836SGerry Liu while (next != last && dip != srh->sr_failed_dip) { 438a3114836SGerry Liu dip = next; 439a3114836SGerry Liu next = ddi_get_next_sibling(dip); 440a3114836SGerry Liu } 441a3114836SGerry Liu if (dip == srh->sr_failed_dip) { 442a3114836SGerry Liu /* release hold acquired in dr_suspend_devices() */ 443a3114836SGerry Liu srh->sr_failed_dip = NULL; 444a3114836SGerry Liu ndi_rele_devi(dip); 445a3114836SGerry Liu } else if (dr_is_real_device(dip) && 446a3114836SGerry Liu srh->sr_failed_dip == NULL) { 447a3114836SGerry Liu 448a3114836SGerry Liu if ((bn = ddi_binding_name(dip)) != NULL) { 449a3114836SGerry Liu major = ddi_name_to_major(bn); 450a3114836SGerry Liu } else { 451a3114836SGerry Liu bn = "<null>"; 452a3114836SGerry Liu } 453a3114836SGerry Liu if (!dr_bypass_device(bn) && 454a3114836SGerry Liu !drmach_verify_sr(dip, 0)) { 455a3114836SGerry Liu char d_name[40], d_alias[40], *d_info; 456a3114836SGerry Liu 457a3114836SGerry Liu d_name[0] = 0; 458a3114836SGerry Liu d_info = ddi_get_name_addr(dip); 459a3114836SGerry Liu if (d_info == NULL) 460a3114836SGerry Liu d_info = "<null>"; 461a3114836SGerry Liu 462a3114836SGerry Liu if (!dr_resolve_devname(dip, d_name, d_alias)) { 463a3114836SGerry Liu if (d_alias[0] != 0) { 464a3114836SGerry Liu prom_printf("\tresuming " 465a3114836SGerry Liu "%s@%s (aka %s)\n", d_name, 466a3114836SGerry Liu d_info, d_alias); 467a3114836SGerry Liu } else { 468a3114836SGerry Liu prom_printf("\tresuming " 469a3114836SGerry Liu "%s@%s\n", d_name, d_info); 470a3114836SGerry Liu } 471a3114836SGerry Liu } else { 472a3114836SGerry Liu prom_printf("\tresuming %s@%s\n", bn, 473a3114836SGerry Liu d_info); 474a3114836SGerry Liu } 475a3114836SGerry Liu 476a3114836SGerry Liu if (devi_attach(dip, DDI_RESUME) != 477a3114836SGerry Liu DDI_SUCCESS) { 478a3114836SGerry Liu /* 479a3114836SGerry Liu * Print a console warning, 480a3114836SGerry Liu * set an e_code of ESBD_RESUME, 481a3114836SGerry Liu * and save the driver major 482a3114836SGerry Liu * number in the e_rsc. 483a3114836SGerry Liu */ 484a3114836SGerry Liu prom_printf("\tFAILED to resume %s@%s", 485a3114836SGerry Liu d_name[0] ? d_name : bn, d_info); 486a3114836SGerry Liu 487a3114836SGerry Liu srh->sr_err_idx = 488a3114836SGerry Liu dr_add_int(srh->sr_err_ints, 489a3114836SGerry Liu srh->sr_err_idx, DR_MAX_ERR_INT, 490a3114836SGerry Liu (uint64_t)major); 491a3114836SGerry Liu 492a3114836SGerry Liu handle = srh->sr_dr_handlep; 493a3114836SGerry Liu 494a3114836SGerry Liu dr_op_err(CE_IGNORE, handle, 495a3114836SGerry Liu ESBD_RESUME, "%s@%s", 496a3114836SGerry Liu d_name[0] ? d_name : bn, d_info); 497a3114836SGerry Liu } 498a3114836SGerry Liu } 499a3114836SGerry Liu } 500a3114836SGerry Liu 501a3114836SGerry Liu /* Hold parent busy while walking its children */ 502a3114836SGerry Liu ndi_devi_enter(dip, &circ); 503a3114836SGerry Liu dr_resume_devices(ddi_get_child(dip), srh); 504a3114836SGerry Liu ndi_devi_exit(dip, circ); 505a3114836SGerry Liu last = dip; 506a3114836SGerry Liu } 507a3114836SGerry Liu } 508a3114836SGerry Liu 509a3114836SGerry Liu /* 510a3114836SGerry Liu * True if thread is virtually stopped. Similar to CPR_VSTOPPED 511a3114836SGerry Liu * but from DR point of view. These user threads are waiting in 512a3114836SGerry Liu * the kernel. Once they complete in the kernel, they will process 513a3114836SGerry Liu * the stop signal and stop. 514a3114836SGerry Liu */ 515a3114836SGerry Liu #define DR_VSTOPPED(t) \ 516a3114836SGerry Liu ((t)->t_state == TS_SLEEP && \ 517a3114836SGerry Liu (t)->t_wchan != NULL && \ 518a3114836SGerry Liu (t)->t_astflag && \ 519a3114836SGerry Liu ((t)->t_proc_flag & TP_CHKPT)) 520a3114836SGerry Liu 521a3114836SGerry Liu /* ARGSUSED */ 522a3114836SGerry Liu static int 523a3114836SGerry Liu dr_stop_user_threads(dr_sr_handle_t *srh) 524a3114836SGerry Liu { 525a3114836SGerry Liu int count; 526a3114836SGerry Liu int bailout; 527a3114836SGerry Liu dr_handle_t *handle = srh->sr_dr_handlep; 528a3114836SGerry Liu static fn_t f = "dr_stop_user_threads"; 529a3114836SGerry Liu kthread_id_t tp; 530a3114836SGerry Liu 531a3114836SGerry Liu extern void add_one_utstop(); 532a3114836SGerry Liu extern void utstop_timedwait(clock_t); 533a3114836SGerry Liu extern void utstop_init(void); 534a3114836SGerry Liu 535a3114836SGerry Liu #define DR_UTSTOP_RETRY 4 536a3114836SGerry Liu #define DR_UTSTOP_WAIT hz 537a3114836SGerry Liu 538a3114836SGerry Liu if (dr_skip_user_threads) 539a3114836SGerry Liu return (DDI_SUCCESS); 540a3114836SGerry Liu 541a3114836SGerry Liu utstop_init(); 542a3114836SGerry Liu 543a3114836SGerry Liu /* we need to try a few times to get past fork, etc. */ 544a3114836SGerry Liu srh->sr_err_idx = 0; 545a3114836SGerry Liu for (count = 0; count < DR_UTSTOP_RETRY; count++) { 546a3114836SGerry Liu /* walk the entire threadlist */ 547a3114836SGerry Liu mutex_enter(&pidlock); 548a3114836SGerry Liu for (tp = curthread->t_next; tp != curthread; tp = tp->t_next) { 549a3114836SGerry Liu proc_t *p = ttoproc(tp); 550a3114836SGerry Liu 551a3114836SGerry Liu /* handle kernel threads separately */ 552a3114836SGerry Liu if (p->p_as == &kas || p->p_stat == SZOMB) 553a3114836SGerry Liu continue; 554a3114836SGerry Liu 555a3114836SGerry Liu mutex_enter(&p->p_lock); 556a3114836SGerry Liu thread_lock(tp); 557a3114836SGerry Liu 558a3114836SGerry Liu if (tp->t_state == TS_STOPPED) { 559a3114836SGerry Liu /* add another reason to stop this thread */ 560a3114836SGerry Liu tp->t_schedflag &= ~TS_RESUME; 561a3114836SGerry Liu } else { 562a3114836SGerry Liu tp->t_proc_flag |= TP_CHKPT; 563a3114836SGerry Liu 564a3114836SGerry Liu thread_unlock(tp); 565a3114836SGerry Liu mutex_exit(&p->p_lock); 566a3114836SGerry Liu add_one_utstop(); 567a3114836SGerry Liu mutex_enter(&p->p_lock); 568a3114836SGerry Liu thread_lock(tp); 569a3114836SGerry Liu 570a3114836SGerry Liu aston(tp); 571a3114836SGerry Liu 572a3114836SGerry Liu if (ISWAKEABLE(tp) || ISWAITING(tp)) { 573a3114836SGerry Liu setrun_locked(tp); 574a3114836SGerry Liu } 575a3114836SGerry Liu 576a3114836SGerry Liu } 577a3114836SGerry Liu 578a3114836SGerry Liu /* grab thread if needed */ 579a3114836SGerry Liu if (tp->t_state == TS_ONPROC && tp->t_cpu != CPU) 580a3114836SGerry Liu poke_cpu(tp->t_cpu->cpu_id); 581a3114836SGerry Liu 582a3114836SGerry Liu 583a3114836SGerry Liu thread_unlock(tp); 584a3114836SGerry Liu mutex_exit(&p->p_lock); 585a3114836SGerry Liu } 586a3114836SGerry Liu mutex_exit(&pidlock); 587a3114836SGerry Liu 588a3114836SGerry Liu 589a3114836SGerry Liu /* let everything catch up */ 590a3114836SGerry Liu utstop_timedwait(count * count * DR_UTSTOP_WAIT); 591a3114836SGerry Liu 592a3114836SGerry Liu 593a3114836SGerry Liu /* now, walk the threadlist again to see if we are done */ 594a3114836SGerry Liu mutex_enter(&pidlock); 595a3114836SGerry Liu for (tp = curthread->t_next, bailout = 0; 596a3114836SGerry Liu tp != curthread; tp = tp->t_next) { 597a3114836SGerry Liu proc_t *p = ttoproc(tp); 598a3114836SGerry Liu 599a3114836SGerry Liu /* handle kernel threads separately */ 600a3114836SGerry Liu if (p->p_as == &kas || p->p_stat == SZOMB) 601a3114836SGerry Liu continue; 602a3114836SGerry Liu 603a3114836SGerry Liu /* 604a3114836SGerry Liu * If this thread didn't stop, and we don't allow 605a3114836SGerry Liu * unstopped blocked threads, bail. 606a3114836SGerry Liu */ 607a3114836SGerry Liu thread_lock(tp); 608a3114836SGerry Liu if (!CPR_ISTOPPED(tp) && 609a3114836SGerry Liu !(dr_allow_blocked_threads && 610a3114836SGerry Liu DR_VSTOPPED(tp))) { 611a3114836SGerry Liu bailout = 1; 612a3114836SGerry Liu if (count == DR_UTSTOP_RETRY - 1) { 613a3114836SGerry Liu /* 614a3114836SGerry Liu * save the pid for later reporting 615a3114836SGerry Liu */ 616a3114836SGerry Liu srh->sr_err_idx = 617a3114836SGerry Liu dr_add_int(srh->sr_err_ints, 618a3114836SGerry Liu srh->sr_err_idx, DR_MAX_ERR_INT, 619a3114836SGerry Liu (uint64_t)p->p_pid); 620a3114836SGerry Liu 621a3114836SGerry Liu cmn_err(CE_WARN, "%s: " 622a3114836SGerry Liu "failed to stop thread: " 623a3114836SGerry Liu "process=%s, pid=%d", 624a3114836SGerry Liu f, p->p_user.u_psargs, p->p_pid); 625a3114836SGerry Liu 626a3114836SGerry Liu PR_QR("%s: failed to stop thread: " 627a3114836SGerry Liu "process=%s, pid=%d, t_id=0x%p, " 628a3114836SGerry Liu "t_state=0x%x, t_proc_flag=0x%x, " 629a3114836SGerry Liu "t_schedflag=0x%x\n", 630a3114836SGerry Liu f, p->p_user.u_psargs, p->p_pid, 631a3114836SGerry Liu (void *)tp, tp->t_state, 632a3114836SGerry Liu tp->t_proc_flag, tp->t_schedflag); 633a3114836SGerry Liu } 634a3114836SGerry Liu 635a3114836SGerry Liu } 636a3114836SGerry Liu thread_unlock(tp); 637a3114836SGerry Liu } 638a3114836SGerry Liu mutex_exit(&pidlock); 639a3114836SGerry Liu 640a3114836SGerry Liu /* were all the threads stopped? */ 641a3114836SGerry Liu if (!bailout) 642a3114836SGerry Liu break; 643a3114836SGerry Liu } 644a3114836SGerry Liu 645a3114836SGerry Liu /* were we unable to stop all threads after a few tries? */ 646a3114836SGerry Liu if (bailout) { 647a3114836SGerry Liu handle->h_err = drerr_int(ESBD_UTHREAD, srh->sr_err_ints, 648a3114836SGerry Liu srh->sr_err_idx, 0); 649a3114836SGerry Liu return (ESRCH); 650a3114836SGerry Liu } 651a3114836SGerry Liu 652a3114836SGerry Liu return (DDI_SUCCESS); 653a3114836SGerry Liu } 654a3114836SGerry Liu 655a3114836SGerry Liu static void 656a3114836SGerry Liu dr_start_user_threads(void) 657a3114836SGerry Liu { 658a3114836SGerry Liu kthread_id_t tp; 659a3114836SGerry Liu 660a3114836SGerry Liu mutex_enter(&pidlock); 661a3114836SGerry Liu 662a3114836SGerry Liu /* walk all threads and release them */ 663a3114836SGerry Liu for (tp = curthread->t_next; tp != curthread; tp = tp->t_next) { 664a3114836SGerry Liu proc_t *p = ttoproc(tp); 665a3114836SGerry Liu 666a3114836SGerry Liu /* skip kernel threads */ 667a3114836SGerry Liu if (ttoproc(tp)->p_as == &kas) 668a3114836SGerry Liu continue; 669a3114836SGerry Liu 670a3114836SGerry Liu mutex_enter(&p->p_lock); 671a3114836SGerry Liu tp->t_proc_flag &= ~TP_CHKPT; 672a3114836SGerry Liu mutex_exit(&p->p_lock); 673a3114836SGerry Liu 674a3114836SGerry Liu thread_lock(tp); 675a3114836SGerry Liu if (CPR_ISTOPPED(tp)) { 676a3114836SGerry Liu /* back on the runq */ 677a3114836SGerry Liu tp->t_schedflag |= TS_RESUME; 678a3114836SGerry Liu setrun_locked(tp); 679a3114836SGerry Liu } 680a3114836SGerry Liu thread_unlock(tp); 681a3114836SGerry Liu } 682a3114836SGerry Liu 683a3114836SGerry Liu mutex_exit(&pidlock); 684a3114836SGerry Liu } 685a3114836SGerry Liu 686a3114836SGerry Liu static void 687a3114836SGerry Liu dr_signal_user(int sig) 688a3114836SGerry Liu { 689a3114836SGerry Liu struct proc *p; 690a3114836SGerry Liu 691a3114836SGerry Liu mutex_enter(&pidlock); 692a3114836SGerry Liu 693a3114836SGerry Liu for (p = practive; p != NULL; p = p->p_next) { 694a3114836SGerry Liu /* only user threads */ 695a3114836SGerry Liu if (p->p_exec == NULL || p->p_stat == SZOMB || 696a3114836SGerry Liu p == proc_init || p == ttoproc(curthread)) 697a3114836SGerry Liu continue; 698a3114836SGerry Liu 699a3114836SGerry Liu mutex_enter(&p->p_lock); 700a3114836SGerry Liu sigtoproc(p, NULL, sig); 701a3114836SGerry Liu mutex_exit(&p->p_lock); 702a3114836SGerry Liu } 703a3114836SGerry Liu 704a3114836SGerry Liu mutex_exit(&pidlock); 705a3114836SGerry Liu 706a3114836SGerry Liu /* add a bit of delay */ 707a3114836SGerry Liu delay(hz); 708a3114836SGerry Liu } 709a3114836SGerry Liu 710a3114836SGerry Liu void 711a3114836SGerry Liu dr_resume(dr_sr_handle_t *srh) 712a3114836SGerry Liu { 713a3114836SGerry Liu switch (srh->sr_suspend_state) { 714a3114836SGerry Liu case DR_SRSTATE_FULL: 715a3114836SGerry Liu 716a3114836SGerry Liu ASSERT(MUTEX_HELD(&cpu_lock)); 717a3114836SGerry Liu 718a3114836SGerry Liu /* 719a3114836SGerry Liu * Prevent false alarm in tod_validate() due to tod 720a3114836SGerry Liu * value change between suspend and resume 721a3114836SGerry Liu */ 722a3114836SGerry Liu mutex_enter(&tod_lock); 723a3114836SGerry Liu tod_status_set(TOD_DR_RESUME_DONE); 724a3114836SGerry Liu mutex_exit(&tod_lock); 725a3114836SGerry Liu 726a3114836SGerry Liu dr_enable_intr(); /* enable intr & clock */ 727a3114836SGerry Liu 728a3114836SGerry Liu start_cpus(); 729a3114836SGerry Liu mutex_exit(&cpu_lock); 730a3114836SGerry Liu 731a3114836SGerry Liu /* 732a3114836SGerry Liu * This should only be called if drmach_suspend_last() 733a3114836SGerry Liu * was called and state transitioned to DR_SRSTATE_FULL 734a3114836SGerry Liu * to prevent resume attempts on device instances that 735a3114836SGerry Liu * were not previously suspended. 736a3114836SGerry Liu */ 737a3114836SGerry Liu drmach_resume_first(); 738a3114836SGerry Liu 739a3114836SGerry Liu /* FALLTHROUGH */ 740a3114836SGerry Liu 741a3114836SGerry Liu case DR_SRSTATE_DRIVER: 742a3114836SGerry Liu /* 743a3114836SGerry Liu * resume drivers 744a3114836SGerry Liu */ 745a3114836SGerry Liu srh->sr_err_idx = 0; 746a3114836SGerry Liu 747a3114836SGerry Liu /* no parent dip to hold busy */ 748a3114836SGerry Liu dr_resume_devices(ddi_root_node(), srh); 749a3114836SGerry Liu 750a3114836SGerry Liu if (srh->sr_err_idx && srh->sr_dr_handlep) { 751a3114836SGerry Liu (srh->sr_dr_handlep)->h_err = drerr_int(ESBD_RESUME, 752a3114836SGerry Liu srh->sr_err_ints, srh->sr_err_idx, 1); 753a3114836SGerry Liu } 754a3114836SGerry Liu 755a3114836SGerry Liu /* 756a3114836SGerry Liu * resume the lock manager 757a3114836SGerry Liu */ 758a3114836SGerry Liu lm_cprresume(); 759a3114836SGerry Liu 760a3114836SGerry Liu /* FALLTHROUGH */ 761a3114836SGerry Liu 762a3114836SGerry Liu case DR_SRSTATE_USER: 763a3114836SGerry Liu /* 764a3114836SGerry Liu * finally, resume user threads 765a3114836SGerry Liu */ 766a3114836SGerry Liu if (!dr_skip_user_threads) { 767a3114836SGerry Liu prom_printf("DR: resuming user threads...\n"); 768a3114836SGerry Liu dr_start_user_threads(); 769a3114836SGerry Liu } 770a3114836SGerry Liu /* FALLTHROUGH */ 771a3114836SGerry Liu 772a3114836SGerry Liu case DR_SRSTATE_BEGIN: 773a3114836SGerry Liu default: 774a3114836SGerry Liu /* 775a3114836SGerry Liu * let those who care know that we've just resumed 776a3114836SGerry Liu */ 777a3114836SGerry Liu PR_QR("sending SIGTHAW...\n"); 778a3114836SGerry Liu dr_signal_user(SIGTHAW); 779a3114836SGerry Liu break; 780a3114836SGerry Liu } 781a3114836SGerry Liu 782a3114836SGerry Liu prom_printf("DR: resume COMPLETED\n"); 783a3114836SGerry Liu } 784a3114836SGerry Liu 785a3114836SGerry Liu int 786a3114836SGerry Liu dr_suspend(dr_sr_handle_t *srh) 787a3114836SGerry Liu { 788a3114836SGerry Liu dr_handle_t *handle; 789a3114836SGerry Liu int force; 790a3114836SGerry Liu int dev_errs_idx; 791a3114836SGerry Liu uint64_t dev_errs[DR_MAX_ERR_INT]; 792a3114836SGerry Liu int rc = DDI_SUCCESS; 793a3114836SGerry Liu 794a3114836SGerry Liu handle = srh->sr_dr_handlep; 795a3114836SGerry Liu 796a3114836SGerry Liu force = dr_cmd_flags(handle) & SBD_FLAG_FORCE; 797a3114836SGerry Liu 798a3114836SGerry Liu prom_printf("\nDR: suspending user threads...\n"); 799a3114836SGerry Liu srh->sr_suspend_state = DR_SRSTATE_USER; 800a3114836SGerry Liu if (((rc = dr_stop_user_threads(srh)) != DDI_SUCCESS) && 801a3114836SGerry Liu dr_check_user_stop_result) { 802a3114836SGerry Liu dr_resume(srh); 803a3114836SGerry Liu return (rc); 804a3114836SGerry Liu } 805a3114836SGerry Liu 806a3114836SGerry Liu if (!force) { 807a3114836SGerry Liu struct dr_ref drc = {0}; 808a3114836SGerry Liu 809a3114836SGerry Liu prom_printf("\nDR: checking devices...\n"); 810a3114836SGerry Liu dev_errs_idx = 0; 811a3114836SGerry Liu 812a3114836SGerry Liu drc.arr = dev_errs; 813a3114836SGerry Liu drc.idx = &dev_errs_idx; 814a3114836SGerry Liu drc.len = DR_MAX_ERR_INT; 815a3114836SGerry Liu 816a3114836SGerry Liu /* 817a3114836SGerry Liu * Since the root node can never go away, it 818a3114836SGerry Liu * doesn't have to be held. 819a3114836SGerry Liu */ 820a3114836SGerry Liu ddi_walk_devs(ddi_root_node(), dr_check_unsafe_major, &drc); 821a3114836SGerry Liu if (dev_errs_idx) { 822a3114836SGerry Liu handle->h_err = drerr_int(ESBD_UNSAFE, dev_errs, 823a3114836SGerry Liu dev_errs_idx, 1); 824a3114836SGerry Liu dr_resume(srh); 825a3114836SGerry Liu return (DDI_FAILURE); 826a3114836SGerry Liu } 827a3114836SGerry Liu PR_QR("done\n"); 828a3114836SGerry Liu } else { 829a3114836SGerry Liu prom_printf("\nDR: dr_suspend invoked with force flag\n"); 830a3114836SGerry Liu } 831a3114836SGerry Liu 832a3114836SGerry Liu #ifndef SKIP_SYNC 833a3114836SGerry Liu /* 834a3114836SGerry Liu * This sync swap out all user pages 835a3114836SGerry Liu */ 836a3114836SGerry Liu vfs_sync(SYNC_ALL); 837a3114836SGerry Liu #endif 838a3114836SGerry Liu 839a3114836SGerry Liu /* 840a3114836SGerry Liu * special treatment for lock manager 841a3114836SGerry Liu */ 842a3114836SGerry Liu lm_cprsuspend(); 843a3114836SGerry Liu 844a3114836SGerry Liu #ifndef SKIP_SYNC 845a3114836SGerry Liu /* 846a3114836SGerry Liu * sync the file system in case we never make it back 847a3114836SGerry Liu */ 848a3114836SGerry Liu sync(); 849a3114836SGerry Liu #endif 850a3114836SGerry Liu 851a3114836SGerry Liu /* 852a3114836SGerry Liu * now suspend drivers 853a3114836SGerry Liu */ 854a3114836SGerry Liu prom_printf("DR: suspending drivers...\n"); 855a3114836SGerry Liu srh->sr_suspend_state = DR_SRSTATE_DRIVER; 856a3114836SGerry Liu srh->sr_err_idx = 0; 857a3114836SGerry Liu /* No parent to hold busy */ 858a3114836SGerry Liu if ((rc = dr_suspend_devices(ddi_root_node(), srh)) != DDI_SUCCESS) { 859a3114836SGerry Liu if (srh->sr_err_idx && srh->sr_dr_handlep) { 860a3114836SGerry Liu (srh->sr_dr_handlep)->h_err = drerr_int(ESBD_SUSPEND, 861a3114836SGerry Liu srh->sr_err_ints, srh->sr_err_idx, 1); 862a3114836SGerry Liu } 863a3114836SGerry Liu dr_resume(srh); 864a3114836SGerry Liu return (rc); 865a3114836SGerry Liu } 866a3114836SGerry Liu 867a3114836SGerry Liu drmach_suspend_last(); 868a3114836SGerry Liu 869a3114836SGerry Liu /* 870a3114836SGerry Liu * finally, grab all cpus 871a3114836SGerry Liu */ 872a3114836SGerry Liu srh->sr_suspend_state = DR_SRSTATE_FULL; 873a3114836SGerry Liu 874a3114836SGerry Liu mutex_enter(&cpu_lock); 875*0ed5c46eSJosef 'Jeff' Sipek pause_cpus(NULL, NULL); 876a3114836SGerry Liu dr_stop_intr(); 877a3114836SGerry Liu 878a3114836SGerry Liu return (rc); 879a3114836SGerry Liu } 880a3114836SGerry Liu 881a3114836SGerry Liu int 882a3114836SGerry Liu dr_pt_test_suspend(dr_handle_t *hp) 883a3114836SGerry Liu { 884a3114836SGerry Liu dr_sr_handle_t *srh; 885a3114836SGerry Liu int err; 886a3114836SGerry Liu uint_t psmerr; 887a3114836SGerry Liu static fn_t f = "dr_pt_test_suspend"; 888a3114836SGerry Liu 889a3114836SGerry Liu PR_QR("%s...\n", f); 890a3114836SGerry Liu 891a3114836SGerry Liu srh = dr_get_sr_handle(hp); 892a3114836SGerry Liu if ((err = dr_suspend(srh)) == DDI_SUCCESS) { 893a3114836SGerry Liu dr_resume(srh); 894a3114836SGerry Liu if ((hp->h_err) && ((psmerr = hp->h_err->e_code) != 0)) { 895a3114836SGerry Liu PR_QR("%s: error on dr_resume()", f); 896a3114836SGerry Liu switch (psmerr) { 897a3114836SGerry Liu case ESBD_RESUME: 898a3114836SGerry Liu PR_QR("Couldn't resume devices: %s\n", 899a3114836SGerry Liu DR_GET_E_RSC(hp->h_err)); 900a3114836SGerry Liu break; 901a3114836SGerry Liu 902a3114836SGerry Liu case ESBD_KTHREAD: 903a3114836SGerry Liu PR_ALL("psmerr is ESBD_KTHREAD\n"); 904a3114836SGerry Liu break; 905a3114836SGerry Liu default: 906a3114836SGerry Liu PR_ALL("Resume error unknown = %d\n", psmerr); 907a3114836SGerry Liu break; 908a3114836SGerry Liu } 909a3114836SGerry Liu } 910a3114836SGerry Liu } else { 911a3114836SGerry Liu PR_ALL("%s: dr_suspend() failed, err = 0x%x\n", f, err); 912a3114836SGerry Liu psmerr = hp->h_err ? hp->h_err->e_code : ESBD_NOERROR; 913a3114836SGerry Liu switch (psmerr) { 914a3114836SGerry Liu case ESBD_UNSAFE: 915a3114836SGerry Liu PR_ALL("Unsafe devices (major #): %s\n", 916a3114836SGerry Liu DR_GET_E_RSC(hp->h_err)); 917a3114836SGerry Liu break; 918a3114836SGerry Liu 919a3114836SGerry Liu case ESBD_RTTHREAD: 920a3114836SGerry Liu PR_ALL("RT threads (PIDs): %s\n", 921a3114836SGerry Liu DR_GET_E_RSC(hp->h_err)); 922a3114836SGerry Liu break; 923a3114836SGerry Liu 924a3114836SGerry Liu case ESBD_UTHREAD: 925a3114836SGerry Liu PR_ALL("User threads (PIDs): %s\n", 926a3114836SGerry Liu DR_GET_E_RSC(hp->h_err)); 927a3114836SGerry Liu break; 928a3114836SGerry Liu 929a3114836SGerry Liu case ESBD_SUSPEND: 930a3114836SGerry Liu PR_ALL("Non-suspendable devices (major #): %s\n", 931a3114836SGerry Liu DR_GET_E_RSC(hp->h_err)); 932a3114836SGerry Liu break; 933a3114836SGerry Liu 934a3114836SGerry Liu case ESBD_RESUME: 935a3114836SGerry Liu PR_ALL("Could not resume devices (major #): %s\n", 936a3114836SGerry Liu DR_GET_E_RSC(hp->h_err)); 937a3114836SGerry Liu break; 938a3114836SGerry Liu 939a3114836SGerry Liu case ESBD_KTHREAD: 940a3114836SGerry Liu PR_ALL("psmerr is ESBD_KTHREAD\n"); 941a3114836SGerry Liu break; 942a3114836SGerry Liu 943a3114836SGerry Liu case ESBD_NOERROR: 944a3114836SGerry Liu PR_ALL("sbd_error_t error code not set\n"); 945a3114836SGerry Liu break; 946a3114836SGerry Liu 947a3114836SGerry Liu default: 948a3114836SGerry Liu PR_ALL("Unknown error psmerr = %d\n", psmerr); 949a3114836SGerry Liu break; 950a3114836SGerry Liu } 951a3114836SGerry Liu } 952a3114836SGerry Liu dr_release_sr_handle(srh); 953a3114836SGerry Liu 954a3114836SGerry Liu return (0); 955a3114836SGerry Liu } 956a3114836SGerry Liu 957a3114836SGerry Liu /* 958a3114836SGerry Liu * Add a new integer value to the end of an array. Don't allow duplicates to 959a3114836SGerry Liu * appear in the array, and don't allow the array to overflow. Return the new 960a3114836SGerry Liu * total number of entries in the array. 961a3114836SGerry Liu */ 962a3114836SGerry Liu static int 963a3114836SGerry Liu dr_add_int(uint64_t *arr, int idx, int len, uint64_t val) 964a3114836SGerry Liu { 965a3114836SGerry Liu int i; 966a3114836SGerry Liu 967a3114836SGerry Liu if (arr == NULL) 968a3114836SGerry Liu return (0); 969a3114836SGerry Liu 970a3114836SGerry Liu if (idx >= len) 971a3114836SGerry Liu return (idx); 972a3114836SGerry Liu 973a3114836SGerry Liu for (i = 0; i < idx; i++) { 974a3114836SGerry Liu if (arr[i] == val) 975a3114836SGerry Liu return (idx); 976a3114836SGerry Liu } 977a3114836SGerry Liu 978a3114836SGerry Liu arr[idx++] = val; 979a3114836SGerry Liu 980a3114836SGerry Liu return (idx); 981a3114836SGerry Liu } 982a3114836SGerry Liu 983a3114836SGerry Liu /* 984a3114836SGerry Liu * Construct an sbd_error_t featuring a string representation of an array of 985a3114836SGerry Liu * integers as its e_rsc. 986a3114836SGerry Liu */ 987a3114836SGerry Liu static sbd_error_t * 988a3114836SGerry Liu drerr_int(int e_code, uint64_t *arr, int idx, int majors) 989a3114836SGerry Liu { 990a3114836SGerry Liu int i, n, buf_len, buf_idx, buf_avail; 991a3114836SGerry Liu char *dname; 992a3114836SGerry Liu char *buf; 993a3114836SGerry Liu sbd_error_t *new_sbd_err; 994a3114836SGerry Liu static char s_ellipsis[] = "..."; 995a3114836SGerry Liu 996a3114836SGerry Liu if (arr == NULL || idx <= 0) 997a3114836SGerry Liu return (NULL); 998a3114836SGerry Liu 999a3114836SGerry Liu /* MAXPATHLEN is the size of the e_rsc field in sbd_error_t. */ 1000a3114836SGerry Liu buf = (char *)kmem_zalloc(MAXPATHLEN, KM_SLEEP); 1001a3114836SGerry Liu 1002a3114836SGerry Liu /* 1003a3114836SGerry Liu * This is the total working area of the buffer. It must be computed 1004a3114836SGerry Liu * as the size of 'buf', minus reserved space for the null terminator 1005a3114836SGerry Liu * and the ellipsis string. 1006a3114836SGerry Liu */ 1007a3114836SGerry Liu buf_len = MAXPATHLEN - (strlen(s_ellipsis) + 1); 1008a3114836SGerry Liu 1009a3114836SGerry Liu /* Construct a string representation of the array values */ 1010a3114836SGerry Liu for (buf_idx = 0, i = 0; i < idx; i++) { 1011a3114836SGerry Liu buf_avail = buf_len - buf_idx; 1012a3114836SGerry Liu if (majors) { 1013a3114836SGerry Liu dname = ddi_major_to_name(arr[i]); 1014a3114836SGerry Liu if (dname) { 1015a3114836SGerry Liu n = snprintf(&buf[buf_idx], buf_avail, "%s, ", 1016a3114836SGerry Liu dname); 1017a3114836SGerry Liu } else { 1018a3114836SGerry Liu n = snprintf(&buf[buf_idx], buf_avail, 1019a3114836SGerry Liu "major %" PRIu64 ", ", arr[i]); 1020a3114836SGerry Liu } 1021a3114836SGerry Liu } else { 1022a3114836SGerry Liu n = snprintf(&buf[buf_idx], buf_avail, "%" PRIu64 ", ", 1023a3114836SGerry Liu arr[i]); 1024a3114836SGerry Liu } 1025a3114836SGerry Liu 1026a3114836SGerry Liu /* An ellipsis gets appended when no more values fit */ 1027a3114836SGerry Liu if (n >= buf_avail) { 1028a3114836SGerry Liu (void) strcpy(&buf[buf_idx], s_ellipsis); 1029a3114836SGerry Liu break; 1030a3114836SGerry Liu } 1031a3114836SGerry Liu 1032a3114836SGerry Liu buf_idx += n; 1033a3114836SGerry Liu } 1034a3114836SGerry Liu 1035a3114836SGerry Liu /* If all the contents fit, remove the trailing comma */ 1036a3114836SGerry Liu if (n < buf_avail) { 1037a3114836SGerry Liu buf[--buf_idx] = '\0'; 1038a3114836SGerry Liu buf[--buf_idx] = '\0'; 1039a3114836SGerry Liu } 1040a3114836SGerry Liu 1041a3114836SGerry Liu /* Return an sbd_error_t with the buffer and e_code */ 1042a3114836SGerry Liu new_sbd_err = drerr_new(1, e_code, buf); 1043a3114836SGerry Liu kmem_free(buf, MAXPATHLEN); 1044a3114836SGerry Liu return (new_sbd_err); 1045a3114836SGerry Liu } 1046