xref: /titanic_52/usr/src/uts/sun4u/ngdr/io/dr_cpu.c (revision 07d06da50d310a325b457d6330165aebab1e0064)
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
525cf1a30Sjl139090  * Common Development and Distribution License (the "License").
625cf1a30Sjl139090  * 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  */
21*07d06da5SSurya Prakki 
227c478bd9Sstevel@tonic-gate /*
23*07d06da5SSurya Prakki  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate /*
287c478bd9Sstevel@tonic-gate  * CPU support routines for DR
297c478bd9Sstevel@tonic-gate  */
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate #include <sys/note.h>
327c478bd9Sstevel@tonic-gate #include <sys/debug.h>
337c478bd9Sstevel@tonic-gate #include <sys/types.h>
347c478bd9Sstevel@tonic-gate #include <sys/errno.h>
357c478bd9Sstevel@tonic-gate #include <sys/cred.h>
367c478bd9Sstevel@tonic-gate #include <sys/dditypes.h>
377c478bd9Sstevel@tonic-gate #include <sys/devops.h>
387c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
397c478bd9Sstevel@tonic-gate #include <sys/poll.h>
407c478bd9Sstevel@tonic-gate #include <sys/conf.h>
417c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
427c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
437c478bd9Sstevel@tonic-gate #include <sys/sunndi.h>
447c478bd9Sstevel@tonic-gate #include <sys/ndi_impldefs.h>
457c478bd9Sstevel@tonic-gate #include <sys/stat.h>
467c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
477c478bd9Sstevel@tonic-gate #include <sys/processor.h>
487c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h>
497c478bd9Sstevel@tonic-gate #include <sys/mem_config.h>
507c478bd9Sstevel@tonic-gate #include <sys/promif.h>
517c478bd9Sstevel@tonic-gate #include <sys/x_call.h>
527c478bd9Sstevel@tonic-gate #include <sys/cpu_sgnblk_defs.h>
537c478bd9Sstevel@tonic-gate #include <sys/membar.h>
547c478bd9Sstevel@tonic-gate #include <sys/stack.h>
557c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
567c478bd9Sstevel@tonic-gate #include <sys/machsystm.h>
577c478bd9Sstevel@tonic-gate #include <sys/spitregs.h>
587c478bd9Sstevel@tonic-gate 
597c478bd9Sstevel@tonic-gate #include <sys/archsystm.h>
607c478bd9Sstevel@tonic-gate #include <vm/hat_sfmmu.h>
617c478bd9Sstevel@tonic-gate #include <sys/pte.h>
627c478bd9Sstevel@tonic-gate #include <sys/mmu.h>
637c478bd9Sstevel@tonic-gate #include <sys/x_call.h>
647c478bd9Sstevel@tonic-gate #include <sys/cpu_module.h>
6525cf1a30Sjl139090 #include <sys/cpu_impl.h>
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate #include <sys/autoconf.h>
687c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate #include <sys/dr.h>
717c478bd9Sstevel@tonic-gate #include <sys/dr_util.h>
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate #ifdef _STARFIRE
747c478bd9Sstevel@tonic-gate #include <sys/starfire.h>
757c478bd9Sstevel@tonic-gate extern struct cpu	*SIGBCPU;
767c478bd9Sstevel@tonic-gate #else
777c478bd9Sstevel@tonic-gate /* for the DR*INTERNAL_ERROR macros.  see sys/dr.h. */
787c478bd9Sstevel@tonic-gate static char *dr_ie_fmt = "dr_cpu.c %d";
797c478bd9Sstevel@tonic-gate #endif /* _STARFIRE */
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate int
827c478bd9Sstevel@tonic-gate dr_cpu_unit_is_sane(dr_board_t *bp, dr_cpu_unit_t *cp)
837c478bd9Sstevel@tonic-gate {
847c478bd9Sstevel@tonic-gate #ifdef DEBUG
857c478bd9Sstevel@tonic-gate 	processorid_t	cpuid;
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate 	/*
887c478bd9Sstevel@tonic-gate 	 * cpuid and unit number should never be different
897c478bd9Sstevel@tonic-gate 	 * than they were at discovery/connect time
907c478bd9Sstevel@tonic-gate 	 */
917c478bd9Sstevel@tonic-gate 	ASSERT(drmach_cpu_get_id(cp->sbc_cm.sbdev_id, &cpuid) == 0);
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate 	ASSERT(cp->sbc_cm.sbdev_bp == bp);
947c478bd9Sstevel@tonic-gate 	ASSERT(cp->sbc_cm.sbdev_type == SBD_COMP_CPU);
957c478bd9Sstevel@tonic-gate 	ASSERT(cp->sbc_cpu_id == cpuid);
967c478bd9Sstevel@tonic-gate #else
977c478bd9Sstevel@tonic-gate 	_NOTE(ARGUNUSED(bp))
987c478bd9Sstevel@tonic-gate 	_NOTE(ARGUNUSED(cp))
997c478bd9Sstevel@tonic-gate #endif
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate 	return (1);
1027c478bd9Sstevel@tonic-gate }
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate static int
1057c478bd9Sstevel@tonic-gate dr_errno2ecode(int error)
1067c478bd9Sstevel@tonic-gate {
1077c478bd9Sstevel@tonic-gate 	int	rv;
1087c478bd9Sstevel@tonic-gate 
1097c478bd9Sstevel@tonic-gate 	switch (error) {
1107c478bd9Sstevel@tonic-gate 	case EBUSY:
1117c478bd9Sstevel@tonic-gate 		rv = ESBD_BUSY;
1127c478bd9Sstevel@tonic-gate 		break;
1137c478bd9Sstevel@tonic-gate 	case EINVAL:
1147c478bd9Sstevel@tonic-gate 		rv = ESBD_INVAL;
1157c478bd9Sstevel@tonic-gate 		break;
1167c478bd9Sstevel@tonic-gate 	case EALREADY:
1177c478bd9Sstevel@tonic-gate 		rv = ESBD_ALREADY;
1187c478bd9Sstevel@tonic-gate 		break;
1197c478bd9Sstevel@tonic-gate 	case ENODEV:
1207c478bd9Sstevel@tonic-gate 		rv = ESBD_NODEV;
1217c478bd9Sstevel@tonic-gate 		break;
1227c478bd9Sstevel@tonic-gate 	case ENOMEM:
1237c478bd9Sstevel@tonic-gate 		rv = ESBD_NOMEM;
1247c478bd9Sstevel@tonic-gate 		break;
1257c478bd9Sstevel@tonic-gate 	default:
1267c478bd9Sstevel@tonic-gate 		rv = ESBD_INVAL;
1277c478bd9Sstevel@tonic-gate 	}
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate 	return (rv);
1307c478bd9Sstevel@tonic-gate }
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate static void
1337c478bd9Sstevel@tonic-gate dr_cpu_set_prop(dr_cpu_unit_t *cp)
1347c478bd9Sstevel@tonic-gate {
1357c478bd9Sstevel@tonic-gate 	sbd_error_t	*err;
1367c478bd9Sstevel@tonic-gate 	dev_info_t	*dip;
1377c478bd9Sstevel@tonic-gate 	uint64_t	clock_freq;
1387c478bd9Sstevel@tonic-gate 	int		ecache_size = 0;
1397c478bd9Sstevel@tonic-gate 	char		*cache_str = NULL;
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate 	err = drmach_get_dip(cp->sbc_cm.sbdev_id, &dip);
1427c478bd9Sstevel@tonic-gate 	if (err) {
1437c478bd9Sstevel@tonic-gate 		DRERR_SET_C(&cp->sbc_cm.sbdev_error, &err);
1447c478bd9Sstevel@tonic-gate 		return;
1457c478bd9Sstevel@tonic-gate 	}
1467c478bd9Sstevel@tonic-gate 
1477c478bd9Sstevel@tonic-gate 	if (dip == NULL) {
1487c478bd9Sstevel@tonic-gate #ifndef _STARFIRE
1497c478bd9Sstevel@tonic-gate 		/*
1507c478bd9Sstevel@tonic-gate 		 * Do not report an error on Starfire since
1517c478bd9Sstevel@tonic-gate 		 * the dip will not be created until after
1527c478bd9Sstevel@tonic-gate 		 * the CPU has been configured.
1537c478bd9Sstevel@tonic-gate 		 */
1547c478bd9Sstevel@tonic-gate 		DR_DEV_INTERNAL_ERROR(&cp->sbc_cm);
1557c478bd9Sstevel@tonic-gate #endif /* !_STARFIRE */
1567c478bd9Sstevel@tonic-gate 		return;
1577c478bd9Sstevel@tonic-gate 	}
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate 	/* read in the CPU speed */
16025cf1a30Sjl139090 
16125cf1a30Sjl139090 	/*
16225cf1a30Sjl139090 	 * If the property is not found in the CPU node, it has to be
16325cf1a30Sjl139090 	 * kept in the core or cmp node so we just keep looking.
16425cf1a30Sjl139090 	 */
165e98fafb9Sjl139090 	clock_freq = (unsigned int)ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
166e98fafb9Sjl139090 	    "clock-frequency", 0);
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate 	ASSERT(clock_freq != 0);
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate 	/*
1717c478bd9Sstevel@tonic-gate 	 * The ecache property string is not the same
1727c478bd9Sstevel@tonic-gate 	 * for all CPU implementations.
1737c478bd9Sstevel@tonic-gate 	 */
17425cf1a30Sjl139090 
1757c478bd9Sstevel@tonic-gate 	switch (cp->sbc_cpu_impl) {
1767c478bd9Sstevel@tonic-gate 	case BLACKBIRD_IMPL:
1777c478bd9Sstevel@tonic-gate 	case CHEETAH_IMPL:
1787c478bd9Sstevel@tonic-gate 	case CHEETAH_PLUS_IMPL:
1797c478bd9Sstevel@tonic-gate 		cache_str = "ecache-size";
1807c478bd9Sstevel@tonic-gate 		break;
1817c478bd9Sstevel@tonic-gate 	case JAGUAR_IMPL:
18225cf1a30Sjl139090 	case OLYMPUS_C_IMPL:
183e98fafb9Sjl139090 	case JUPITER_IMPL:
1847c478bd9Sstevel@tonic-gate 		cache_str = "l2-cache-size";
1857c478bd9Sstevel@tonic-gate 		break;
1867c478bd9Sstevel@tonic-gate 	case PANTHER_IMPL:
1877c478bd9Sstevel@tonic-gate 		cache_str = "l3-cache-size";
1887c478bd9Sstevel@tonic-gate 		break;
1897c478bd9Sstevel@tonic-gate 	default:
1907c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "Unknown cpu implementation=0x%x",
1917c478bd9Sstevel@tonic-gate 		    cp->sbc_cpu_impl);
1927c478bd9Sstevel@tonic-gate 		ASSERT(0);
1937c478bd9Sstevel@tonic-gate 		break;
1947c478bd9Sstevel@tonic-gate 	}
1957c478bd9Sstevel@tonic-gate 
1967c478bd9Sstevel@tonic-gate 	if (cache_str != NULL) {
1977c478bd9Sstevel@tonic-gate 		/* read in the ecache size */
19825cf1a30Sjl139090 		/*
19925cf1a30Sjl139090 		 * If the property is not found in the CPU node,
20025cf1a30Sjl139090 		 * it has to be kept in the core or cmp node so
20125cf1a30Sjl139090 		 * we just keep looking.
20225cf1a30Sjl139090 		 */
20325cf1a30Sjl139090 
204e98fafb9Sjl139090 		ecache_size = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
205e98fafb9Sjl139090 		    cache_str, 0);
2067c478bd9Sstevel@tonic-gate 	}
2077c478bd9Sstevel@tonic-gate 
2087c478bd9Sstevel@tonic-gate 	ASSERT(ecache_size != 0);
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate 	/* convert to the proper units */
2117c478bd9Sstevel@tonic-gate 	cp->sbc_speed = (clock_freq + 500000) / 1000000;
2127c478bd9Sstevel@tonic-gate 	cp->sbc_ecache = ecache_size / (1024 * 1024);
2137c478bd9Sstevel@tonic-gate }
2147c478bd9Sstevel@tonic-gate 
2157c478bd9Sstevel@tonic-gate void
2167c478bd9Sstevel@tonic-gate dr_init_cpu_unit(dr_cpu_unit_t *cp)
2177c478bd9Sstevel@tonic-gate {
2187c478bd9Sstevel@tonic-gate 	sbd_error_t	*err;
2197c478bd9Sstevel@tonic-gate 	dr_state_t	new_state;
2207c478bd9Sstevel@tonic-gate 	int		cpuid;
2217c478bd9Sstevel@tonic-gate 	int		impl;
2227c478bd9Sstevel@tonic-gate 
2237c478bd9Sstevel@tonic-gate 	if (DR_DEV_IS_ATTACHED(&cp->sbc_cm)) {
2247c478bd9Sstevel@tonic-gate 		new_state = DR_STATE_CONFIGURED;
2257c478bd9Sstevel@tonic-gate 		cp->sbc_cm.sbdev_cond = SBD_COND_OK;
2267c478bd9Sstevel@tonic-gate 	} else if (DR_DEV_IS_PRESENT(&cp->sbc_cm)) {
2277c478bd9Sstevel@tonic-gate 		new_state = DR_STATE_CONNECTED;
2287c478bd9Sstevel@tonic-gate 		cp->sbc_cm.sbdev_cond = SBD_COND_OK;
2297c478bd9Sstevel@tonic-gate 	} else {
2307c478bd9Sstevel@tonic-gate 		new_state = DR_STATE_EMPTY;
2317c478bd9Sstevel@tonic-gate 		cp->sbc_cm.sbdev_cond = SBD_COND_UNKNOWN;
2327c478bd9Sstevel@tonic-gate 	}
2337c478bd9Sstevel@tonic-gate 
2347c478bd9Sstevel@tonic-gate 	if (DR_DEV_IS_PRESENT(&cp->sbc_cm)) {
2357c478bd9Sstevel@tonic-gate 		err = drmach_cpu_get_id(cp->sbc_cm.sbdev_id, &cpuid);
2367c478bd9Sstevel@tonic-gate 		if (err) {
2377c478bd9Sstevel@tonic-gate 			DRERR_SET_C(&cp->sbc_cm.sbdev_error, &err);
2387c478bd9Sstevel@tonic-gate 			new_state = DR_STATE_FATAL;
2397c478bd9Sstevel@tonic-gate 			goto done;
2407c478bd9Sstevel@tonic-gate 		}
2417c478bd9Sstevel@tonic-gate 
2427c478bd9Sstevel@tonic-gate 		err = drmach_cpu_get_impl(cp->sbc_cm.sbdev_id, &impl);
2437c478bd9Sstevel@tonic-gate 		if (err) {
2447c478bd9Sstevel@tonic-gate 			DRERR_SET_C(&cp->sbc_cm.sbdev_error, &err);
2457c478bd9Sstevel@tonic-gate 			new_state = DR_STATE_FATAL;
2467c478bd9Sstevel@tonic-gate 			goto done;
2477c478bd9Sstevel@tonic-gate 		}
2487c478bd9Sstevel@tonic-gate 	} else {
2497c478bd9Sstevel@tonic-gate 		cp->sbc_cpu_id = -1;
2507c478bd9Sstevel@tonic-gate 		cp->sbc_cpu_impl = -1;
2517c478bd9Sstevel@tonic-gate 		goto done;
2527c478bd9Sstevel@tonic-gate 	}
2537c478bd9Sstevel@tonic-gate 
2547c478bd9Sstevel@tonic-gate 	cp->sbc_cpu_id = cpuid;
2557c478bd9Sstevel@tonic-gate 	cp->sbc_cpu_impl = impl;
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate 	/* if true at init time, it must always be true */
2587c478bd9Sstevel@tonic-gate 	ASSERT(dr_cpu_unit_is_sane(cp->sbc_cm.sbdev_bp, cp));
2597c478bd9Sstevel@tonic-gate 
2607c478bd9Sstevel@tonic-gate 	mutex_enter(&cpu_lock);
2617c478bd9Sstevel@tonic-gate 	if ((cpuid >= 0) && cpu[cpuid])
2627c478bd9Sstevel@tonic-gate 		cp->sbc_cpu_flags = cpu[cpuid]->cpu_flags;
2637c478bd9Sstevel@tonic-gate 	else
2647c478bd9Sstevel@tonic-gate 		cp->sbc_cpu_flags = P_OFFLINE | P_POWEROFF;
2657c478bd9Sstevel@tonic-gate 	mutex_exit(&cpu_lock);
2667c478bd9Sstevel@tonic-gate 
2677c478bd9Sstevel@tonic-gate 	dr_cpu_set_prop(cp);
2687c478bd9Sstevel@tonic-gate 
2697c478bd9Sstevel@tonic-gate done:
2707c478bd9Sstevel@tonic-gate 	/* delay transition until fully initialized */
2717c478bd9Sstevel@tonic-gate 	dr_device_transition(&cp->sbc_cm, new_state);
2727c478bd9Sstevel@tonic-gate }
2737c478bd9Sstevel@tonic-gate 
2747c478bd9Sstevel@tonic-gate int
2757c478bd9Sstevel@tonic-gate dr_pre_attach_cpu(dr_handle_t *hp, dr_common_unit_t **devlist, int devnum)
2767c478bd9Sstevel@tonic-gate {
2777c478bd9Sstevel@tonic-gate 	int		i;
2787c478bd9Sstevel@tonic-gate 	int		curr_cpu;
2797c478bd9Sstevel@tonic-gate 	int		next_cpu;
2807c478bd9Sstevel@tonic-gate 	static fn_t	f = "dr_pre_attach_cpu";
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate 	PR_CPU("%s...\n", f);
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate 	for (next_cpu = 0, i = 0; i < devnum; i++) {
2857c478bd9Sstevel@tonic-gate 		dr_cpu_unit_t *up = (dr_cpu_unit_t *)devlist[i];
2867c478bd9Sstevel@tonic-gate 
2877c478bd9Sstevel@tonic-gate 		ASSERT(dr_cpu_unit_is_sane(hp->h_bd, up));
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate 		/*
2907c478bd9Sstevel@tonic-gate 		 * Print a console message for each attachment
2917c478bd9Sstevel@tonic-gate 		 * point. For CMP devices, this means that only
2927c478bd9Sstevel@tonic-gate 		 * one message should be printed, no matter how
2937c478bd9Sstevel@tonic-gate 		 * many cores are actually present.
2947c478bd9Sstevel@tonic-gate 		 */
29525cf1a30Sjl139090 		curr_cpu = DR_UNUM2SBD_UNUM(up->sbc_cm.sbdev_unum,
29625cf1a30Sjl139090 		    SBD_COMP_CPU);
2977c478bd9Sstevel@tonic-gate 		if (curr_cpu >= next_cpu) {
2987c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "OS configure %s",
2997c478bd9Sstevel@tonic-gate 			    up->sbc_cm.sbdev_path);
3007c478bd9Sstevel@tonic-gate 			next_cpu = curr_cpu + 1;
3017c478bd9Sstevel@tonic-gate 		}
3027c478bd9Sstevel@tonic-gate 
3037c478bd9Sstevel@tonic-gate 		if (up->sbc_cm.sbdev_state == DR_STATE_UNCONFIGURED) {
3047c478bd9Sstevel@tonic-gate 			/*
3057c478bd9Sstevel@tonic-gate 			 * If we're coming from the UNCONFIGURED
3067c478bd9Sstevel@tonic-gate 			 * state then the cpu's sigblock will
3077c478bd9Sstevel@tonic-gate 			 * still be mapped in.  Need to unmap it
3087c478bd9Sstevel@tonic-gate 			 * before continuing with attachment.
3097c478bd9Sstevel@tonic-gate 			 */
310e98fafb9Sjl139090 			PR_CPU("%s: unmapping sigblk for cpu %d\n", f,
311e98fafb9Sjl139090 			    up->sbc_cpu_id);
3127c478bd9Sstevel@tonic-gate 
3137c478bd9Sstevel@tonic-gate 			CPU_SGN_MAPOUT(up->sbc_cpu_id);
3147c478bd9Sstevel@tonic-gate 		}
3157c478bd9Sstevel@tonic-gate 	}
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate 	/*
3187c478bd9Sstevel@tonic-gate 	 * Block out status threads while creating
3197c478bd9Sstevel@tonic-gate 	 * devinfo tree branches
3207c478bd9Sstevel@tonic-gate 	 */
3217c478bd9Sstevel@tonic-gate 	dr_lock_status(hp->h_bd);
322afc2fd2aSbm42561 	ndi_devi_enter(ddi_root_node(), (int *)(&hp->h_ndi));
3237c478bd9Sstevel@tonic-gate 	mutex_enter(&cpu_lock);
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate 	return (0);
3267c478bd9Sstevel@tonic-gate }
3277c478bd9Sstevel@tonic-gate 
3287c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3297c478bd9Sstevel@tonic-gate void
3307c478bd9Sstevel@tonic-gate dr_attach_cpu(dr_handle_t *hp, dr_common_unit_t *cp)
3317c478bd9Sstevel@tonic-gate {
3327c478bd9Sstevel@tonic-gate 	sbd_error_t	*err;
3337c478bd9Sstevel@tonic-gate 	processorid_t	 cpuid;
3347c478bd9Sstevel@tonic-gate 	int		 rv;
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&cpu_lock));
3377c478bd9Sstevel@tonic-gate 
3387c478bd9Sstevel@tonic-gate 	err = drmach_configure(cp->sbdev_id, 0);
3397c478bd9Sstevel@tonic-gate 	if (err) {
3407c478bd9Sstevel@tonic-gate 		DRERR_SET_C(&cp->sbdev_error, &err);
3417c478bd9Sstevel@tonic-gate 		return;
3427c478bd9Sstevel@tonic-gate 	}
3437c478bd9Sstevel@tonic-gate 
3447c478bd9Sstevel@tonic-gate 	err = drmach_cpu_get_id(cp->sbdev_id, &cpuid);
3457c478bd9Sstevel@tonic-gate 	if (err) {
3467c478bd9Sstevel@tonic-gate 		DRERR_SET_C(&cp->sbdev_error, &err);
3477c478bd9Sstevel@tonic-gate 
34825cf1a30Sjl139090 		err = drmach_unconfigure(cp->sbdev_id, DEVI_BRANCH_DESTROY);
3497c478bd9Sstevel@tonic-gate 		if (err)
3507c478bd9Sstevel@tonic-gate 			sbd_err_clear(&err);
3517c478bd9Sstevel@tonic-gate 	} else if ((rv = cpu_configure(cpuid)) != 0) {
3527c478bd9Sstevel@tonic-gate 		dr_dev_err(CE_WARN, cp, dr_errno2ecode(rv));
35325cf1a30Sjl139090 		err = drmach_unconfigure(cp->sbdev_id, DEVI_BRANCH_DESTROY);
3547c478bd9Sstevel@tonic-gate 		if (err)
3557c478bd9Sstevel@tonic-gate 			sbd_err_clear(&err);
3567c478bd9Sstevel@tonic-gate 	}
3577c478bd9Sstevel@tonic-gate }
3587c478bd9Sstevel@tonic-gate 
3597c478bd9Sstevel@tonic-gate /*
3607c478bd9Sstevel@tonic-gate  * dr_post_attach_cpu
3617c478bd9Sstevel@tonic-gate  *
3627c478bd9Sstevel@tonic-gate  * sbd error policy: Does not stop on error.  Processes all units in list.
3637c478bd9Sstevel@tonic-gate  */
3647c478bd9Sstevel@tonic-gate int
3657c478bd9Sstevel@tonic-gate dr_post_attach_cpu(dr_handle_t *hp, dr_common_unit_t **devlist, int devnum)
3667c478bd9Sstevel@tonic-gate {
3677c478bd9Sstevel@tonic-gate 	int		i;
3687c478bd9Sstevel@tonic-gate 	int		errflag = 0;
3697c478bd9Sstevel@tonic-gate 	static fn_t	f = "dr_post_attach_cpu";
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate 	PR_CPU("%s...\n", f);
3727c478bd9Sstevel@tonic-gate 
3737c478bd9Sstevel@tonic-gate 	/* Startup and online newly-attached CPUs */
3747c478bd9Sstevel@tonic-gate 	for (i = 0; i < devnum; i++) {
3757c478bd9Sstevel@tonic-gate 		dr_cpu_unit_t *up = (dr_cpu_unit_t *)devlist[i];
3767c478bd9Sstevel@tonic-gate 		struct cpu	*cp;
3777c478bd9Sstevel@tonic-gate 
3787c478bd9Sstevel@tonic-gate 		ASSERT(dr_cpu_unit_is_sane(hp->h_bd, up));
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate 		cp = cpu_get(up->sbc_cpu_id);
3817c478bd9Sstevel@tonic-gate 		if (cp == NULL) {
3827c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "%s: cpu_get failed for cpu %d",
3837c478bd9Sstevel@tonic-gate 			    f, up->sbc_cpu_id);
3847c478bd9Sstevel@tonic-gate 			continue;
3857c478bd9Sstevel@tonic-gate 		}
3867c478bd9Sstevel@tonic-gate 
3877c478bd9Sstevel@tonic-gate 		if (cpu_is_poweredoff(cp)) {
3887c478bd9Sstevel@tonic-gate 			if (cpu_poweron(cp) != 0) {
3897c478bd9Sstevel@tonic-gate 				dr_dev_err(CE_WARN, &up->sbc_cm, ESBD_CPUSTART);
3907c478bd9Sstevel@tonic-gate 				errflag = 1;
3917c478bd9Sstevel@tonic-gate 			}
3927c478bd9Sstevel@tonic-gate 			PR_CPU("%s: cpu %d powered ON\n", f, up->sbc_cpu_id);
3937c478bd9Sstevel@tonic-gate 		}
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate 		if (cpu_is_offline(cp)) {
3967c478bd9Sstevel@tonic-gate 			PR_CPU("%s: onlining cpu %d...\n", f, up->sbc_cpu_id);
3977c478bd9Sstevel@tonic-gate 
3987c478bd9Sstevel@tonic-gate 			if (cpu_online(cp) != 0) {
3997c478bd9Sstevel@tonic-gate 				dr_dev_err(CE_WARN, &up->sbc_cm, ESBD_ONLINE);
4007c478bd9Sstevel@tonic-gate 				errflag = 1;
4017c478bd9Sstevel@tonic-gate 			}
4027c478bd9Sstevel@tonic-gate 		}
4037c478bd9Sstevel@tonic-gate 
4047c478bd9Sstevel@tonic-gate 	}
4057c478bd9Sstevel@tonic-gate 
4067c478bd9Sstevel@tonic-gate 	mutex_exit(&cpu_lock);
407afc2fd2aSbm42561 	ndi_devi_exit(ddi_root_node(), hp->h_ndi);
4087c478bd9Sstevel@tonic-gate 	dr_unlock_status(hp->h_bd);
4097c478bd9Sstevel@tonic-gate 
4107c478bd9Sstevel@tonic-gate 	if (errflag)
4117c478bd9Sstevel@tonic-gate 		return (-1);
4127c478bd9Sstevel@tonic-gate 	else
4137c478bd9Sstevel@tonic-gate 		return (0);
4147c478bd9Sstevel@tonic-gate }
4157c478bd9Sstevel@tonic-gate 
4167c478bd9Sstevel@tonic-gate /*
4177c478bd9Sstevel@tonic-gate  * dr_pre_release_cpu
4187c478bd9Sstevel@tonic-gate  *
4197c478bd9Sstevel@tonic-gate  * sbd error policy: Stops on first error.
4207c478bd9Sstevel@tonic-gate  */
4217c478bd9Sstevel@tonic-gate int
4227c478bd9Sstevel@tonic-gate dr_pre_release_cpu(dr_handle_t *hp, dr_common_unit_t **devlist, int devnum)
4237c478bd9Sstevel@tonic-gate {
4247c478bd9Sstevel@tonic-gate 	int		c, cix, i, lastoffline = -1, rv = 0;
4257c478bd9Sstevel@tonic-gate 	processorid_t	cpuid;
4267c478bd9Sstevel@tonic-gate 	struct cpu	*cp;
4277c478bd9Sstevel@tonic-gate 	dr_cpu_unit_t	*up;
4287c478bd9Sstevel@tonic-gate 	dr_devset_t	devset;
4297c478bd9Sstevel@tonic-gate 	sbd_dev_stat_t	*ds;
4307c478bd9Sstevel@tonic-gate 	static fn_t	f = "dr_pre_release_cpu";
4317c478bd9Sstevel@tonic-gate 	int		cpu_flags = 0;
4327c478bd9Sstevel@tonic-gate 
4337c478bd9Sstevel@tonic-gate 	devset = DR_DEVS_PRESENT(hp->h_bd);
4347c478bd9Sstevel@tonic-gate 
4357c478bd9Sstevel@tonic-gate 	/* allocate status struct storage. */
4367c478bd9Sstevel@tonic-gate 	ds = (sbd_dev_stat_t *) kmem_zalloc(sizeof (sbd_dev_stat_t) *
4377c478bd9Sstevel@tonic-gate 	    MAX_CPU_UNITS_PER_BOARD, KM_SLEEP);
4387c478bd9Sstevel@tonic-gate 
4397c478bd9Sstevel@tonic-gate 	cix = dr_cpu_status(hp, devset, ds);
4407c478bd9Sstevel@tonic-gate 
4417c478bd9Sstevel@tonic-gate 	mutex_enter(&cpu_lock);
4427c478bd9Sstevel@tonic-gate 
4437c478bd9Sstevel@tonic-gate 	for (i = 0; i < devnum; i++) {
4447c478bd9Sstevel@tonic-gate 		up = (dr_cpu_unit_t *)devlist[i];
4457c478bd9Sstevel@tonic-gate 		ASSERT(dr_cpu_unit_is_sane(hp->h_bd, up));
4467c478bd9Sstevel@tonic-gate 
4477c478bd9Sstevel@tonic-gate 		/*
4487c478bd9Sstevel@tonic-gate 		 * The STARCAT platform borrows cpus for use by POST in
4497c478bd9Sstevel@tonic-gate 		 * iocage testing.  These cpus cannot be unconfigured
4507c478bd9Sstevel@tonic-gate 		 * while they are in use for the iocage.
4517c478bd9Sstevel@tonic-gate 		 * This check determines if a CPU is currently in use
4527c478bd9Sstevel@tonic-gate 		 * for iocage testing, and if so, returns a "Device busy"
4537c478bd9Sstevel@tonic-gate 		 * error.
4547c478bd9Sstevel@tonic-gate 		 */
4557c478bd9Sstevel@tonic-gate 		for (c = 0; c < cix; c++) {
4567c478bd9Sstevel@tonic-gate 			if (ds[c].d_cpu.cs_unit == up->sbc_cm.sbdev_unum) {
4577c478bd9Sstevel@tonic-gate 				if (ds[c].d_cpu.cs_busy) {
458e98fafb9Sjl139090 					dr_dev_err(CE_WARN, &up->sbc_cm,
459e98fafb9Sjl139090 					    ESBD_BUSY);
4607c478bd9Sstevel@tonic-gate 					rv = -1;
4617c478bd9Sstevel@tonic-gate 					break;
4627c478bd9Sstevel@tonic-gate 				}
4637c478bd9Sstevel@tonic-gate 			}
4647c478bd9Sstevel@tonic-gate 		}
4657c478bd9Sstevel@tonic-gate 		if (c < cix)
4667c478bd9Sstevel@tonic-gate 			break;
4677c478bd9Sstevel@tonic-gate 		cpuid = up->sbc_cpu_id;
4687c478bd9Sstevel@tonic-gate 		if ((cp = cpu_get(cpuid)) == NULL) {
4697c478bd9Sstevel@tonic-gate 			dr_dev_err(CE_WARN, &up->sbc_cm, ESBD_OFFLINE);
4707c478bd9Sstevel@tonic-gate 			rv = -1;
4717c478bd9Sstevel@tonic-gate 			break;
4727c478bd9Sstevel@tonic-gate 		}
4737c478bd9Sstevel@tonic-gate 
4747c478bd9Sstevel@tonic-gate 		/* used by dr_cancel_cpu during error flow */
4757c478bd9Sstevel@tonic-gate 		up->sbc_cpu_flags = cp->cpu_flags;
4767c478bd9Sstevel@tonic-gate 
4777c478bd9Sstevel@tonic-gate 		if (CPU_ACTIVE(cp)) {
4787c478bd9Sstevel@tonic-gate 			if (dr_cmd_flags(hp) & SBD_FLAG_FORCE)
4797c478bd9Sstevel@tonic-gate 				cpu_flags = CPU_FORCED;
4807c478bd9Sstevel@tonic-gate 
4817c478bd9Sstevel@tonic-gate 			PR_CPU("%s: offlining cpu %d\n", f, cpuid);
4827c478bd9Sstevel@tonic-gate 			if (cpu_offline(cp, cpu_flags)) {
483e98fafb9Sjl139090 				PR_CPU("%s: failed to offline cpu %d\n", f,
484e98fafb9Sjl139090 				    cpuid);
4857c478bd9Sstevel@tonic-gate 				dr_dev_err(CE_WARN, &up->sbc_cm, ESBD_OFFLINE);
4867c478bd9Sstevel@tonic-gate 				if (disp_bound_threads(cp, 0)) {
487e98fafb9Sjl139090 					cmn_err(CE_WARN, "%s: thread(s) bound "
488e98fafb9Sjl139090 					    "to cpu %d", f, cp->cpu_id);
4897c478bd9Sstevel@tonic-gate 				}
4907c478bd9Sstevel@tonic-gate 				rv = -1;
4917c478bd9Sstevel@tonic-gate 				break;
4927c478bd9Sstevel@tonic-gate 			} else
4937c478bd9Sstevel@tonic-gate 				lastoffline = i;
4947c478bd9Sstevel@tonic-gate 		}
4957c478bd9Sstevel@tonic-gate 
4967c478bd9Sstevel@tonic-gate 		if (!rv) {
4977c478bd9Sstevel@tonic-gate 			sbd_error_t *err;
4987c478bd9Sstevel@tonic-gate 
4997c478bd9Sstevel@tonic-gate 			err = drmach_release(up->sbc_cm.sbdev_id);
5007c478bd9Sstevel@tonic-gate 			if (err) {
5017c478bd9Sstevel@tonic-gate 				DRERR_SET_C(&up->sbc_cm.sbdev_error, &err);
5027c478bd9Sstevel@tonic-gate 				rv = -1;
5037c478bd9Sstevel@tonic-gate 				break;
5047c478bd9Sstevel@tonic-gate 			}
5057c478bd9Sstevel@tonic-gate 		}
5067c478bd9Sstevel@tonic-gate 	}
5077c478bd9Sstevel@tonic-gate 
5087c478bd9Sstevel@tonic-gate 	mutex_exit(&cpu_lock);
5097c478bd9Sstevel@tonic-gate 
5107c478bd9Sstevel@tonic-gate 	if (rv) {
5117c478bd9Sstevel@tonic-gate 		/*
5127c478bd9Sstevel@tonic-gate 		 * Need to unwind others since at this level (pre-release)
5137c478bd9Sstevel@tonic-gate 		 * the device state has not yet transitioned and failures
5147c478bd9Sstevel@tonic-gate 		 * will prevent us from reaching the "post" release
5157c478bd9Sstevel@tonic-gate 		 * function where states are normally transitioned.
5167c478bd9Sstevel@tonic-gate 		 */
5177c478bd9Sstevel@tonic-gate 		for (i = lastoffline; i >= 0; i--) {
5187c478bd9Sstevel@tonic-gate 			up = (dr_cpu_unit_t *)devlist[i];
5197c478bd9Sstevel@tonic-gate 			(void) dr_cancel_cpu(up);
5207c478bd9Sstevel@tonic-gate 		}
5217c478bd9Sstevel@tonic-gate 	}
5227c478bd9Sstevel@tonic-gate 
5237c478bd9Sstevel@tonic-gate 	kmem_free(ds, sizeof (sbd_dev_stat_t) * MAX_CPU_UNITS_PER_BOARD);
5247c478bd9Sstevel@tonic-gate 	return (rv);
5257c478bd9Sstevel@tonic-gate }
5267c478bd9Sstevel@tonic-gate 
5277c478bd9Sstevel@tonic-gate /*
5287c478bd9Sstevel@tonic-gate  * dr_pre_detach_cpu
5297c478bd9Sstevel@tonic-gate  *
5307c478bd9Sstevel@tonic-gate  * sbd error policy: Stops on first error.
5317c478bd9Sstevel@tonic-gate  */
5327c478bd9Sstevel@tonic-gate int
5337c478bd9Sstevel@tonic-gate dr_pre_detach_cpu(dr_handle_t *hp, dr_common_unit_t **devlist, int devnum)
5347c478bd9Sstevel@tonic-gate {
5357c478bd9Sstevel@tonic-gate 	_NOTE(ARGUNUSED(hp))
5367c478bd9Sstevel@tonic-gate 
5377c478bd9Sstevel@tonic-gate 	int		i;
5387c478bd9Sstevel@tonic-gate 	int		curr_cpu;
5397c478bd9Sstevel@tonic-gate 	int		next_cpu;
5407c478bd9Sstevel@tonic-gate 	int		cpu_flags = 0;
5417c478bd9Sstevel@tonic-gate 	static fn_t	f = "dr_pre_detach_cpu";
5427c478bd9Sstevel@tonic-gate 
5437c478bd9Sstevel@tonic-gate 	PR_CPU("%s...\n", f);
5447c478bd9Sstevel@tonic-gate 
5457c478bd9Sstevel@tonic-gate 	/*
5467c478bd9Sstevel@tonic-gate 	 * Block out status threads while destroying devinfo tree
5477c478bd9Sstevel@tonic-gate 	 * branches
5487c478bd9Sstevel@tonic-gate 	 */
5497c478bd9Sstevel@tonic-gate 	dr_lock_status(hp->h_bd);
5507c478bd9Sstevel@tonic-gate 	mutex_enter(&cpu_lock);
5517c478bd9Sstevel@tonic-gate 
5527c478bd9Sstevel@tonic-gate 	for (next_cpu = 0, i = 0; i < devnum; i++) {
5537c478bd9Sstevel@tonic-gate 		dr_cpu_unit_t *up = (dr_cpu_unit_t *)devlist[i];
5547c478bd9Sstevel@tonic-gate 		struct cpu	*cp;
5557c478bd9Sstevel@tonic-gate 
5567c478bd9Sstevel@tonic-gate 		ASSERT(dr_cpu_unit_is_sane(hp->h_bd, up));
5577c478bd9Sstevel@tonic-gate 
5587c478bd9Sstevel@tonic-gate 		cp = cpu_get(up->sbc_cpu_id);
5597c478bd9Sstevel@tonic-gate 		if (cp == NULL)
5607c478bd9Sstevel@tonic-gate 			continue;
5617c478bd9Sstevel@tonic-gate 
5627c478bd9Sstevel@tonic-gate 		/*
5637c478bd9Sstevel@tonic-gate 		 * Print a console message for each attachment
5647c478bd9Sstevel@tonic-gate 		 * point. For CMP devices, this means that only
5657c478bd9Sstevel@tonic-gate 		 * one message should be printed, no matter how
5667c478bd9Sstevel@tonic-gate 		 * many cores are actually present.
5677c478bd9Sstevel@tonic-gate 		 */
56825cf1a30Sjl139090 		curr_cpu = DR_UNUM2SBD_UNUM(up->sbc_cm.sbdev_unum,
56925cf1a30Sjl139090 		    SBD_COMP_CPU);
5707c478bd9Sstevel@tonic-gate 		if (curr_cpu >= next_cpu) {
5717c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "OS unconfigure %s\n",
5727c478bd9Sstevel@tonic-gate 			    up->sbc_cm.sbdev_path);
5737c478bd9Sstevel@tonic-gate 			next_cpu = curr_cpu + 1;
5747c478bd9Sstevel@tonic-gate 		}
5757c478bd9Sstevel@tonic-gate 
5767c478bd9Sstevel@tonic-gate 		/*
5777c478bd9Sstevel@tonic-gate 		 * CPUs were offlined during Release.
5787c478bd9Sstevel@tonic-gate 		 */
5797c478bd9Sstevel@tonic-gate 		if (cpu_is_poweredoff(cp)) {
5807c478bd9Sstevel@tonic-gate 			PR_CPU("%s: cpu %d already powered OFF\n",
5817c478bd9Sstevel@tonic-gate 			    f, up->sbc_cpu_id);
5827c478bd9Sstevel@tonic-gate 			continue;
5837c478bd9Sstevel@tonic-gate 		}
5847c478bd9Sstevel@tonic-gate 
5857c478bd9Sstevel@tonic-gate 		if (!cpu_is_offline(cp)) {
5867c478bd9Sstevel@tonic-gate 			if (dr_cmd_flags(hp) & SBD_FLAG_FORCE)
5877c478bd9Sstevel@tonic-gate 				cpu_flags = CPU_FORCED;
5887c478bd9Sstevel@tonic-gate 			/* cpu was onlined after release.  Offline it again */
5897c478bd9Sstevel@tonic-gate 			PR_CPU("%s: offlining cpu %d\n", f, up->sbc_cpu_id);
5907c478bd9Sstevel@tonic-gate 			if (cpu_offline(cp, cpu_flags)) {
5917c478bd9Sstevel@tonic-gate 				PR_CPU("%s: failed to offline cpu %d\n",
5927c478bd9Sstevel@tonic-gate 				    f, up->sbc_cpu_id);
5937c478bd9Sstevel@tonic-gate 				dr_dev_err(CE_WARN, &up->sbc_cm, ESBD_OFFLINE);
5947c478bd9Sstevel@tonic-gate 				if (disp_bound_threads(cp, 0)) {
595e98fafb9Sjl139090 					cmn_err(CE_WARN, "%s: thread(s) bound "
596e98fafb9Sjl139090 					    "to cpu %d", f, cp->cpu_id);
5977c478bd9Sstevel@tonic-gate 				}
5987c478bd9Sstevel@tonic-gate 				goto err;
5997c478bd9Sstevel@tonic-gate 			}
6007c478bd9Sstevel@tonic-gate 		}
6017c478bd9Sstevel@tonic-gate 		if (cpu_poweroff(cp) != 0) {
6027c478bd9Sstevel@tonic-gate 			dr_dev_err(CE_WARN, &up->sbc_cm, ESBD_CPUSTOP);
6037c478bd9Sstevel@tonic-gate 			goto err;
6047c478bd9Sstevel@tonic-gate 		} else {
6057c478bd9Sstevel@tonic-gate 			PR_CPU("%s: cpu %d powered OFF\n", f, up->sbc_cpu_id);
6067c478bd9Sstevel@tonic-gate 		}
6077c478bd9Sstevel@tonic-gate 	}
6087c478bd9Sstevel@tonic-gate 
6097c478bd9Sstevel@tonic-gate 	return (0);
6107c478bd9Sstevel@tonic-gate 
6117c478bd9Sstevel@tonic-gate err:
6127c478bd9Sstevel@tonic-gate 	mutex_exit(&cpu_lock);
6137c478bd9Sstevel@tonic-gate 	dr_unlock_status(hp->h_bd);
6147c478bd9Sstevel@tonic-gate 	return (-1);
6157c478bd9Sstevel@tonic-gate }
6167c478bd9Sstevel@tonic-gate 
6177c478bd9Sstevel@tonic-gate /*ARGSUSED*/
6187c478bd9Sstevel@tonic-gate void
6197c478bd9Sstevel@tonic-gate dr_detach_cpu(dr_handle_t *hp, dr_common_unit_t *cp)
6207c478bd9Sstevel@tonic-gate {
6217c478bd9Sstevel@tonic-gate 	sbd_error_t	*err;
6227c478bd9Sstevel@tonic-gate 	processorid_t	 cpuid;
6237c478bd9Sstevel@tonic-gate 	int		 rv;
6247c478bd9Sstevel@tonic-gate 
6257c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&cpu_lock));
6267c478bd9Sstevel@tonic-gate 
6277c478bd9Sstevel@tonic-gate 	err = drmach_cpu_get_id(cp->sbdev_id, &cpuid);
6287c478bd9Sstevel@tonic-gate 	if (err) {
6297c478bd9Sstevel@tonic-gate 		DRERR_SET_C(&cp->sbdev_error, &err);
6307c478bd9Sstevel@tonic-gate 	} else if ((rv = cpu_unconfigure(cpuid)) != 0) {
6317c478bd9Sstevel@tonic-gate 		dr_dev_err(CE_IGNORE, cp, dr_errno2ecode(rv));
6327c478bd9Sstevel@tonic-gate 	} else {
63325cf1a30Sjl139090 		err = drmach_unconfigure(cp->sbdev_id, DEVI_BRANCH_DESTROY);
6347c478bd9Sstevel@tonic-gate 		if (err) {
6357c478bd9Sstevel@tonic-gate 			DRERR_SET_C(&cp->sbdev_error, &err);
6367c478bd9Sstevel@tonic-gate 		}
6377c478bd9Sstevel@tonic-gate 	}
6387c478bd9Sstevel@tonic-gate }
6397c478bd9Sstevel@tonic-gate 
6407c478bd9Sstevel@tonic-gate /*ARGSUSED1*/
6417c478bd9Sstevel@tonic-gate int
6427c478bd9Sstevel@tonic-gate dr_post_detach_cpu(dr_handle_t *hp, dr_common_unit_t **devlist, int devnum)
6437c478bd9Sstevel@tonic-gate {
6447c478bd9Sstevel@tonic-gate 	static fn_t	f = "dr_post_detach_cpu";
6457c478bd9Sstevel@tonic-gate 
6467c478bd9Sstevel@tonic-gate 	PR_CPU("%s...\n", f);
6477c478bd9Sstevel@tonic-gate 	hp->h_ndi = 0;
6487c478bd9Sstevel@tonic-gate 
6497c478bd9Sstevel@tonic-gate 	mutex_exit(&cpu_lock);
6507c478bd9Sstevel@tonic-gate 	dr_unlock_status(hp->h_bd);
6517c478bd9Sstevel@tonic-gate 
6527c478bd9Sstevel@tonic-gate 	return (0);
6537c478bd9Sstevel@tonic-gate }
6547c478bd9Sstevel@tonic-gate 
6557c478bd9Sstevel@tonic-gate static void
6567c478bd9Sstevel@tonic-gate dr_fill_cpu_stat(dr_cpu_unit_t *cp, drmach_status_t *pstat, sbd_cpu_stat_t *csp)
6577c478bd9Sstevel@tonic-gate {
6587c478bd9Sstevel@tonic-gate 	ASSERT(cp && pstat && csp);
6597c478bd9Sstevel@tonic-gate 
6607c478bd9Sstevel@tonic-gate 	/* Fill in the common status information */
6617c478bd9Sstevel@tonic-gate 	bzero((caddr_t)csp, sizeof (*csp));
6627c478bd9Sstevel@tonic-gate 	csp->cs_type = cp->sbc_cm.sbdev_type;
6637c478bd9Sstevel@tonic-gate 	csp->cs_unit = cp->sbc_cm.sbdev_unum;
664*07d06da5SSurya Prakki 	(void) strncpy(csp->cs_name, pstat->type, sizeof (csp->cs_name));
6657c478bd9Sstevel@tonic-gate 	csp->cs_cond = cp->sbc_cm.sbdev_cond;
6667c478bd9Sstevel@tonic-gate 	csp->cs_busy = cp->sbc_cm.sbdev_busy | pstat->busy;
6677c478bd9Sstevel@tonic-gate 	csp->cs_time = cp->sbc_cm.sbdev_time;
6687c478bd9Sstevel@tonic-gate 	csp->cs_ostate = cp->sbc_cm.sbdev_ostate;
6697c478bd9Sstevel@tonic-gate 	csp->cs_suspend = 0;
6707c478bd9Sstevel@tonic-gate 
6717c478bd9Sstevel@tonic-gate 	/* CPU specific status data */
6727c478bd9Sstevel@tonic-gate 	csp->cs_cpuid = cp->sbc_cpu_id;
6737c478bd9Sstevel@tonic-gate 
6747c478bd9Sstevel@tonic-gate #ifdef _STARFIRE
6757c478bd9Sstevel@tonic-gate 	csp->cs_isbootproc = (SIGBCPU->cpu_id == cp->sbc_cpu_id) ? 1 : 0;
6767c478bd9Sstevel@tonic-gate #endif /* _STARFIRE */
6777c478bd9Sstevel@tonic-gate 
6787c478bd9Sstevel@tonic-gate 	/*
6797c478bd9Sstevel@tonic-gate 	 * If the speed and ecache properties have not been
6807c478bd9Sstevel@tonic-gate 	 * cached yet, read them in from the device tree.
6817c478bd9Sstevel@tonic-gate 	 */
6827c478bd9Sstevel@tonic-gate 	if ((cp->sbc_speed == 0) || (cp->sbc_ecache == 0))
6837c478bd9Sstevel@tonic-gate 		dr_cpu_set_prop(cp);
6847c478bd9Sstevel@tonic-gate 
6857c478bd9Sstevel@tonic-gate 	/* use the cached speed and ecache values */
6867c478bd9Sstevel@tonic-gate 	csp->cs_speed = cp->sbc_speed;
6877c478bd9Sstevel@tonic-gate 	csp->cs_ecache = cp->sbc_ecache;
6887c478bd9Sstevel@tonic-gate 
6897c478bd9Sstevel@tonic-gate 	mutex_enter(&cpu_lock);
6907c478bd9Sstevel@tonic-gate 	if (!cpu_get(csp->cs_cpuid)) {
6917c478bd9Sstevel@tonic-gate 		/* ostate must be UNCONFIGURED */
6927c478bd9Sstevel@tonic-gate 		csp->cs_cm.c_ostate = SBD_STAT_UNCONFIGURED;
6937c478bd9Sstevel@tonic-gate 	}
6947c478bd9Sstevel@tonic-gate 	mutex_exit(&cpu_lock);
6957c478bd9Sstevel@tonic-gate }
6967c478bd9Sstevel@tonic-gate 
6977c478bd9Sstevel@tonic-gate static void
6987c478bd9Sstevel@tonic-gate dr_fill_cmp_stat(sbd_cpu_stat_t *csp, int ncores, int impl, sbd_cmp_stat_t *psp)
6997c478bd9Sstevel@tonic-gate {
7007c478bd9Sstevel@tonic-gate 	int	core;
7017c478bd9Sstevel@tonic-gate 
7027c478bd9Sstevel@tonic-gate 	ASSERT(csp && psp && (ncores >= 1));
7037c478bd9Sstevel@tonic-gate 
7047c478bd9Sstevel@tonic-gate 	bzero((caddr_t)psp, sizeof (*psp));
7057c478bd9Sstevel@tonic-gate 
7067c478bd9Sstevel@tonic-gate 	/*
7077c478bd9Sstevel@tonic-gate 	 * Fill in the common status information based
7087c478bd9Sstevel@tonic-gate 	 * on the data for the first core.
7097c478bd9Sstevel@tonic-gate 	 */
7107c478bd9Sstevel@tonic-gate 	psp->ps_type = SBD_COMP_CMP;
71125cf1a30Sjl139090 	psp->ps_unit = DR_UNUM2SBD_UNUM(csp->cs_unit, SBD_COMP_CMP);
712*07d06da5SSurya Prakki 	(void) strncpy(psp->ps_name, csp->cs_name, sizeof (psp->ps_name));
7137c478bd9Sstevel@tonic-gate 	psp->ps_cond = csp->cs_cond;
7147c478bd9Sstevel@tonic-gate 	psp->ps_busy = csp->cs_busy;
7157c478bd9Sstevel@tonic-gate 	psp->ps_time = csp->cs_time;
7167c478bd9Sstevel@tonic-gate 	psp->ps_ostate = csp->cs_ostate;
7177c478bd9Sstevel@tonic-gate 	psp->ps_suspend = csp->cs_suspend;
7187c478bd9Sstevel@tonic-gate 
7197c478bd9Sstevel@tonic-gate 	/* CMP specific status data */
7207c478bd9Sstevel@tonic-gate 	*psp->ps_cpuid = csp->cs_cpuid;
7217c478bd9Sstevel@tonic-gate 	psp->ps_ncores = 1;
7227c478bd9Sstevel@tonic-gate 	psp->ps_speed = csp->cs_speed;
7237c478bd9Sstevel@tonic-gate 	psp->ps_ecache = csp->cs_ecache;
7247c478bd9Sstevel@tonic-gate 
7257c478bd9Sstevel@tonic-gate 	/*
7267c478bd9Sstevel@tonic-gate 	 * Walk through the data for the remaining cores.
7277c478bd9Sstevel@tonic-gate 	 * Make any adjustments to the common status data,
7287c478bd9Sstevel@tonic-gate 	 * or the shared CMP specific data if necessary.
7297c478bd9Sstevel@tonic-gate 	 */
7307c478bd9Sstevel@tonic-gate 	for (core = 1; core < ncores; core++) {
7317c478bd9Sstevel@tonic-gate 
7327c478bd9Sstevel@tonic-gate 		/*
7337c478bd9Sstevel@tonic-gate 		 * The following properties should be the same
7347c478bd9Sstevel@tonic-gate 		 * for all the cores of the CMP.
7357c478bd9Sstevel@tonic-gate 		 */
736e98fafb9Sjl139090 		ASSERT(psp->ps_unit == DR_UNUM2SBD_UNUM(csp[core].cs_unit,
737e98fafb9Sjl139090 		    SBD_COMP_CMP));
7387c478bd9Sstevel@tonic-gate 		ASSERT(psp->ps_speed == csp[core].cs_speed);
7397c478bd9Sstevel@tonic-gate 
7407c478bd9Sstevel@tonic-gate 		psp->ps_cpuid[core] = csp[core].cs_cpuid;
7417c478bd9Sstevel@tonic-gate 		psp->ps_ncores++;
7427c478bd9Sstevel@tonic-gate 
7437c478bd9Sstevel@tonic-gate 		/*
7447c478bd9Sstevel@tonic-gate 		 * Jaguar has a split ecache, so the ecache
7457c478bd9Sstevel@tonic-gate 		 * for each core must be added together to
7467c478bd9Sstevel@tonic-gate 		 * get the total ecache for the whole chip.
7477c478bd9Sstevel@tonic-gate 		 */
7487c478bd9Sstevel@tonic-gate 		if (IS_JAGUAR(impl)) {
7497c478bd9Sstevel@tonic-gate 			psp->ps_ecache += csp[core].cs_ecache;
7507c478bd9Sstevel@tonic-gate 		}
7517c478bd9Sstevel@tonic-gate 
7527c478bd9Sstevel@tonic-gate 		/* adjust time if necessary */
7537c478bd9Sstevel@tonic-gate 		if (csp[core].cs_time > psp->ps_time) {
7547c478bd9Sstevel@tonic-gate 			psp->ps_time = csp[core].cs_time;
7557c478bd9Sstevel@tonic-gate 		}
7567c478bd9Sstevel@tonic-gate 
7577c478bd9Sstevel@tonic-gate 		psp->ps_busy |= csp[core].cs_busy;
7587c478bd9Sstevel@tonic-gate 
7597c478bd9Sstevel@tonic-gate 		/*
7607c478bd9Sstevel@tonic-gate 		 * If any of the cores are configured, the
7617c478bd9Sstevel@tonic-gate 		 * entire CMP is marked as configured.
7627c478bd9Sstevel@tonic-gate 		 */
7637c478bd9Sstevel@tonic-gate 		if (csp[core].cs_ostate == SBD_STAT_CONFIGURED) {
7647c478bd9Sstevel@tonic-gate 			psp->ps_ostate = csp[core].cs_ostate;
7657c478bd9Sstevel@tonic-gate 		}
7667c478bd9Sstevel@tonic-gate 	}
7677c478bd9Sstevel@tonic-gate }
7687c478bd9Sstevel@tonic-gate 
7697c478bd9Sstevel@tonic-gate int
7707c478bd9Sstevel@tonic-gate dr_cpu_status(dr_handle_t *hp, dr_devset_t devset, sbd_dev_stat_t *dsp)
7717c478bd9Sstevel@tonic-gate {
7727c478bd9Sstevel@tonic-gate 	int		cmp;
7737c478bd9Sstevel@tonic-gate 	int		core;
7747c478bd9Sstevel@tonic-gate 	int		ncpu;
7757c478bd9Sstevel@tonic-gate 	dr_board_t	*bp;
7767c478bd9Sstevel@tonic-gate 	sbd_cpu_stat_t	cstat[MAX_CORES_PER_CMP];
77725cf1a30Sjl139090 	int		impl;
7787c478bd9Sstevel@tonic-gate 
7797c478bd9Sstevel@tonic-gate 	bp = hp->h_bd;
7807c478bd9Sstevel@tonic-gate 	ncpu = 0;
7817c478bd9Sstevel@tonic-gate 
7827c478bd9Sstevel@tonic-gate 	devset &= DR_DEVS_PRESENT(bp);
7837c478bd9Sstevel@tonic-gate 
7847c478bd9Sstevel@tonic-gate 	/*
7857c478bd9Sstevel@tonic-gate 	 * Treat every CPU as a CMP. In the case where the
7867c478bd9Sstevel@tonic-gate 	 * device is not a CMP, treat it as a CMP with only
7877c478bd9Sstevel@tonic-gate 	 * one core.
7887c478bd9Sstevel@tonic-gate 	 */
7897c478bd9Sstevel@tonic-gate 	for (cmp = 0; cmp < MAX_CMP_UNITS_PER_BOARD; cmp++) {
7907c478bd9Sstevel@tonic-gate 
7917c478bd9Sstevel@tonic-gate 		int		ncores;
7927c478bd9Sstevel@tonic-gate 		dr_cpu_unit_t	*cp;
7937c478bd9Sstevel@tonic-gate 		drmach_status_t	pstat;
7947c478bd9Sstevel@tonic-gate 		sbd_error_t	*err;
7957c478bd9Sstevel@tonic-gate 		sbd_cmp_stat_t	*psp;
7967c478bd9Sstevel@tonic-gate 
7977c478bd9Sstevel@tonic-gate 		if ((devset & DEVSET(SBD_COMP_CMP, cmp)) == 0) {
7987c478bd9Sstevel@tonic-gate 			continue;
7997c478bd9Sstevel@tonic-gate 		}
8007c478bd9Sstevel@tonic-gate 
8017c478bd9Sstevel@tonic-gate 		ncores = 0;
8027c478bd9Sstevel@tonic-gate 
8037c478bd9Sstevel@tonic-gate 		for (core = 0; core < MAX_CORES_PER_CMP; core++) {
8047c478bd9Sstevel@tonic-gate 
8057c478bd9Sstevel@tonic-gate 			cp = dr_get_cpu_unit(bp, DR_CMP_CORE_UNUM(cmp, core));
8067c478bd9Sstevel@tonic-gate 
8077c478bd9Sstevel@tonic-gate 			if (cp->sbc_cm.sbdev_state == DR_STATE_EMPTY) {
8087c478bd9Sstevel@tonic-gate 				/* present, but not fully initialized */
8097c478bd9Sstevel@tonic-gate 				continue;
8107c478bd9Sstevel@tonic-gate 			}
8117c478bd9Sstevel@tonic-gate 
8127c478bd9Sstevel@tonic-gate 			ASSERT(dr_cpu_unit_is_sane(hp->h_bd, cp));
8137c478bd9Sstevel@tonic-gate 
8147c478bd9Sstevel@tonic-gate 			/* skip if not present */
8157c478bd9Sstevel@tonic-gate 			if (cp->sbc_cm.sbdev_id == (drmachid_t)0) {
8167c478bd9Sstevel@tonic-gate 				continue;
8177c478bd9Sstevel@tonic-gate 			}
8187c478bd9Sstevel@tonic-gate 
8197c478bd9Sstevel@tonic-gate 			/* fetch platform status */
8207c478bd9Sstevel@tonic-gate 			err = drmach_status(cp->sbc_cm.sbdev_id, &pstat);
8217c478bd9Sstevel@tonic-gate 			if (err) {
8227c478bd9Sstevel@tonic-gate 				DRERR_SET_C(&cp->sbc_cm.sbdev_error, &err);
8237c478bd9Sstevel@tonic-gate 				continue;
8247c478bd9Sstevel@tonic-gate 			}
8257c478bd9Sstevel@tonic-gate 
8267c478bd9Sstevel@tonic-gate 			dr_fill_cpu_stat(cp, &pstat, &cstat[ncores++]);
82725cf1a30Sjl139090 			/*
82825cf1a30Sjl139090 			 * We should set impl here because the last core
82925cf1a30Sjl139090 			 * found might be EMPTY or not present.
83025cf1a30Sjl139090 			 */
83125cf1a30Sjl139090 			impl = cp->sbc_cpu_impl;
8327c478bd9Sstevel@tonic-gate 		}
8337c478bd9Sstevel@tonic-gate 
8347c478bd9Sstevel@tonic-gate 		if (ncores == 0) {
8357c478bd9Sstevel@tonic-gate 			continue;
8367c478bd9Sstevel@tonic-gate 		}
8377c478bd9Sstevel@tonic-gate 
8387c478bd9Sstevel@tonic-gate 		/*
8397c478bd9Sstevel@tonic-gate 		 * Store the data to the outgoing array. If the
8407c478bd9Sstevel@tonic-gate 		 * device is a CMP, combine all the data for the
8417c478bd9Sstevel@tonic-gate 		 * cores into a single stat structure.
8427c478bd9Sstevel@tonic-gate 		 *
8437c478bd9Sstevel@tonic-gate 		 * The check for a CMP device uses the last core
8447c478bd9Sstevel@tonic-gate 		 * found, assuming that all cores will have the
8457c478bd9Sstevel@tonic-gate 		 * same implementation.
8467c478bd9Sstevel@tonic-gate 		 */
84725cf1a30Sjl139090 
84825cf1a30Sjl139090 		if (CPU_IMPL_IS_CMP(impl)) {
8497c478bd9Sstevel@tonic-gate 			psp = (sbd_cmp_stat_t *)dsp;
85025cf1a30Sjl139090 			dr_fill_cmp_stat(cstat, ncores, impl, psp);
8517c478bd9Sstevel@tonic-gate 		} else {
8527c478bd9Sstevel@tonic-gate 			ASSERT(ncores == 1);
8537c478bd9Sstevel@tonic-gate 			bcopy(cstat, dsp, sizeof (sbd_cpu_stat_t));
8547c478bd9Sstevel@tonic-gate 		}
8557c478bd9Sstevel@tonic-gate 
8567c478bd9Sstevel@tonic-gate 		dsp++;
8577c478bd9Sstevel@tonic-gate 		ncpu++;
8587c478bd9Sstevel@tonic-gate 	}
8597c478bd9Sstevel@tonic-gate 
8607c478bd9Sstevel@tonic-gate 	return (ncpu);
8617c478bd9Sstevel@tonic-gate }
8627c478bd9Sstevel@tonic-gate 
8637c478bd9Sstevel@tonic-gate /*
8647c478bd9Sstevel@tonic-gate  * Cancel previous release operation for cpu.
8657c478bd9Sstevel@tonic-gate  * For cpus this means simply bringing cpus that
8667c478bd9Sstevel@tonic-gate  * were offline back online.  Note that they had
8677c478bd9Sstevel@tonic-gate  * to have been online at the time there were
8687c478bd9Sstevel@tonic-gate  * released.
8697c478bd9Sstevel@tonic-gate  */
8707c478bd9Sstevel@tonic-gate int
8717c478bd9Sstevel@tonic-gate dr_cancel_cpu(dr_cpu_unit_t *up)
8727c478bd9Sstevel@tonic-gate {
8737c478bd9Sstevel@tonic-gate 	int		rv = 0;
8747c478bd9Sstevel@tonic-gate 	static fn_t	f = "dr_cancel_cpu";
8757c478bd9Sstevel@tonic-gate 
8767c478bd9Sstevel@tonic-gate 	ASSERT(dr_cpu_unit_is_sane(up->sbc_cm.sbdev_bp, up));
8777c478bd9Sstevel@tonic-gate 
8787c478bd9Sstevel@tonic-gate 	if (cpu_flagged_active(up->sbc_cpu_flags)) {
8797c478bd9Sstevel@tonic-gate 		struct cpu	*cp;
8807c478bd9Sstevel@tonic-gate 
8817c478bd9Sstevel@tonic-gate 		/*
8827c478bd9Sstevel@tonic-gate 		 * CPU had been online, go ahead
8837c478bd9Sstevel@tonic-gate 		 * bring it back online.
8847c478bd9Sstevel@tonic-gate 		 */
885e98fafb9Sjl139090 		PR_CPU("%s: bringing cpu %d back ONLINE\n", f, up->sbc_cpu_id);
8867c478bd9Sstevel@tonic-gate 
8877c478bd9Sstevel@tonic-gate 		mutex_enter(&cpu_lock);
8887c478bd9Sstevel@tonic-gate 		cp = cpu[up->sbc_cpu_id];
8897c478bd9Sstevel@tonic-gate 
8907c478bd9Sstevel@tonic-gate 		if (cpu_is_poweredoff(cp)) {
8917c478bd9Sstevel@tonic-gate 			if (cpu_poweron(cp)) {
8927c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN, "%s: failed to power-on "
8937c478bd9Sstevel@tonic-gate 				    "cpu %d", f, up->sbc_cpu_id);
8947c478bd9Sstevel@tonic-gate 				rv = -1;
8957c478bd9Sstevel@tonic-gate 			}
8967c478bd9Sstevel@tonic-gate 		}
8977c478bd9Sstevel@tonic-gate 
8987c478bd9Sstevel@tonic-gate 		if (cpu_is_offline(cp)) {
8997c478bd9Sstevel@tonic-gate 			if (cpu_online(cp)) {
9007c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN, "%s: failed to online cpu %d",
9017c478bd9Sstevel@tonic-gate 				    f, up->sbc_cpu_id);
9027c478bd9Sstevel@tonic-gate 				rv = -1;
9037c478bd9Sstevel@tonic-gate 			}
9047c478bd9Sstevel@tonic-gate 		}
9057c478bd9Sstevel@tonic-gate 
9067c478bd9Sstevel@tonic-gate 		if (cpu_is_online(cp)) {
9077c478bd9Sstevel@tonic-gate 			if (cpu_flagged_nointr(up->sbc_cpu_flags)) {
9087c478bd9Sstevel@tonic-gate 				if (cpu_intr_disable(cp) != 0) {
9097c478bd9Sstevel@tonic-gate 					cmn_err(CE_WARN, "%s: failed to "
910e98fafb9Sjl139090 					    "disable interrupts on cpu %d", f,
911e98fafb9Sjl139090 					    up->sbc_cpu_id);
9127c478bd9Sstevel@tonic-gate 				}
9137c478bd9Sstevel@tonic-gate 			}
9147c478bd9Sstevel@tonic-gate 		}
9157c478bd9Sstevel@tonic-gate 
9167c478bd9Sstevel@tonic-gate 		mutex_exit(&cpu_lock);
9177c478bd9Sstevel@tonic-gate 	}
9187c478bd9Sstevel@tonic-gate 
9197c478bd9Sstevel@tonic-gate 	return (rv);
9207c478bd9Sstevel@tonic-gate }
9217c478bd9Sstevel@tonic-gate 
9227c478bd9Sstevel@tonic-gate int
9237c478bd9Sstevel@tonic-gate dr_disconnect_cpu(dr_cpu_unit_t *up)
9247c478bd9Sstevel@tonic-gate {
9257c478bd9Sstevel@tonic-gate 	sbd_error_t	*err;
9267c478bd9Sstevel@tonic-gate 	static fn_t	f = "dr_disconnect_cpu";
9277c478bd9Sstevel@tonic-gate 
9287c478bd9Sstevel@tonic-gate 	PR_CPU("%s...\n", f);
9297c478bd9Sstevel@tonic-gate 
9307c478bd9Sstevel@tonic-gate 	ASSERT((up->sbc_cm.sbdev_state == DR_STATE_CONNECTED) ||
9317c478bd9Sstevel@tonic-gate 	    (up->sbc_cm.sbdev_state == DR_STATE_UNCONFIGURED));
9327c478bd9Sstevel@tonic-gate 
9337c478bd9Sstevel@tonic-gate 	ASSERT(dr_cpu_unit_is_sane(up->sbc_cm.sbdev_bp, up));
9347c478bd9Sstevel@tonic-gate 
9357c478bd9Sstevel@tonic-gate 	if (up->sbc_cm.sbdev_state == DR_STATE_CONNECTED) {
9367c478bd9Sstevel@tonic-gate 		/*
9377c478bd9Sstevel@tonic-gate 		 * Cpus were never brought in and so are still
9387c478bd9Sstevel@tonic-gate 		 * effectively disconnected, so nothing to do here.
9397c478bd9Sstevel@tonic-gate 		 */
940e98fafb9Sjl139090 		PR_CPU("%s: cpu %d never brought in\n", f, up->sbc_cpu_id);
9417c478bd9Sstevel@tonic-gate 		return (0);
9427c478bd9Sstevel@tonic-gate 	}
9437c478bd9Sstevel@tonic-gate 
9447c478bd9Sstevel@tonic-gate 	err = drmach_cpu_disconnect(up->sbc_cm.sbdev_id);
9457c478bd9Sstevel@tonic-gate 	if (err == NULL)
9467c478bd9Sstevel@tonic-gate 		return (0);
9477c478bd9Sstevel@tonic-gate 	else {
9487c478bd9Sstevel@tonic-gate 		DRERR_SET_C(&up->sbc_cm.sbdev_error, &err);
9497c478bd9Sstevel@tonic-gate 		return (-1);
9507c478bd9Sstevel@tonic-gate 	}
9517c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
9527c478bd9Sstevel@tonic-gate }
953