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