17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5646e55b6Scth * Common Development and Distribution License (the "License"). 6646e55b6Scth * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 2107d06da5SSurya Prakki 227c478bd9Sstevel@tonic-gate /* 23bec42f4bSMary Beale * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate /* 277c478bd9Sstevel@tonic-gate * A CPR derivative specifically for starfire/starcat 287c478bd9Sstevel@tonic-gate */ 297c478bd9Sstevel@tonic-gate 307c478bd9Sstevel@tonic-gate #include <sys/types.h> 317c478bd9Sstevel@tonic-gate #include <sys/systm.h> 327c478bd9Sstevel@tonic-gate #include <sys/machparam.h> 337c478bd9Sstevel@tonic-gate #include <sys/machsystm.h> 347c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 357c478bd9Sstevel@tonic-gate #define SUNDDI_IMPL 367c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 377c478bd9Sstevel@tonic-gate #include <sys/sunndi.h> 387c478bd9Sstevel@tonic-gate #include <sys/devctl.h> 397c478bd9Sstevel@tonic-gate #include <sys/time.h> 407c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 417c478bd9Sstevel@tonic-gate #include <nfs/lm.h> 427c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 437c478bd9Sstevel@tonic-gate #include <sys/ndi_impldefs.h> 447c478bd9Sstevel@tonic-gate #include <sys/obpdefs.h> 457c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 467c478bd9Sstevel@tonic-gate #include <sys/debug.h> 477c478bd9Sstevel@tonic-gate #include <sys/errno.h> 487c478bd9Sstevel@tonic-gate #include <sys/callb.h> 497c478bd9Sstevel@tonic-gate #include <sys/clock.h> 507c478bd9Sstevel@tonic-gate #include <sys/x_call.h> 517c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h> 527c478bd9Sstevel@tonic-gate #include <sys/epm.h> 537c478bd9Sstevel@tonic-gate #include <sys/vfs.h> 547c478bd9Sstevel@tonic-gate 557c478bd9Sstevel@tonic-gate #include <sys/cpu_sgnblk_defs.h> 567c478bd9Sstevel@tonic-gate #include <sys/dr.h> 577c478bd9Sstevel@tonic-gate #include <sys/dr_util.h> 587c478bd9Sstevel@tonic-gate 597c478bd9Sstevel@tonic-gate #include <sys/promif.h> 607c478bd9Sstevel@tonic-gate #include <sys/conf.h> 617c478bd9Sstevel@tonic-gate #include <sys/cyclic.h> 627c478bd9Sstevel@tonic-gate 637c478bd9Sstevel@tonic-gate extern void e_ddi_enter_driver_list(struct devnames *dnp, int *listcnt); 647c478bd9Sstevel@tonic-gate extern void e_ddi_exit_driver_list(struct devnames *dnp, int listcnt); 657c478bd9Sstevel@tonic-gate extern int is_pseudo_device(dev_info_t *dip); 667c478bd9Sstevel@tonic-gate 677c478bd9Sstevel@tonic-gate extern kmutex_t cpu_lock; 687c478bd9Sstevel@tonic-gate extern dr_unsafe_devs_t dr_unsafe_devs; 697c478bd9Sstevel@tonic-gate 707c478bd9Sstevel@tonic-gate static int dr_is_real_device(dev_info_t *dip); 717c478bd9Sstevel@tonic-gate static int dr_is_unsafe_major(major_t major); 727c478bd9Sstevel@tonic-gate static int dr_bypass_device(char *dname); 737c478bd9Sstevel@tonic-gate static int dr_check_dip(dev_info_t *dip, void *arg, uint_t ref); 747c478bd9Sstevel@tonic-gate static int dr_resolve_devname(dev_info_t *dip, char *buffer, 757c478bd9Sstevel@tonic-gate char *alias); 767c478bd9Sstevel@tonic-gate static sbd_error_t *drerr_int(int e_code, uint64_t *arr, int idx, 777c478bd9Sstevel@tonic-gate int majors); 787c478bd9Sstevel@tonic-gate static int dr_add_int(uint64_t *arr, int idx, int len, 797c478bd9Sstevel@tonic-gate uint64_t val); 807c478bd9Sstevel@tonic-gate 817c478bd9Sstevel@tonic-gate int dr_pt_test_suspend(dr_handle_t *hp); 827c478bd9Sstevel@tonic-gate 837c478bd9Sstevel@tonic-gate /* 847c478bd9Sstevel@tonic-gate * dr_quiesce.c interface 857c478bd9Sstevel@tonic-gate * NOTE: states used internally by dr_suspend and dr_resume 867c478bd9Sstevel@tonic-gate */ 877c478bd9Sstevel@tonic-gate typedef enum dr_suspend_state { 887c478bd9Sstevel@tonic-gate DR_SRSTATE_BEGIN = 0, 897c478bd9Sstevel@tonic-gate DR_SRSTATE_USER, 907c478bd9Sstevel@tonic-gate DR_SRSTATE_DRIVER, 917c478bd9Sstevel@tonic-gate DR_SRSTATE_FULL 927c478bd9Sstevel@tonic-gate } suspend_state_t; 937c478bd9Sstevel@tonic-gate 947c478bd9Sstevel@tonic-gate struct dr_sr_handle { 957c478bd9Sstevel@tonic-gate dr_handle_t *sr_dr_handlep; 967c478bd9Sstevel@tonic-gate dev_info_t *sr_failed_dip; 977c478bd9Sstevel@tonic-gate suspend_state_t sr_suspend_state; 987c478bd9Sstevel@tonic-gate uint_t sr_flags; 997c478bd9Sstevel@tonic-gate uint64_t sr_err_ints[DR_MAX_ERR_INT]; 1007c478bd9Sstevel@tonic-gate int sr_err_idx; 1017c478bd9Sstevel@tonic-gate }; 1027c478bd9Sstevel@tonic-gate 1037c478bd9Sstevel@tonic-gate #define SR_FLAG_WATCHDOG 0x1 1047c478bd9Sstevel@tonic-gate 1057c478bd9Sstevel@tonic-gate /* 1067c478bd9Sstevel@tonic-gate * XXX 1077c478bd9Sstevel@tonic-gate * This hack will go away before RTI. Just for testing. 1087c478bd9Sstevel@tonic-gate * List of drivers to bypass when performing a suspend. 1097c478bd9Sstevel@tonic-gate */ 1107c478bd9Sstevel@tonic-gate static char *dr_bypass_list[] = { 1117c478bd9Sstevel@tonic-gate "" 1127c478bd9Sstevel@tonic-gate }; 1137c478bd9Sstevel@tonic-gate 1147c478bd9Sstevel@tonic-gate 1157c478bd9Sstevel@tonic-gate #define SKIP_SYNC /* bypass sync ops in dr_suspend */ 1167c478bd9Sstevel@tonic-gate 1177c478bd9Sstevel@tonic-gate /* 1187c478bd9Sstevel@tonic-gate * dr_skip_user_threads is used to control if user threads should 1197c478bd9Sstevel@tonic-gate * be suspended. If dr_skip_user_threads is true, the rest of the 1207c478bd9Sstevel@tonic-gate * flags are not used; if it is false, dr_check_user_stop_result 1217c478bd9Sstevel@tonic-gate * will be used to control whether or not we need to check suspend 1227c478bd9Sstevel@tonic-gate * result, and dr_allow_blocked_threads will be used to control 1237c478bd9Sstevel@tonic-gate * whether or not we allow suspend to continue if there are blocked 1247c478bd9Sstevel@tonic-gate * threads. We allow all combinations of dr_check_user_stop_result 1257c478bd9Sstevel@tonic-gate * and dr_allow_block_threads, even though it might not make much 1267c478bd9Sstevel@tonic-gate * sense to not allow block threads when we don't even check stop 1277c478bd9Sstevel@tonic-gate * result. 1287c478bd9Sstevel@tonic-gate */ 1297c478bd9Sstevel@tonic-gate static int dr_skip_user_threads = 0; /* default to FALSE */ 1307c478bd9Sstevel@tonic-gate static int dr_check_user_stop_result = 1; /* default to TRUE */ 1317c478bd9Sstevel@tonic-gate static int dr_allow_blocked_threads = 1; /* default to TRUE */ 1327c478bd9Sstevel@tonic-gate 1337c478bd9Sstevel@tonic-gate #define DR_CPU_LOOP_MSEC 1000 1347c478bd9Sstevel@tonic-gate 1357c478bd9Sstevel@tonic-gate static void 1367c478bd9Sstevel@tonic-gate dr_stop_intr(void) 1377c478bd9Sstevel@tonic-gate { 1387c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&cpu_lock)); 1397c478bd9Sstevel@tonic-gate 1407c478bd9Sstevel@tonic-gate kpreempt_disable(); 1417c478bd9Sstevel@tonic-gate cyclic_suspend(); 1427c478bd9Sstevel@tonic-gate } 1437c478bd9Sstevel@tonic-gate 1447c478bd9Sstevel@tonic-gate static void 1457c478bd9Sstevel@tonic-gate dr_enable_intr(void) 1467c478bd9Sstevel@tonic-gate { 1477c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&cpu_lock)); 1487c478bd9Sstevel@tonic-gate 1497c478bd9Sstevel@tonic-gate cyclic_resume(); 1507c478bd9Sstevel@tonic-gate kpreempt_enable(); 1517c478bd9Sstevel@tonic-gate } 1527c478bd9Sstevel@tonic-gate 1537c478bd9Sstevel@tonic-gate dr_sr_handle_t * 1547c478bd9Sstevel@tonic-gate dr_get_sr_handle(dr_handle_t *hp) 1557c478bd9Sstevel@tonic-gate { 1567c478bd9Sstevel@tonic-gate dr_sr_handle_t *srh; 1577c478bd9Sstevel@tonic-gate 1587c478bd9Sstevel@tonic-gate srh = GETSTRUCT(dr_sr_handle_t, 1); 1597c478bd9Sstevel@tonic-gate srh->sr_dr_handlep = hp; 1607c478bd9Sstevel@tonic-gate 1617c478bd9Sstevel@tonic-gate return (srh); 1627c478bd9Sstevel@tonic-gate } 1637c478bd9Sstevel@tonic-gate 1647c478bd9Sstevel@tonic-gate void 1657c478bd9Sstevel@tonic-gate dr_release_sr_handle(dr_sr_handle_t *srh) 1667c478bd9Sstevel@tonic-gate { 1677c478bd9Sstevel@tonic-gate ASSERT(srh->sr_failed_dip == NULL); 1687c478bd9Sstevel@tonic-gate FREESTRUCT(srh, dr_sr_handle_t, 1); 1697c478bd9Sstevel@tonic-gate } 1707c478bd9Sstevel@tonic-gate 1717c478bd9Sstevel@tonic-gate static int 1727c478bd9Sstevel@tonic-gate dr_is_real_device(dev_info_t *dip) 1737c478bd9Sstevel@tonic-gate { 1747c478bd9Sstevel@tonic-gate struct regspec *regbuf = NULL; 1757c478bd9Sstevel@tonic-gate int length = 0; 1767c478bd9Sstevel@tonic-gate int rc; 1777c478bd9Sstevel@tonic-gate 1787c478bd9Sstevel@tonic-gate if (ddi_get_driver(dip) == NULL) 1797c478bd9Sstevel@tonic-gate return (0); 1807c478bd9Sstevel@tonic-gate 1817c478bd9Sstevel@tonic-gate if (DEVI(dip)->devi_pm_flags & (PMC_NEEDS_SR|PMC_PARENTAL_SR)) 1827c478bd9Sstevel@tonic-gate return (1); 1837c478bd9Sstevel@tonic-gate if (DEVI(dip)->devi_pm_flags & PMC_NO_SR) 1847c478bd9Sstevel@tonic-gate return (0); 1857c478bd9Sstevel@tonic-gate 1867c478bd9Sstevel@tonic-gate /* 1877c478bd9Sstevel@tonic-gate * now the general case 1887c478bd9Sstevel@tonic-gate */ 189a3282898Scth rc = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg", 1907c478bd9Sstevel@tonic-gate (caddr_t)®buf, &length); 1917c478bd9Sstevel@tonic-gate ASSERT(rc != DDI_PROP_NO_MEMORY); 1927c478bd9Sstevel@tonic-gate if (rc != DDI_PROP_SUCCESS) { 1937c478bd9Sstevel@tonic-gate return (0); 1947c478bd9Sstevel@tonic-gate } else { 1957c478bd9Sstevel@tonic-gate if ((length > 0) && (regbuf != NULL)) 1967c478bd9Sstevel@tonic-gate kmem_free(regbuf, length); 1977c478bd9Sstevel@tonic-gate return (1); 1987c478bd9Sstevel@tonic-gate } 1997c478bd9Sstevel@tonic-gate } 2007c478bd9Sstevel@tonic-gate 2017c478bd9Sstevel@tonic-gate static int 2027c478bd9Sstevel@tonic-gate dr_is_unsafe_major(major_t major) 2037c478bd9Sstevel@tonic-gate { 2047c478bd9Sstevel@tonic-gate char *dname, **cpp; 2057c478bd9Sstevel@tonic-gate int i, ndevs; 2067c478bd9Sstevel@tonic-gate 2077c478bd9Sstevel@tonic-gate if ((dname = ddi_major_to_name(major)) == NULL) { 2087c478bd9Sstevel@tonic-gate PR_QR("dr_is_unsafe_major: invalid major # %d\n", major); 2097c478bd9Sstevel@tonic-gate return (0); 2107c478bd9Sstevel@tonic-gate } 2117c478bd9Sstevel@tonic-gate 2127c478bd9Sstevel@tonic-gate ndevs = dr_unsafe_devs.ndevs; 2137c478bd9Sstevel@tonic-gate for (i = 0, cpp = dr_unsafe_devs.devnames; i < ndevs; i++) { 2147c478bd9Sstevel@tonic-gate if (strcmp(dname, *cpp++) == 0) 2157c478bd9Sstevel@tonic-gate return (1); 2167c478bd9Sstevel@tonic-gate } 2177c478bd9Sstevel@tonic-gate return (0); 2187c478bd9Sstevel@tonic-gate } 2197c478bd9Sstevel@tonic-gate 2207c478bd9Sstevel@tonic-gate static int 2217c478bd9Sstevel@tonic-gate dr_bypass_device(char *dname) 2227c478bd9Sstevel@tonic-gate { 2237c478bd9Sstevel@tonic-gate int i; 2247c478bd9Sstevel@tonic-gate char **lname; 225bec42f4bSMary Beale 226bec42f4bSMary Beale if (dname == NULL) 227bec42f4bSMary Beale return (0); 228bec42f4bSMary Beale 2297c478bd9Sstevel@tonic-gate /* check the bypass list */ 2307c478bd9Sstevel@tonic-gate for (i = 0, lname = &dr_bypass_list[i]; **lname != '\0'; lname++) { 2317c478bd9Sstevel@tonic-gate if (strcmp(dname, dr_bypass_list[i++]) == 0) 2327c478bd9Sstevel@tonic-gate return (1); 2337c478bd9Sstevel@tonic-gate } 2347c478bd9Sstevel@tonic-gate return (0); 2357c478bd9Sstevel@tonic-gate } 2367c478bd9Sstevel@tonic-gate 2377c478bd9Sstevel@tonic-gate static int 2387c478bd9Sstevel@tonic-gate dr_resolve_devname(dev_info_t *dip, char *buffer, char *alias) 2397c478bd9Sstevel@tonic-gate { 2407c478bd9Sstevel@tonic-gate major_t devmajor; 2417c478bd9Sstevel@tonic-gate char *aka, *name; 2427c478bd9Sstevel@tonic-gate 2437c478bd9Sstevel@tonic-gate *buffer = *alias = 0; 2447c478bd9Sstevel@tonic-gate 2457c478bd9Sstevel@tonic-gate if (dip == NULL) 2467c478bd9Sstevel@tonic-gate return (-1); 2477c478bd9Sstevel@tonic-gate 2487c478bd9Sstevel@tonic-gate if ((name = ddi_get_name(dip)) == NULL) 2497c478bd9Sstevel@tonic-gate name = "<null name>"; 2507c478bd9Sstevel@tonic-gate 2517c478bd9Sstevel@tonic-gate aka = name; 2527c478bd9Sstevel@tonic-gate 2537c478bd9Sstevel@tonic-gate if ((devmajor = ddi_name_to_major(aka)) != -1) 2547c478bd9Sstevel@tonic-gate aka = ddi_major_to_name(devmajor); 2557c478bd9Sstevel@tonic-gate 25607d06da5SSurya Prakki (void) strcpy(buffer, name); 2577c478bd9Sstevel@tonic-gate 2587c478bd9Sstevel@tonic-gate if (strcmp(name, aka)) 25907d06da5SSurya Prakki (void) strcpy(alias, aka); 2607c478bd9Sstevel@tonic-gate else 2617c478bd9Sstevel@tonic-gate *alias = 0; 2627c478bd9Sstevel@tonic-gate 2637c478bd9Sstevel@tonic-gate return (0); 2647c478bd9Sstevel@tonic-gate } 2657c478bd9Sstevel@tonic-gate 2667c478bd9Sstevel@tonic-gate struct dr_ref { 2677c478bd9Sstevel@tonic-gate int *refcount; 268df3cd224SVijay S Balakrishna int *refcount_non_gldv3; 2697c478bd9Sstevel@tonic-gate uint64_t *arr; 2707c478bd9Sstevel@tonic-gate int *idx; 2717c478bd9Sstevel@tonic-gate int len; 2727c478bd9Sstevel@tonic-gate }; 2737c478bd9Sstevel@tonic-gate 2747c478bd9Sstevel@tonic-gate /* ARGSUSED */ 2757c478bd9Sstevel@tonic-gate static int 2767c478bd9Sstevel@tonic-gate dr_check_dip(dev_info_t *dip, void *arg, uint_t ref) 2777c478bd9Sstevel@tonic-gate { 2787c478bd9Sstevel@tonic-gate major_t major; 2797c478bd9Sstevel@tonic-gate char *dname; 2807c478bd9Sstevel@tonic-gate struct dr_ref *rp = (struct dr_ref *)arg; 2817c478bd9Sstevel@tonic-gate 2827c478bd9Sstevel@tonic-gate if (dip == NULL) 2837c478bd9Sstevel@tonic-gate return (DDI_WALK_CONTINUE); 2847c478bd9Sstevel@tonic-gate 2857c478bd9Sstevel@tonic-gate if (!dr_is_real_device(dip)) 2867c478bd9Sstevel@tonic-gate return (DDI_WALK_CONTINUE); 2877c478bd9Sstevel@tonic-gate 2887c478bd9Sstevel@tonic-gate dname = ddi_binding_name(dip); 2897c478bd9Sstevel@tonic-gate 2907c478bd9Sstevel@tonic-gate if (dr_bypass_device(dname)) 2917c478bd9Sstevel@tonic-gate return (DDI_WALK_CONTINUE); 2927c478bd9Sstevel@tonic-gate 2937c478bd9Sstevel@tonic-gate if (dname && ((major = ddi_name_to_major(dname)) != (major_t)-1)) { 2947c478bd9Sstevel@tonic-gate if (ref && rp->refcount) { 2957c478bd9Sstevel@tonic-gate *rp->refcount += ref; 2968fc99e42STrevor Thompson PR_QR("\n %s (major# %d) is referenced(%u)\n", dname, 2978fc99e42STrevor Thompson major, ref); 2987c478bd9Sstevel@tonic-gate } 299df3cd224SVijay S Balakrishna if (ref && rp->refcount_non_gldv3) { 300df3cd224SVijay S Balakrishna if (NETWORK_PHYSDRV(major) && !GLDV3_DRV(major)) 301df3cd224SVijay S Balakrishna *rp->refcount_non_gldv3 += ref; 302df3cd224SVijay S Balakrishna } 303737d277aScth if (dr_is_unsafe_major(major) && i_ddi_devi_attached(dip)) { 3048fc99e42STrevor Thompson PR_QR("\n %s (major# %d) not hotpluggable\n", dname, 3058fc99e42STrevor Thompson major); 3067c478bd9Sstevel@tonic-gate if (rp->arr != NULL && rp->idx != NULL) 3077c478bd9Sstevel@tonic-gate *rp->idx = dr_add_int(rp->arr, *rp->idx, 3087c478bd9Sstevel@tonic-gate rp->len, (uint64_t)major); 3097c478bd9Sstevel@tonic-gate } 3107c478bd9Sstevel@tonic-gate } 3117c478bd9Sstevel@tonic-gate return (DDI_WALK_CONTINUE); 3127c478bd9Sstevel@tonic-gate } 3137c478bd9Sstevel@tonic-gate 3147c478bd9Sstevel@tonic-gate static int 3157c478bd9Sstevel@tonic-gate dr_check_unsafe_major(dev_info_t *dip, void *arg) 3167c478bd9Sstevel@tonic-gate { 3177c478bd9Sstevel@tonic-gate return (dr_check_dip(dip, arg, 0)); 3187c478bd9Sstevel@tonic-gate } 3197c478bd9Sstevel@tonic-gate 3207c478bd9Sstevel@tonic-gate 3217c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3227c478bd9Sstevel@tonic-gate void 3237c478bd9Sstevel@tonic-gate dr_check_devices(dev_info_t *dip, int *refcount, dr_handle_t *handle, 324df3cd224SVijay S Balakrishna uint64_t *arr, int *idx, int len, int *refcount_non_gldv3) 3257c478bd9Sstevel@tonic-gate { 3267c478bd9Sstevel@tonic-gate struct dr_ref bref = {0}; 3277c478bd9Sstevel@tonic-gate 3287c478bd9Sstevel@tonic-gate if (dip == NULL) 3297c478bd9Sstevel@tonic-gate return; 3307c478bd9Sstevel@tonic-gate 3317c478bd9Sstevel@tonic-gate bref.refcount = refcount; 332df3cd224SVijay S Balakrishna bref.refcount_non_gldv3 = refcount_non_gldv3; 3337c478bd9Sstevel@tonic-gate bref.arr = arr; 3347c478bd9Sstevel@tonic-gate bref.idx = idx; 3357c478bd9Sstevel@tonic-gate bref.len = len; 3367c478bd9Sstevel@tonic-gate 3377c478bd9Sstevel@tonic-gate ASSERT(e_ddi_branch_held(dip)); 3387c478bd9Sstevel@tonic-gate (void) e_ddi_branch_referenced(dip, dr_check_dip, &bref); 3397c478bd9Sstevel@tonic-gate } 3407c478bd9Sstevel@tonic-gate 3417c478bd9Sstevel@tonic-gate /* 3427c478bd9Sstevel@tonic-gate * The "dip" argument's parent (if it exists) must be held busy. 3437c478bd9Sstevel@tonic-gate */ 3447c478bd9Sstevel@tonic-gate static int 3457c478bd9Sstevel@tonic-gate dr_suspend_devices(dev_info_t *dip, dr_sr_handle_t *srh) 3467c478bd9Sstevel@tonic-gate { 3477c478bd9Sstevel@tonic-gate dr_handle_t *handle; 3487c478bd9Sstevel@tonic-gate major_t major; 3497c478bd9Sstevel@tonic-gate char *dname; 3507c478bd9Sstevel@tonic-gate int circ; 3517c478bd9Sstevel@tonic-gate 3527c478bd9Sstevel@tonic-gate /* 3537c478bd9Sstevel@tonic-gate * If dip is the root node, it has no siblings and it is 3547c478bd9Sstevel@tonic-gate * always held. If dip is not the root node, dr_suspend_devices() 3557c478bd9Sstevel@tonic-gate * will be invoked with the parent held busy. 3567c478bd9Sstevel@tonic-gate */ 3577c478bd9Sstevel@tonic-gate for (; dip != NULL; dip = ddi_get_next_sibling(dip)) { 3587c478bd9Sstevel@tonic-gate char d_name[40], d_alias[40], *d_info; 3597c478bd9Sstevel@tonic-gate 3607c478bd9Sstevel@tonic-gate ndi_devi_enter(dip, &circ); 3617c478bd9Sstevel@tonic-gate if (dr_suspend_devices(ddi_get_child(dip), srh)) { 3627c478bd9Sstevel@tonic-gate ndi_devi_exit(dip, circ); 3637c478bd9Sstevel@tonic-gate return (ENXIO); 3647c478bd9Sstevel@tonic-gate } 3657c478bd9Sstevel@tonic-gate ndi_devi_exit(dip, circ); 3667c478bd9Sstevel@tonic-gate 3677c478bd9Sstevel@tonic-gate if (!dr_is_real_device(dip)) 3687c478bd9Sstevel@tonic-gate continue; 3697c478bd9Sstevel@tonic-gate 3707c478bd9Sstevel@tonic-gate major = (major_t)-1; 3717c478bd9Sstevel@tonic-gate if ((dname = ddi_binding_name(dip)) != NULL) 3727c478bd9Sstevel@tonic-gate major = ddi_name_to_major(dname); 3737c478bd9Sstevel@tonic-gate 3747c478bd9Sstevel@tonic-gate if (dr_bypass_device(dname)) { 3757c478bd9Sstevel@tonic-gate PR_QR(" bypassed suspend of %s (major# %d)\n", dname, 3767c478bd9Sstevel@tonic-gate major); 3777c478bd9Sstevel@tonic-gate continue; 3787c478bd9Sstevel@tonic-gate } 3797c478bd9Sstevel@tonic-gate 3807c478bd9Sstevel@tonic-gate if (drmach_verify_sr(dip, 1)) { 3817c478bd9Sstevel@tonic-gate PR_QR(" bypassed suspend of %s (major# %d)\n", dname, 3827c478bd9Sstevel@tonic-gate major); 3837c478bd9Sstevel@tonic-gate continue; 3847c478bd9Sstevel@tonic-gate } 3857c478bd9Sstevel@tonic-gate 3867c478bd9Sstevel@tonic-gate if ((d_info = ddi_get_name_addr(dip)) == NULL) 3877c478bd9Sstevel@tonic-gate d_info = "<null>"; 3887c478bd9Sstevel@tonic-gate 3897c478bd9Sstevel@tonic-gate d_name[0] = 0; 3907c478bd9Sstevel@tonic-gate if (dr_resolve_devname(dip, d_name, d_alias) == 0) { 3917c478bd9Sstevel@tonic-gate if (d_alias[0] != 0) { 3927c478bd9Sstevel@tonic-gate prom_printf("\tsuspending %s@%s (aka %s)\n", 3937c478bd9Sstevel@tonic-gate d_name, d_info, d_alias); 3947c478bd9Sstevel@tonic-gate } else { 3958fc99e42STrevor Thompson prom_printf("\tsuspending %s@%s\n", d_name, 3968fc99e42STrevor Thompson d_info); 3977c478bd9Sstevel@tonic-gate } 3987c478bd9Sstevel@tonic-gate } else { 3997c478bd9Sstevel@tonic-gate prom_printf("\tsuspending %s@%s\n", dname, d_info); 4007c478bd9Sstevel@tonic-gate } 4017c478bd9Sstevel@tonic-gate 4027c478bd9Sstevel@tonic-gate if (devi_detach(dip, DDI_SUSPEND) != DDI_SUCCESS) { 4037c478bd9Sstevel@tonic-gate prom_printf("\tFAILED to suspend %s@%s\n", 4047c478bd9Sstevel@tonic-gate d_name[0] ? d_name : dname, d_info); 4057c478bd9Sstevel@tonic-gate 4067c478bd9Sstevel@tonic-gate srh->sr_err_idx = dr_add_int(srh->sr_err_ints, 407df3cd224SVijay S Balakrishna srh->sr_err_idx, DR_MAX_ERR_INT, (uint64_t)major); 4087c478bd9Sstevel@tonic-gate 4097c478bd9Sstevel@tonic-gate ndi_hold_devi(dip); 4107c478bd9Sstevel@tonic-gate srh->sr_failed_dip = dip; 4117c478bd9Sstevel@tonic-gate 4127c478bd9Sstevel@tonic-gate handle = srh->sr_dr_handlep; 4137c478bd9Sstevel@tonic-gate dr_op_err(CE_IGNORE, handle, ESBD_SUSPEND, "%s@%s", 4147c478bd9Sstevel@tonic-gate d_name[0] ? d_name : dname, d_info); 4157c478bd9Sstevel@tonic-gate 4167c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 4177c478bd9Sstevel@tonic-gate } 4187c478bd9Sstevel@tonic-gate } 4197c478bd9Sstevel@tonic-gate 4207c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 4217c478bd9Sstevel@tonic-gate } 4227c478bd9Sstevel@tonic-gate 4237c478bd9Sstevel@tonic-gate static void 4247c478bd9Sstevel@tonic-gate dr_resume_devices(dev_info_t *start, dr_sr_handle_t *srh) 4257c478bd9Sstevel@tonic-gate { 4267c478bd9Sstevel@tonic-gate dr_handle_t *handle; 4277c478bd9Sstevel@tonic-gate dev_info_t *dip, *next, *last = NULL; 4287c478bd9Sstevel@tonic-gate major_t major; 4297c478bd9Sstevel@tonic-gate char *bn; 4307c478bd9Sstevel@tonic-gate int circ; 4317c478bd9Sstevel@tonic-gate 4327c478bd9Sstevel@tonic-gate major = (major_t)-1; 4337c478bd9Sstevel@tonic-gate 4347c478bd9Sstevel@tonic-gate /* attach in reverse device tree order */ 4357c478bd9Sstevel@tonic-gate while (last != start) { 4367c478bd9Sstevel@tonic-gate dip = start; 4377c478bd9Sstevel@tonic-gate next = ddi_get_next_sibling(dip); 4387c478bd9Sstevel@tonic-gate while (next != last && dip != srh->sr_failed_dip) { 4397c478bd9Sstevel@tonic-gate dip = next; 4407c478bd9Sstevel@tonic-gate next = ddi_get_next_sibling(dip); 4417c478bd9Sstevel@tonic-gate } 4427c478bd9Sstevel@tonic-gate if (dip == srh->sr_failed_dip) { 4437c478bd9Sstevel@tonic-gate /* release hold acquired in dr_suspend_devices() */ 4447c478bd9Sstevel@tonic-gate srh->sr_failed_dip = NULL; 4457c478bd9Sstevel@tonic-gate ndi_rele_devi(dip); 4468fc99e42STrevor Thompson } else if (dr_is_real_device(dip) && 4478fc99e42STrevor Thompson srh->sr_failed_dip == NULL) { 4487c478bd9Sstevel@tonic-gate 4497c478bd9Sstevel@tonic-gate if ((bn = ddi_binding_name(dip)) != NULL) { 4507c478bd9Sstevel@tonic-gate major = ddi_name_to_major(bn); 4517c478bd9Sstevel@tonic-gate } else { 4527c478bd9Sstevel@tonic-gate bn = "<null>"; 4537c478bd9Sstevel@tonic-gate } 4547c478bd9Sstevel@tonic-gate if (!dr_bypass_device(bn) && 4557c478bd9Sstevel@tonic-gate !drmach_verify_sr(dip, 0)) { 4567c478bd9Sstevel@tonic-gate char d_name[40], d_alias[40], *d_info; 4577c478bd9Sstevel@tonic-gate 4587c478bd9Sstevel@tonic-gate d_name[0] = 0; 4597c478bd9Sstevel@tonic-gate d_info = ddi_get_name_addr(dip); 4607c478bd9Sstevel@tonic-gate if (d_info == NULL) 4617c478bd9Sstevel@tonic-gate d_info = "<null>"; 4627c478bd9Sstevel@tonic-gate 4638fc99e42STrevor Thompson if (!dr_resolve_devname(dip, d_name, d_alias)) { 4647c478bd9Sstevel@tonic-gate if (d_alias[0] != 0) { 4657c478bd9Sstevel@tonic-gate prom_printf("\tresuming " 4668fc99e42STrevor Thompson "%s@%s (aka %s)\n", d_name, 4678fc99e42STrevor Thompson d_info, d_alias); 4687c478bd9Sstevel@tonic-gate } else { 4697c478bd9Sstevel@tonic-gate prom_printf("\tresuming " 470df3cd224SVijay S Balakrishna "%s@%s\n", d_name, d_info); 4717c478bd9Sstevel@tonic-gate } 4727c478bd9Sstevel@tonic-gate } else { 4738fc99e42STrevor Thompson prom_printf("\tresuming %s@%s\n", bn, 4748fc99e42STrevor Thompson d_info); 4757c478bd9Sstevel@tonic-gate } 4767c478bd9Sstevel@tonic-gate 4777c478bd9Sstevel@tonic-gate if (devi_attach(dip, DDI_RESUME) != 4787c478bd9Sstevel@tonic-gate DDI_SUCCESS) { 4797c478bd9Sstevel@tonic-gate /* 4807c478bd9Sstevel@tonic-gate * Print a console warning, 4817c478bd9Sstevel@tonic-gate * set an e_code of ESBD_RESUME, 4827c478bd9Sstevel@tonic-gate * and save the driver major 4837c478bd9Sstevel@tonic-gate * number in the e_rsc. 4847c478bd9Sstevel@tonic-gate */ 4857c478bd9Sstevel@tonic-gate prom_printf("\tFAILED to resume %s@%s", 4867c478bd9Sstevel@tonic-gate d_name[0] ? d_name : bn, d_info); 4877c478bd9Sstevel@tonic-gate 4887c478bd9Sstevel@tonic-gate srh->sr_err_idx = 4897c478bd9Sstevel@tonic-gate dr_add_int(srh->sr_err_ints, 4907c478bd9Sstevel@tonic-gate srh->sr_err_idx, DR_MAX_ERR_INT, 4917c478bd9Sstevel@tonic-gate (uint64_t)major); 4927c478bd9Sstevel@tonic-gate 4937c478bd9Sstevel@tonic-gate handle = srh->sr_dr_handlep; 4947c478bd9Sstevel@tonic-gate 4957c478bd9Sstevel@tonic-gate dr_op_err(CE_IGNORE, handle, 4967c478bd9Sstevel@tonic-gate ESBD_RESUME, "%s@%s", 4977c478bd9Sstevel@tonic-gate d_name[0] ? d_name : bn, d_info); 4987c478bd9Sstevel@tonic-gate } 4997c478bd9Sstevel@tonic-gate } 5007c478bd9Sstevel@tonic-gate } 5017c478bd9Sstevel@tonic-gate 5027c478bd9Sstevel@tonic-gate /* Hold parent busy while walking its children */ 5037c478bd9Sstevel@tonic-gate ndi_devi_enter(dip, &circ); 5047c478bd9Sstevel@tonic-gate dr_resume_devices(ddi_get_child(dip), srh); 5057c478bd9Sstevel@tonic-gate ndi_devi_exit(dip, circ); 5067c478bd9Sstevel@tonic-gate last = dip; 5077c478bd9Sstevel@tonic-gate } 5087c478bd9Sstevel@tonic-gate } 5097c478bd9Sstevel@tonic-gate 5107c478bd9Sstevel@tonic-gate /* 5117c478bd9Sstevel@tonic-gate * True if thread is virtually stopped. Similar to CPR_VSTOPPED 5127c478bd9Sstevel@tonic-gate * but from DR point of view. These user threads are waiting in 5137c478bd9Sstevel@tonic-gate * the kernel. Once they complete in the kernel, they will process 5147c478bd9Sstevel@tonic-gate * the stop signal and stop. 5157c478bd9Sstevel@tonic-gate */ 5167c478bd9Sstevel@tonic-gate #define DR_VSTOPPED(t) \ 5177c478bd9Sstevel@tonic-gate ((t)->t_state == TS_SLEEP && \ 5187c478bd9Sstevel@tonic-gate (t)->t_wchan != NULL && \ 5197c478bd9Sstevel@tonic-gate (t)->t_astflag && \ 5207c478bd9Sstevel@tonic-gate ((t)->t_proc_flag & TP_CHKPT)) 5217c478bd9Sstevel@tonic-gate 5227c478bd9Sstevel@tonic-gate /* ARGSUSED */ 5237c478bd9Sstevel@tonic-gate static int 5247c478bd9Sstevel@tonic-gate dr_stop_user_threads(dr_sr_handle_t *srh) 5257c478bd9Sstevel@tonic-gate { 5267c478bd9Sstevel@tonic-gate int count; 5277c478bd9Sstevel@tonic-gate int bailout; 5287c478bd9Sstevel@tonic-gate dr_handle_t *handle = srh->sr_dr_handlep; 5297c478bd9Sstevel@tonic-gate static fn_t f = "dr_stop_user_threads"; 5307c478bd9Sstevel@tonic-gate kthread_id_t tp; 5317c478bd9Sstevel@tonic-gate 5327c478bd9Sstevel@tonic-gate extern void add_one_utstop(); 5337c478bd9Sstevel@tonic-gate extern void utstop_timedwait(clock_t); 5347c478bd9Sstevel@tonic-gate extern void utstop_init(void); 5357c478bd9Sstevel@tonic-gate 5367c478bd9Sstevel@tonic-gate #define DR_UTSTOP_RETRY 4 5377c478bd9Sstevel@tonic-gate #define DR_UTSTOP_WAIT hz 5387c478bd9Sstevel@tonic-gate 5397c478bd9Sstevel@tonic-gate if (dr_skip_user_threads) 5407c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 5417c478bd9Sstevel@tonic-gate 5427c478bd9Sstevel@tonic-gate utstop_init(); 5437c478bd9Sstevel@tonic-gate 5447c478bd9Sstevel@tonic-gate /* we need to try a few times to get past fork, etc. */ 5457c478bd9Sstevel@tonic-gate srh->sr_err_idx = 0; 5467c478bd9Sstevel@tonic-gate for (count = 0; count < DR_UTSTOP_RETRY; count++) { 5477c478bd9Sstevel@tonic-gate /* walk the entire threadlist */ 5487c478bd9Sstevel@tonic-gate mutex_enter(&pidlock); 5497c478bd9Sstevel@tonic-gate for (tp = curthread->t_next; tp != curthread; tp = tp->t_next) { 5507c478bd9Sstevel@tonic-gate proc_t *p = ttoproc(tp); 5517c478bd9Sstevel@tonic-gate 5527c478bd9Sstevel@tonic-gate /* handle kernel threads separately */ 5537c478bd9Sstevel@tonic-gate if (p->p_as == &kas || p->p_stat == SZOMB) 5547c478bd9Sstevel@tonic-gate continue; 5557c478bd9Sstevel@tonic-gate 5567c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 5577c478bd9Sstevel@tonic-gate thread_lock(tp); 5587c478bd9Sstevel@tonic-gate 5597c478bd9Sstevel@tonic-gate if (tp->t_state == TS_STOPPED) { 5607c478bd9Sstevel@tonic-gate /* add another reason to stop this thread */ 5617c478bd9Sstevel@tonic-gate tp->t_schedflag &= ~TS_RESUME; 5627c478bd9Sstevel@tonic-gate } else { 5637c478bd9Sstevel@tonic-gate tp->t_proc_flag |= TP_CHKPT; 5647c478bd9Sstevel@tonic-gate 5657c478bd9Sstevel@tonic-gate thread_unlock(tp); 5667c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 5677c478bd9Sstevel@tonic-gate add_one_utstop(); 5687c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 5697c478bd9Sstevel@tonic-gate thread_lock(tp); 5707c478bd9Sstevel@tonic-gate 5717c478bd9Sstevel@tonic-gate aston(tp); 5727c478bd9Sstevel@tonic-gate 573c97ad5cdSakolb if (ISWAKEABLE(tp) || ISWAITING(tp)) { 5747c478bd9Sstevel@tonic-gate setrun_locked(tp); 5757c478bd9Sstevel@tonic-gate } 5767c478bd9Sstevel@tonic-gate 5777c478bd9Sstevel@tonic-gate } 5787c478bd9Sstevel@tonic-gate 5797c478bd9Sstevel@tonic-gate /* grab thread if needed */ 5807c478bd9Sstevel@tonic-gate if (tp->t_state == TS_ONPROC && tp->t_cpu != CPU) 5817c478bd9Sstevel@tonic-gate poke_cpu(tp->t_cpu->cpu_id); 5827c478bd9Sstevel@tonic-gate 5837c478bd9Sstevel@tonic-gate 5847c478bd9Sstevel@tonic-gate thread_unlock(tp); 5857c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 5867c478bd9Sstevel@tonic-gate } 5877c478bd9Sstevel@tonic-gate mutex_exit(&pidlock); 5887c478bd9Sstevel@tonic-gate 5897c478bd9Sstevel@tonic-gate 5907c478bd9Sstevel@tonic-gate /* let everything catch up */ 5917c478bd9Sstevel@tonic-gate utstop_timedwait(count * count * DR_UTSTOP_WAIT); 5927c478bd9Sstevel@tonic-gate 5937c478bd9Sstevel@tonic-gate 5947c478bd9Sstevel@tonic-gate /* now, walk the threadlist again to see if we are done */ 5957c478bd9Sstevel@tonic-gate mutex_enter(&pidlock); 5967c478bd9Sstevel@tonic-gate for (tp = curthread->t_next, bailout = 0; 5977c478bd9Sstevel@tonic-gate tp != curthread; tp = tp->t_next) { 5987c478bd9Sstevel@tonic-gate proc_t *p = ttoproc(tp); 5997c478bd9Sstevel@tonic-gate 6007c478bd9Sstevel@tonic-gate /* handle kernel threads separately */ 6017c478bd9Sstevel@tonic-gate if (p->p_as == &kas || p->p_stat == SZOMB) 6027c478bd9Sstevel@tonic-gate continue; 6037c478bd9Sstevel@tonic-gate 6047c478bd9Sstevel@tonic-gate /* 6057c478bd9Sstevel@tonic-gate * If this thread didn't stop, and we don't allow 6067c478bd9Sstevel@tonic-gate * unstopped blocked threads, bail. 6077c478bd9Sstevel@tonic-gate */ 6087c478bd9Sstevel@tonic-gate thread_lock(tp); 6097c478bd9Sstevel@tonic-gate if (!CPR_ISTOPPED(tp) && 6107c478bd9Sstevel@tonic-gate !(dr_allow_blocked_threads && 6117c478bd9Sstevel@tonic-gate DR_VSTOPPED(tp))) { 6127c478bd9Sstevel@tonic-gate bailout = 1; 6137c478bd9Sstevel@tonic-gate if (count == DR_UTSTOP_RETRY - 1) { 6147c478bd9Sstevel@tonic-gate /* 6157c478bd9Sstevel@tonic-gate * save the pid for later reporting 6167c478bd9Sstevel@tonic-gate */ 6177c478bd9Sstevel@tonic-gate srh->sr_err_idx = 6187c478bd9Sstevel@tonic-gate dr_add_int(srh->sr_err_ints, 6197c478bd9Sstevel@tonic-gate srh->sr_err_idx, DR_MAX_ERR_INT, 6207c478bd9Sstevel@tonic-gate (uint64_t)p->p_pid); 6217c478bd9Sstevel@tonic-gate 6227c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s: " 6237c478bd9Sstevel@tonic-gate "failed to stop thread: " 6247c478bd9Sstevel@tonic-gate "process=%s, pid=%d", 6257c478bd9Sstevel@tonic-gate f, p->p_user.u_psargs, p->p_pid); 6267c478bd9Sstevel@tonic-gate 6277c478bd9Sstevel@tonic-gate PR_QR("%s: failed to stop thread: " 62804580fdfSmathue "process=%s, pid=%d, t_id=0x%p, " 6297c478bd9Sstevel@tonic-gate "t_state=0x%x, t_proc_flag=0x%x, " 6307c478bd9Sstevel@tonic-gate "t_schedflag=0x%x\n", 6317c478bd9Sstevel@tonic-gate f, p->p_user.u_psargs, p->p_pid, 63207d06da5SSurya Prakki (void *)tp, tp->t_state, 63307d06da5SSurya Prakki tp->t_proc_flag, tp->t_schedflag); 6347c478bd9Sstevel@tonic-gate } 6357c478bd9Sstevel@tonic-gate 6367c478bd9Sstevel@tonic-gate } 6377c478bd9Sstevel@tonic-gate thread_unlock(tp); 6387c478bd9Sstevel@tonic-gate } 6397c478bd9Sstevel@tonic-gate mutex_exit(&pidlock); 6407c478bd9Sstevel@tonic-gate 6417c478bd9Sstevel@tonic-gate /* were all the threads stopped? */ 6427c478bd9Sstevel@tonic-gate if (!bailout) 6437c478bd9Sstevel@tonic-gate break; 6447c478bd9Sstevel@tonic-gate } 6457c478bd9Sstevel@tonic-gate 6467c478bd9Sstevel@tonic-gate /* were we unable to stop all threads after a few tries? */ 6477c478bd9Sstevel@tonic-gate if (bailout) { 6487c478bd9Sstevel@tonic-gate handle->h_err = drerr_int(ESBD_UTHREAD, srh->sr_err_ints, 6497c478bd9Sstevel@tonic-gate srh->sr_err_idx, 0); 6507c478bd9Sstevel@tonic-gate return (ESRCH); 6517c478bd9Sstevel@tonic-gate } 6527c478bd9Sstevel@tonic-gate 6537c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 6547c478bd9Sstevel@tonic-gate } 6557c478bd9Sstevel@tonic-gate 6567c478bd9Sstevel@tonic-gate static void 6577c478bd9Sstevel@tonic-gate dr_start_user_threads(void) 6587c478bd9Sstevel@tonic-gate { 6597c478bd9Sstevel@tonic-gate kthread_id_t tp; 6607c478bd9Sstevel@tonic-gate 6617c478bd9Sstevel@tonic-gate mutex_enter(&pidlock); 6627c478bd9Sstevel@tonic-gate 6637c478bd9Sstevel@tonic-gate /* walk all threads and release them */ 6647c478bd9Sstevel@tonic-gate for (tp = curthread->t_next; tp != curthread; tp = tp->t_next) { 6657c478bd9Sstevel@tonic-gate proc_t *p = ttoproc(tp); 6667c478bd9Sstevel@tonic-gate 6677c478bd9Sstevel@tonic-gate /* skip kernel threads */ 6687c478bd9Sstevel@tonic-gate if (ttoproc(tp)->p_as == &kas) 6697c478bd9Sstevel@tonic-gate continue; 6707c478bd9Sstevel@tonic-gate 6717c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 6727c478bd9Sstevel@tonic-gate tp->t_proc_flag &= ~TP_CHKPT; 6737c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 6747c478bd9Sstevel@tonic-gate 6757c478bd9Sstevel@tonic-gate thread_lock(tp); 6767c478bd9Sstevel@tonic-gate if (CPR_ISTOPPED(tp)) { 6777c478bd9Sstevel@tonic-gate /* back on the runq */ 6787c478bd9Sstevel@tonic-gate tp->t_schedflag |= TS_RESUME; 6797c478bd9Sstevel@tonic-gate setrun_locked(tp); 6807c478bd9Sstevel@tonic-gate } 6817c478bd9Sstevel@tonic-gate thread_unlock(tp); 6827c478bd9Sstevel@tonic-gate } 6837c478bd9Sstevel@tonic-gate 6847c478bd9Sstevel@tonic-gate mutex_exit(&pidlock); 6857c478bd9Sstevel@tonic-gate } 6867c478bd9Sstevel@tonic-gate 6877c478bd9Sstevel@tonic-gate static void 6887c478bd9Sstevel@tonic-gate dr_signal_user(int sig) 6897c478bd9Sstevel@tonic-gate { 6907c478bd9Sstevel@tonic-gate struct proc *p; 6917c478bd9Sstevel@tonic-gate 6927c478bd9Sstevel@tonic-gate mutex_enter(&pidlock); 6937c478bd9Sstevel@tonic-gate 6947c478bd9Sstevel@tonic-gate for (p = practive; p != NULL; p = p->p_next) { 6957c478bd9Sstevel@tonic-gate /* only user threads */ 6967c478bd9Sstevel@tonic-gate if (p->p_exec == NULL || p->p_stat == SZOMB || 6977c478bd9Sstevel@tonic-gate p == proc_init || p == ttoproc(curthread)) 6987c478bd9Sstevel@tonic-gate continue; 6997c478bd9Sstevel@tonic-gate 7007c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 7017c478bd9Sstevel@tonic-gate sigtoproc(p, NULL, sig); 7027c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 7037c478bd9Sstevel@tonic-gate } 7047c478bd9Sstevel@tonic-gate 7057c478bd9Sstevel@tonic-gate mutex_exit(&pidlock); 7067c478bd9Sstevel@tonic-gate 7077c478bd9Sstevel@tonic-gate /* add a bit of delay */ 7087c478bd9Sstevel@tonic-gate delay(hz); 7097c478bd9Sstevel@tonic-gate } 7107c478bd9Sstevel@tonic-gate 7117c478bd9Sstevel@tonic-gate void 7127c478bd9Sstevel@tonic-gate dr_resume(dr_sr_handle_t *srh) 7137c478bd9Sstevel@tonic-gate { 7147c478bd9Sstevel@tonic-gate if (srh->sr_suspend_state < DR_SRSTATE_FULL) { 7157c478bd9Sstevel@tonic-gate /* 7167c478bd9Sstevel@tonic-gate * Update the signature block. 7177c478bd9Sstevel@tonic-gate * If cpus are not paused, this can be done now. 7187c478bd9Sstevel@tonic-gate * See comments below. 7197c478bd9Sstevel@tonic-gate */ 7207c478bd9Sstevel@tonic-gate CPU_SIGNATURE(OS_SIG, SIGST_RESUME_INPROGRESS, SIGSUBST_NULL, 7217c478bd9Sstevel@tonic-gate CPU->cpu_id); 7227c478bd9Sstevel@tonic-gate } 7237c478bd9Sstevel@tonic-gate 7247c478bd9Sstevel@tonic-gate switch (srh->sr_suspend_state) { 7257c478bd9Sstevel@tonic-gate case DR_SRSTATE_FULL: 7267c478bd9Sstevel@tonic-gate 7277c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&cpu_lock)); 7287c478bd9Sstevel@tonic-gate 729646e55b6Scth /* 730646e55b6Scth * Prevent false alarm in tod_validate() due to tod 731646e55b6Scth * value change between suspend and resume 732646e55b6Scth */ 733646e55b6Scth mutex_enter(&tod_lock); 7348fc99e42STrevor Thompson tod_status_set(TOD_DR_RESUME_DONE); 735646e55b6Scth mutex_exit(&tod_lock); 736646e55b6Scth 7377c478bd9Sstevel@tonic-gate dr_enable_intr(); /* enable intr & clock */ 7387c478bd9Sstevel@tonic-gate 7397c478bd9Sstevel@tonic-gate start_cpus(); 7407c478bd9Sstevel@tonic-gate mutex_exit(&cpu_lock); 7417c478bd9Sstevel@tonic-gate 7427c478bd9Sstevel@tonic-gate /* 7437c478bd9Sstevel@tonic-gate * Update the signature block. 7447c478bd9Sstevel@tonic-gate * This must not be done while cpus are paused, since on 7457c478bd9Sstevel@tonic-gate * Starcat the cpu signature update aquires an adaptive 7467c478bd9Sstevel@tonic-gate * mutex in the iosram driver. Blocking with cpus paused 7477c478bd9Sstevel@tonic-gate * can lead to deadlock. 7487c478bd9Sstevel@tonic-gate */ 7497c478bd9Sstevel@tonic-gate CPU_SIGNATURE(OS_SIG, SIGST_RESUME_INPROGRESS, SIGSUBST_NULL, 7507c478bd9Sstevel@tonic-gate CPU->cpu_id); 7517c478bd9Sstevel@tonic-gate 7527c478bd9Sstevel@tonic-gate /* 7537c478bd9Sstevel@tonic-gate * If we suspended hw watchdog at suspend, 7547c478bd9Sstevel@tonic-gate * re-enable it now. 7557c478bd9Sstevel@tonic-gate */ 7567c478bd9Sstevel@tonic-gate if (srh->sr_flags & (SR_FLAG_WATCHDOG)) { 7577c478bd9Sstevel@tonic-gate mutex_enter(&tod_lock); 7587c478bd9Sstevel@tonic-gate tod_ops.tod_set_watchdog_timer( 7597c478bd9Sstevel@tonic-gate watchdog_timeout_seconds); 7607c478bd9Sstevel@tonic-gate mutex_exit(&tod_lock); 7617c478bd9Sstevel@tonic-gate } 7627c478bd9Sstevel@tonic-gate 7637c478bd9Sstevel@tonic-gate /* 7647c478bd9Sstevel@tonic-gate * This should only be called if drmach_suspend_last() 7657c478bd9Sstevel@tonic-gate * was called and state transitioned to DR_SRSTATE_FULL 7667c478bd9Sstevel@tonic-gate * to prevent resume attempts on device instances that 7677c478bd9Sstevel@tonic-gate * were not previously suspended. 7687c478bd9Sstevel@tonic-gate */ 7697c478bd9Sstevel@tonic-gate drmach_resume_first(); 7707c478bd9Sstevel@tonic-gate 7717c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 7727c478bd9Sstevel@tonic-gate 7737c478bd9Sstevel@tonic-gate case DR_SRSTATE_DRIVER: 7747c478bd9Sstevel@tonic-gate /* 7757c478bd9Sstevel@tonic-gate * resume drivers 7767c478bd9Sstevel@tonic-gate */ 7777c478bd9Sstevel@tonic-gate srh->sr_err_idx = 0; 7787c478bd9Sstevel@tonic-gate 7797c478bd9Sstevel@tonic-gate /* no parent dip to hold busy */ 7807c478bd9Sstevel@tonic-gate dr_resume_devices(ddi_root_node(), srh); 7817c478bd9Sstevel@tonic-gate 7827c478bd9Sstevel@tonic-gate if (srh->sr_err_idx && srh->sr_dr_handlep) { 7837c478bd9Sstevel@tonic-gate (srh->sr_dr_handlep)->h_err = drerr_int(ESBD_RESUME, 7847c478bd9Sstevel@tonic-gate srh->sr_err_ints, srh->sr_err_idx, 1); 7857c478bd9Sstevel@tonic-gate } 7867c478bd9Sstevel@tonic-gate 7877c478bd9Sstevel@tonic-gate /* 7887c478bd9Sstevel@tonic-gate * resume the lock manager 7897c478bd9Sstevel@tonic-gate */ 7907c478bd9Sstevel@tonic-gate lm_cprresume(); 7917c478bd9Sstevel@tonic-gate 7927c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 7937c478bd9Sstevel@tonic-gate 7947c478bd9Sstevel@tonic-gate case DR_SRSTATE_USER: 7957c478bd9Sstevel@tonic-gate /* 7967c478bd9Sstevel@tonic-gate * finally, resume user threads 7977c478bd9Sstevel@tonic-gate */ 7987c478bd9Sstevel@tonic-gate if (!dr_skip_user_threads) { 7997c478bd9Sstevel@tonic-gate prom_printf("DR: resuming user threads...\n"); 8007c478bd9Sstevel@tonic-gate dr_start_user_threads(); 8017c478bd9Sstevel@tonic-gate } 8027c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 8037c478bd9Sstevel@tonic-gate 8047c478bd9Sstevel@tonic-gate case DR_SRSTATE_BEGIN: 8057c478bd9Sstevel@tonic-gate default: 8067c478bd9Sstevel@tonic-gate /* 8077c478bd9Sstevel@tonic-gate * let those who care know that we've just resumed 8087c478bd9Sstevel@tonic-gate */ 8097c478bd9Sstevel@tonic-gate PR_QR("sending SIGTHAW...\n"); 8107c478bd9Sstevel@tonic-gate dr_signal_user(SIGTHAW); 8117c478bd9Sstevel@tonic-gate break; 8127c478bd9Sstevel@tonic-gate } 8137c478bd9Sstevel@tonic-gate 8147c478bd9Sstevel@tonic-gate /* 8157c478bd9Sstevel@tonic-gate * update the signature block 8167c478bd9Sstevel@tonic-gate */ 8177c478bd9Sstevel@tonic-gate CPU_SIGNATURE(OS_SIG, SIGST_RUN, SIGSUBST_NULL, CPU->cpu_id); 8187c478bd9Sstevel@tonic-gate 8197c478bd9Sstevel@tonic-gate prom_printf("DR: resume COMPLETED\n"); 8207c478bd9Sstevel@tonic-gate } 8217c478bd9Sstevel@tonic-gate 8227c478bd9Sstevel@tonic-gate int 8237c478bd9Sstevel@tonic-gate dr_suspend(dr_sr_handle_t *srh) 8247c478bd9Sstevel@tonic-gate { 8257c478bd9Sstevel@tonic-gate dr_handle_t *handle; 8267c478bd9Sstevel@tonic-gate int force; 8277c478bd9Sstevel@tonic-gate int dev_errs_idx; 8287c478bd9Sstevel@tonic-gate uint64_t dev_errs[DR_MAX_ERR_INT]; 8297c478bd9Sstevel@tonic-gate int rc = DDI_SUCCESS; 8307c478bd9Sstevel@tonic-gate 8317c478bd9Sstevel@tonic-gate handle = srh->sr_dr_handlep; 8327c478bd9Sstevel@tonic-gate 8337c478bd9Sstevel@tonic-gate force = dr_cmd_flags(handle) & SBD_FLAG_FORCE; 8347c478bd9Sstevel@tonic-gate 8357c478bd9Sstevel@tonic-gate /* 8367c478bd9Sstevel@tonic-gate * update the signature block 8377c478bd9Sstevel@tonic-gate */ 8387c478bd9Sstevel@tonic-gate CPU_SIGNATURE(OS_SIG, SIGST_QUIESCE_INPROGRESS, SIGSUBST_NULL, 8397c478bd9Sstevel@tonic-gate CPU->cpu_id); 8407c478bd9Sstevel@tonic-gate 8417c478bd9Sstevel@tonic-gate prom_printf("\nDR: suspending user threads...\n"); 8427c478bd9Sstevel@tonic-gate srh->sr_suspend_state = DR_SRSTATE_USER; 8437c478bd9Sstevel@tonic-gate if (((rc = dr_stop_user_threads(srh)) != DDI_SUCCESS) && 8447c478bd9Sstevel@tonic-gate dr_check_user_stop_result) { 8457c478bd9Sstevel@tonic-gate dr_resume(srh); 8467c478bd9Sstevel@tonic-gate return (rc); 8477c478bd9Sstevel@tonic-gate } 8487c478bd9Sstevel@tonic-gate 8497c478bd9Sstevel@tonic-gate if (!force) { 8507c478bd9Sstevel@tonic-gate struct dr_ref drc = {0}; 8517c478bd9Sstevel@tonic-gate 8527c478bd9Sstevel@tonic-gate prom_printf("\nDR: checking devices...\n"); 8537c478bd9Sstevel@tonic-gate dev_errs_idx = 0; 8547c478bd9Sstevel@tonic-gate 8557c478bd9Sstevel@tonic-gate drc.arr = dev_errs; 8567c478bd9Sstevel@tonic-gate drc.idx = &dev_errs_idx; 8577c478bd9Sstevel@tonic-gate drc.len = DR_MAX_ERR_INT; 8587c478bd9Sstevel@tonic-gate 8597c478bd9Sstevel@tonic-gate /* 8607c478bd9Sstevel@tonic-gate * Since the root node can never go away, it 8617c478bd9Sstevel@tonic-gate * doesn't have to be held. 8627c478bd9Sstevel@tonic-gate */ 8637c478bd9Sstevel@tonic-gate ddi_walk_devs(ddi_root_node(), dr_check_unsafe_major, &drc); 8647c478bd9Sstevel@tonic-gate if (dev_errs_idx) { 8657c478bd9Sstevel@tonic-gate handle->h_err = drerr_int(ESBD_UNSAFE, dev_errs, 8667c478bd9Sstevel@tonic-gate dev_errs_idx, 1); 8677c478bd9Sstevel@tonic-gate dr_resume(srh); 8687c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 8697c478bd9Sstevel@tonic-gate } 8707c478bd9Sstevel@tonic-gate PR_QR("done\n"); 8717c478bd9Sstevel@tonic-gate } else { 8727c478bd9Sstevel@tonic-gate prom_printf("\nDR: dr_suspend invoked with force flag\n"); 8737c478bd9Sstevel@tonic-gate } 8747c478bd9Sstevel@tonic-gate 8757c478bd9Sstevel@tonic-gate #ifndef SKIP_SYNC 8767c478bd9Sstevel@tonic-gate /* 8777c478bd9Sstevel@tonic-gate * This sync swap out all user pages 8787c478bd9Sstevel@tonic-gate */ 8797c478bd9Sstevel@tonic-gate vfs_sync(SYNC_ALL); 8807c478bd9Sstevel@tonic-gate #endif 8817c478bd9Sstevel@tonic-gate 8827c478bd9Sstevel@tonic-gate /* 8837c478bd9Sstevel@tonic-gate * special treatment for lock manager 8847c478bd9Sstevel@tonic-gate */ 8857c478bd9Sstevel@tonic-gate lm_cprsuspend(); 8867c478bd9Sstevel@tonic-gate 8877c478bd9Sstevel@tonic-gate #ifndef SKIP_SYNC 8887c478bd9Sstevel@tonic-gate /* 8897c478bd9Sstevel@tonic-gate * sync the file system in case we never make it back 8907c478bd9Sstevel@tonic-gate */ 8917c478bd9Sstevel@tonic-gate sync(); 8927c478bd9Sstevel@tonic-gate #endif 8937c478bd9Sstevel@tonic-gate 8947c478bd9Sstevel@tonic-gate /* 8957c478bd9Sstevel@tonic-gate * now suspend drivers 8967c478bd9Sstevel@tonic-gate */ 8977c478bd9Sstevel@tonic-gate prom_printf("DR: suspending drivers...\n"); 8987c478bd9Sstevel@tonic-gate srh->sr_suspend_state = DR_SRSTATE_DRIVER; 8997c478bd9Sstevel@tonic-gate srh->sr_err_idx = 0; 9007c478bd9Sstevel@tonic-gate /* No parent to hold busy */ 9017c478bd9Sstevel@tonic-gate if ((rc = dr_suspend_devices(ddi_root_node(), srh)) != DDI_SUCCESS) { 9027c478bd9Sstevel@tonic-gate if (srh->sr_err_idx && srh->sr_dr_handlep) { 9037c478bd9Sstevel@tonic-gate (srh->sr_dr_handlep)->h_err = drerr_int(ESBD_SUSPEND, 9047c478bd9Sstevel@tonic-gate srh->sr_err_ints, srh->sr_err_idx, 1); 9057c478bd9Sstevel@tonic-gate } 9067c478bd9Sstevel@tonic-gate dr_resume(srh); 9077c478bd9Sstevel@tonic-gate return (rc); 9087c478bd9Sstevel@tonic-gate } 9097c478bd9Sstevel@tonic-gate 9107c478bd9Sstevel@tonic-gate drmach_suspend_last(); 9117c478bd9Sstevel@tonic-gate 9127c478bd9Sstevel@tonic-gate /* 9137c478bd9Sstevel@tonic-gate * finally, grab all cpus 9147c478bd9Sstevel@tonic-gate */ 9157c478bd9Sstevel@tonic-gate srh->sr_suspend_state = DR_SRSTATE_FULL; 9167c478bd9Sstevel@tonic-gate 9177c478bd9Sstevel@tonic-gate /* 9187c478bd9Sstevel@tonic-gate * if watchdog was activated, disable it 9197c478bd9Sstevel@tonic-gate */ 9207c478bd9Sstevel@tonic-gate if (watchdog_activated) { 9217c478bd9Sstevel@tonic-gate mutex_enter(&tod_lock); 9227c478bd9Sstevel@tonic-gate tod_ops.tod_clear_watchdog_timer(); 9237c478bd9Sstevel@tonic-gate mutex_exit(&tod_lock); 9247c478bd9Sstevel@tonic-gate srh->sr_flags |= SR_FLAG_WATCHDOG; 9257c478bd9Sstevel@tonic-gate } else { 9267c478bd9Sstevel@tonic-gate srh->sr_flags &= ~(SR_FLAG_WATCHDOG); 9277c478bd9Sstevel@tonic-gate } 9287c478bd9Sstevel@tonic-gate 9297c478bd9Sstevel@tonic-gate /* 9307c478bd9Sstevel@tonic-gate * Update the signature block. 9317c478bd9Sstevel@tonic-gate * This must be done before cpus are paused, since on Starcat the 9327c478bd9Sstevel@tonic-gate * cpu signature update aquires an adaptive mutex in the iosram driver. 9337c478bd9Sstevel@tonic-gate * Blocking with cpus paused can lead to deadlock. 9347c478bd9Sstevel@tonic-gate */ 9357c478bd9Sstevel@tonic-gate CPU_SIGNATURE(OS_SIG, SIGST_QUIESCED, SIGSUBST_NULL, CPU->cpu_id); 9367c478bd9Sstevel@tonic-gate 9377c478bd9Sstevel@tonic-gate mutex_enter(&cpu_lock); 938*0ed5c46eSJosef 'Jeff' Sipek pause_cpus(NULL, NULL); 9397c478bd9Sstevel@tonic-gate dr_stop_intr(); 9407c478bd9Sstevel@tonic-gate 9417c478bd9Sstevel@tonic-gate return (rc); 9427c478bd9Sstevel@tonic-gate } 9437c478bd9Sstevel@tonic-gate 9447c478bd9Sstevel@tonic-gate int 9457c478bd9Sstevel@tonic-gate dr_pt_test_suspend(dr_handle_t *hp) 9467c478bd9Sstevel@tonic-gate { 9477c478bd9Sstevel@tonic-gate dr_sr_handle_t *srh; 9487c478bd9Sstevel@tonic-gate int err; 9497c478bd9Sstevel@tonic-gate uint_t psmerr; 9507c478bd9Sstevel@tonic-gate static fn_t f = "dr_pt_test_suspend"; 9517c478bd9Sstevel@tonic-gate 9527c478bd9Sstevel@tonic-gate PR_QR("%s...\n", f); 9537c478bd9Sstevel@tonic-gate 9547c478bd9Sstevel@tonic-gate srh = dr_get_sr_handle(hp); 9557c478bd9Sstevel@tonic-gate if ((err = dr_suspend(srh)) == DDI_SUCCESS) { 9567c478bd9Sstevel@tonic-gate dr_resume(srh); 9577c478bd9Sstevel@tonic-gate if ((hp->h_err) && ((psmerr = hp->h_err->e_code) != 0)) { 9587c478bd9Sstevel@tonic-gate PR_QR("%s: error on dr_resume()", f); 9597c478bd9Sstevel@tonic-gate switch (psmerr) { 9607c478bd9Sstevel@tonic-gate case ESBD_RESUME: 9617c478bd9Sstevel@tonic-gate PR_QR("Couldn't resume devices: %s\n", 9627c478bd9Sstevel@tonic-gate DR_GET_E_RSC(hp->h_err)); 9637c478bd9Sstevel@tonic-gate break; 9647c478bd9Sstevel@tonic-gate 9657c478bd9Sstevel@tonic-gate case ESBD_KTHREAD: 9667c478bd9Sstevel@tonic-gate PR_ALL("psmerr is ESBD_KTHREAD\n"); 9677c478bd9Sstevel@tonic-gate break; 9687c478bd9Sstevel@tonic-gate default: 9698fc99e42STrevor Thompson PR_ALL("Resume error unknown = %d\n", psmerr); 9707c478bd9Sstevel@tonic-gate break; 9717c478bd9Sstevel@tonic-gate } 9727c478bd9Sstevel@tonic-gate } 9737c478bd9Sstevel@tonic-gate } else { 9748fc99e42STrevor Thompson PR_ALL("%s: dr_suspend() failed, err = 0x%x\n", f, err); 9757c478bd9Sstevel@tonic-gate psmerr = hp->h_err ? hp->h_err->e_code : ESBD_NOERROR; 9767c478bd9Sstevel@tonic-gate switch (psmerr) { 9777c478bd9Sstevel@tonic-gate case ESBD_UNSAFE: 9787c478bd9Sstevel@tonic-gate PR_ALL("Unsafe devices (major #): %s\n", 9797c478bd9Sstevel@tonic-gate DR_GET_E_RSC(hp->h_err)); 9807c478bd9Sstevel@tonic-gate break; 9817c478bd9Sstevel@tonic-gate 9827c478bd9Sstevel@tonic-gate case ESBD_RTTHREAD: 9837c478bd9Sstevel@tonic-gate PR_ALL("RT threads (PIDs): %s\n", 9847c478bd9Sstevel@tonic-gate DR_GET_E_RSC(hp->h_err)); 9857c478bd9Sstevel@tonic-gate break; 9867c478bd9Sstevel@tonic-gate 9877c478bd9Sstevel@tonic-gate case ESBD_UTHREAD: 9887c478bd9Sstevel@tonic-gate PR_ALL("User threads (PIDs): %s\n", 9897c478bd9Sstevel@tonic-gate DR_GET_E_RSC(hp->h_err)); 9907c478bd9Sstevel@tonic-gate break; 9917c478bd9Sstevel@tonic-gate 9927c478bd9Sstevel@tonic-gate case ESBD_SUSPEND: 9937c478bd9Sstevel@tonic-gate PR_ALL("Non-suspendable devices (major #): %s\n", 9947c478bd9Sstevel@tonic-gate DR_GET_E_RSC(hp->h_err)); 9957c478bd9Sstevel@tonic-gate break; 9967c478bd9Sstevel@tonic-gate 9977c478bd9Sstevel@tonic-gate case ESBD_RESUME: 9987c478bd9Sstevel@tonic-gate PR_ALL("Could not resume devices (major #): %s\n", 9997c478bd9Sstevel@tonic-gate DR_GET_E_RSC(hp->h_err)); 10007c478bd9Sstevel@tonic-gate break; 10017c478bd9Sstevel@tonic-gate 10027c478bd9Sstevel@tonic-gate case ESBD_KTHREAD: 10037c478bd9Sstevel@tonic-gate PR_ALL("psmerr is ESBD_KTHREAD\n"); 10047c478bd9Sstevel@tonic-gate break; 10057c478bd9Sstevel@tonic-gate 10067c478bd9Sstevel@tonic-gate case ESBD_NOERROR: 10077c478bd9Sstevel@tonic-gate PR_ALL("sbd_error_t error code not set\n"); 10087c478bd9Sstevel@tonic-gate break; 10097c478bd9Sstevel@tonic-gate 10107c478bd9Sstevel@tonic-gate default: 10117c478bd9Sstevel@tonic-gate PR_ALL("Unknown error psmerr = %d\n", psmerr); 10127c478bd9Sstevel@tonic-gate break; 10137c478bd9Sstevel@tonic-gate } 10147c478bd9Sstevel@tonic-gate } 10157c478bd9Sstevel@tonic-gate dr_release_sr_handle(srh); 10167c478bd9Sstevel@tonic-gate 10177c478bd9Sstevel@tonic-gate return (0); 10187c478bd9Sstevel@tonic-gate } 10197c478bd9Sstevel@tonic-gate 10207c478bd9Sstevel@tonic-gate /* 10217c478bd9Sstevel@tonic-gate * Add a new integer value to the end of an array. Don't allow duplicates to 10227c478bd9Sstevel@tonic-gate * appear in the array, and don't allow the array to overflow. Return the new 10237c478bd9Sstevel@tonic-gate * total number of entries in the array. 10247c478bd9Sstevel@tonic-gate */ 10257c478bd9Sstevel@tonic-gate static int 10267c478bd9Sstevel@tonic-gate dr_add_int(uint64_t *arr, int idx, int len, uint64_t val) 10277c478bd9Sstevel@tonic-gate { 10287c478bd9Sstevel@tonic-gate int i; 10297c478bd9Sstevel@tonic-gate 10307c478bd9Sstevel@tonic-gate if (arr == NULL) 10317c478bd9Sstevel@tonic-gate return (0); 10327c478bd9Sstevel@tonic-gate 10337c478bd9Sstevel@tonic-gate if (idx >= len) 10347c478bd9Sstevel@tonic-gate return (idx); 10357c478bd9Sstevel@tonic-gate 10367c478bd9Sstevel@tonic-gate for (i = 0; i < idx; i++) { 10377c478bd9Sstevel@tonic-gate if (arr[i] == val) 10387c478bd9Sstevel@tonic-gate return (idx); 10397c478bd9Sstevel@tonic-gate } 10407c478bd9Sstevel@tonic-gate 10417c478bd9Sstevel@tonic-gate arr[idx++] = val; 10427c478bd9Sstevel@tonic-gate 10437c478bd9Sstevel@tonic-gate return (idx); 10447c478bd9Sstevel@tonic-gate } 10457c478bd9Sstevel@tonic-gate 10467c478bd9Sstevel@tonic-gate /* 10477c478bd9Sstevel@tonic-gate * Construct an sbd_error_t featuring a string representation of an array of 10487c478bd9Sstevel@tonic-gate * integers as its e_rsc. 10497c478bd9Sstevel@tonic-gate */ 10507c478bd9Sstevel@tonic-gate static sbd_error_t * 10517c478bd9Sstevel@tonic-gate drerr_int(int e_code, uint64_t *arr, int idx, int majors) 10527c478bd9Sstevel@tonic-gate { 10537c478bd9Sstevel@tonic-gate int i, n, buf_len, buf_idx, buf_avail; 10547c478bd9Sstevel@tonic-gate char *dname; 10557c478bd9Sstevel@tonic-gate char *buf; 10567c478bd9Sstevel@tonic-gate sbd_error_t *new_sbd_err; 10577c478bd9Sstevel@tonic-gate static char s_ellipsis[] = "..."; 10587c478bd9Sstevel@tonic-gate 10597c478bd9Sstevel@tonic-gate if (arr == NULL || idx <= 0) 10607c478bd9Sstevel@tonic-gate return (NULL); 10617c478bd9Sstevel@tonic-gate 10627c478bd9Sstevel@tonic-gate /* MAXPATHLEN is the size of the e_rsc field in sbd_error_t. */ 10637c478bd9Sstevel@tonic-gate buf = (char *)kmem_zalloc(MAXPATHLEN, KM_SLEEP); 10647c478bd9Sstevel@tonic-gate 10657c478bd9Sstevel@tonic-gate /* 10667c478bd9Sstevel@tonic-gate * This is the total working area of the buffer. It must be computed 10677c478bd9Sstevel@tonic-gate * as the size of 'buf', minus reserved space for the null terminator 10687c478bd9Sstevel@tonic-gate * and the ellipsis string. 10697c478bd9Sstevel@tonic-gate */ 10707c478bd9Sstevel@tonic-gate buf_len = MAXPATHLEN - (strlen(s_ellipsis) + 1); 10717c478bd9Sstevel@tonic-gate 10727c478bd9Sstevel@tonic-gate /* Construct a string representation of the array values */ 10737c478bd9Sstevel@tonic-gate for (buf_idx = 0, i = 0; i < idx; i++) { 10747c478bd9Sstevel@tonic-gate buf_avail = buf_len - buf_idx; 10757c478bd9Sstevel@tonic-gate if (majors) { 10767c478bd9Sstevel@tonic-gate dname = ddi_major_to_name(arr[i]); 10777c478bd9Sstevel@tonic-gate if (dname) { 10788fc99e42STrevor Thompson n = snprintf(&buf[buf_idx], buf_avail, "%s, ", 10798fc99e42STrevor Thompson dname); 10807c478bd9Sstevel@tonic-gate } else { 10817c478bd9Sstevel@tonic-gate n = snprintf(&buf[buf_idx], buf_avail, 108204580fdfSmathue "major %lu, ", arr[i]); 10837c478bd9Sstevel@tonic-gate } 10847c478bd9Sstevel@tonic-gate } else { 1085df3cd224SVijay S Balakrishna n = snprintf(&buf[buf_idx], buf_avail, "%lu, ", arr[i]); 10867c478bd9Sstevel@tonic-gate } 10877c478bd9Sstevel@tonic-gate 10887c478bd9Sstevel@tonic-gate /* An ellipsis gets appended when no more values fit */ 10897c478bd9Sstevel@tonic-gate if (n >= buf_avail) { 10907c478bd9Sstevel@tonic-gate (void) strcpy(&buf[buf_idx], s_ellipsis); 10917c478bd9Sstevel@tonic-gate break; 10927c478bd9Sstevel@tonic-gate } 10937c478bd9Sstevel@tonic-gate 10947c478bd9Sstevel@tonic-gate buf_idx += n; 10957c478bd9Sstevel@tonic-gate } 10967c478bd9Sstevel@tonic-gate 10977c478bd9Sstevel@tonic-gate /* If all the contents fit, remove the trailing comma */ 10987c478bd9Sstevel@tonic-gate if (n < buf_avail) { 10997c478bd9Sstevel@tonic-gate buf[--buf_idx] = '\0'; 11007c478bd9Sstevel@tonic-gate buf[--buf_idx] = '\0'; 11017c478bd9Sstevel@tonic-gate } 11027c478bd9Sstevel@tonic-gate 11037c478bd9Sstevel@tonic-gate /* Return an sbd_error_t with the buffer and e_code */ 11047c478bd9Sstevel@tonic-gate new_sbd_err = drerr_new(1, e_code, buf); 11057c478bd9Sstevel@tonic-gate kmem_free(buf, MAXPATHLEN); 11067c478bd9Sstevel@tonic-gate return (new_sbd_err); 11077c478bd9Sstevel@tonic-gate } 1108