a31148363f598def767ac48c5d82e1572e44b935Gerry Liu/*
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * CDDL HEADER START
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu *
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * The contents of this file are subject to the terms of the
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * Common Development and Distribution License (the "License").
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * You may not use this file except in compliance with the License.
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu *
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * or http://www.opensolaris.org/os/licensing.
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * See the License for the specific language governing permissions
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * and limitations under the License.
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu *
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * When distributing Covered Code, include this CDDL HEADER in each
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * If applicable, add the following below this CDDL HEADER, with the
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * fields enclosed by brackets "[]" replaced with your own identifying
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * information: Portions Copyright [yyyy] [name of copyright owner]
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu *
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * CDDL HEADER END
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu/*
bec42f4bc1a5f12e6920d2a698474e565b6d68d7Mary Beale * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu/*
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * A CPR derivative specifically for starfire/starcat
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * X86 doesn't make use of the quiesce interfaces, it's kept for simplicity.
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu#include <sys/types.h>
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu#include <sys/systm.h>
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu#include <sys/machparam.h>
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu#include <sys/machsystm.h>
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu#include <sys/ddi.h>
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu#define SUNDDI_IMPL
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu#include <sys/sunddi.h>
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu#include <sys/sunndi.h>
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu#include <sys/devctl.h>
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu#include <sys/time.h>
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu#include <sys/kmem.h>
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu#include <nfs/lm.h>
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu#include <sys/ddi_impldefs.h>
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu#include <sys/ndi_impldefs.h>
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu#include <sys/obpdefs.h>
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu#include <sys/cmn_err.h>
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu#include <sys/debug.h>
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu#include <sys/errno.h>
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu#include <sys/callb.h>
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu#include <sys/clock.h>
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu#include <sys/x_call.h>
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu#include <sys/cpuvar.h>
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu#include <sys/epm.h>
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu#include <sys/vfs.h>
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu#include <sys/promif.h>
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu#include <sys/conf.h>
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu#include <sys/cyclic.h>
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu#include <sys/dr.h>
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu#include <sys/dr_util.h>
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liuextern void e_ddi_enter_driver_list(struct devnames *dnp, int *listcnt);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liuextern void e_ddi_exit_driver_list(struct devnames *dnp, int listcnt);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liuextern int is_pseudo_device(dev_info_t *dip);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liuextern kmutex_t cpu_lock;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liuextern dr_unsafe_devs_t dr_unsafe_devs;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liustatic int dr_is_real_device(dev_info_t *dip);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liustatic int dr_is_unsafe_major(major_t major);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liustatic int dr_bypass_device(char *dname);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liustatic int dr_check_dip(dev_info_t *dip, void *arg, uint_t ref);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liustatic int dr_resolve_devname(dev_info_t *dip, char *buffer,
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu char *alias);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liustatic sbd_error_t *drerr_int(int e_code, uint64_t *arr, int idx,
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu int majors);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liustatic int dr_add_int(uint64_t *arr, int idx, int len,
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu uint64_t val);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liuint dr_pt_test_suspend(dr_handle_t *hp);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu/*
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * dr_quiesce.c interface
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * NOTE: states used internally by dr_suspend and dr_resume
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liutypedef enum dr_suspend_state {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu DR_SRSTATE_BEGIN = 0,
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu DR_SRSTATE_USER,
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu DR_SRSTATE_DRIVER,
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu DR_SRSTATE_FULL
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu} suspend_state_t;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liustruct dr_sr_handle {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu dr_handle_t *sr_dr_handlep;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu dev_info_t *sr_failed_dip;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu suspend_state_t sr_suspend_state;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu uint_t sr_flags;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu uint64_t sr_err_ints[DR_MAX_ERR_INT];
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu int sr_err_idx;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu};
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu#define SR_FLAG_WATCHDOG 0x1
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu/*
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * XXX
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * This hack will go away before RTI. Just for testing.
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * List of drivers to bypass when performing a suspend.
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liustatic char *dr_bypass_list[] = {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu ""
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu};
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu#define SKIP_SYNC /* bypass sync ops in dr_suspend */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu/*
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * dr_skip_user_threads is used to control if user threads should
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * be suspended. If dr_skip_user_threads is true, the rest of the
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * flags are not used; if it is false, dr_check_user_stop_result
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * will be used to control whether or not we need to check suspend
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * result, and dr_allow_blocked_threads will be used to control
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * whether or not we allow suspend to continue if there are blocked
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * threads. We allow all combinations of dr_check_user_stop_result
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * and dr_allow_block_threads, even though it might not make much
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * sense to not allow block threads when we don't even check stop
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * result.
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liustatic int dr_skip_user_threads = 0; /* default to FALSE */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liustatic int dr_check_user_stop_result = 1; /* default to TRUE */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liustatic int dr_allow_blocked_threads = 1; /* default to TRUE */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu#define DR_CPU_LOOP_MSEC 1000
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liustatic void
a31148363f598def767ac48c5d82e1572e44b935Gerry Liudr_stop_intr(void)
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu{
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu ASSERT(MUTEX_HELD(&cpu_lock));
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu kpreempt_disable();
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu cyclic_suspend();
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu}
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liustatic void
a31148363f598def767ac48c5d82e1572e44b935Gerry Liudr_enable_intr(void)
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu{
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu ASSERT(MUTEX_HELD(&cpu_lock));
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu cyclic_resume();
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu kpreempt_enable();
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu}
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liudr_sr_handle_t *
a31148363f598def767ac48c5d82e1572e44b935Gerry Liudr_get_sr_handle(dr_handle_t *hp)
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu{
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu dr_sr_handle_t *srh;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu srh = GETSTRUCT(dr_sr_handle_t, 1);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu srh->sr_dr_handlep = hp;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu return (srh);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu}
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liuvoid
a31148363f598def767ac48c5d82e1572e44b935Gerry Liudr_release_sr_handle(dr_sr_handle_t *srh)
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu{
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu ASSERT(srh->sr_failed_dip == NULL);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu FREESTRUCT(srh, dr_sr_handle_t, 1);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu}
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liustatic int
a31148363f598def767ac48c5d82e1572e44b935Gerry Liudr_is_real_device(dev_info_t *dip)
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu{
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu struct regspec *regbuf = NULL;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu int length = 0;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu int rc;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if (ddi_get_driver(dip) == NULL)
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu return (0);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if (DEVI(dip)->devi_pm_flags & (PMC_NEEDS_SR|PMC_PARENTAL_SR))
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu return (1);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if (DEVI(dip)->devi_pm_flags & PMC_NO_SR)
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu return (0);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu /*
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * now the general case
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu rc = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg",
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu (caddr_t)&regbuf, &length);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu ASSERT(rc != DDI_PROP_NO_MEMORY);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if (rc != DDI_PROP_SUCCESS) {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu return (0);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu } else {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if ((length > 0) && (regbuf != NULL))
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu kmem_free(regbuf, length);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu return (1);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu }
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu}
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liustatic int
a31148363f598def767ac48c5d82e1572e44b935Gerry Liudr_is_unsafe_major(major_t major)
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu{
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu char *dname, **cpp;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu int i, ndevs;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if ((dname = ddi_major_to_name(major)) == NULL) {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu PR_QR("dr_is_unsafe_major: invalid major # %d\n", major);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu return (0);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu }
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu ndevs = dr_unsafe_devs.ndevs;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu for (i = 0, cpp = dr_unsafe_devs.devnames; i < ndevs; i++) {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if (strcmp(dname, *cpp++) == 0)
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu return (1);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu }
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu return (0);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu}
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liustatic int
a31148363f598def767ac48c5d82e1572e44b935Gerry Liudr_bypass_device(char *dname)
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu{
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu int i;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu char **lname;
bec42f4bc1a5f12e6920d2a698474e565b6d68d7Mary Beale
bec42f4bc1a5f12e6920d2a698474e565b6d68d7Mary Beale if (dname == NULL)
bec42f4bc1a5f12e6920d2a698474e565b6d68d7Mary Beale return (0);
bec42f4bc1a5f12e6920d2a698474e565b6d68d7Mary Beale
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu /* check the bypass list */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu for (i = 0, lname = &dr_bypass_list[i]; **lname != '\0'; lname++) {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if (strcmp(dname, dr_bypass_list[i++]) == 0)
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu return (1);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu }
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu return (0);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu}
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liustatic int
a31148363f598def767ac48c5d82e1572e44b935Gerry Liudr_resolve_devname(dev_info_t *dip, char *buffer, char *alias)
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu{
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu major_t devmajor;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu char *aka, *name;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu *buffer = *alias = 0;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if (dip == NULL)
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu return (-1);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if ((name = ddi_get_name(dip)) == NULL)
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu name = "<null name>";
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu aka = name;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if ((devmajor = ddi_name_to_major(aka)) != DDI_MAJOR_T_NONE)
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu aka = ddi_major_to_name(devmajor);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu (void) strcpy(buffer, name);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if (strcmp(name, aka))
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu (void) strcpy(alias, aka);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu else
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu *alias = 0;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu return (0);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu}
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liustruct dr_ref {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu int *refcount;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu int *refcount_non_gldv3;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu uint64_t *arr;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu int *idx;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu int len;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu};
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu/* ARGSUSED */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liustatic int
a31148363f598def767ac48c5d82e1572e44b935Gerry Liudr_check_dip(dev_info_t *dip, void *arg, uint_t ref)
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu{
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu major_t major;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu char *dname;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu struct dr_ref *rp = (struct dr_ref *)arg;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if (dip == NULL)
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu return (DDI_WALK_CONTINUE);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if (!dr_is_real_device(dip))
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu return (DDI_WALK_CONTINUE);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu dname = ddi_binding_name(dip);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if (dr_bypass_device(dname))
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu return (DDI_WALK_CONTINUE);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if (dname && ((major = ddi_name_to_major(dname)) != (major_t)-1)) {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if (ref && rp->refcount) {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu *rp->refcount += ref;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu PR_QR("\n %s (major# %d) is referenced(%u)\n", dname,
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu major, ref);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu }
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if (ref && rp->refcount_non_gldv3) {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if (NETWORK_PHYSDRV(major) && !GLDV3_DRV(major))
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu *rp->refcount_non_gldv3 += ref;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu }
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if (dr_is_unsafe_major(major) && i_ddi_devi_attached(dip)) {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu PR_QR("\n %s (major# %d) not hotpluggable\n", dname,
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu major);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if (rp->arr != NULL && rp->idx != NULL)
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu *rp->idx = dr_add_int(rp->arr, *rp->idx,
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu rp->len, (uint64_t)major);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu }
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu }
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu return (DDI_WALK_CONTINUE);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu}
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liustatic int
a31148363f598def767ac48c5d82e1572e44b935Gerry Liudr_check_unsafe_major(dev_info_t *dip, void *arg)
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu{
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu return (dr_check_dip(dip, arg, 0));
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu}
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu/*ARGSUSED*/
a31148363f598def767ac48c5d82e1572e44b935Gerry Liuvoid
a31148363f598def767ac48c5d82e1572e44b935Gerry Liudr_check_devices(dev_info_t *dip, int *refcount, dr_handle_t *handle,
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu uint64_t *arr, int *idx, int len, int *refcount_non_gldv3)
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu{
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu struct dr_ref bref = {0};
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if (dip == NULL)
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu return;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu bref.refcount = refcount;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu bref.refcount_non_gldv3 = refcount_non_gldv3;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu bref.arr = arr;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu bref.idx = idx;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu bref.len = len;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu ASSERT(e_ddi_branch_held(dip));
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu (void) e_ddi_branch_referenced(dip, dr_check_dip, &bref);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu}
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu/*
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * The "dip" argument's parent (if it exists) must be held busy.
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liustatic int
a31148363f598def767ac48c5d82e1572e44b935Gerry Liudr_suspend_devices(dev_info_t *dip, dr_sr_handle_t *srh)
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu{
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu dr_handle_t *handle;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu major_t major;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu char *dname;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu int circ;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu /*
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * If dip is the root node, it has no siblings and it is
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * always held. If dip is not the root node, dr_suspend_devices()
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * will be invoked with the parent held busy.
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu for (; dip != NULL; dip = ddi_get_next_sibling(dip)) {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu char d_name[40], d_alias[40], *d_info;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu ndi_devi_enter(dip, &circ);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if (dr_suspend_devices(ddi_get_child(dip), srh)) {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu ndi_devi_exit(dip, circ);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu return (ENXIO);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu }
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu ndi_devi_exit(dip, circ);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if (!dr_is_real_device(dip))
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu continue;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu major = (major_t)-1;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if ((dname = ddi_binding_name(dip)) != NULL)
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu major = ddi_name_to_major(dname);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if (dr_bypass_device(dname)) {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu PR_QR(" bypassed suspend of %s (major# %d)\n", dname,
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu major);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu continue;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu }
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if (drmach_verify_sr(dip, 1)) {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu PR_QR(" bypassed suspend of %s (major# %d)\n", dname,
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu major);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu continue;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu }
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if ((d_info = ddi_get_name_addr(dip)) == NULL)
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu d_info = "<null>";
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu d_name[0] = 0;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if (dr_resolve_devname(dip, d_name, d_alias) == 0) {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if (d_alias[0] != 0) {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu prom_printf("\tsuspending %s@%s (aka %s)\n",
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu d_name, d_info, d_alias);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu } else {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu prom_printf("\tsuspending %s@%s\n", d_name,
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu d_info);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu }
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu } else {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu prom_printf("\tsuspending %s@%s\n", dname, d_info);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu }
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if (devi_detach(dip, DDI_SUSPEND) != DDI_SUCCESS) {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu prom_printf("\tFAILED to suspend %s@%s\n",
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu d_name[0] ? d_name : dname, d_info);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu srh->sr_err_idx = dr_add_int(srh->sr_err_ints,
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu srh->sr_err_idx, DR_MAX_ERR_INT, (uint64_t)major);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu ndi_hold_devi(dip);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu srh->sr_failed_dip = dip;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu handle = srh->sr_dr_handlep;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu dr_op_err(CE_IGNORE, handle, ESBD_SUSPEND, "%s@%s",
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu d_name[0] ? d_name : dname, d_info);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu return (DDI_FAILURE);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu }
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu }
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu return (DDI_SUCCESS);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu}
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liustatic void
a31148363f598def767ac48c5d82e1572e44b935Gerry Liudr_resume_devices(dev_info_t *start, dr_sr_handle_t *srh)
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu{
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu dr_handle_t *handle;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu dev_info_t *dip, *next, *last = NULL;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu major_t major;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu char *bn;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu int circ;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu major = (major_t)-1;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu /* attach in reverse device tree order */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu while (last != start) {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu dip = start;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu next = ddi_get_next_sibling(dip);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu while (next != last && dip != srh->sr_failed_dip) {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu dip = next;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu next = ddi_get_next_sibling(dip);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu }
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if (dip == srh->sr_failed_dip) {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu /* release hold acquired in dr_suspend_devices() */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu srh->sr_failed_dip = NULL;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu ndi_rele_devi(dip);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu } else if (dr_is_real_device(dip) &&
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu srh->sr_failed_dip == NULL) {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if ((bn = ddi_binding_name(dip)) != NULL) {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu major = ddi_name_to_major(bn);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu } else {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu bn = "<null>";
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu }
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if (!dr_bypass_device(bn) &&
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu !drmach_verify_sr(dip, 0)) {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu char d_name[40], d_alias[40], *d_info;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu d_name[0] = 0;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu d_info = ddi_get_name_addr(dip);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if (d_info == NULL)
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu d_info = "<null>";
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if (!dr_resolve_devname(dip, d_name, d_alias)) {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if (d_alias[0] != 0) {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu prom_printf("\tresuming "
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu "%s@%s (aka %s)\n", d_name,
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu d_info, d_alias);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu } else {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu prom_printf("\tresuming "
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu "%s@%s\n", d_name, d_info);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu }
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu } else {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu prom_printf("\tresuming %s@%s\n", bn,
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu d_info);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu }
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if (devi_attach(dip, DDI_RESUME) !=
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu DDI_SUCCESS) {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu /*
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * Print a console warning,
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * set an e_code of ESBD_RESUME,
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * and save the driver major
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * number in the e_rsc.
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu prom_printf("\tFAILED to resume %s@%s",
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu d_name[0] ? d_name : bn, d_info);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu srh->sr_err_idx =
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu dr_add_int(srh->sr_err_ints,
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu srh->sr_err_idx, DR_MAX_ERR_INT,
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu (uint64_t)major);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu handle = srh->sr_dr_handlep;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu dr_op_err(CE_IGNORE, handle,
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu ESBD_RESUME, "%s@%s",
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu d_name[0] ? d_name : bn, d_info);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu }
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu }
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu }
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu /* Hold parent busy while walking its children */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu ndi_devi_enter(dip, &circ);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu dr_resume_devices(ddi_get_child(dip), srh);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu ndi_devi_exit(dip, circ);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu last = dip;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu }
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu}
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu/*
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * True if thread is virtually stopped. Similar to CPR_VSTOPPED
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * but from DR point of view. These user threads are waiting in
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * the kernel. Once they complete in the kernel, they will process
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * the stop signal and stop.
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu#define DR_VSTOPPED(t) \
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu ((t)->t_state == TS_SLEEP && \
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu (t)->t_wchan != NULL && \
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu (t)->t_astflag && \
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu ((t)->t_proc_flag & TP_CHKPT))
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu/* ARGSUSED */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liustatic int
a31148363f598def767ac48c5d82e1572e44b935Gerry Liudr_stop_user_threads(dr_sr_handle_t *srh)
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu{
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu int count;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu int bailout;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu dr_handle_t *handle = srh->sr_dr_handlep;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu static fn_t f = "dr_stop_user_threads";
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu kthread_id_t tp;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu extern void add_one_utstop();
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu extern void utstop_timedwait(clock_t);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu extern void utstop_init(void);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu#define DR_UTSTOP_RETRY 4
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu#define DR_UTSTOP_WAIT hz
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if (dr_skip_user_threads)
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu return (DDI_SUCCESS);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu utstop_init();
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu /* we need to try a few times to get past fork, etc. */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu srh->sr_err_idx = 0;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu for (count = 0; count < DR_UTSTOP_RETRY; count++) {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu /* walk the entire threadlist */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu mutex_enter(&pidlock);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu for (tp = curthread->t_next; tp != curthread; tp = tp->t_next) {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu proc_t *p = ttoproc(tp);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu /* handle kernel threads separately */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if (p->p_as == &kas || p->p_stat == SZOMB)
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu continue;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu mutex_enter(&p->p_lock);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu thread_lock(tp);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if (tp->t_state == TS_STOPPED) {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu /* add another reason to stop this thread */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu tp->t_schedflag &= ~TS_RESUME;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu } else {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu tp->t_proc_flag |= TP_CHKPT;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu thread_unlock(tp);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu mutex_exit(&p->p_lock);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu add_one_utstop();
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu mutex_enter(&p->p_lock);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu thread_lock(tp);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu aston(tp);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if (ISWAKEABLE(tp) || ISWAITING(tp)) {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu setrun_locked(tp);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu }
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu }
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu /* grab thread if needed */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if (tp->t_state == TS_ONPROC && tp->t_cpu != CPU)
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu poke_cpu(tp->t_cpu->cpu_id);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu thread_unlock(tp);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu mutex_exit(&p->p_lock);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu }
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu mutex_exit(&pidlock);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu /* let everything catch up */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu utstop_timedwait(count * count * DR_UTSTOP_WAIT);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu /* now, walk the threadlist again to see if we are done */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu mutex_enter(&pidlock);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu for (tp = curthread->t_next, bailout = 0;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu tp != curthread; tp = tp->t_next) {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu proc_t *p = ttoproc(tp);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu /* handle kernel threads separately */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if (p->p_as == &kas || p->p_stat == SZOMB)
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu continue;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu /*
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * If this thread didn't stop, and we don't allow
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * unstopped blocked threads, bail.
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu thread_lock(tp);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if (!CPR_ISTOPPED(tp) &&
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu !(dr_allow_blocked_threads &&
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu DR_VSTOPPED(tp))) {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu bailout = 1;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if (count == DR_UTSTOP_RETRY - 1) {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu /*
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * save the pid for later reporting
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu srh->sr_err_idx =
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu dr_add_int(srh->sr_err_ints,
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu srh->sr_err_idx, DR_MAX_ERR_INT,
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu (uint64_t)p->p_pid);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu cmn_err(CE_WARN, "%s: "
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu "failed to stop thread: "
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu "process=%s, pid=%d",
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu f, p->p_user.u_psargs, p->p_pid);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu PR_QR("%s: failed to stop thread: "
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu "process=%s, pid=%d, t_id=0x%p, "
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu "t_state=0x%x, t_proc_flag=0x%x, "
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu "t_schedflag=0x%x\n",
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu f, p->p_user.u_psargs, p->p_pid,
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu (void *)tp, tp->t_state,
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu tp->t_proc_flag, tp->t_schedflag);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu }
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu }
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu thread_unlock(tp);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu }
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu mutex_exit(&pidlock);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu /* were all the threads stopped? */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if (!bailout)
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu break;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu }
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu /* were we unable to stop all threads after a few tries? */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if (bailout) {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu handle->h_err = drerr_int(ESBD_UTHREAD, srh->sr_err_ints,
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu srh->sr_err_idx, 0);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu return (ESRCH);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu }
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu return (DDI_SUCCESS);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu}
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liustatic void
a31148363f598def767ac48c5d82e1572e44b935Gerry Liudr_start_user_threads(void)
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu{
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu kthread_id_t tp;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu mutex_enter(&pidlock);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu /* walk all threads and release them */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu for (tp = curthread->t_next; tp != curthread; tp = tp->t_next) {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu proc_t *p = ttoproc(tp);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu /* skip kernel threads */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if (ttoproc(tp)->p_as == &kas)
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu continue;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu mutex_enter(&p->p_lock);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu tp->t_proc_flag &= ~TP_CHKPT;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu mutex_exit(&p->p_lock);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu thread_lock(tp);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if (CPR_ISTOPPED(tp)) {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu /* back on the runq */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu tp->t_schedflag |= TS_RESUME;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu setrun_locked(tp);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu }
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu thread_unlock(tp);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu }
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu mutex_exit(&pidlock);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu}
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liustatic void
a31148363f598def767ac48c5d82e1572e44b935Gerry Liudr_signal_user(int sig)
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu{
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu struct proc *p;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu mutex_enter(&pidlock);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu for (p = practive; p != NULL; p = p->p_next) {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu /* only user threads */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if (p->p_exec == NULL || p->p_stat == SZOMB ||
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu p == proc_init || p == ttoproc(curthread))
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu continue;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu mutex_enter(&p->p_lock);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu sigtoproc(p, NULL, sig);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu mutex_exit(&p->p_lock);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu }
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu mutex_exit(&pidlock);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu /* add a bit of delay */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu delay(hz);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu}
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liuvoid
a31148363f598def767ac48c5d82e1572e44b935Gerry Liudr_resume(dr_sr_handle_t *srh)
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu{
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu switch (srh->sr_suspend_state) {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu case DR_SRSTATE_FULL:
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu ASSERT(MUTEX_HELD(&cpu_lock));
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu /*
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * Prevent false alarm in tod_validate() due to tod
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * value change between suspend and resume
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu mutex_enter(&tod_lock);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu tod_status_set(TOD_DR_RESUME_DONE);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu mutex_exit(&tod_lock);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu dr_enable_intr(); /* enable intr & clock */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu start_cpus();
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu mutex_exit(&cpu_lock);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu /*
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * This should only be called if drmach_suspend_last()
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * was called and state transitioned to DR_SRSTATE_FULL
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * to prevent resume attempts on device instances that
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * were not previously suspended.
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu drmach_resume_first();
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu /* FALLTHROUGH */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu case DR_SRSTATE_DRIVER:
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu /*
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * resume drivers
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu srh->sr_err_idx = 0;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu /* no parent dip to hold busy */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu dr_resume_devices(ddi_root_node(), srh);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if (srh->sr_err_idx && srh->sr_dr_handlep) {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu (srh->sr_dr_handlep)->h_err = drerr_int(ESBD_RESUME,
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu srh->sr_err_ints, srh->sr_err_idx, 1);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu }
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu /*
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * resume the lock manager
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu lm_cprresume();
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu /* FALLTHROUGH */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu case DR_SRSTATE_USER:
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu /*
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * finally, resume user threads
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if (!dr_skip_user_threads) {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu prom_printf("DR: resuming user threads...\n");
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu dr_start_user_threads();
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu }
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu /* FALLTHROUGH */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu case DR_SRSTATE_BEGIN:
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu default:
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu /*
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * let those who care know that we've just resumed
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu PR_QR("sending SIGTHAW...\n");
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu dr_signal_user(SIGTHAW);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu break;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu }
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu prom_printf("DR: resume COMPLETED\n");
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu}
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liuint
a31148363f598def767ac48c5d82e1572e44b935Gerry Liudr_suspend(dr_sr_handle_t *srh)
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu{
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu dr_handle_t *handle;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu int force;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu int dev_errs_idx;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu uint64_t dev_errs[DR_MAX_ERR_INT];
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu int rc = DDI_SUCCESS;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu handle = srh->sr_dr_handlep;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu force = dr_cmd_flags(handle) & SBD_FLAG_FORCE;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu prom_printf("\nDR: suspending user threads...\n");
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu srh->sr_suspend_state = DR_SRSTATE_USER;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if (((rc = dr_stop_user_threads(srh)) != DDI_SUCCESS) &&
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu dr_check_user_stop_result) {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu dr_resume(srh);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu return (rc);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu }
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if (!force) {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu struct dr_ref drc = {0};
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu prom_printf("\nDR: checking devices...\n");
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu dev_errs_idx = 0;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu drc.arr = dev_errs;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu drc.idx = &dev_errs_idx;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu drc.len = DR_MAX_ERR_INT;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu /*
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * Since the root node can never go away, it
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * doesn't have to be held.
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu ddi_walk_devs(ddi_root_node(), dr_check_unsafe_major, &drc);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if (dev_errs_idx) {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu handle->h_err = drerr_int(ESBD_UNSAFE, dev_errs,
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu dev_errs_idx, 1);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu dr_resume(srh);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu return (DDI_FAILURE);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu }
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu PR_QR("done\n");
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu } else {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu prom_printf("\nDR: dr_suspend invoked with force flag\n");
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu }
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu#ifndef SKIP_SYNC
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu /*
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * This sync swap out all user pages
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu vfs_sync(SYNC_ALL);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu#endif
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu /*
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * special treatment for lock manager
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu lm_cprsuspend();
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu#ifndef SKIP_SYNC
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu /*
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * sync the file system in case we never make it back
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu sync();
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu#endif
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu /*
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * now suspend drivers
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu prom_printf("DR: suspending drivers...\n");
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu srh->sr_suspend_state = DR_SRSTATE_DRIVER;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu srh->sr_err_idx = 0;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu /* No parent to hold busy */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if ((rc = dr_suspend_devices(ddi_root_node(), srh)) != DDI_SUCCESS) {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if (srh->sr_err_idx && srh->sr_dr_handlep) {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu (srh->sr_dr_handlep)->h_err = drerr_int(ESBD_SUSPEND,
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu srh->sr_err_ints, srh->sr_err_idx, 1);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu }
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu dr_resume(srh);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu return (rc);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu }
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu drmach_suspend_last();
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu /*
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * finally, grab all cpus
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu srh->sr_suspend_state = DR_SRSTATE_FULL;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu mutex_enter(&cpu_lock);
0ed5c46e82c989cfa9726d9dae452e3d24ef83beJosef 'Jeff' Sipek pause_cpus(NULL, NULL);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu dr_stop_intr();
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu return (rc);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu}
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liuint
a31148363f598def767ac48c5d82e1572e44b935Gerry Liudr_pt_test_suspend(dr_handle_t *hp)
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu{
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu dr_sr_handle_t *srh;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu int err;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu uint_t psmerr;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu static fn_t f = "dr_pt_test_suspend";
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu PR_QR("%s...\n", f);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu srh = dr_get_sr_handle(hp);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if ((err = dr_suspend(srh)) == DDI_SUCCESS) {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu dr_resume(srh);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if ((hp->h_err) && ((psmerr = hp->h_err->e_code) != 0)) {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu PR_QR("%s: error on dr_resume()", f);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu switch (psmerr) {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu case ESBD_RESUME:
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu PR_QR("Couldn't resume devices: %s\n",
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu DR_GET_E_RSC(hp->h_err));
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu break;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu case ESBD_KTHREAD:
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu PR_ALL("psmerr is ESBD_KTHREAD\n");
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu break;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu default:
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu PR_ALL("Resume error unknown = %d\n", psmerr);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu break;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu }
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu }
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu } else {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu PR_ALL("%s: dr_suspend() failed, err = 0x%x\n", f, err);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu psmerr = hp->h_err ? hp->h_err->e_code : ESBD_NOERROR;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu switch (psmerr) {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu case ESBD_UNSAFE:
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu PR_ALL("Unsafe devices (major #): %s\n",
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu DR_GET_E_RSC(hp->h_err));
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu break;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu case ESBD_RTTHREAD:
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu PR_ALL("RT threads (PIDs): %s\n",
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu DR_GET_E_RSC(hp->h_err));
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu break;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu case ESBD_UTHREAD:
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu PR_ALL("User threads (PIDs): %s\n",
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu DR_GET_E_RSC(hp->h_err));
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu break;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu case ESBD_SUSPEND:
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu PR_ALL("Non-suspendable devices (major #): %s\n",
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu DR_GET_E_RSC(hp->h_err));
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu break;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu case ESBD_RESUME:
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu PR_ALL("Could not resume devices (major #): %s\n",
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu DR_GET_E_RSC(hp->h_err));
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu break;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu case ESBD_KTHREAD:
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu PR_ALL("psmerr is ESBD_KTHREAD\n");
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu break;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu case ESBD_NOERROR:
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu PR_ALL("sbd_error_t error code not set\n");
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu break;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu default:
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu PR_ALL("Unknown error psmerr = %d\n", psmerr);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu break;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu }
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu }
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu dr_release_sr_handle(srh);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu return (0);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu}
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu/*
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * Add a new integer value to the end of an array. Don't allow duplicates to
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * appear in the array, and don't allow the array to overflow. Return the new
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * total number of entries in the array.
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liustatic int
a31148363f598def767ac48c5d82e1572e44b935Gerry Liudr_add_int(uint64_t *arr, int idx, int len, uint64_t val)
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu{
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu int i;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if (arr == NULL)
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu return (0);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if (idx >= len)
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu return (idx);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu for (i = 0; i < idx; i++) {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if (arr[i] == val)
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu return (idx);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu }
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu arr[idx++] = val;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu return (idx);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu}
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu/*
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * Construct an sbd_error_t featuring a string representation of an array of
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * integers as its e_rsc.
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liustatic sbd_error_t *
a31148363f598def767ac48c5d82e1572e44b935Gerry Liudrerr_int(int e_code, uint64_t *arr, int idx, int majors)
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu{
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu int i, n, buf_len, buf_idx, buf_avail;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu char *dname;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu char *buf;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu sbd_error_t *new_sbd_err;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu static char s_ellipsis[] = "...";
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if (arr == NULL || idx <= 0)
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu return (NULL);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu /* MAXPATHLEN is the size of the e_rsc field in sbd_error_t. */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu buf = (char *)kmem_zalloc(MAXPATHLEN, KM_SLEEP);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu /*
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * This is the total working area of the buffer. It must be computed
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * as the size of 'buf', minus reserved space for the null terminator
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * and the ellipsis string.
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu buf_len = MAXPATHLEN - (strlen(s_ellipsis) + 1);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu /* Construct a string representation of the array values */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu for (buf_idx = 0, i = 0; i < idx; i++) {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu buf_avail = buf_len - buf_idx;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if (majors) {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu dname = ddi_major_to_name(arr[i]);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if (dname) {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu n = snprintf(&buf[buf_idx], buf_avail, "%s, ",
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu dname);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu } else {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu n = snprintf(&buf[buf_idx], buf_avail,
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu "major %" PRIu64 ", ", arr[i]);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu }
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu } else {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu n = snprintf(&buf[buf_idx], buf_avail, "%" PRIu64 ", ",
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu arr[i]);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu }
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu /* An ellipsis gets appended when no more values fit */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if (n >= buf_avail) {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu (void) strcpy(&buf[buf_idx], s_ellipsis);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu break;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu }
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu buf_idx += n;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu }
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu /* If all the contents fit, remove the trailing comma */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if (n < buf_avail) {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu buf[--buf_idx] = '\0';
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu buf[--buf_idx] = '\0';
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu }
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu /* Return an sbd_error_t with the buffer and e_code */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu new_sbd_err = drerr_new(1, e_code, buf);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu kmem_free(buf, MAXPATHLEN);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu return (new_sbd_err);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu}